From 7ef75723019f8be32f99c91321f0ff445345d8d2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jo=C3=A3o=20Duarte?= Date: Wed, 6 Feb 2019 15:05:12 +0000 Subject: [PATCH 0001/1126] bump version to 7.1.0 (#10402) --- README.md | 16 ++++++++-------- docs/index.asciidoc | 8 ++++---- versions.yml | 4 ++-- 3 files changed, 14 insertions(+), 14 deletions(-) diff --git a/README.md b/README.md index ceeccd624..f77e47aca 100644 --- a/README.md +++ b/README.md @@ -28,14 +28,14 @@ These builds are created nightly and have undergone no formal QA, so they should | [deb-complete][] | [deb-oss][] | | [rpm-complete][] | [rpm-oss][] | -[tar-complete]: https://snapshots.elastic.co/downloads/logstash/logstash-7.0.0-SNAPSHOT.tar.gz -[zip-complete]: https://snapshots.elastic.co/downloads/logstash/logstash-7.0.0-SNAPSHOT.zip -[deb-complete]: https://snapshots.elastic.co/downloads/logstash/logstash-7.0.0-SNAPSHOT.deb -[rpm-complete]: https://snapshots.elastic.co/downloads/logstash/logstash-7.0.0-SNAPSHOT.rpm -[tar-oss]: https://snapshots.elastic.co/downloads/logstash/logstash-oss-7.0.0-SNAPSHOT.tar.gz -[zip-oss]: https://snapshots.elastic.co/downloads/logstash/logstash-oss-7.0.0-SNAPSHOT.zip -[deb-oss]: https://snapshots.elastic.co/downloads/logstash/logstash-oss-7.0.0-SNAPSHOT.deb -[rpm-oss]: https://snapshots.elastic.co/downloads/logstash/logstash-oss-7.0.0-SNAPSHOT.rpm +[tar-complete]: https://snapshots.elastic.co/downloads/logstash/logstash-7.1.0-SNAPSHOT.tar.gz +[zip-complete]: https://snapshots.elastic.co/downloads/logstash/logstash-7.1.0-SNAPSHOT.zip +[deb-complete]: https://snapshots.elastic.co/downloads/logstash/logstash-7.1.0-SNAPSHOT.deb +[rpm-complete]: https://snapshots.elastic.co/downloads/logstash/logstash-7.1.0-SNAPSHOT.rpm +[tar-oss]: https://snapshots.elastic.co/downloads/logstash/logstash-oss-7.1.0-SNAPSHOT.tar.gz +[zip-oss]: https://snapshots.elastic.co/downloads/logstash/logstash-oss-7.1.0-SNAPSHOT.zip +[deb-oss]: https://snapshots.elastic.co/downloads/logstash/logstash-oss-7.1.0-SNAPSHOT.deb +[rpm-oss]: https://snapshots.elastic.co/downloads/logstash/logstash-oss-7.1.0-SNAPSHOT.rpm ## Need Help? diff --git a/docs/index.asciidoc b/docs/index.asciidoc index ea2d01af1..2673ce1da 100644 --- a/docs/index.asciidoc +++ b/docs/index.asciidoc @@ -8,16 +8,16 @@ :plugins-repo-dir: {docdir}/../../logstash-docs/docs :branch: master :major-version: 7.x -:logstash_version: 7.0.0-alpha2 -:elasticsearch_version: 7.0.0-alpha2 -:kibana_version: 7.0.0-alpha2 +:logstash_version: 7.1.0 +:elasticsearch_version: 7.1.0 +:kibana_version: 7.1.0 :docker-repo: docker.elastic.co/logstash/logstash :docker-image: {docker-repo}:{logstash_version} ////////// release-state can be: released | prerelease | unreleased ////////// -:release-state: prerelease +:release-state: unreleased :versioned_docs: false :jdk: 1.8.0 diff --git a/versions.yml b/versions.yml index b1d44ae95..2f3c3e969 100644 --- a/versions.yml +++ b/versions.yml @@ -1,7 +1,7 @@ --- # alpha and beta qualifiers are now added via VERSION_QUALIFIER environment var -logstash: 7.0.0 -logstash-core: 7.0.0 +logstash: 7.1.0 +logstash-core: 7.1.0 logstash-core-plugin-api: 2.1.16 # jruby must reference a *released* version of jruby which can be downloaded from the official download url From 0e4ab8a784eb50391738b710d94fc42bf28f14c7 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jo=C3=A3o=20Duarte?= Date: Wed, 6 Feb 2019 17:59:05 +0000 Subject: [PATCH 0002/1126] Update :branch: property in 7.x index.asciidoc (#10403) --- docs/index.asciidoc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/index.asciidoc b/docs/index.asciidoc index 2673ce1da..0c329f0b9 100644 --- a/docs/index.asciidoc +++ b/docs/index.asciidoc @@ -6,7 +6,7 @@ :xls-repo-dir: {docdir}/../x-pack/docs/{lang} :log-repo-dir: {docdir} :plugins-repo-dir: {docdir}/../../logstash-docs/docs -:branch: master +:branch: 7.x :major-version: 7.x :logstash_version: 7.1.0 :elasticsearch_version: 7.1.0 From 009e764c103babd4f4c28e6548cfb250fdbffe02 Mon Sep 17 00:00:00 2001 From: Ry Biesemeyer Date: Wed, 6 Feb 2019 19:55:47 +0000 Subject: [PATCH 0003/1126] keystore: instances of `CharsetEncoder` are stateful and cannot be shared Fixes a crash that occurs on pipeline load and/or reload when using both the java keystore and the multi-pipeline feature, when more than one pipeline references `${}`-style variables. Fixes #10408 --- .../java/org/logstash/secret/store/backend/JavaKeyStore.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/logstash-core/src/main/java/org/logstash/secret/store/backend/JavaKeyStore.java b/logstash-core/src/main/java/org/logstash/secret/store/backend/JavaKeyStore.java index 90c64c165..b0424ff58 100644 --- a/logstash-core/src/main/java/org/logstash/secret/store/backend/JavaKeyStore.java +++ b/logstash-core/src/main/java/org/logstash/secret/store/backend/JavaKeyStore.java @@ -41,7 +41,7 @@ public final class JavaKeyStore implements SecretStore { private static final String KEYSTORE_TYPE = "pkcs12"; private static final Logger LOGGER = LogManager.getLogger(JavaKeyStore.class); private static final String PATH_KEY = "keystore.file"; - private static final CharsetEncoder asciiEncoder = StandardCharsets.US_ASCII.newEncoder(); + private final CharsetEncoder asciiEncoder = StandardCharsets.US_ASCII.newEncoder(); private KeyStore keyStore; private char[] keyStorePass; private Path keyStorePath; From 1437cdc2073e4ffa07d94d9f73c91470418edd6f Mon Sep 17 00:00:00 2001 From: Joao Duarte Date: Thu, 7 Feb 2019 11:10:50 +0000 Subject: [PATCH 0004/1126] pin childprocess to 0.9 Fixes #10410 --- Gemfile.template | 1 + 1 file changed, 1 insertion(+) diff --git a/Gemfile.template b/Gemfile.template index 8795c6816..f7b5e56ae 100644 --- a/Gemfile.template +++ b/Gemfile.template @@ -15,6 +15,7 @@ gem "octokit", "~> 4", :group => :build gem "stud", "~> 0.0.22", :group => :build gem "rack-test", :require => "rack/test", :group => :development gem "fpm", "~> 1.3.3", :group => :build +gem "childprocess", "~> 0.9", :group => :build gem "rubyzip", "~> 1", :group => :build gem "gems", "~> 1", :group => :build gem "flores", "~> 0.0.6", :group => :development From 29280c15279a489e0ee09244693661ea5048484c Mon Sep 17 00:00:00 2001 From: Joao Duarte Date: Thu, 7 Feb 2019 14:18:12 +0000 Subject: [PATCH 0005/1126] mute metrics_spec line 138 test Fixes #10412 --- x-pack/spec/monitoring/inputs/metrics_spec.rb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/x-pack/spec/monitoring/inputs/metrics_spec.rb b/x-pack/spec/monitoring/inputs/metrics_spec.rb index b94ebd334..5ca0e9ac4 100644 --- a/x-pack/spec/monitoring/inputs/metrics_spec.rb +++ b/x-pack/spec/monitoring/inputs/metrics_spec.rb @@ -135,7 +135,7 @@ describe LogStash::Inputs::Metrics do let(:schema_file) { File.join(schemas_path, "monitoring_document_schema.json") } describe "data event" do - it "has the correct schema" do + xit "has the correct schema" do wait(60).for { stats_events }.to_not be_empty expect(JSON::Validator.fully_validate(schema_file, stats_events.first.to_json)).to be_empty end From 0ebbb394930d73cc3133155e262fb821a59dec23 Mon Sep 17 00:00:00 2001 From: Rob Bavey Date: Thu, 7 Feb 2019 11:04:59 -0500 Subject: [PATCH 0006/1126] Better handle malformed URIs Raise an error if a URI has inadvertently been supplied without a host Fixes #10414 --- logstash-core/lib/logstash/util/safe_uri.rb | 3 +- .../spec/logstash/util/safe_uri_spec.rb | 78 +++++++++++++++++++ 2 files changed, 80 insertions(+), 1 deletion(-) diff --git a/logstash-core/lib/logstash/util/safe_uri.rb b/logstash-core/lib/logstash/util/safe_uri.rb index 0513833ac..736711ebb 100644 --- a/logstash-core/lib/logstash/util/safe_uri.rb +++ b/logstash-core/lib/logstash/util/safe_uri.rb @@ -14,7 +14,7 @@ class LogStash::Util::SafeURI attr_reader :uri public - def initialize(arg) + def initialize(arg, requires_host=true) @uri = case arg when String arg = "//#{arg}" if HOSTNAME_PORT_REGEX.match(arg) @@ -26,6 +26,7 @@ class LogStash::Util::SafeURI else raise ArgumentError, "Expected a string, java.net.URI, or URI, got a #{arg.class} creating a URL" end + raise ArgumentError, "URI is not valid - host is not specified" if requires_host && @uri.host.nil? end def to_s diff --git a/logstash-core/spec/logstash/util/safe_uri_spec.rb b/logstash-core/spec/logstash/util/safe_uri_spec.rb index 12962ccff..83cccd160 100644 --- a/logstash-core/spec/logstash/util/safe_uri_spec.rb +++ b/logstash-core/spec/logstash/util/safe_uri_spec.rb @@ -32,5 +32,83 @@ module LogStash module Util end end end + + describe "#initialize" do + context 'when host is required' do + MALFORMED_URIS = ['http:/user:pass@localhost:9600', 'http:/localhost', 'http:/localhost:9600', 'h;localhost', 'http:://localhost'] + + context 'malformed uris via string' do + MALFORMED_URIS.each do |arg| + it "#{arg}: should raise an error" do + expect{LogStash::Util::SafeURI.new(arg)}.to raise_error(ArgumentError) + end + end + end + + context 'malformed uris via java.net.URI' do + MALFORMED_URIS.each do |arg| + it "#{arg}: should raise an error" do + java_uri = java.net.URI.new(arg) + expect{LogStash::Util::SafeURI.new(java_uri)}.to raise_error(ArgumentError) + end + end + end + + context 'malformed uris via Ruby URI' do + MALFORMED_URIS.each do |arg| + it "#{arg}: should raise an error" do + ruby_uri = URI.parse(arg) + expect{LogStash::Util::SafeURI.new(ruby_uri)}.to raise_error(ArgumentError) + end + end + end + + context 'uris with a valid host' do + ['http://user:pass@notlocalhost:9600', 'http://notlocalhost', 'https://notlocalhost:9600', '//notlocalhost', 'notlocalhost', 'notlocalhost:9200'].each do |arg| + it "#{arg}: should resolve host correctly" do + expect(LogStash::Util::SafeURI.new(arg).host).to eq('notlocalhost') + end + end + end + end + + context 'when host is not required' do + MALFORMED_URIS = ['http:/user:pass@localhost:9600', 'http:/localhost', 'http:/localhost:9600', 'h;localhost', 'http:://localhost'] + + context 'malformed uris via string' do + MALFORMED_URIS.each do |arg| + it "#{arg}: should not raise an error" do + expect{LogStash::Util::SafeURI.new(arg, false)}.not_to raise_error + end + end + end + + context 'malformed uris via java.net.URI' do + MALFORMED_URIS.each do |arg| + it "#{arg}: should not raise an error" do + java_uri = java.net.URI.new(arg) + expect{LogStash::Util::SafeURI.new(java_uri, false)}.not_to raise_error + end + end + end + + context 'malformed uris via Ruby URI' do + MALFORMED_URIS.each do |arg| + it "#{arg}: should not raise an error" do + ruby_uri = URI.parse(arg) + expect{LogStash::Util::SafeURI.new(ruby_uri, false)}.not_to raise_error + end + end + end + + context 'uris with a valid host' do + ['http://user:pass@notlocalhost:9600', 'http://notlocalhost', 'https://notlocalhost:9600', '//notlocalhost', 'notlocalhost', 'notlocalhost:9200'].each do |arg| + it "#{arg}: should resolve host correctly" do + expect(LogStash::Util::SafeURI.new(arg, false).host).to eq('notlocalhost') + end + end + end + end + end end end end From 92779178759027a5f4c57e0697bc2a7a90704943 Mon Sep 17 00:00:00 2001 From: Rob Bavey Date: Thu, 7 Feb 2019 12:38:56 -0500 Subject: [PATCH 0007/1126] Remove unnecessary option to not require host in SafeURI Fixes #10414 --- logstash-core/lib/logstash/util/safe_uri.rb | 4 +- .../spec/logstash/util/safe_uri_spec.rb | 38 ------------------- 2 files changed, 2 insertions(+), 40 deletions(-) diff --git a/logstash-core/lib/logstash/util/safe_uri.rb b/logstash-core/lib/logstash/util/safe_uri.rb index 736711ebb..29952a29d 100644 --- a/logstash-core/lib/logstash/util/safe_uri.rb +++ b/logstash-core/lib/logstash/util/safe_uri.rb @@ -14,7 +14,7 @@ class LogStash::Util::SafeURI attr_reader :uri public - def initialize(arg, requires_host=true) + def initialize(arg) @uri = case arg when String arg = "//#{arg}" if HOSTNAME_PORT_REGEX.match(arg) @@ -26,7 +26,7 @@ class LogStash::Util::SafeURI else raise ArgumentError, "Expected a string, java.net.URI, or URI, got a #{arg.class} creating a URL" end - raise ArgumentError, "URI is not valid - host is not specified" if requires_host && @uri.host.nil? + raise ArgumentError, "URI is not valid - host is not specified" if @uri.host.nil? end def to_s diff --git a/logstash-core/spec/logstash/util/safe_uri_spec.rb b/logstash-core/spec/logstash/util/safe_uri_spec.rb index 83cccd160..478fabec3 100644 --- a/logstash-core/spec/logstash/util/safe_uri_spec.rb +++ b/logstash-core/spec/logstash/util/safe_uri_spec.rb @@ -71,44 +71,6 @@ module LogStash module Util end end end - - context 'when host is not required' do - MALFORMED_URIS = ['http:/user:pass@localhost:9600', 'http:/localhost', 'http:/localhost:9600', 'h;localhost', 'http:://localhost'] - - context 'malformed uris via string' do - MALFORMED_URIS.each do |arg| - it "#{arg}: should not raise an error" do - expect{LogStash::Util::SafeURI.new(arg, false)}.not_to raise_error - end - end - end - - context 'malformed uris via java.net.URI' do - MALFORMED_URIS.each do |arg| - it "#{arg}: should not raise an error" do - java_uri = java.net.URI.new(arg) - expect{LogStash::Util::SafeURI.new(java_uri, false)}.not_to raise_error - end - end - end - - context 'malformed uris via Ruby URI' do - MALFORMED_URIS.each do |arg| - it "#{arg}: should not raise an error" do - ruby_uri = URI.parse(arg) - expect{LogStash::Util::SafeURI.new(ruby_uri, false)}.not_to raise_error - end - end - end - - context 'uris with a valid host' do - ['http://user:pass@notlocalhost:9600', 'http://notlocalhost', 'https://notlocalhost:9600', '//notlocalhost', 'notlocalhost', 'notlocalhost:9200'].each do |arg| - it "#{arg}: should resolve host correctly" do - expect(LogStash::Util::SafeURI.new(arg, false).host).to eq('notlocalhost') - end - end - end - end end end end end From cfeaa5411564ebf4086c3bf548bd88bc1df3c90c Mon Sep 17 00:00:00 2001 From: Ry Biesemeyer Date: Thu, 7 Feb 2019 18:53:13 +0000 Subject: [PATCH 0008/1126] ast/lir: simplify concurrent use of AST, which is globally stateful Fixes #10415 --- .../lib/logstash/config/config_ast.rb | 76 ++++++++++++++----- 1 file changed, 59 insertions(+), 17 deletions(-) diff --git a/logstash-core/lib/logstash/config/config_ast.rb b/logstash-core/lib/logstash/config/config_ast.rb index 5e796475b..1d0019616 100644 --- a/logstash-core/lib/logstash/config/config_ast.rb +++ b/logstash-core/lib/logstash/config/config_ast.rb @@ -7,28 +7,60 @@ require "logstash/compiler/treetop_monkeypatches" module LogStash; module Config; module AST PROCESS_ESCAPE_SEQUENCES = :process_escape_sequences - def self.deferred_conditionals=(val) - @deferred_conditionals = val - end + class << self + # @api private + MUTEX = Mutex.new - def self.deferred_conditionals - @deferred_conditionals - end + # Executes the given block with exclusive access to the AST global variables + # + # @yieldreturn [Object]: the object that is returned from the block is returned by this method + # + # @return [Object] + def exclusive + MUTEX.synchronize { yield } + end - def self.deferred_conditionals_index - @deferred_conditionals_index - end + def deferred_conditionals=(val) + ensure_exclusive! + @deferred_conditionals = val + end - def self.deferred_conditionals_index=(val) - @deferred_conditionals_index = val - end + def deferred_conditionals + ensure_exclusive! + @deferred_conditionals + end - def self.plugin_instance_index - @plugin_instance_index - end + def deferred_conditionals_index + ensure_exclusive! + @deferred_conditionals_index + end - def self.plugin_instance_index=(val) - @plugin_instance_index = val + def deferred_conditionals_index=(val) + ensure_exclusive! + @deferred_conditionals_index = val + end + + def plugin_instance_index + ensure_exclusive! + @plugin_instance_index + end + + def plugin_instance_index=(val) + ensure_exclusive! + @plugin_instance_index = val + end + + private + + # Raises a descriptive error if the thread in which it is invoked does + # not have exclusive access. + # + # @raise [RuntimeError] + def ensure_exclusive! + return if MUTEX.owned? + + raise "Illegal access without exclusive lock at `#{caller[1]}`" + end end class Node < Treetop::Runtime::SyntaxNode @@ -46,6 +78,15 @@ module LogStash; module Config; module AST def compile + LogStash::Config::AST.exclusive { do_compile } + end + + private + + # NON-threadsafe method compiles an AST into executable Ruby code. + # @see Config#compile, which is a threadsafe wrapper around this method. + # @api private + def do_compile LogStash::Config::AST.deferred_conditionals = [] LogStash::Config::AST.deferred_conditionals_index = 0 LogStash::Config::AST.plugin_instance_index = 0 @@ -491,6 +532,7 @@ module LogStash; module Config; module AST end; end; end + # Monkeypatch Treetop::Runtime::SyntaxNode's inspect method to skip # any Whitespace or SyntaxNodes with no children. class Treetop::Runtime::SyntaxNode From 42c63b75df2a26143f7b602ae3d19a726728400a Mon Sep 17 00:00:00 2001 From: Joao Duarte Date: Fri, 8 Feb 2019 23:09:12 +0000 Subject: [PATCH 0009/1126] factor in OS and architecture when downloading ES - use artifacts api to fetch latest build - use latest build info to find download url - download package Fixes #10422 --- build.gradle | 31 ++++++++++++++++++++++++++++--- 1 file changed, 28 insertions(+), 3 deletions(-) diff --git a/build.gradle b/build.gradle index 5086ea303..5ea084509 100644 --- a/build.gradle +++ b/build.gradle @@ -431,8 +431,33 @@ def dlVersions = new JsonSlurper().parseText(apiResponse) // in the build invoked by the release manager it is '7.0.0-alpha1' etc. // the artifacts-api will return JSON like this: `{"versions":["5.6.13-SNAPSHOT","6.4.3-SNAPSHOT","6.5.0-SNAPSHOT","6.6.0-SNAPSHOT","7.0.0-alpha1-SNAPSHOT"]}` String qualifiedVersion = dlVersions['versions'].grep(~/^${version}.*/)[0] -String downloadedElasticsearchName = "elasticsearch-${qualifiedVersion}" -String elasticsearchSnapshotURL = System.getenv("ELASTICSEARCH_SNAPSHOT_URL") ?: "https://snapshots.elastic.co/downloads/elasticsearch/${downloadedElasticsearchName}.tar.gz" + +String arch = "x86_64" +String osName = System.properties['os.name'] + +if (osName ==~ /Mac OS X/) { + osName = "darwin" +} else { + osName = "linux" +} + +String architecture = "${osName}-${arch}" + +String downloadedElasticsearchName = "elasticsearch-${qualifiedVersion}-${architecture}" +String unpackedElasticsearchName = "elasticsearch-${qualifiedVersion}" + +// find latest reference to last build +String buildsListApi = "https://artifacts-api.elastic.co/v1/versions/${qualifiedVersion}/builds/" +apiResponse = buildsListApi.toURL().text +def dlBuilds = new JsonSlurper().parseText(apiResponse) +String build = dlBuilds["builds"][0] + +// find url of build artifact +String artifactApiUrl = "https://artifacts-api.elastic.co/v1/versions/${qualifiedVersion}/builds/${build}/projects/elasticsearch/packages/${downloadedElasticsearchName}.tar.gz" +apiResponse = artifactApiUrl.toURL().text +def buildUrls = new JsonSlurper().parseText(apiResponse) + +String elasticsearchSnapshotURL = System.getenv("ELASTICSEARCH_SNAPSHOT_URL") ?: buildUrls["package"]["url"] String elasticsearchDownloadLocation = "${projectDir}/build/${downloadedElasticsearchName}.tar.gz" task downloadEs(type: Download) { @@ -460,7 +485,7 @@ task copyEs(type: Copy, dependsOn: [downloadEs, deleteLocalEs]) { from tarTree(resources.gzip(elasticsearchDownloadLocation)) into "./build/" doLast { - file("./build/${downloadedElasticsearchName}").renameTo('./build/elasticsearch') + file("./build/${unpackedElasticsearchName}").renameTo('./build/elasticsearch') } } From 22648332a642217da52296d81fe6cf5ef755f422 Mon Sep 17 00:00:00 2001 From: Karen Metts Date: Tue, 12 Feb 2019 10:31:33 -0500 Subject: [PATCH 0010/1126] Reorder files in index to unhide lost topics Add comment about placement of include Fixes #10429 --- docs/index.asciidoc | 13 ++++++++++--- 1 file changed, 10 insertions(+), 3 deletions(-) diff --git a/docs/index.asciidoc b/docs/index.asciidoc index 0c329f0b9..e7568a39b 100644 --- a/docs/index.asciidoc +++ b/docs/index.asciidoc @@ -101,9 +101,6 @@ include::static/upgrading.asciidoc[] :edit_url: https://github.com/elastic/logstash/edit/{branch}/docs/static/configuration.asciidoc include::static/configuration.asciidoc[] -:edit_url: https://github.com/elastic/logstash/edit/{branch}/docs/static/field-reference.asciidoc -include::static/field-reference.asciidoc[] - :edit_url: https://github.com/elastic/logstash/edit/{branch}/docs/static/multiple-pipelines.asciidoc include::static/multiple-pipelines.asciidoc[] @@ -125,6 +122,16 @@ include::static/ingest-convert.asciidoc[] :edit_url: https://github.com/elastic/logstash/edit/{branch}/docs/static/ls-ls-config.asciidoc include::static/ls-ls-config.asciidoc[] +:edit_url: https://github.com/elastic/logstash/edit/{branch}/docs/static/field-reference.asciidoc +include::static/field-reference.asciidoc[] + +//The `field-reference.asciidoc` file (included above) contains a +//`role="exclude"` attribute to pull in the topic and make it linkable in the LS +//Ref, but not appear in the main TOC. The `exclude`attribute was carrying +//forward for all subsequent topics under the `configuration.asciidoc` heading. +//This include should remain after includes for all other topics under the +//`Configuring Logstash` heading. + ifdef::include-xpack[] :edit_url: https://github.com/elastic/logstash/edit/{branch}/docs/static/management/configuring-centralized-pipelines.asciidoc include::static/management/configuring-centralized-pipelines.asciidoc[] From f87da37e1647e414da7c5dca52eb7fb17e5d1323 Mon Sep 17 00:00:00 2001 From: Karen Metts Date: Fri, 1 Feb 2019 18:01:12 -0500 Subject: [PATCH 0011/1126] Add http and memcached filters to lookup plugins Fixes #10376 --- docs/static/transforming-data.asciidoc | 24 ++++++++++++++++++++++-- 1 file changed, 22 insertions(+), 2 deletions(-) diff --git a/docs/static/transforming-data.asciidoc b/docs/static/transforming-data.asciidoc index cc2d67448..3888975c4 100644 --- a/docs/static/transforming-data.asciidoc +++ b/docs/static/transforming-data.asciidoc @@ -359,8 +359,22 @@ TIP: If you need help building grok patterns, try out the [[lookup-enrichment]] === Enriching Data with Lookups -The plugins described in this section are useful for enriching data with -additional info, such as GeoIP and user agent info. +These plugins can help you enriching data with +additional info, such as GeoIP and user agent info: + +* dns filter +* elasticsearch filter +* geoip filter +* http filter +* jdbc_static filter +* jdbc_streaming filter +* memcached filter +* translate filter +* useragent filter + +[float] +[[lookup-plugins]] +=== Lookup plugins <>:: @@ -450,6 +464,9 @@ For example: } -------------------------------------------------------------------------------- +<>:: + +Provides integration with external web services/REST APIs. <>:: @@ -554,6 +571,9 @@ filter { } -------------------------------------------------------------------------------- +<>:: + +Provides integration with external data in Memcached. <>:: From 257e3ce11729015f84f28172e80c5e3af1c48f7b Mon Sep 17 00:00:00 2001 From: Karen Metts Date: Mon, 4 Feb 2019 19:42:03 -0500 Subject: [PATCH 0012/1126] Expande descriptions Fixes #10376 --- docs/static/transforming-data.asciidoc | 65 +++++++++++++++++--------- 1 file changed, 44 insertions(+), 21 deletions(-) diff --git a/docs/static/transforming-data.asciidoc b/docs/static/transforming-data.asciidoc index 3888975c4..2001d3aba 100644 --- a/docs/static/transforming-data.asciidoc +++ b/docs/static/transforming-data.asciidoc @@ -443,30 +443,39 @@ For example: + [source,json] -------------------------------------------------------------------------------- - "geoip" => { - "timezone" => "Europe/Moscow", - "ip" => "83.149.9.216", - "latitude" => 55.7522, - "continent_code" => "EU", - "city_name" => "Moscow", - "country_code2" => "RU", - "country_name" => "Russia", - "dma_code" => nil, - "country_code3" => "RU", - "region_name" => "Moscow", - "location" => [ - [0] 37.6156, - [1] 55.7522 - ], - "postal_code" => "101194", - "longitude" => 37.6156, - "region_code" => "MOW" - } +filter { + geoip { + source => "clientip" + } +} -------------------------------------------------------------------------------- <>:: -Provides integration with external web services/REST APIs. +Integrates with external web services/REST APIs, and +enables lookup enrichment against any HTTP service or endpoint. +The <> is well suited to many enrichment use +cases, such as social APIs, sentiment APIs, security feed APIs, and business +service APIs. ++ +[source,txt] +----- +filter { + http { + url => "http://example.com" + verb => GET + body => { + "user-id" => "%{user}" + "api-key" => "%{api_key}" + } + body_format => "json" + headers => + "Content-type" => "application/json" + } + target_body => "new_field" + } +} +----- <>:: @@ -573,7 +582,21 @@ filter { <>:: -Provides integration with external data in Memcached. +Enables key/value lookup enrichment against a Memcached object caching system. +It supports both read (GET) and write (SET) operations. It is a notable addition +for security analytics use cases. For example, you can use this plugin to query +for a value, and set it if not found. ++ +[source,txt] +----- +filter { + memcached { + url => "http://example.com" + verb => GET + body => {TODO-complete example + } +} +----- <>:: From 907d2ba944a6b5832857cd2af6693f9c5c0eafff Mon Sep 17 00:00:00 2001 From: Karen Metts Date: Mon, 11 Feb 2019 12:42:15 -0500 Subject: [PATCH 0013/1126] Edits from review comments Fixes #10376 --- docs/static/transforming-data.asciidoc | 124 +++++++++++-------------- 1 file changed, 55 insertions(+), 69 deletions(-) diff --git a/docs/static/transforming-data.asciidoc b/docs/static/transforming-data.asciidoc index 2001d3aba..769578ab7 100644 --- a/docs/static/transforming-data.asciidoc +++ b/docs/static/transforming-data.asciidoc @@ -352,33 +352,34 @@ After the filter is applied, the event in the example will have these fields: * `bytes: 15824` * `duration: 0.043` -TIP: If you need help building grok patterns, try out the +TIP: If you need help building grok patterns, try the {kibana-ref}/xpack-grokdebugger.html[Grok Debugger]. The Grok Debugger is an {xpack} feature under the Basic License and is therefore *free to use*. + [[lookup-enrichment]] === Enriching Data with Lookups -These plugins can help you enriching data with +These plugins can help you enrich data with additional info, such as GeoIP and user agent info: -* dns filter -* elasticsearch filter -* geoip filter -* http filter -* jdbc_static filter -* jdbc_streaming filter -* memcached filter -* translate filter -* useragent filter +* <> +* <> +* <> +* <> +* <> +* <> +* <> +* <> +* <> [float] [[lookup-plugins]] === Lookup plugins -<>:: +[[dns-def]]dns filter:: -Performs a standard or reverse DNS lookup. +The <> performs a standard or reverse DNS lookup. + The following config performs a reverse lookup on the address in the `source_host` field and replaces it with the domain name: @@ -393,10 +394,9 @@ filter { } -------------------------------------------------------------------------------- +[[es-def]]elasticsearch filter:: -<>:: - -Copies fields from previous log events in Elasticsearch to current events. +The <> copies fields from previous log events in Elasticsearch to current events. + The following config shows a complete example of how this filter might be used. Whenever Logstash receives an "end" event, it uses this Elasticsearch @@ -420,14 +420,13 @@ between the two events. } ruby { code => 'event.set("duration_hrs", (event.get("@timestamp") - event.get("started")) / 3600) rescue nil' - } + } } -------------------------------------------------- +[[geoip-def]]geoip filter:: -<>:: - -Adds geographical information about the location of IP addresses. For example: +The <> adds geographical information about the location of IP addresses. For example: + [source,json] -------------------------------------------------------------------------------- @@ -450,36 +449,35 @@ filter { } -------------------------------------------------------------------------------- -<>:: +[[http-def]]http filter:: -Integrates with external web services/REST APIs, and -enables lookup enrichment against any HTTP service or endpoint. -The <> is well suited to many enrichment use -cases, such as social APIs, sentiment APIs, security feed APIs, and business -service APIs. -+ -[source,txt] ------ -filter { - http { - url => "http://example.com" - verb => GET - body => { - "user-id" => "%{user}" - "api-key" => "%{api_key}" - } - body_format => "json" - headers => - "Content-type" => "application/json" - } - target_body => "new_field" - } -} ------ +The <> integrates with external web +services/REST APIs, and enables lookup enrichment against any HTTP service or +endpoint. This plugin is well suited for many enrichment use cases, such as +social APIs, sentiment APIs, security feed APIs, and business service APIs. +//+ +//[source,txt] +//----- +//filter { +// http { +// url => "http://example.com" +// verb => GET +// body => { +// "user-id" => "%{user}" +// "api-key" => "%{api_key}" +// } +// body_format => "json" +// headers => +// "Content-type" => "application/json" +// } +// target_body => "new_field" +// } +//} +//----- -<>:: +[[jdbc-static-def]]jdbc_static filter:: -Enriches events with data pre-loaded from a remote database. +The <> enriches events with data pre-loaded from a remote database. + The following example fetches data from a remote database, caches it in a local database, and uses lookups to enrich events with data cached in the local @@ -557,9 +555,9 @@ returns multiple columns, the data is stored as a JSON object within the field. <5> Takes data from the JSON object and stores it in top-level event fields for easier analysis in Kibana. -<>:: +[[jdbc-stream-def]]jdbc_streaming filter:: -Enriches events with database data. +The <> enriches events with database data. + The following example executes a SQL query and stores the result set in a field called `country_details`: @@ -580,27 +578,16 @@ filter { } -------------------------------------------------------------------------------- -<>:: +[[memcached-def]]memcached filter:: -Enables key/value lookup enrichment against a Memcached object caching system. +The <> enables key/value lookup +enrichment against a Memcached object caching system. It supports both read (GET) and write (SET) operations. It is a notable addition -for security analytics use cases. For example, you can use this plugin to query -for a value, and set it if not found. -+ -[source,txt] ------ -filter { - memcached { - url => "http://example.com" - verb => GET - body => {TODO-complete example - } -} ------ +for security analytics use cases. -<>:: +[[translate-def]]translate filter:: -Replaces field contents based on replacement values specified in a hash or file. +The <> replaces field contents based on replacement values specified in a hash or file. Currently supports these file types: YAML, JSON, and CSV. + The following example takes the value of the `response_code` field, translates @@ -624,10 +611,9 @@ filter { } -------------------------------------------------------------------------------- +[[useragent-def]]useragent filter:: -<>:: - -Parses user agent strings into fields. +The <> parses user agent strings into fields. + The following example takes the user agent string in the `agent` field, parses it into user agent fields, and adds the user agent fields to a new field called From ff89aa140531c2874b0ac7e647e66deb4c4242c1 Mon Sep 17 00:00:00 2001 From: Karen Metts Date: Tue, 12 Feb 2019 16:20:58 -0500 Subject: [PATCH 0014/1126] Move field-ref include below xpack content Fixes #10437 --- docs/index.asciidoc | 20 ++++++++++---------- 1 file changed, 10 insertions(+), 10 deletions(-) diff --git a/docs/index.asciidoc b/docs/index.asciidoc index e7568a39b..03cbe5a69 100644 --- a/docs/index.asciidoc +++ b/docs/index.asciidoc @@ -122,16 +122,6 @@ include::static/ingest-convert.asciidoc[] :edit_url: https://github.com/elastic/logstash/edit/{branch}/docs/static/ls-ls-config.asciidoc include::static/ls-ls-config.asciidoc[] -:edit_url: https://github.com/elastic/logstash/edit/{branch}/docs/static/field-reference.asciidoc -include::static/field-reference.asciidoc[] - -//The `field-reference.asciidoc` file (included above) contains a -//`role="exclude"` attribute to pull in the topic and make it linkable in the LS -//Ref, but not appear in the main TOC. The `exclude`attribute was carrying -//forward for all subsequent topics under the `configuration.asciidoc` heading. -//This include should remain after includes for all other topics under the -//`Configuring Logstash` heading. - ifdef::include-xpack[] :edit_url: https://github.com/elastic/logstash/edit/{branch}/docs/static/management/configuring-centralized-pipelines.asciidoc include::static/management/configuring-centralized-pipelines.asciidoc[] @@ -146,6 +136,16 @@ include::static/security/logstash.asciidoc[] include::static/setup/configuring-xls.asciidoc[] endif::include-xpack[] +:edit_url: https://github.com/elastic/logstash/edit/{branch}/docs/static/field-reference.asciidoc +include::static/field-reference.asciidoc[] + +//The `field-reference.asciidoc` file (included above) contains a +//`role="exclude"` attribute to pull in the topic and make it linkable in the LS +//Ref, but not appear in the main TOC. The `exclude`attribute was carrying +//forward for all subsequent topics under the `configuration.asciidoc` heading. +//This include should remain after includes for all other topics under the +//`Configuring Logstash` heading. + // Centralized configuration managements :edit_url: https://github.com/elastic/logstash/edit/{branch}/docs/static/config-management.asciidoc include::static/config-management.asciidoc[] From ef56ca124911d4fb59a3c27fef3824cb52abada0 Mon Sep 17 00:00:00 2001 From: Dan Hermann Date: Wed, 13 Feb 2019 16:19:03 -0600 Subject: [PATCH 0015/1126] Fix line codec tests so they work on platforms such as Windows that do not have UTF-8 as the default character encoding Fixes #10446 --- .../org/logstash/plugins/codecs/LineTest.java | 35 +++++++++++-------- 1 file changed, 21 insertions(+), 14 deletions(-) diff --git a/logstash-core/src/test/java/org/logstash/plugins/codecs/LineTest.java b/logstash-core/src/test/java/org/logstash/plugins/codecs/LineTest.java index f8e303910..68bcb9df1 100644 --- a/logstash-core/src/test/java/org/logstash/plugins/codecs/LineTest.java +++ b/logstash-core/src/test/java/org/logstash/plugins/codecs/LineTest.java @@ -7,7 +7,9 @@ import org.logstash.Event; import org.logstash.plugins.ConfigurationImpl; import org.logstash.plugins.TestContext; +import java.io.UnsupportedEncodingException; import java.nio.ByteBuffer; +import java.nio.charset.Charset; import java.util.ArrayList; import java.util.Collections; import java.util.HashMap; @@ -22,7 +24,7 @@ public class LineTest { @Test public void testSimpleDecode() { - String input = "abc"; + String input = new String("abc".getBytes(), Charset.forName("UTF-8")); testDecode(null, null, input, 0, 1, new String[]{input}); } @@ -45,7 +47,7 @@ public class LineTest { @Test public void testDecodeWithTrailingDelimiter() { - String delimiter = "\n"; + String delimiter = System.lineSeparator(); String[] inputs = {"foo", "bar", "baz"}; String input = String.join(delimiter, inputs) + delimiter; @@ -55,7 +57,7 @@ public class LineTest { @Test public void testSuccessiveDecodesWithTrailingDelimiter() { // setup inputs - String delimiter = "\n"; + String delimiter = System.lineSeparator(); String[] inputs = {"foo", "bar", "baz"}; String input = String.join(delimiter, inputs) + delimiter; byte[] inputBytes = input.getBytes(); @@ -114,17 +116,18 @@ public class LineTest { @Test public void testDecodeWithUtf8() { - String input = "München 安装中文输入法"; + String input = new String("München 安装中文输入法".getBytes(), Charset.forName("UTF-8")); testDecode(null, null, input + Line.DEFAULT_DELIMITER, 1, 0, new String[]{input}); } @Test - public void testDecodeAcrossMultibyteCharBoundary() { + public void testDecodeAcrossMultibyteCharBoundary() throws Exception { final int BUFFER_SIZE = 12; int lastPos = 0; TestEventConsumer eventConsumer = new TestEventConsumer(); - String input = "安安安\n安安安\n安安安"; - byte[] bytes = input.getBytes(); + String delimiter = System.lineSeparator(); + String input = new String(("安安安" + delimiter + "安安安" + delimiter + "安安安").getBytes(), Charset.forName("UTF-8")); + byte[] bytes = input.getBytes("UTF-8"); assertTrue(bytes.length > input.length()); ByteBuffer b1 = ByteBuffer.allocate(BUFFER_SIZE); b1.put(bytes, lastPos, 12); @@ -161,7 +164,12 @@ public class LineTest { private void testDecode(String delimiter, String charset, String inputString, Integer expectedPreflushEvents, Integer expectedFlushEvents, String[] expectedMessages) { Line line = getLineCodec(delimiter, charset); - byte[] inputBytes = inputString.getBytes(); + byte[] inputBytes = null; + try { + inputBytes = inputString.getBytes("UTF-8"); + } catch (UnsupportedEncodingException ex) { + Assert.fail(); + } TestEventConsumer eventConsumer = new TestEventConsumer(); ByteBuffer inputBuffer = ByteBuffer.wrap(inputBytes, 0, inputBytes.length); line.decode(inputBuffer, eventConsumer); @@ -297,7 +305,7 @@ public class LineTest { @Test public void testEncodeWithUtf8() throws Codec.EncodeException { String delimiter = "z"; - String message = "München 安装中文输入法"; + String message = new String("München 安装中文输入法".getBytes(), Charset.forName("UTF-8")); Map config = new HashMap<>(); config.put("delimiter", delimiter); config.put("format", "%{message}"); @@ -308,12 +316,12 @@ public class LineTest { boolean result = line.encode(e1, buffer); Assert.assertTrue(result); String expectedResult = message + delimiter; - Assert.assertEquals(expectedResult, new String(buffer.array(), buffer.position(), buffer.limit())); + Assert.assertEquals(expectedResult, new String(buffer.array(), buffer.position(), buffer.limit(), Charset.forName("UTF-8"))); } @Test public void testEncodeAcrossMultibyteCharBoundary() throws Codec.EncodeException { - String message = "安安安安安安安安安"; + String message = new String("安安安安安安安安安".getBytes(), Charset.forName("UTF-8")); String delimiter = ""; Map config = new HashMap<>(); config.put("delimiter", delimiter); @@ -345,7 +353,7 @@ public class LineTest { @Test public void testEncodeWithCharset() throws Exception { byte[] rightSingleQuoteInUtf8 = {(byte) 0xE2, (byte) 0x80, (byte) 0x99}; - String rightSingleQuote = new String(rightSingleQuoteInUtf8); + String rightSingleQuote = new String(rightSingleQuoteInUtf8, Charset.forName("UTF-8")); // encode with cp-1252 Map config = new HashMap<>(); @@ -370,7 +378,7 @@ public class LineTest { String delimiter = "x"; String charset = "cp1252"; byte[] rightSingleQuoteInUtf8 = {(byte) 0xE2, (byte) 0x80, (byte) 0x99}; - String rightSingleQuote = new String(rightSingleQuoteInUtf8); + String rightSingleQuote = new String(rightSingleQuoteInUtf8, Charset.forName("UTF-8")); // encode with cp-1252 Map config = new HashMap<>(); @@ -408,4 +416,3 @@ class TestEventConsumer implements Consumer> { events.add(new HashMap<>(stringObjectMap)); } } - From b0bccd865b063400a4b8ecbf8bd45146521186af Mon Sep 17 00:00:00 2001 From: Dan Hermann Date: Thu, 14 Feb 2019 10:19:30 -0600 Subject: [PATCH 0016/1126] fix Stdin tests to work on platforms that do not have UTF-8 as the default character encoding Fixes #10449 --- .../test/java/org/logstash/plugins/inputs/StdinTest.java | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/logstash-core/src/test/java/org/logstash/plugins/inputs/StdinTest.java b/logstash-core/src/test/java/org/logstash/plugins/inputs/StdinTest.java index dc77056c4..5b558fef7 100644 --- a/logstash-core/src/test/java/org/logstash/plugins/inputs/StdinTest.java +++ b/logstash-core/src/test/java/org/logstash/plugins/inputs/StdinTest.java @@ -10,6 +10,7 @@ import java.io.IOException; import java.io.RandomAccessFile; import java.nio.ByteBuffer; import java.nio.channels.FileChannel; +import java.nio.charset.Charset; import java.nio.file.Files; import java.nio.file.Path; import java.util.ArrayList; @@ -44,7 +45,11 @@ public class StdinTest { @Test public void testUtf8Events() throws IOException { - String[] inputs = {"München1", "安装中文输入法", "München3"}; + String[] inputs = { + new String("München1".getBytes(), Charset.forName("UTF-8")), + new String("安装中文输入法".getBytes(), Charset.forName("UTF-8")), + new String("München3".getBytes(), Charset.forName("UTF-8")) + }; String testInput = String.join(Line.DEFAULT_DELIMITER, inputs) + Line.DEFAULT_DELIMITER; TestConsumer queueWriter = testStdin(testInput.getBytes()); From bf56ff763eae987fa186269454545f655823834d Mon Sep 17 00:00:00 2001 From: Karen Metts Date: Tue, 12 Feb 2019 15:14:07 -0500 Subject: [PATCH 0017/1126] Add prilileges required for ilm Fixes #10433 --- docs/static/security/logstash.asciidoc | 26 ++++++++++++++++++-------- 1 file changed, 18 insertions(+), 8 deletions(-) diff --git a/docs/static/security/logstash.asciidoc b/docs/static/security/logstash.asciidoc index d1376cc31..19f41e6e5 100644 --- a/docs/static/security/logstash.asciidoc +++ b/docs/static/security/logstash.asciidoc @@ -35,28 +35,38 @@ and write and delete documents in the indices it creates. To set up authentication credentials for Logstash: -. Create a `logstash_writer` role that has the `manage_index_templates` and -`monitor` cluster privileges, and the `write`, `delete`, and `create_index` -privileges for the Logstash indices. You can create roles from the **Management > -Roles** UI in {kib} or through the `role` API: +. Use the the **Management > Roles** UI in {kib} or the `role` API to create a +`logstash_writer` role. For *cluster* privileges, add `manage_index_templates` and `monitor`. +For *indices* privileges, add `write`, `delete`, and `create_index`. ++ +If you plan to use {ref}/getting-started-index-lifecycle-management.html[index lifecycle +management], also add `manage_ilm` for cluster and `manage` and `manage_ilm` for indices. + [source, sh] --------------------------------------------------------------- POST _xpack/security/role/logstash_writer { - "cluster": ["manage_index_templates", "monitor"], + "cluster": ["manage_index_templates", "monitor", `manage_ilm`], <1> "indices": [ { - "names": [ "logstash-*" ], <1> - "privileges": ["write","delete","create_index"] + "names": [ "logstash-*" ], <2> + "privileges": ["write","delete","create_index","manage","manage_ilm"] <3> } ] } --------------------------------------------------------------- -<1> If you use a custom Logstash index pattern, specify that pattern +<1> The cluster needs the `manage_ilm` privilege if want to use +{ref}/getting-started-index-lifecycle-management.html[index lifecycle management]. + +<2> If you use a custom Logstash index pattern, specify your custom pattern instead of the default `logstash-*` pattern. +<3> If {ref}/getting-started-index-lifecycle-management.html[index lifecycle +management] is enabled, the role requires the `manage` and `manage_ilm` +privileges to load index lifecycle policies, create rollover aliases, and create +and manage rollover indices. + . Create a `logstash_internal` user and assign it the `logstash_writer` role. You can create users from the **Management > Users** UI in {kib} or through the `user` API: From 94bade3717db3babf165178db854c4ab4334e2c2 Mon Sep 17 00:00:00 2001 From: Karen Metts Date: Wed, 13 Feb 2019 19:38:58 -0500 Subject: [PATCH 0018/1126] Incorporate review comments Fixes #10433 --- docs/static/security/logstash.asciidoc | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/docs/static/security/logstash.asciidoc b/docs/static/security/logstash.asciidoc index 19f41e6e5..2d7bdca99 100644 --- a/docs/static/security/logstash.asciidoc +++ b/docs/static/security/logstash.asciidoc @@ -5,8 +5,7 @@ {security} ++++ -The Logstash {es} plugins ( -{logstash-ref}/plugins-outputs-elasticsearch.html[output], +The Logstash {es} plugins ({logstash-ref}/plugins-outputs-elasticsearch.html[output], {logstash-ref}/plugins-inputs-elasticsearch.html[input], {logstash-ref}/plugins-filters-elasticsearch.html[filter] and {logstash-ref}/monitoring-logstash.html[monitoring]) @@ -46,7 +45,7 @@ management], also add `manage_ilm` for cluster and `manage` and `manage_ilm` for --------------------------------------------------------------- POST _xpack/security/role/logstash_writer { - "cluster": ["manage_index_templates", "monitor", `manage_ilm`], <1> + "cluster": ["manage_index_templates", "monitor", "manage_ilm"], <1> "indices": [ { "names": [ "logstash-*" ], <2> @@ -56,8 +55,9 @@ POST _xpack/security/role/logstash_writer } --------------------------------------------------------------- -<1> The cluster needs the `manage_ilm` privilege if want to use -{ref}/getting-started-index-lifecycle-management.html[index lifecycle management]. +<1> The cluster needs the `manage_ilm` privilege if +{ref}/getting-started-index-lifecycle-management.html[index lifecycle management] +is enabled. <2> If you use a custom Logstash index pattern, specify your custom pattern instead of the default `logstash-*` pattern. From 41c6354119de8d7d67becfbe459247f1cbb9d4f3 Mon Sep 17 00:00:00 2001 From: Karen Metts Date: Thu, 14 Feb 2019 13:03:26 -0500 Subject: [PATCH 0019/1126] Add placeholder for 7.0.0.-beta1 Fixes #10451 --- docs/static/releasenotes.asciidoc | 23 ++++++++++++++++++----- 1 file changed, 18 insertions(+), 5 deletions(-) diff --git a/docs/static/releasenotes.asciidoc b/docs/static/releasenotes.asciidoc index e6aaa71a5..149579ee5 100644 --- a/docs/static/releasenotes.asciidoc +++ b/docs/static/releasenotes.asciidoc @@ -3,15 +3,28 @@ This section summarizes the changes in the following releases: -* <> +* <> * <> +* <> -[[logstash-7-0-0-alpha1]] -=== Logstash 7.0.0-alpha1 Release Notes +[[logstash-7-0-0-beta1]] +=== Logstash 7.0.0-beta1 Release Notes -Placeholder for alpha1 release notes +Placeholder for release notes [[logstash-7-0-0-alpha2]] === Logstash 7.0.0-alpha2 Release Notes -Placeholder for alpha2 release notes +Placeholder for release notes + +[[logstash-7-0-0-alpha1]] +=== Logstash 7.0.0-alpha1 Release Notes + +Placeholder for release notes + + + + + + + From 94cb37bedd0d098f463e83a5cfde002890009982 Mon Sep 17 00:00:00 2001 From: Dan Hermann Date: Thu, 14 Feb 2019 14:30:58 -0600 Subject: [PATCH 0020/1126] One more character encoding fix Fixes #10452 --- .../src/test/java/org/logstash/plugins/inputs/StdinTest.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/logstash-core/src/test/java/org/logstash/plugins/inputs/StdinTest.java b/logstash-core/src/test/java/org/logstash/plugins/inputs/StdinTest.java index 5b558fef7..c36eeaafb 100644 --- a/logstash-core/src/test/java/org/logstash/plugins/inputs/StdinTest.java +++ b/logstash-core/src/test/java/org/logstash/plugins/inputs/StdinTest.java @@ -51,7 +51,7 @@ public class StdinTest { new String("München3".getBytes(), Charset.forName("UTF-8")) }; String testInput = String.join(Line.DEFAULT_DELIMITER, inputs) + Line.DEFAULT_DELIMITER; - TestConsumer queueWriter = testStdin(testInput.getBytes()); + TestConsumer queueWriter = testStdin(testInput.getBytes("UTF-8")); List> events = queueWriter.getEvents(); assertEquals(3, events.size()); From b941c17da41a932c25cd0a6a5bd0e35a0d83a55a Mon Sep 17 00:00:00 2001 From: Rob Bavey Date: Fri, 15 Feb 2019 11:38:59 -0500 Subject: [PATCH 0021/1126] Mute Failing Test on Windows Mute mixin_spec, tracked by #10454 Fixes #10455 --- logstash-core/spec/logstash/config/mixin_spec.rb | 1 + 1 file changed, 1 insertion(+) diff --git a/logstash-core/spec/logstash/config/mixin_spec.rb b/logstash-core/spec/logstash/config/mixin_spec.rb index a0a9742e7..c4cdfe180 100644 --- a/logstash-core/spec/logstash/config/mixin_spec.rb +++ b/logstash-core/spec/logstash/config/mixin_spec.rb @@ -419,6 +419,7 @@ describe LogStash::Config::Mixin do end it "should use the value in the variable" do + skip("This test fails on Windows, tracked in https://github.com/elastic/logstash/issues/10454") expect(subject.oneString).to(be == "fancy") expect(subject.oneBoolean).to(be_truthy) expect(subject.oneArray).to(be == [ "first array value", "fancy" ]) From 2d5df520bff8e809b6709bb4bb1e9913e150ab88 Mon Sep 17 00:00:00 2001 From: Rob Bavey Date: Fri, 15 Feb 2019 16:38:30 -0500 Subject: [PATCH 0022/1126] Mute CLI integration plugin acceptance test Test is failing CI https://github.com/elastic/logstash/issues/10459 Fixes #10460 --- .../shared_examples/cli/logstash-plugin/integration_plugin.rb | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/qa/acceptance/spec/shared_examples/cli/logstash-plugin/integration_plugin.rb b/qa/acceptance/spec/shared_examples/cli/logstash-plugin/integration_plugin.rb index 7ebfe6c11..bfec59cf5 100644 --- a/qa/acceptance/spec/shared_examples/cli/logstash-plugin/integration_plugin.rb +++ b/qa/acceptance/spec/shared_examples/cli/logstash-plugin/integration_plugin.rb @@ -26,7 +26,8 @@ shared_examples "integration plugins compatible" do |logstash| end end context "when the integration is not installed" do - context "if an inner plugin is installed" do + # Muting test. Tracked in https://github.com/elastic/logstash/issues/10459 + xcontext "if an inner plugin is installed" do before(:each) do logstash.run_command_in_path("bin/logstash-plugin install logstash-input-rabbitmq") end From 116228213001316bc8d520b3d100d68504f3c49f Mon Sep 17 00:00:00 2001 From: Colin Surprenant Date: Sat, 16 Feb 2019 13:33:18 -0500 Subject: [PATCH 0023/1126] remove exclusive lock for Ruby pipeline initialization (#10461) 7.x clean backport of #10431 --- logstash-core/lib/logstash/agent.rb | 5 ---- .../lib/logstash/pipeline_action/create.rb | 15 ++--------- .../lib/logstash/pipeline_action/reload.rb | 27 +++---------------- 3 files changed, 6 insertions(+), 41 deletions(-) diff --git a/logstash-core/lib/logstash/agent.rb b/logstash-core/lib/logstash/agent.rb index 6cd3408d6..f05134748 100644 --- a/logstash-core/lib/logstash/agent.rb +++ b/logstash-core/lib/logstash/agent.rb @@ -36,7 +36,6 @@ class LogStash::Agent # Mutex to synchonize in the exclusive method # Initial usage for the Ruby pipeline initialization which is not thread safe - @exclusive_lock = Mutex.new @webserver_control_lock = Mutex.new # Special bus object for inter-pipelines communications. Used by the `pipeline` input/output @@ -86,10 +85,6 @@ class LogStash::Agent @running = Concurrent::AtomicBoolean.new(false) end - def exclusive(&block) - @exclusive_lock.synchronize { block.call } - end - def execute @thread = Thread.current # this var is implicitly used by Stud.stop? logger.debug("Starting agent") diff --git a/logstash-core/lib/logstash/pipeline_action/create.rb b/logstash-core/lib/logstash/pipeline_action/create.rb index 708a9dd3c..ede2eb3ef 100644 --- a/logstash-core/lib/logstash/pipeline_action/create.rb +++ b/logstash-core/lib/logstash/pipeline_action/create.rb @@ -32,22 +32,11 @@ module LogStash module PipelineAction # The execute assume that the thread safety access of the pipeline # is managed by the caller. def execute(agent, pipelines_registry) - new_pipeline = - if @pipeline_config.settings.get_value("pipeline.java_execution") - LogStash::JavaPipeline.new(@pipeline_config, @metric, agent) - else - agent.exclusive do - # The Ruby pipeline initialization is not thread safe because of the module level - # shared state in LogsStash::Config::AST. When using multiple pipelines this gets - # executed simultaneously in different threads and we need to synchronize this initialization. - LogStash::Pipeline.new(@pipeline_config, @metric, agent) - end - end - + pipeline_class = @pipeline_config.settings.get_value("pipeline.java_execution") ? LogStash::JavaPipeline : LogStash::Pipeline + new_pipeline = pipeline_class.new(@pipeline_config, @metric, agent) success = pipelines_registry.create_pipeline(pipeline_id, new_pipeline) do new_pipeline.start # block until the pipeline is correctly started or crashed end - LogStash::ConvergeResult::ActionResult.create(self, success) end diff --git a/logstash-core/lib/logstash/pipeline_action/reload.rb b/logstash-core/lib/logstash/pipeline_action/reload.rb index a24f6ad53..2ce5c2921 100644 --- a/logstash-core/lib/logstash/pipeline_action/reload.rb +++ b/logstash-core/lib/logstash/pipeline_action/reload.rb @@ -31,18 +31,10 @@ module LogStash module PipelineAction return LogStash::ConvergeResult::FailedAction.new("Cannot reload pipeline, because the existing pipeline is not reloadable") end + java_exec = @pipeline_config.settings.get_value("pipeline.java_execution") + begin - pipeline_validator = - if @pipeline_config.settings.get_value("pipeline.java_execution") - LogStash::JavaBasePipeline.new(@pipeline_config, nil, logger, nil) - else - agent.exclusive do - # The Ruby pipeline initialization is not thread safe because of the module level - # shared state in LogsStash::Config::AST. When using multiple pipelines this gets - # executed simultaneously in different threads and we need to synchronize this initialization. - LogStash::BasePipeline.new(@pipeline_config) - end - end + pipeline_validator = java_exec ? LogStash::JavaBasePipeline.new(@pipeline_config, nil, logger, nil) : LogStash::BasePipeline.new(@pipeline_config) rescue => e return LogStash::ConvergeResult::FailedAction.from_exception(e) end @@ -62,18 +54,7 @@ module LogStash module PipelineAction old_pipeline.thread.join # Then create a new pipeline - new_pipeline = - if @pipeline_config.settings.get_value("pipeline.java_execution") - LogStash::JavaPipeline.new(@pipeline_config, @metric, agent) - else - agent.exclusive do - # The Ruby pipeline initialization is not thread safe because of the module level - # shared state in LogsStash::Config::AST. When using multiple pipelines this gets - # executed simultaneously in different threads and we need to synchronize this initialization. - LogStash::Pipeline.new(@pipeline_config, @metric, agent) - end - end - + new_pipeline = java_exec ? LogStash::JavaPipeline.new(@pipeline_config, @metric, agent) : LogStash::Pipeline.new(@pipeline_config, @metric, agent) success = new_pipeline.start # block until the pipeline is correctly started or crashed # return success and new_pipeline to registry reload_pipeline From 1c88792d49ee2544dd75e4cfe1e4b046716a99d3 Mon Sep 17 00:00:00 2001 From: Joao Duarte Date: Mon, 11 Feb 2019 22:41:50 +0000 Subject: [PATCH 0024/1126] bump jruby to 9.2.6.0 Fixes #10425 --- buildSrc/build.gradle | 2 +- versions.yml | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/buildSrc/build.gradle b/buildSrc/build.gradle index 29e903be3..d41a08344 100644 --- a/buildSrc/build.gradle +++ b/buildSrc/build.gradle @@ -8,5 +8,5 @@ repositories { } dependencies { - compile group: 'org.jruby', name: 'jruby-complete', version: '9.2.5.0' + compile group: 'org.jruby', name: 'jruby-complete', version: '9.2.6.0' } diff --git a/versions.yml b/versions.yml index 2f3c3e969..cfa505279 100644 --- a/versions.yml +++ b/versions.yml @@ -7,8 +7,8 @@ logstash-core-plugin-api: 2.1.16 # jruby must reference a *released* version of jruby which can be downloaded from the official download url # *and* for which jars artifacts are published for compile-time jruby: - version: 9.2.5.0 - sha1: c78526ce98b1b4273d11989246cb9bf224ce9712 + version: 9.2.6.0 + sha1: 3c13ec3966f6cc44966f3978c96325b9e56174f1 # jruby-runtime-override, if specified, will override the jruby version installed in vendor/jruby for logstash runtime only, # not for the compile-time jars From ca6ad64c7fdf95e94df36d5627d8350b9b2e3b97 Mon Sep 17 00:00:00 2001 From: DeDe Morton Date: Fri, 15 Feb 2019 12:39:28 -0800 Subject: [PATCH 0025/1126] Improve docs about using Filebeat modules with Logstash (#10438) * Improve docs about using Filebeat modules with Logstash * Add fixes from review Fixes #10482 --- docs/static/fb-ls-kafka-example.asciidoc | 151 ++++++++++++++++ docs/static/filebeat-modules.asciidoc | 216 +++++++++++------------ 2 files changed, 255 insertions(+), 112 deletions(-) create mode 100644 docs/static/fb-ls-kafka-example.asciidoc diff --git a/docs/static/fb-ls-kafka-example.asciidoc b/docs/static/fb-ls-kafka-example.asciidoc new file mode 100644 index 000000000..86b428f9b --- /dev/null +++ b/docs/static/fb-ls-kafka-example.asciidoc @@ -0,0 +1,151 @@ +[[use-filebeat-modules-kafka]] +=== Example: Set up {filebeat} modules to work with Kafka and {ls} + +This section shows how to set up {filebeat} +{filebeat-ref}/filebeat-modules-overview.html[modules] to work with {ls} when +you are using Kafka in between {filebeat} and {ls} in your publishing pipeline. +The main goal of this example is to show how to load ingest pipelines from +{filebeat} and use them with {ls}. + +The examples in this section show simple configurations with topic names hard +coded. For a full list of configuration options, see documentation about +configuring the <>. Also see +{filebeat-ref}/kafka-output.html[Configure the Kafka output] in the _{filebeat} +Reference_. + +==== Set up and run {filebeat} + +. If you haven't already set up the {filebeat} index template and sample {kib} +dashboards, run the {filebeat} `setup` command to do that now: ++ +[source,shell] +---------------------------------------------------------------------- +filebeat -e setup +---------------------------------------------------------------------- ++ +The `-e` flag is optional and sends output to standard error instead of syslog. ++ +A connection to {es} and {kib} is required for this one-time setup +step because {filebeat} needs to create the index template in {es} and +load the sample dashboards into {kib}. For more information about configuring +the connection to {es}, see the Filebeat modules +{filebeat-ref}/filebeat-modules-quickstart.html[quick start]. ++ +After the template and dashboards are loaded, you'll see the message `INFO +{kib} dashboards successfully loaded. Loaded dashboards`. + +. Run the `modules enable` command to enable the modules that you want to run. +For example: ++ +[source,shell] +---------------------------------------------------------------------- +filebeat modules enable system +---------------------------------------------------------------------- ++ +You can further configure the module by editing the config file under the +{filebeat} `modules.d` directory. For example, if the log files are not in the +location expected by the module, you can set the `var.paths` option. + +. Run the `setup` command with the `--pipelines` and `--modules` options +specified to load ingest pipelines for the modules you've enabled. This step +also requires a connection to {es}. If you want use a {ls} pipeline instead of +ingest node to parse the data, skip this step. ++ +[source,shell] +---------------------------------------------------------------------- +filebeat setup --pipelines --modules system +---------------------------------------------------------------------- + +. Configure {filebeat} to send log lines to Kafka. To do this, in the ++filebeat.yml+ config file, disable the {es} output by commenting it out, and +enable the Kafka output. For example: ++ +[source,yaml] +----- +#output.elasticsearch: + #hosts: ["localhost:9200"] +output.kafka: + hosts: ["kafka:9092"] + topic: "filebeat" + codec.json: + pretty: false +----- + +. Start {filebeat}. For example: ++ +[source,shell] +---------------------------------------------------------------------- +filebeat -e +---------------------------------------------------------------------- ++ +{filebeat} will attempt to send messages to {ls} and continue until {ls} is +available to receive them. ++ +NOTE: Depending on how you've installed {filebeat}, you might see errors +related to file ownership or permissions when you try to run {filebeat} modules. +See {beats-ref}/config-file-permissions.html[Config File Ownership and Permissions] +in the _Beats Platform Reference_ if you encounter errors related to file +ownership or permissions. + + +==== Create and start the {ls} pipeline + +. On the system where {ls} is installed, create a {ls} pipeline configuration +that reads from a Kafka input and sends events to an {es} output: ++ +-- +[source,yaml] +----- +input { + kafka { + bootstrap_servers => "myhost:9092" + topics => ["filebeat"] + codec => json + } +} + +output { + if [@metadata][pipeline] { + elasticsearch { + hosts => "https://myEShost:9200" + manage_template => false + index => "%{[@metadata][beat]}-%{[@metadata][version]}-%{+YYYY.MM.dd}" + pipeline => "%{[@metadata][pipeline]}" <1> + user => "elastic" + password => "secret" + } + } else { + elasticsearch { + hosts => "https://myEShost:9200" + manage_template => false + index => "%{[@metadata][beat]}-%{[@metadata][version]}-%{+YYYY.MM.dd}" + user => "elastic" + password => "secret" + } + } +} +----- +<1> Set the `pipeline` option to `%{[@metadata][pipeline]}`. This setting +configures {ls} to select the correct ingest pipeline based on metadata +passed in the event. + +If you want use a {ls} pipeline instead of ingest node to parse the data, see +the `filter` and `output` settings in the examples under +<>. +-- + +. Start {ls}, passing in the pipeline configuration file you just defined. For +example: ++ +[source,shell] +---------------------------------------------------------------------- +bin/logstash -f mypipeline.conf +---------------------------------------------------------------------- ++ +{ls} should start a pipeline and begin receiving events from the Kafka input. + +==== Visualize the data + +To visualize the data in {kib}, launch the {kib} web interface by pointing your +browser to port 5601. For example, http://127.0.0.1:5601[http://127.0.0.1:5601]. +Click *Dashboards* then view the {filebeat} dashboards. \ No newline at end of file diff --git a/docs/static/filebeat-modules.asciidoc b/docs/static/filebeat-modules.asciidoc index 1b601f685..dd43a974d 100644 --- a/docs/static/filebeat-modules.asciidoc +++ b/docs/static/filebeat-modules.asciidoc @@ -1,143 +1,134 @@ [[filebeat-modules]] -== Working with Filebeat Modules +== Working with {filebeat} Modules -Filebeat comes packaged with pre-built {filebeat-ref}/filebeat-modules.html[modules] -that contain the configurations needed to collect, parse, enrich, and visualize -data from various log file formats. Each Filebeat module consists of one or more -filesets that contain ingest node pipelines, Elasticsearch templates, Filebeat -prospector configurations, and Kibana dashboards. +{filebeat} comes packaged with pre-built +{filebeat-ref}/filebeat-modules.html[modules] that contain the configurations +needed to collect, parse, enrich, and visualize data from various log file +formats. Each {filebeat} module consists of one or more filesets that contain +ingest node pipelines, {es} templates, {filebeat} input configurations, and +{kib} dashboards. -Filebeat modules are a great way to get started, but you might find that ingest -pipelines don't offer the processing power that you require. If that's the case, -you'll need to use Logstash. +You can use {filebeat} modules with {ls}, but you need to do some extra setup. +The simplest approach is to <> provided by {filebeat}. If the ingest pipelines don't meet your +requirements, you can +<> to use +instead of the ingest pipelines. -[float] -[[graduating-to-Logstash]] -=== Using Logstash instead of Ingest Node +Either approach allows you to use the configurations, index templates, and +dashboards available with {filebeat} modules, as long as you maintain the +field structure expected by the index and dashboards. -Logstash provides an <> -to help you migrate ingest pipeline definitions to Logstash configs. However, -the tool does not currently support all the processors that are available for -ingest node. +[[use-ingest-pipelines]] +=== Use ingest pipelines for parsing -You can follow the steps in this section to build and run Logstash -configurations that parse the data collected by Filebeat modules. Then you'll be -able to use the same dashboards available with Filebeat to visualize your data -in Kibana. +When you use {filebeat} modules with {ls}, you can use the ingest pipelines +provided by {filebeat} to parse the data. You need to load the pipelines +into {es} and configure {ls} to use them. -[float] -==== Create and start the Logstash pipeline +*To load the ingest pipelines:* -. Create a Logstash pipeline configuration that reads from the Beats input and -parses the events. -+ -See <> for detailed examples. +On the system where {filebeat} is installed, run the `setup` command with the +`--pipelines` option specified to load ingest pipelines for specific modules. +For example, the following command loads ingest pipelines for the system and +nginx modules: -. Start Logstash, passing in the pipeline configuration file that parses the -log. For example: -+ [source,shell] ----------------------------------------------------------------------- -bin/logstash -f mypipeline.conf ----------------------------------------------------------------------- -+ -You'll see the following message when Logstash is running and listening for -input from Beats: -+ -[source,shell] ----------------------------------------------------------------------- -[2017-10-13T00:01:15,413][INFO ][logstash.inputs.beats ] Beats inputs: Starting input listener {:address=>"127.0.0.1:5044"} -[2017-10-13T00:01:15,443][INFO ][logstash.pipeline ] Pipeline started {"pipeline.id"=>"main"} ----------------------------------------------------------------------- +----- +filebeat setup --pipelines --modules nginx,system +----- +A connection to {es} is required for this setup step because {filebeat} needs to +load the ingest pipelines into {es}. If necessary, you can temporarily disable +your configured output and enable the {es} output before running the command. -The Logstash pipeline is now ready to receive events from Filebeat. Next, you -set up and run Filebeat. +*To configure {ls} to use the pipelines:* -[float] -==== Set up and run Filebeat +On the system where {ls} is installed, create a {ls} pipeline configuration +that reads from a {ls} input, such as {beats} or Kafka, and sends events to an +{es} output. Set the `pipeline` option in the {es} output to +`%{[@metadata][pipeline]}` to use the ingest pipelines that you loaded +previously. -. If you haven't already set up the Filebeat index template and sample Kibana -dashboards, run the Filebeat `setup` command to do that now: -+ -[source,shell] ----------------------------------------------------------------------- -./filebeat -e setup ----------------------------------------------------------------------- -+ -The `-e` flag is optional and sends output to standard error instead of syslog. -+ -A connection to Elasticsearch and Kibana is required for this one-time setup -step because Filebeat needs to create the index template in Elasticsearch and -load the sample dashboards into Kibana. -+ -After the template and dashboards are loaded, you'll see the message `INFO -Kibana dashboards successfully loaded. Loaded dashboards`. +Here's an example configuration that reads data from the Beats input and uses +{filebeat} ingest pipelines to parse data collected by modules: -. Configure Filebeat to send log lines to Logstash. To do this, in the -+filebeat.yml+ config file, disable the Elasticsearch output, and enable the -Logstash output. For example: -+ [source,yaml] ----- -#output.elasticsearch: - #hosts: ["localhost:9200"] -output.logstash: - hosts: ["localhost:5044"] +input { + beats { + port => 5044 + } +} + +output { + if [@metadata][pipeline] { + elasticsearch { + hosts => "https://061ab24010a2482e9d64729fdb0fd93a.us-east-1.aws.found.io:9243" + manage_template => false + index => "%{[@metadata][beat]}-%{[@metadata][version]}-%{+YYYY.MM.dd}" + pipeline => "%{[@metadata][pipeline]}" <1> + user => "elastic" + password => "secret" + } + } else { + elasticsearch { + hosts => "https://061ab24010a2482e9d64729fdb0fd93a.us-east-1.aws.found.io:9243" + manage_template => false + index => "%{[@metadata][beat]}-%{[@metadata][version]}-%{+YYYY.MM.dd}" + user => "elastic" + password => "secret" + } + } +} ----- +<1> Set the `pipeline` option to `%{[@metadata][pipeline]}`. This setting +configures {ls} to select the correct ingest pipeline based on metadata +passed in the event. -. Run the `modules enable` command to enable the modules that you want to run. -For example: -+ -[source,shell] ----------------------------------------------------------------------- -./filebeat modules enable nginx ----------------------------------------------------------------------- -+ -You can further configure the module by editing the config file under the -Filebeat `modules.d` directory. For example, if the log files are not in the -location expected by the module, you can set the `var.paths` option. +See the {filebeat} {filebeat-ref}/filebeat-modules-overview.html[Modules] +documentation for more information about setting up and running modules. -. Start Filebeat. For example, to start Filebeat in the foreground, use: -+ -[source,shell] ----------------------------------------------------------------------- -./filebeat -e ----------------------------------------------------------------------- -+ -NOTE: Depending on how you've installed Filebeat, you might see errors -related to file ownership or permissions when you try to run Filebeat modules. -See {beats-ref}/config-file-permissions.html[Config File Ownership and Permissions] -in the _Beats Platform Reference_ if you encounter errors related to file -ownership or permissions. -+ -See {filebeat-ref}/filebeat-starting.html[Starting Filebeat] for more info. - -[float] -==== Visualize the data - -To visualize the data in Kibana, launch the Kibana web interface by pointing -your browser to port 5601. For example, -http://127.0.0.1:5601[http://127.0.0.1:5601]. +For a full example, see <>. [[logstash-config-for-filebeat-modules]] -=== Configuration Examples +=== Use {ls} pipelines for parsing -The examples in this section show you how to build Logstash pipelines that parse -data sent collected by Filebeat modules: +The examples in this section show how to build {ls} pipeline configurations that +replace the ingest pipelines provided with {filebeat} modules. The pipelines +take the data collected by {filebeat} modules, parse it into fields expected by +the {filebeat} index, and send the fields to {es} so that you can visualize the +data in the pre-built dashboards provided by {filebeat}. + +This approach is more time consuming than using the existing ingest pipelines to +parse the data, but it gives you more control over how the data is processed. +By writing your own pipeline configurations, you can do additional processing, +such as dropping fields, after the fields are extracted, or you can move your +load from {es} ingest nodes to {ls} nodes. + +Before deciding to replaced the ingest pipelines with {ls} configurations, +read <>. + +Here are some examples that show how to implement {ls} configurations to replace +ingest pipelines: * <> * <> * <> * <> +TIP: {ls} provides an <> +to help you migrate ingest pipeline definitions to {ls} configs. The tool does +not currently support all the processors that are available for ingest node, but +it's a good starting point. + [[parsing-apache2]] ==== Apache 2 Logs -The Logstash pipeline configuration in this example shows how to ship and parse +The {ls} pipeline configuration in this example shows how to ship and parse access and error logs collected by the -{filebeat-ref}/filebeat-module-apache.html[`apache` Filebeat module]. +{filebeat-ref}/filebeat-module-apache.html[`apache` {filebeat} module]. [source,json] ---------------------------------------------------------------------------- @@ -148,9 +139,9 @@ include::filebeat_modules/apache2/pipeline.conf[] [[parsing-mysql]] ==== MySQL Logs -The Logstash pipeline configuration in this example shows how to ship and parse +The {ls} pipeline configuration in this example shows how to ship and parse error and slowlog logs collected by the -{filebeat-ref}/filebeat-module-mysql.html[`mysql` Filebeat module]. +{filebeat-ref}/filebeat-module-mysql.html[`mysql` {filebeat} module]. [source,json] ---------------------------------------------------------------------------- @@ -161,9 +152,9 @@ include::filebeat_modules/mysql/pipeline.conf[] [[parsing-nginx]] ==== Nginx Logs -The Logstash pipeline configuration in this example shows how to ship and parse +The {ls} pipeline configuration in this example shows how to ship and parse access and error logs collected by the -{filebeat-ref}/filebeat-module-nginx.html[`nginx` Filebeat module]. +{filebeat-ref}/filebeat-module-nginx.html[`nginx` {filebeat} module]. [source,json] ---------------------------------------------------------------------------- @@ -174,12 +165,13 @@ include::filebeat_modules/nginx/pipeline.conf[] [[parsing-system]] ==== System Logs -The Logstash pipeline configuration in this example shows how to ship and parse +The {ls} pipeline configuration in this example shows how to ship and parse system logs collected by the -{filebeat-ref}/filebeat-module-system.html[`system` Filebeat module]. +{filebeat-ref}/filebeat-module-system.html[`system` {filebeat} module]. [source,json] ---------------------------------------------------------------------------- include::filebeat_modules/system/pipeline.conf[] ---------------------------------------------------------------------------- +include::fb-ls-kafka-example.asciidoc[] From 59e51127af1e804297cacf5e7226c98044456758 Mon Sep 17 00:00:00 2001 From: Guy Boertje Date: Wed, 27 Feb 2019 16:44:55 +0000 Subject: [PATCH 0026/1126] Mute CI integration DLQ acceptance test Fixes #10504 --- qa/integration/specs/dlq_spec.rb | 1 + 1 file changed, 1 insertion(+) diff --git a/qa/integration/specs/dlq_spec.rb b/qa/integration/specs/dlq_spec.rb index 6ef2d59f5..1b4db43c8 100644 --- a/qa/integration/specs/dlq_spec.rb +++ b/qa/integration/specs/dlq_spec.rb @@ -117,6 +117,7 @@ describe "Test Dead Letter Queue" do end context 'using logstash.yml and separate config file' do + skip("This test fails Jenkins CI, tracked in https://github.com/elastic/logstash/issues/10275") let(:generator_config_file) { config_to_temp_file(@fixture.config("root",{ :dlq_dir => dlq_dir })) } before :each do From 7ca98d34102de41c52b89767ac3581a9efa1b35b Mon Sep 17 00:00:00 2001 From: Jake Landis Date: Fri, 8 Feb 2019 11:25:21 -0600 Subject: [PATCH 0027/1126] Central management typeless API This commit adopts Elasticsearch's typeless API for central management. Relates: https://github.com/elastic/elasticsearch/issues/3863 Fixes #10421 --- x-pack/lib/config_management/elasticsearch_source.rb | 3 +-- x-pack/spec/config_management/elasticsearch_source_spec.rb | 4 ++-- 2 files changed, 3 insertions(+), 4 deletions(-) diff --git a/x-pack/lib/config_management/elasticsearch_source.rb b/x-pack/lib/config_management/elasticsearch_source.rb index f8a860fbb..a319c23a9 100644 --- a/x-pack/lib/config_management/elasticsearch_source.rb +++ b/x-pack/lib/config_management/elasticsearch_source.rb @@ -20,7 +20,6 @@ module LogStash class RemoteConfigError < LogStash::Error; end PIPELINE_INDEX = ".logstash" - PIPELINE_TYPE = "doc" VALID_LICENSES = %w(trial standard gold platinum) FEATURE_INTERNAL = 'management' FEATURE_EXTERNAL = 'logstash' @@ -138,7 +137,7 @@ module LogStash end def config_path - "#{PIPELINE_INDEX}/#{PIPELINE_TYPE}/_mget" + "#{PIPELINE_INDEX}/_mget" end def populate_license_state(xpack_info) diff --git a/x-pack/spec/config_management/elasticsearch_source_spec.rb b/x-pack/spec/config_management/elasticsearch_source_spec.rb index e34069b9e..3728639ee 100644 --- a/x-pack/spec/config_management/elasticsearch_source_spec.rb +++ b/x-pack/spec/config_management/elasticsearch_source_spec.rb @@ -132,7 +132,7 @@ describe LogStash::ConfigManagement::ElasticsearchSource do } } it "generates the path to get the configuration" do - expect(subject.config_path).to eq("#{described_class::PIPELINE_INDEX}/#{described_class::PIPELINE_TYPE}/_mget") + expect(subject.config_path).to eq("#{described_class::PIPELINE_INDEX}/_mget") end end @@ -168,7 +168,7 @@ describe LogStash::ConfigManagement::ElasticsearchSource do let(:pipeline_id) { "apache" } let(:mock_client) { double("http_client") } let(:settings) { super.merge({ "xpack.management.pipeline.id" => pipeline_id }) } - let(:es_path) { "#{described_class::PIPELINE_INDEX}/#{described_class::PIPELINE_TYPE}/_mget" } + let(:es_path) { "#{described_class::PIPELINE_INDEX}/_mget" } let(:request_body_string) { LogStash::Json.dump({ "docs" => [{ "_id" => pipeline_id }] }) } before do From 439ef7f1ce713ba741e464c20b5479d1d72fb45e Mon Sep 17 00:00:00 2001 From: Jake Landis Date: Wed, 6 Mar 2019 15:27:36 -0600 Subject: [PATCH 0028/1126] update to send api version 6 Fixes #10518 --- x-pack/lib/monitoring/monitoring.rb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/x-pack/lib/monitoring/monitoring.rb b/x-pack/lib/monitoring/monitoring.rb index 8fcdab088..4dbeefff0 100644 --- a/x-pack/lib/monitoring/monitoring.rb +++ b/x-pack/lib/monitoring/monitoring.rb @@ -83,7 +83,7 @@ module LogStash include LogStash::Util::Loggable, LogStash::Helpers::ElasticsearchOptions PIPELINE_ID = ".monitoring-logstash" - API_VERSION = 2 + API_VERSION = 6 def initialize # nothing to do here From 182639a64a64bad06777f27a33986583dc2525c8 Mon Sep 17 00:00:00 2001 From: Dan Hermann Date: Thu, 7 Mar 2019 17:30:02 -0600 Subject: [PATCH 0029/1126] fix bug with explicitly-specified Java codecs Fixes #10520 --- .../src/main/java/org/logstash/plugins/ConfigurationImpl.java | 3 +++ 1 file changed, 3 insertions(+) diff --git a/logstash-core/src/main/java/org/logstash/plugins/ConfigurationImpl.java b/logstash-core/src/main/java/org/logstash/plugins/ConfigurationImpl.java index 3ede75ebf..6b802dba1 100644 --- a/logstash-core/src/main/java/org/logstash/plugins/ConfigurationImpl.java +++ b/logstash-core/src/main/java/org/logstash/plugins/ConfigurationImpl.java @@ -39,6 +39,9 @@ public final class ConfigurationImpl implements Configuration { Object o = rawSettings.get(configSpec.name()); if (configSpec.type().isAssignableFrom(o.getClass())) { return (T) o; + } else if (configSpec.type() == Codec.class && o instanceof String && pluginFactory != null) { + Codec codec = pluginFactory.buildDefaultCodec((String)o); + return configSpec.type().cast(codec); } else { throw new IllegalStateException( String.format("Setting value for '%s' of type '%s' incompatible with defined type of '%s'", From ecba50c280ee08a482c48ce4b06f5f916d159e14 Mon Sep 17 00:00:00 2001 From: Rob Bavey Date: Mon, 11 Mar 2019 14:09:51 -0400 Subject: [PATCH 0030/1126] Change internal document type to push "_doc" instead of "doc" This commit fixes x-pack integration tests that were broken by https://github.com/elastic/elasticsearch/pull/39888 removing the "doc" type, and using `_doc` in templates. Fixes #10533 --- x-pack/qa/integration/support/helpers.rb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/x-pack/qa/integration/support/helpers.rb b/x-pack/qa/integration/support/helpers.rb index 23c6135e7..62170bbaa 100644 --- a/x-pack/qa/integration/support/helpers.rb +++ b/x-pack/qa/integration/support/helpers.rb @@ -95,7 +95,7 @@ def elasticsearch_client(options = { :url => "http://elastic:#{elastic_password} end def push_elasticsearch_config(pipeline_id, config) - elasticsearch_client.index :index => '.logstash', :type => "doc", id: pipeline_id, :body => { :pipeline => config } + elasticsearch_client.index :index => '.logstash', :type => "_doc", id: pipeline_id, :body => { :pipeline => config } end def cleanup_elasticsearch(index = MONITORING_INDEXES) From 3c3e769bb064c77ad7cf86f177a1e5f8a2dcd080 Mon Sep 17 00:00:00 2001 From: Jake Landis Date: Sun, 10 Mar 2019 16:18:52 -0500 Subject: [PATCH 0031/1126] Update monitoring HTTP end point This commit changes /_xpack/monitoring/_bulk to /_monitoring/bulk. The former is deprecrated as 7.0.0. Relates https://github.com/elastic/elasticsearch/pull/36130 Relates https://github.com/elastic/elasticsearch/issues/35958 Fixes #10528 --- x-pack/lib/template.cfg.erb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/x-pack/lib/template.cfg.erb b/x-pack/lib/template.cfg.erb index 80e7b65f6..7378412d2 100644 --- a/x-pack/lib/template.cfg.erb +++ b/x-pack/lib/template.cfg.erb @@ -13,7 +13,7 @@ input { output { elasticsearch { hosts => <%= es_hosts %> - bulk_path => "/_xpack/monitoring/_bulk?system_id=logstash&system_api_version=<%= system_api_version %>&interval=1s" + bulk_path => "/_monitoring/bulk?system_id=logstash&system_api_version=<%= system_api_version %>&interval=1s" manage_template => false document_type => "%{[@metadata][document_type]}" index => "" From 80cf579e596dacac0cf5f35b254a64d12b52e694 Mon Sep 17 00:00:00 2001 From: Ry Biesemeyer Date: Mon, 11 Mar 2019 21:42:46 +0000 Subject: [PATCH 0032/1126] prevent concurrent convergence (e.g., SIGHUP during in-flight convergence) There are several scenarios in which we can trigger concurrent convergence in the agent, resulting in two or more threads working to perform interleaved and potentially conflicting or overlapping pipeline actions. Notably, our trap on `SIGHUP` will be resolved in its own thread, so if we are sent `SIGHUP` while in the process of converging, the second in-flight convergence may get its starting state before, during, or after the effects of the first convergence. By mutually excluding execution of the convergence cycle, we eliminate the class of bugs in which one convergence acquires actions that cannot succeed due to the prior success of actions given to the other convergence. Fixes #10537 --- logstash-core/lib/logstash/agent.rb | 23 +++++++++++++++-------- 1 file changed, 15 insertions(+), 8 deletions(-) diff --git a/logstash-core/lib/logstash/agent.rb b/logstash-core/lib/logstash/agent.rb index f05134748..d8ffa82bb 100644 --- a/logstash-core/lib/logstash/agent.rb +++ b/logstash-core/lib/logstash/agent.rb @@ -38,6 +38,8 @@ class LogStash::Agent # Initial usage for the Ruby pipeline initialization which is not thread safe @webserver_control_lock = Mutex.new + @convergence_lock = Mutex.new + # Special bus object for inter-pipelines communications. Used by the `pipeline` input/output @pipeline_bus = org.logstash.plugins.pipeline.PipelineBus.new @@ -154,12 +156,7 @@ class LogStash::Agent end end - # We Lock any access on the pipelines, since the actions will modify the - # content of it. - converge_result = nil - - pipeline_actions = resolve_actions(results.response) - converge_result = converge_state(pipeline_actions) + converge_result = resolve_actions_and_converge_state(results.response) update_metrics(converge_result) logger.info( @@ -283,6 +280,15 @@ class LogStash::Agent @running.make_true end + # @param pipeline_configs [Array] + # @return [ConvergeResult] + def resolve_actions_and_converge_state(pipeline_configs) + @convergence_lock.synchronize do + pipeline_actions = resolve_actions(pipeline_configs) + converge_state(pipeline_actions) + end + end + # We depends on a series of task derived from the internal state and what # need to be run, theses actions are applied to the current pipelines to converge to # the desired state. @@ -295,6 +301,7 @@ class LogStash::Agent # def converge_state(pipeline_actions) logger.debug("Converging pipelines state", :actions_count => pipeline_actions.size) + fail("Illegal access to `LogStash::Agent#converge_state()` without exclusive lock at #{caller[1]}") unless @convergence_lock.owned? converge_result = LogStash::ConvergeResult.new(pipeline_actions.size) @@ -343,6 +350,7 @@ class LogStash::Agent end def resolve_actions(pipeline_configs) + fail("Illegal access to `LogStash::Agent#resolve_actions()` without exclusive lock at #{caller[1]}") unless @convergence_lock.owned? @state_resolver.resolve(@pipelines_registry, pipeline_configs) end @@ -410,8 +418,7 @@ class LogStash::Agent # In this context I could just call shutdown, but I've decided to # use the stop action implementation for that so we have the same code. # This also give us some context into why a shutdown is failing - pipeline_actions = resolve_actions([]) # We stop all the pipeline, so we converge to a empty state - converge_state(pipeline_actions) + resolve_actions_and_converge_state([]) # We stop all the pipeline, so we converge to a empty state end From 2ec00019a4e8efde611edc69183560dd22d97700 Mon Sep 17 00:00:00 2001 From: Rob Bavey Date: Mon, 11 Mar 2019 16:43:56 -0400 Subject: [PATCH 0033/1126] Fix issue setting 'enable_metric => false' on a plugin This commit fixes a ClassCastException which happens when a plugin has the `enable_metric` setting set to false - a NullMetricExt is assumed, but that is only created when 'metric.collect' is set to 'false' in the Logstash configuration, not when an individual plugin disables its metrics. Fixes #10538 --- logstash-core/spec/logstash/filters/base_spec.rb | 14 ++++++++++++++ .../metrics/NullNamespacedMetricExt.java | 2 +- 2 files changed, 15 insertions(+), 1 deletion(-) diff --git a/logstash-core/spec/logstash/filters/base_spec.rb b/logstash-core/spec/logstash/filters/base_spec.rb index d943567d6..7d6f2eb5f 100644 --- a/logstash-core/spec/logstash/filters/base_spec.rb +++ b/logstash-core/spec/logstash/filters/base_spec.rb @@ -322,4 +322,18 @@ describe LogStash::Filters::NOOP do end end + + describe "when metrics are disabled" do + describe "An error should not be raised, and the event should be processed" do + config <<-CONFIG + filter { + noop { enable_metric => false } + } + CONFIG + + sample_one("type" => "noop", "tags" => {"blackhole" => "go"}) do + expect(subject.get("[tags][blackhole]")).to eq("go") + end + end + end end diff --git a/logstash-core/src/main/java/org/logstash/instrument/metrics/NullNamespacedMetricExt.java b/logstash-core/src/main/java/org/logstash/instrument/metrics/NullNamespacedMetricExt.java index 0a02c26c3..5f8ecb033 100644 --- a/logstash-core/src/main/java/org/logstash/instrument/metrics/NullNamespacedMetricExt.java +++ b/logstash-core/src/main/java/org/logstash/instrument/metrics/NullNamespacedMetricExt.java @@ -39,7 +39,7 @@ public final class NullNamespacedMetricExt extends AbstractNamespacedMetricExt { @JRubyMethod(optional = 2) public NullNamespacedMetricExt initialize(final ThreadContext context, final IRubyObject[] args) { - this.metric = args.length > 0 && !args[0].isNil() ? (NullMetricExt) args[0] : new NullMetricExt(context.runtime, metaClass); + this.metric = args.length > 0 && !args[0].isNil() && (args[0] instanceof NullMetricExt) ? (NullMetricExt) args[0] : new NullMetricExt(context.runtime, metaClass); final IRubyObject namespaceName = args.length == 2 ? args[1] : NULL; if (namespaceName instanceof RubyArray) { this.namespaceName = (RubyArray) namespaceName; From 6850509623b49fe0045e4762470a530288838260 Mon Sep 17 00:00:00 2001 From: Karen Metts <35154725+karenzone@users.noreply.github.com> Date: Wed, 13 Mar 2019 12:12:44 -0400 Subject: [PATCH 0034/1126] Cherrypick to 7.x: Convert instructions for Java plugins to asciidoc (#10550) * Convert instructions for Java plugins to asciidoc * Update java plugin docs for beta --- docs/index.asciidoc | 5 +- docs/static/contributing-java-plugin.asciidoc | 54 +++ docs/static/include/javapluginpkg.asciidoc | 134 ++++++ docs/static/include/javapluginsetup.asciidoc | 52 +++ docs/static/java-codec.asciidoc | 410 ++++++++++++++++++ docs/static/java-filter.asciidoc | 284 ++++++++++++ docs/static/java-input.asciidoc | 317 ++++++++++++++ docs/static/java-output.asciidoc | 288 ++++++++++++ 8 files changed, 1543 insertions(+), 1 deletion(-) create mode 100644 docs/static/contributing-java-plugin.asciidoc create mode 100644 docs/static/include/javapluginpkg.asciidoc create mode 100644 docs/static/include/javapluginsetup.asciidoc create mode 100644 docs/static/java-codec.asciidoc create mode 100644 docs/static/java-filter.asciidoc create mode 100644 docs/static/java-input.asciidoc create mode 100644 docs/static/java-output.asciidoc diff --git a/docs/index.asciidoc b/docs/index.asciidoc index 03cbe5a69..0a42808b8 100644 --- a/docs/index.asciidoc +++ b/docs/index.asciidoc @@ -247,12 +247,15 @@ include::static/maintainer-guide.asciidoc[] // A space is necessary here ^^^ - // Submitting a Plugin :edit_url: https://github.com/elastic/logstash/edit/{branch}/docs/static/submitting-a-plugin.asciidoc include::static/submitting-a-plugin.asciidoc[] +// Contributing to Logstash - JAVA EDITION + +:edit_url: https://github.com/elastic/logstash/edit/{branch}/docs/static/contributing-java-plugin.asciidoc +include::static/contributing-java-plugin.asciidoc[] // Glossary of Terms diff --git a/docs/static/contributing-java-plugin.asciidoc b/docs/static/contributing-java-plugin.asciidoc new file mode 100644 index 000000000..04e994fed --- /dev/null +++ b/docs/static/contributing-java-plugin.asciidoc @@ -0,0 +1,54 @@ +[[contributing-java-plugin]] +== Contributing a Java Plugin + +beta[] + +Now you can write your own Java plugin for use with {ls}. +We have provided instructions and GitHub examples to give +you a head start. + +Native support for Java plugins in {ls} consists of several components +including: + +* Extensions to the Java execution engine to support running Java plugins in +Logstash pipelines +* APIs for developing Java plugins. +The APIs are in the `co.elastic.logstash.api` package. +A Java plugin might break if it references classes or specific concrete +implementations of API interfaces outside that package. The implementation of +classes outside of the API package may change at any time. +* Coming in a future release: Tooling to automate the packaging and deployment of +Java plugins in Logstash. (Currently, this process is manual.) + +[float] +=== Process overview +Here are the steps: + +. Choose the type of plugin you want to create: input, codec, filter, or output. +. Set up your environment. +. Code the plugin. +. Package and deploy the plugin. +. Run Logstash with your new plugin. + +[float] +==== Let's get started +Here are the example repos: + +* https://github.com/logstash-plugins/logstash-input-java_input_example[Input plugin example] +* https://github.com/logstash-plugins/logstash-codec-java_codec_example[Codec plugin example] +* https://github.com/logstash-plugins/logstash-filter-java_filter_example[Filter plugin example] +* https://github.com/logstash-plugins/logstash-output-java_output_example[Output plugin example] + +Here are the instructions: + +* <> +* <> +* <> +* <> + + +include::java-input.asciidoc[] +include::java-codec.asciidoc[] +include::java-filter.asciidoc[] +include::java-output.asciidoc[] + diff --git a/docs/static/include/javapluginpkg.asciidoc b/docs/static/include/javapluginpkg.asciidoc new file mode 100644 index 000000000..b3f16c198 --- /dev/null +++ b/docs/static/include/javapluginpkg.asciidoc @@ -0,0 +1,134 @@ +[float] +=== Package and deploy + +Java plugins are packaged as Ruby gems for dependency management and +interoperability with Ruby plugins. + +NOTE: One of the goals for Java plugin support is to eliminate the need for any +knowledge of Ruby or its toolchain for Java plugin development. Future phases of +the Java plugin project will automate the packaging of Java plugins as Ruby gems +so no direct knowledge of or interaction with Ruby will be required. In the +current phase, Java plugins must still be manually packaged as Ruby gems +and installed with the `logstash-plugin` utility. + +[float] +==== Compile to JAR file + +The Java plugin should be compiled and assembled into a fat jar with the +`vendor` task in the Gradle build file. This will package all Java dependencies +into a single jar and write it to the correct folder for later packaging into a +Ruby gem. + +[float] +==== Manually package as Ruby gem + +Several Ruby source files are required to package the jar file as a +Ruby gem. These Ruby files are used only at Logstash startup time to identify +the Java plugin and are not used during runtime event processing. + +NOTE: These Ruby source files will be automatically generated in a future release. + +**+logstash-{plugintype}-<{plugintype}-name>.gemspec+** + +[source,txt] +[subs="attributes"] +----- +Gem::Specification.new do |s| + s.name = 'logstash-{plugintype}-java_{plugintype}_example' + s.version = PLUGIN_VERSION + s.licenses = ['Apache-2.0'] + s.summary = "Example {plugintype} using Java plugin API" + s.description = "" + s.authors = ['Elasticsearch'] + s.email = 'info@elastic.co' + s.homepage = "http://www.elastic.co/guide/en/logstash/current/index.html" + s.require_paths = ['lib', 'vendor/jar-dependencies'] + + # Files + s.files = Dir["lib/**/*","spec/**/*","*.gemspec","*.md","CONTRIBUTORS","Gemfile","LICENSE","NOTICE.TXT", "vendor/jar-dependencies/**/*.jar", "vendor/jar-dependencies/**/*.rb", "VERSION", "docs/**/*"] + + # Special flag to let us know this is actually a logstash plugin + s.metadata = { 'logstash_plugin' => 'true', 'logstash_group' => '{plugintype}'} + + # Gem dependencies + s.add_runtime_dependency "logstash-core-plugin-api", ">= 1.60", "<= 2.99" + s.add_runtime_dependency 'jar-dependencies' + + s.add_development_dependency 'logstash-devutils' +end +----- + +You can use this file with the following modifications: + +* `s.name` must follow the +logstash-pass:attributes[{plugintype}]-<{plugintype}-name>+ pattern +* `s.version` must match the `project.version` specified in the `build.gradle` file. +Both versions should be set to be read from the `VERSION` file in this example. + +**+lib/logstash/{plugintype}s/<{plugintype}-name>.rb+** + +[source,ruby] +[subs="attributes"] +----- +# encoding: utf-8 +require "logstash/{plugintype}s/base" +require "logstash/namespace" +require "logstash-{plugintype}-java_{plugintype}_example_jars" +require "java" + +class LogStash::{plugintype}s::Java{plugintypecap}Example < LogStash::{pluginclass}::Base + config_name "java_{plugintype}_example" + + def self.javaClass() org.logstash.javaapi.Java{plugintypecap}Example.java_class; end +end +----- + +Modify these items in the file above: + +* Change the name to correspond with the {plugintype} name. +* Change +require "logstash-{plugintype}-java_{plugintype}_example_jars"+ to reference the appropriate "jars" file +as described below. +* Change +class LogStash::{pluginclass}::Java{plugintypecap}Example < LogStash::{pluginclass}::Base+ to provide a unique and +descriptive Ruby class name. +* Change +config_name "java_{plugintype}_example"+ to match the name of the plugin as specified in the `name` property of +the `@LogstashPlugin` annotation. +* Change +def self.javaClass() org.logstash.javaapi.Java{plugintypecap}Example.java_class; end+ to return the +class of the Java {plugintype}. + +**+lib/logstash-{plugintype}-<{plugintype}-name>_jars.rb+** + +[source,txt] +[subs="attributes"] +----- +require 'jar_dependencies' +require_jar('org.logstash.javaapi', 'logstash-{plugintype}-java_{plugintype}_example', {sversion}) +----- + +In the file above: + +* Rename the file to correspond to the {plugintype} name. +* Change the `require_jar` directive to correspond to the `group` specified in the +Gradle build file, the name of the {plugintype} JAR file, and the version as +specified in both the gemspec and Gradle build file. + +After you have created the previous files and the plugin JAR file, build the gem using the +following command: + +[source,shell] +[subs="attributes"] +----- +gem build logstash-{plugintype}-<{plugintype}-name>.gemspec +----- + +[float] +==== Installing the Java plugin in Logstash + +After you have packaged your Java plugin as a Ruby gem, you can install it in +Logstash with this command: + +[source,shell] +----- +bin/logstash-plugin install --no-verify --local /path/to/javaPlugin.gem +----- + +For Windows platforms: Substitute backslashes for forward slashes as appropriate in the command. + diff --git a/docs/static/include/javapluginsetup.asciidoc b/docs/static/include/javapluginsetup.asciidoc new file mode 100644 index 000000000..02e5d6011 --- /dev/null +++ b/docs/static/include/javapluginsetup.asciidoc @@ -0,0 +1,52 @@ +To develop a new Java {plugintype} for Logstash, you write a new Java class that +conforms to the Logstash Java {pluginclass} API, package it, and install it with the +logstash-plugin utility. We'll go through each of those steps. + +[float] +=== Set up your environment + +[float] +==== Copy the example repo + +Start by copying the {pluginrepo}. The plugin API is currently part of the +Logstash codebase so you must have a local copy of that available. You can +obtain a copy of the Logstash codebase with the following `git` command: + +[source,shell] +----- +git clone --branch --single-branch https://github.com/elastic/logstash.git +----- + +The `branch_name` should correspond to the version of Logstash containing the +preferred revision of the Java plugin API. + +NOTE: The beta version of the Java plugin API is available in the `6.7` +branch of the Logstash codebase. + +Specify the `target_folder` for your local copy of the Logstash codebase. If you +do not specify `target_folder`, it defaults to a new folder called `logstash` +under your current folder. + +[float] +==== Generate the .jar file + +After you have obtained a copy of the appropriate revision of the Logstash +codebase, you need to compile it to generate the .jar file containing the Java +plugin API. From the root directory of your Logstash codebase ($LS_HOME), you +can compile it with `./gradlew assemble` (or `gradlew.bat assemble` if you're +running on Windows). This should produce the +`$LS_HOME/logstash-core/build/libs/logstash-core-x.y.z.jar` where `x`, `y`, and +`z` refer to the version of Logstash. + +After you have successfully compiled Logstash, you need to tell your Java plugin +where to find the `logstash-core-x.y.z.jar` file. Create a new file named +`gradle.properties` in the root folder of your plugin project. That file should +have a single line: + +[source,txt] +----- +LOGSTASH_CORE_PATH=/logstash-core +----- + +where `target_folder` is the root folder of your local copy of the Logstash codebase. + diff --git a/docs/static/java-codec.asciidoc b/docs/static/java-codec.asciidoc new file mode 100644 index 000000000..5ed4d3c90 --- /dev/null +++ b/docs/static/java-codec.asciidoc @@ -0,0 +1,410 @@ +:register_method: true +:encode_method: true +:decode_method: true +:plugintype: codec +:pluginclass: Codecs +:pluginname: example +:pluginnamecap: Example +:plugintypecap: Codec +:sversion: '0.2.0' + +:pluginrepo: https://github.com/logstash-plugins/logstash-codec-java_codec_example[example codec plugin] + +:blockinput: true + +//:getstarted: Let's step through creating a {plugintype} plugin using the https://github.com/logstash-plugins/logstash-codec-example/[example {plugintype} plugin]. + +//:methodheader: Logstash codecs must implement the `register` method, and the `decode` method or the `encode` method (or both). + +[[java-codec-plugin]] +=== How to write a Java codec plugin + +beta[] + +// Pulls in shared section: Setting Up Environment +include::include/javapluginsetup.asciidoc[] + +[float] +=== Code the plugin + +The example codec plugin decodes messages separated by a configurable delimiter +and encodes messages by writing their string representation separated by a +delimiter. For example, if the codec were configured with `/` as the delimiter, +the input text `event1/event2/` would be decoded into two separate events with +`message` fields of `event1` and `event2`, respectively. Note that this is only +an example codec and does not cover all the edge cases that a production-grade +codec should cover. + +Let's look at the main class in that codec filter: + +[source,java] +----- +@LogstashPlugin(name="java_codec_example") +public class JavaCodecExample implements Codec { + + public static final PluginConfigSpec DELIMITER_CONFIG = + PluginConfigSpec.stringSetting("delimiter", ","); + + private final String id; + private final String delimiter; + private final CharsetEncoder encoder; + private Event currentEncodedEvent; + private CharBuffer currentEncoding; + + public JavaCodecExample(final Configuration config, final Context context) { + this(config.get(DELIMITER_CONFIG)); + } + + private JavaCodecExample(String delimiter) { + this.id = UUID.randomUUID().toString(); + this.delimiter = delimiter; + this.encoder = Charset.defaultCharset().newEncoder(); + } + + @Override + public void decode(ByteBuffer byteBuffer, Consumer> consumer) { + // a not-production-grade delimiter decoder + byte[] byteInput = new byte[byteBuffer.remaining()]; + byteBuffer.get(byteInput); + if (byteInput.length > 0) { + String input = new String(byteInput); + String[] split = input.split(delimiter); + for (String s : split) { + Map map = new HashMap<>(); + map.put("message", s); + consumer.accept(map); + } + } + } + + @Override + public void flush(ByteBuffer byteBuffer, Consumer> consumer) { + // if the codec maintains any internal state such as partially-decoded input, this + // method should flush that state along with any additional input supplied in + // the ByteBuffer + + decode(byteBuffer, consumer); // this is a simplistic implementation + } + + @Override + public boolean encode(Event event, ByteBuffer buffer) throws EncodeException { + try { + if (currentEncodedEvent != null && event != currentEncodedEvent) { + throw new EncodeException("New event supplied before encoding of previous event was completed"); + } else if (currentEncodedEvent == null) { + currentEncoding = CharBuffer.wrap(event.toString() + delimiter); + } + + CoderResult result = encoder.encode(currentEncoding, buffer, true); + buffer.flip(); + if (result.isError()) { + result.throwException(); + } + + if (result.isOverflow()) { + currentEncodedEvent = event; + return false; + } else { + currentEncodedEvent = null; + return true; + } + } catch (IOException e) { + throw new IllegalStateException(e); + } + } + + @Override + public Collection> configSchema() { + // should return a list of all configuration options for this plugin + return Collections.singletonList(DELIMITER_CONFIG); + } + + @Override + public Codec cloneCodec() { + return new JavaCodecExample(this.delimiter); + } + + @Override + public String getId() { + return this.id; + } +} +----- + +Let's step through and examine each part of that class. + +[float] +==== Class declaration + +[source,java] +----- +@LogstashPlugin(name="java_codec_example") +public class JavaCodecExample implements Codec { +----- + +Notes about the class declaration: + +* All Java plugins must be annotated with the `@LogstashPlugin` annotation. Additionally: +** The `name` property of the annotation must be supplied and defines the name of the plugin as it will be used + in the Logstash pipeline definition. For example, this codec would be referenced in the codec section of the + an appropriate input or output in the Logstash pipeline defintion as `codec => java_codec_example { }` +** The value of the `name` property must match the name of the class excluding casing and underscores. +* The class must implement the `co.elastic.logstash.api.Codec` interface. + +[float] +===== Plugin settings + +The snippet below contains both the setting definition and the method referencing it: + +[source,java] +----- +public static final PluginConfigSpec DELIMITER_CONFIG = + PluginConfigSpec.stringSetting("delimiter", ","); + +@Override +public Collection> configSchema() { + return Collections.singletonList(DELIMITER_CONFIG); +} +----- + +The `PluginConfigSpec` class allows developers to specify the settings that a +plugin supports complete with setting name, data type, deprecation status, +required status, and default value. In this example, the `delimiter` setting +defines the delimiter on which the codec will split events. It is not a required +setting and if it is not explicitly set, its default value will be `,`. + +The `configSchema` method must return a list of all settings that the plugin +supports. The Logstash execution engine will validate that all required +settings are present and that no unsupported settings are present. + +[float] +===== Constructor and initialization + +[source,java] +----- +private final String id; +private final String delimiter; +private final CharsetEncoder encoder; + +public JavaCodecExample(final Configuration config, final Context context) { + this(config.get(DELIMITER_CONFIG)); +} + +private JavaCodecExample(String delimiter) { + this.id = UUID.randomUUID().toString(); + this.delimiter = delimiter; + this.encoder = Charset.defaultCharset().newEncoder(); +} +----- + +All Java codec plugins must have a constructor taking a `Configuration` and +`Context` argument. This is the constructor that will be used to instantiate +them at runtime. The retrieval and validation of all plugin settings should +occur in this constructor. In this example, the delimiter to be used for +delimiting events is retrieved from its setting and stored in a local variable +so that it can be used later in the `decode` and `encode` methods. The codec's +ID is initialized to a random UUID (as should be done for most codecs), and a +local `encoder` variable is initialized to encode and decode with a specified +character set. + +Any additional initialization may occur in the constructor as well. If there are +any unrecoverable errors encountered in the configuration or initialization of +the codec plugin, a descriptive exception should be thrown. The exception will +be logged and will prevent Logstash from starting. + +[float] +==== Codec methods + +[source,java] +----- +@Override +public void decode(ByteBuffer byteBuffer, Consumer> consumer) { + // a not-production-grade delimiter decoder + byte[] byteInput = new byte[byteBuffer.remaining()]; + byteBuffer.get(byteInput); + if (byteInput.length > 0) { + String input = new String(byteInput); + String[] split = input.split(delimiter); + for (String s : split) { + Map map = new HashMap<>(); + map.put("message", s); + consumer.accept(map); + } + } +} + +@Override +public void flush(ByteBuffer byteBuffer, Consumer> consumer) { + decode(byteBuffer, consumer); // this is a simplistic implementation +} + +@Override +public boolean encode(Event event, ByteBuffer buffer) throws EncodeException { + try { + if (currentEncodedEvent != null && event != currentEncodedEvent) { + throw new EncodeException("New event supplied before encoding of previous event was completed"); + } else if (currentEncodedEvent == null) { + currentEncoding = CharBuffer.wrap(event.toString() + delimiter); + } + + CoderResult result = encoder.encode(currentEncoding, buffer, true); + buffer.flip(); + if (result.isError()) { + result.throwException(); + } + + if (result.isOverflow()) { + currentEncodedEvent = event; + return false; + } else { + currentEncodedEvent = null; + return true; + } + } catch (IOException e) { + throw new IllegalStateException(e); + } +} + +----- + +The `decode`, `flush`, and `encode` methods provide the core functionality of +the codec. Codecs may be used by inputs to decode a sequence or stream of bytes +into events or by outputs to encode events into a sequence of bytes. + +The `decode` method decodes events from the specified `ByteBuffer` and passes +them to the provided `Consumer`. The input must provide a `ByteBuffer` that is +ready for reading with `byteBuffer.position()` indicating the next position to +read and `byteBuffer.limit()` indicating the first byte in the buffer that is +not safe to read. Codecs must ensure that `byteBuffer.position()` reflects the +last-read position before returning control to the input. The input is then +responsible for returning the buffer to write mode via either +`byteBuffer.clear()` or `byteBuffer.compact()` before resuming writes. In the +example above, the `decode` method simply splits the incoming byte stream on the +specified delimiter. A production-grade codec such as +https://github.com/elastic/logstash/blob/6.7/logstash-core/src/main/java/org/logstash/plugins/codecs/Line.java[`java-line`] +would not make the simplifying assumption that the end of the supplied byte +stream corresponded with the end of an event. + +The `flush` method works in coordination with the `decode` method to decode all +remaining events from the specified `ByteBuffer` along with any internal state +that may remain after previous calls to the `decode` method. As an example of +internal state that a codec might maintain, consider an input stream of bytes +`event1/event2/event3` with a delimiter of `/`. Due to buffering or other +reasons, the input might supply a partial stream of bytes such as `event1/eve` +to the codec's `decode` method. In this case, the codec could save the beginning +three characters `eve` of the second event rather than assuming that the +supplied byte stream ends on an event boundary. If the next call to `decode` +supplied the `nt2/ev` bytes, the codec would prepend the saved `eve` bytes to +produce the full `event2` event and then save the remaining `ev` bytes for +decoding when the remainder of the bytes for that event were supplied. A call to +`flush` signals the codec that the supplied bytes represent the end of an event +stream and all remaining bytes should be decoded to events. The `flush` example +above is a simplistic implementation that does not maintain any state about +partially-supplied byte streams across calls to `decode`. + +The `encode` method encodes an event into a sequence of bytes and writes it into +the specified `ByteBuffer`. Under ideal circumstances, the entirety of the +event's encoding will fit into the supplied buffer. In cases where the buffer +has insufficient space to hold the event's encoding, the codec must fill the +buffer with as much of the event's encoding as possible, the `encode` must +return `false`, and the output must call the `encode` method with the same event +and a buffer that has more `buffer.remaining()` bytes. The output typically does +that by draining the partial encoding from the supplied buffer. This process +must be repeated until the event's entire encoding is written to the buffer at +which point the `encode` method will return `true`. Attempting to call this +method with a new event before the entirety of the previous event's encoding has +been written to a buffer must result in an `EncodeException`. As the coneptual +inverse of the `decode` method, the `encode` method must return the buffer in a +state from which it can be read, typically by calling `buffer.flip()` before +returning. In the example above, the `encode` method attempts to write the +event's encoding to the supplied buffer. If the buffer contains sufficient free +space, the entirety of the event is written and `true` is returned. Otherwise, +the method writes as much of the event's encoding to the buffer as possible, +returns `false`, and stores the remainder to be written to the buffer in the +next call to the `encode` method. + +[float] +==== cloneCodec method + +[source,java] +----- +@Override +public Codec cloneCodec() { + return new JavaCodecExample(this.delimiter); +} +----- + +The `cloneCodec` method should return an identical instance of the codec with the exception of its ID. Because codecs +may be stateful, a separate instance of each codec must be supplied to each worker thread in a pipeline. For all +pipelines with more than one worker, the `cloneCodec` method is called by the Logstash execution engine to create all +codec instances beyond the first. In the example above, the codec is cloned with the same delimiter but a different ID. + +[float] +==== getId method + +[source,java] +----- +@Override +public String getId() { + return id; +} +----- + +For codec plugins, the `getId` method should always return the id that was set at instantiation time. This is typically +an UUID. + +[float] +==== Unit tests + +Lastly, but certainly not least importantly, unit tests are strongly encouraged. +The example codec plugin includes an +https://github.com/logstash-plugins/logstash-codec-java_codec_example/blob/master/src/test/java/org/logstash/javaapi/JavaCodecExampleTest.java[example unit +test] that you can use as a template for your own. + +// Pulls in shared section about Packaging and Deploying +include::include/javapluginpkg.asciidoc[] + +[float] +=== Run Logstash with the Java codec plugin + +To test the plugin, start Logstash with: + +[source,java] +----- +echo "foo,bar" | bin/logstash --java-execution -e 'input { java_stdin { codec => java_codec_example } } }' +----- + +Note that the `--java-execution` flag to enable the Java execution engine is required as Java plugins are not supported +in the Ruby execution engine. +The expected Logstash output (excluding initialization) with the configuration above is: + +[source,txt] +----- +{ + "@version" => "1", + "message" => "foo", + "@timestamp" => yyyy-MM-ddThh:mm:ss.SSSZ, + "host" => "" +} +{ + "@version" => "1", + "message" => "bar\n", + "@timestamp" => yyyy-MM-ddThh:mm:ss.SSSZ, + "host" => "" +} +----- + +[float] +=== Feedback + +If you have any feedback on Java plugin support in Logstash, please comment on our +https://github.com/elastic/logstash/issues/9215[main Github issue] or post in the +https://discuss.elastic.co/c/logstash[Logstash forum]. + +:pluginrepo!: +:sversion!: +:plugintypecap!: +:pluginnamecap!: +:pluginname!: +:pluginclass!: +:plugintype!: diff --git a/docs/static/java-filter.asciidoc b/docs/static/java-filter.asciidoc new file mode 100644 index 000000000..886b8a4d0 --- /dev/null +++ b/docs/static/java-filter.asciidoc @@ -0,0 +1,284 @@ +:register_method: true +:filter_method: true +:plugintype: filter +:pluginclass: Filters +:pluginname: example +:pluginnamecap: Example +:plugintypecap: Filter +:sversion: '0.0.1' + +:pluginrepo: https://github.com/logstash-plugins/logstash-filter-java_filter_example[example filter plugin] + +:blockcodec: true + +[[java-filter-plugin]] +=== How to write a Java filter plugin + +beta[] + +// Pulls in shared section: Setting Up Environment +include::include/javapluginsetup.asciidoc[] + +[float] +=== Code the plugin + +The example filter plugin allows one to configure a field in each event that +will be reversed. For example, if the filter were configured to reverse the +`day_of_week` field, an event with `day_of_week: "Monday"` would be transformed +to `day_of_week: "yadnoM"`. Let's look at the main class in that example filter: + +[source,java] +----- +@LogstashPlugin(name = "java_filter_example") +public class JavaFilterExample implements Filter { + + public static final PluginConfigSpec SOURCE_CONFIG = + PluginConfigSpec.stringSetting("source", "message"); + + private String id; + private String sourceField; + + public JavaFilterExample(String id, Configuration config, Context context) { + this.id = id; + this.sourceField = config.get(SOURCE_CONFIG); + } + + @Override + public Collection filter(Collection events, FilterMatchListener matchListener) { + for (Event e : events) { + Object f = e.getField(sourceField); + if (f instanceof String) { + e.setField(sourceField, StringUtils.reverse((String)f)); + matchListener.filterMatched(e); + } + } + return events; + } + + @Override + public Collection> configSchema() { + return Collections.singletonList(SOURCE_CONFIG); + } + + @Override + public String getId() { + return this.id; + } +} +----- + +Let's step through and examine each part of that class. + +[float] +==== Class declaration + +[source,java] +----- +@LogstashPlugin(name = "java_filter_example") +public class JavaFilterExample implements Filter { +----- + +Notes about the class declaration: + +* All Java plugins must be annotated with the `@LogstashPlugin` annotation. Additionally: +** The `name` property of the annotation must be supplied and defines the name of the plugin as it will be used + in the Logstash pipeline definition. For example, this filter would be referenced in the filter section of the + Logstash pipeline defintion as `filter { java_filter_example => { .... } }` +** The value of the `name` property must match the name of the class excluding casing and underscores. +* The class must implement the `co.elastic.logstash.api.Filter` interface. + +[float] +==== Plugin settings +The snippet below contains both the setting definition and the method referencing it: + +[source,java] +----- +public static final PluginConfigSpec SOURCE_CONFIG = + PluginConfigSpec.stringSetting("source", "message"); + +@Override +public Collection> configSchema() { + return Collections.singletonList(SOURCE_CONFIG); +} +----- + +The `PluginConfigSpec` class allows developers to specify the settings that a plugin supports complete with setting +name, data type, deprecation status, required status, and default value. In this example, the `source` setting defines +the name of the field in each event that will be reversed. It is not a required setting and if it is not explicitly +set, its default value will be `message`. + +The `configSchema` method must return a list of all settings that the plugin supports. In a future phase of the +Java plugin project, the Logstash execution engine will validate that all required settings are present and that +no unsupported settings are present. + +[float] +==== Constructor and initialization + +[source,java] +----- +private String id; +private String sourceField; + +public JavaFilterExample(String id, Configuration config, Context context) { + this.id = id; + this.sourceField = config.get(SOURCE_CONFIG); +} +----- + +All Java filter plugins must have a constructor taking a `String` id and a +`Configuration` and `Context` argument. This is the constructor that will be +used to instantiate them at runtime. The retrieval and validation of all plugin +settings should occur in this constructor. In this example, the name of the +field to be reversed in each event is retrieved from its setting and stored in +a local variable so that it can be used later in the `filter` method. + +Any additional initialization may occur in the constructor as well. If there are +any unrecoverable errors encountered in the configuration or initialization of +the filter plugin, a descriptive exception should be thrown. The exception will +be logged and will prevent Logstash from starting. + +[float] +==== Filter method + +[source,java] +----- +@Override +public Collection filter(Collection events, FilterMatchListener matchListener) { + for (Event e : events) { + Object f = e.getField(sourceField); + if (f instanceof String) { + e.setField(sourceField, StringUtils.reverse((String)f)); + matchListener.filterMatched(e); + } + } + return events; +----- + +Finally, we come to the `filter` method that is invoked by the Logstash +execution engine on batches of events as they flow through the event processing +pipeline. The events to be filtered are supplied in the `events` argument and +the method should return a collection of filtered events. Filters may perform a +variety of actions on events as they flow through the pipeline including: + +* Mutation -- Fields in events may be added, removed, or changed by a filter. This +is the most common scenario for filters that perform various kinds of +enrichment on events. In this scenario, the incoming `events` collection may be +returned unmodified since the events in the collection are mutated in place. + +* Deletion -- Events may be removed from the event pipeline by a filter so that +subsequent filters and outputs do not receive them. In this scenario, the +events to be deleted must be removed from the collection of filtered events +before it is returned. + +* Creation -- A filter may insert new events into the event pipeline that will be +seen only by subsequent filters and outputs. In this scenario, the new events +must be added to the collection of filtered events before it is returned. + +* Observation -- Events may pass unchanged by a filter through the event pipeline. +This may be useful in scenarios where a filter performs external actions (e.g., +updating an external cache) based on the events observed in the event pipeline. +In this scenario, the incoming `events` collection may be returned unmodified +since no changes were made. + +In the example above, the value of the `source` field is retrieved from each +event and reversed if it is a string value. Because each event is mutated in +place, the incoming `events` collection can be returned. + +The `matchListener` is the mechanism by which filters indicate which events +"match". The common actions for filters such as `add_field` and `add_tag` are +applied only to events that are designated as "matching". Some filters such as +the https://www.elastic.co/guide/en/logstash/current/plugins-filters-grok.html[grok +filter] +have a clear definition for what constitutes a matching event and will notify +the listener only for matching events. Other filters such as the +https://www.elastic.co/guide/en/logstash/current/plugins-filters-uuid.html[UUID +filter] +have no specific match criteria and should notify the listener for every event +filtered. In this example, the filter notifies the match listener for any event +that had a `String` value in its `source` field and was therefore able to be +reversed. + +[float] +==== getId method + +[source,java] +----- +@Override +public String getId() { + return id; +} +---- + +For filter plugins, the `getId` method should always return the id that was provided to the plugin through its +constructor at instantiation time. + +[float] +==== Unit tests + +Lastly, but certainly not least importantly, unit tests are strongly encouraged. +The example filter plugin includes an +https://github.com/logstash-plugins/logstash-filter-java_filter_example/blob/master/src/test/java/org/logstash/javaapi/JavaFilterExampleTest.java)[example +unit test] that you can use as a template for your own. + + +// Pulls in shared section about Packaging and Deploying +include::include/javapluginpkg.asciidoc[] + +[float] +=== Run Logstash with the Java filter plugin + +The following is a minimal Logstash configuration that can be used to test that +the Java filter plugin is correctly installed and functioning. + +[source,java] +----- +input { + generator { message => "Hello world!" count => 1 } +} +filter { + java_filter_example {} +} +output { + stdout { codec => rubydebug } +} +----- + +Copy the above Logstash configuration to a file such as `java_filter.conf`. +Start Logstash with: + +[source,shell] +----- +bin/logstash --java-execution -f /path/to/java_filter.conf +----- + +Note that the `--java-execution` flag to enable the Java execution engine is +required as Java plugins are not supported in the Ruby execution engine. + +The expected Logstash output (excluding initialization) with the configuration +above is: + +[source,txt] +----- +{ + "sequence" => 0, + "@version" => "1", + "message" => "!dlrow olleH", + "@timestamp" => yyyy-MM-ddThh:mm:ss.SSSZ, + "host" => "" +} +----- + +[float] +=== Feedback + +If you have any feedback on Java plugin support in Logstash, please comment on our +https://github.com/elastic/logstash/issues/9215[main Github issue] or post in the +https://discuss.elastic.co/c/logstash[Logstash forum]. + +:pluginrepo!: +:sversion!: +:plugintypecap!: +:pluginnamecap!: +:pluginname!: +:pluginclass!: +:plugintype!: diff --git a/docs/static/java-input.asciidoc b/docs/static/java-input.asciidoc new file mode 100644 index 000000000..917348275 --- /dev/null +++ b/docs/static/java-input.asciidoc @@ -0,0 +1,317 @@ +:register_method: true +:run_method: true +:plugintype: input +:pluginclass: Inputs +:pluginname: example +:pluginnamecap: Example +:plugintypecap: Input +:sversion: '0.0.1' + +:pluginrepo: https://github.com/logstash-plugins/logstash-input-java_input_example[example input plugin] + + +[[java-input-plugin]] +=== How to write a Java input plugin + +beta[] + +// Pulls in shared section: Setting Up Environment +include::include/javapluginsetup.asciidoc[] + +[float] +=== Code the plugin + +The example input plugin generates a configurable number of simple events before +terminating. Let's look at the main class in the example input. + +[source,java] +----- +@LogstashPlugin(name="java_input_example") +public class JavaInputExample implements Input { + + public static final PluginConfigSpec EVENT_COUNT_CONFIG = + PluginConfigSpec.numSetting("count", 3); + + public static final PluginConfigSpec PREFIX_CONFIG = + PluginConfigSpec.stringSetting("prefix", "message"); + + private String id; + private long count; + private String prefix; + private final CountDownLatch done = new CountDownLatch(1); + private volatile boolean stopped; + + + public JavaInputExample(String id, Configuration config, Context context) { + this.id = id; + count = config.get(EVENT_COUNT_CONFIG); + prefix = config.get(PREFIX_CONFIG); + } + + @Override + public void start(Consumer> consumer) { + int eventCount = 0; + try { + while (!stopped && eventCount < count) { + eventCount++; + consumer.accept.push(Collections.singletonMap("message", + prefix + " " + StringUtils.center(eventCount + " of " + count, 20))); + } + } finally { + stopped = true; + done.countDown(); + } + } + + @Override + public void stop() { + stopped = true; // set flag to request cooperative stop of input + } + + @Override + public void awaitStop() throws InterruptedException { + done.await(); // blocks until input has stopped + } + + @Override + public Collection> configSchema() { + return Arrays.asList(EVENT_COUNT_CONFIG, PREFIX_CONFIG); + } + + @Override + public String getId() { + return this.id; + } +} +----- + +Let's step through and examine each part of that class. + +[float] +==== Class declaration + +[source,java] +----- +@LogstashPlugin(name="java_input_example") +public class JavaInputExample implements Input { +----- + +Notes about the class declaration: + +* All Java plugins must be annotated with the `@LogstashPlugin` annotation. Additionally: +** The `name` property of the annotation must be supplied and defines the name of the plugin as it will be used + in the Logstash pipeline definition. For example, this input would be referenced in the input section of the + Logstash pipeline defintion as `input { java_input_example => { .... } }` +** The value of the `name` property must match the name of the class excluding casing and underscores. +* The class must implement the `co.elastic.logstash.api.Input` interface. + +[float] +==== Plugin settings + +The snippet below contains both the setting definition and the method referencing it. + +[source,java] +----- +public static final PluginConfigSpec EVENT_COUNT_CONFIG = + PluginConfigSpec.numSetting("count", 3); + +public static final PluginConfigSpec PREFIX_CONFIG = + PluginConfigSpec.stringSetting("prefix", "message"); + +@Override +public Collection> configSchema() { + return Arrays.asList(EVENT_COUNT_CONFIG, PREFIX_CONFIG); +} +----- + +The `PluginConfigSpec` class allows developers to specify the settings that a +plugin supports complete with setting name, data type, deprecation status, +required status, and default value. In this example, the `count` setting defines +the number of events that will be generated and the `prefix` setting defines an +optional prefix to include in the event field. Neither setting is required and +if it is not explicitly set, the settings default to `3` and `message`, +respectively. + +The `configSchema` method must return a list of all settings that the plugin +supports. In a future phase of the Java plugin project, the Logstash execution +engine will validate that all required settings are present and that no +unsupported settings are present. + +[float] +==== Constructor and initialization + +[source,java] +----- +private String id; +private long count; +private String prefix; + +public JavaInputExample(String id, Configuration config, Context context) { + this.id = id; + count = config.get(EVENT_COUNT_CONFIG); + prefix = config.get(PREFIX_CONFIG); +} +----- + +All Java input plugins must have a constructor taking a `String` id and +`Configuration` and `Context` argument. This is the constructor that will be +used to instantiate them at runtime. The retrieval and validation of all plugin +settings should occur in this constructor. In this example, the values of the +two plugin settings are retrieved and stored in local variables for later use in +the `start` method. + +Any additional initialization may occur in the constructor as well. If there are +any unrecoverable errors encountered in the configuration or initialization of +the input plugin, a descriptive exception should be thrown. The exception will +be logged and will prevent Logstash from starting. + +[float] +==== Start method + +[source,java] +----- +@Override +public void start(Consumer> consumer) { + int eventCount = 0; + try { + while (!stopped && eventCount < count) { + eventCount++; + consumer.accept.push(Collections.singletonMap("message", + prefix + " " + StringUtils.center(eventCount + " of " + count, 20))); + } + } finally { + stopped = true; + done.countDown(); + } +} +----- + +The `start` method begins the event-producing loop in an input. Inputs are flexible and may produce events through +many different mechanisms including: + + * a pull mechanism such as periodic queries of external database + * a push mechanism such as events sent from clients to a local network port + * a timed computation such as a heartbeat + * any other mechanism that produces a useful stream of events. Event streams may be either finite or infinite. +If the input produces an infinite stream of events, this method should loop until a stop request is made through +the `stop` method. If the input produces a finite stream of events, this method should terminate when the last +event in the stream is produced or a stop request is made, whichever comes first. + +Events should be constructed as instances of `Map` and pushed into the event pipeline via the +`Consumer>.accept()` method. + +[float] +==== Stop and awaitStop methods + +[source,java] +----- +private final CountDownLatch done = new CountDownLatch(1); +private volatile boolean stopped; + +@Override +public void stop() { + stopped = true; // set flag to request cooperative stop of input +} + +@Override +public void awaitStop() throws InterruptedException { + done.await(); // blocks until input has stopped +} +----- + +The `stop` method notifies the input to stop producing events. The stop +mechanism may be implemented in any way that honors the API contract though a +`volatile boolean` flag works well for many use cases. + +Inputs stop both asynchronously and cooperatively. Use the `awaitStop` method to +block until the input has completed the stop process. Note that this method +should **not** signal the input to stop as the `stop` method does. The +awaitStop mechanism may be implemented in any way that honors the API contract +though a `CountDownLatch` works well for many use cases. + +[float] +==== getId method + +[source,java] +----- +@Override +public String getId() { + return id; +} +----- + +For input plugins, the `getId` method should always return the id that was provided to the plugin through its +constructor at instantiation time. + +[float] +==== Unit tests +Lastly, but certainly not least importantly, unit tests are strongly encouraged. +The example input plugin includes an +https://github.com/logstash-plugins/logstash-input-java_input_example/blob/master/src/test/java/org/logstash/javaapi/JavaInputExampleTest.java[example unit +test] that you can use as a template for your own. + +// Pulls in shared section about Packaging and Deploying +include::include/javapluginpkg.asciidoc[] + +[float] +=== Running Logstash with the Java input plugin + +The following is a minimal Logstash configuration that can be used to test that +the Java input plugin is correctly installed and functioning. + +[source,java] +----- +input { + java_input_example {} +} +output { + stdout { codec => rubydebug } +} +----- + +Copy the above Logstash configuration to a file such as `java_input.conf`. +Start {ls} with: + +[source,shell] +----- +bin/logstash --java-execution -f /path/to/java_input.conf +----- + +Note that the `--java-execution` flag to enable the Java execution engine is +required as Java plugins are not supported in the Ruby execution engine. + +The expected Logstash output (excluding initialization) with the configuration above is: + +[source,txt] +----- +{ + "@version" => "1", + "message" => "message 1 of 3 ", + "@timestamp" => yyyy-MM-ddThh:mm:ss.SSSZ +} +{ + "@version" => "1", + "message" => "message 2 of 3 ", + "@timestamp" => yyyy-MM-ddThh:mm:ss.SSSZ +} +{ + "@version" => "1", + "message" => "message 3 of 3 ", + "@timestamp" => yyyy-MM-ddThh:mm:ss.SSSZ +} +----- + +[float] +=== Feedback + +If you have any feedback on Java plugin support in Logstash, please comment on our +https://github.com/elastic/logstash/issues/9215[main Github issue] or post in the +https://discuss.elastic.co/c/logstash[Logstash forum]. + +:pluginrepo!: +:sversion!: +:plugintypecap!: +:pluginnamecap!: +:pluginname!: +:pluginclass!: +:plugintype!: diff --git a/docs/static/java-output.asciidoc b/docs/static/java-output.asciidoc new file mode 100644 index 000000000..0ea374768 --- /dev/null +++ b/docs/static/java-output.asciidoc @@ -0,0 +1,288 @@ +:register_method: true +:multi_receive_method: true +:plugintype: output +:pluginclass: Outputs +:pluginname: example +:pluginnamecap: Example +:plugintypecap: Output +:sversion: '0.0.1' + +:pluginrepo: https://github.com/logstash-plugins/logstash-output-java_output_example[example output plugin] + +:blockfilter: true + + +[[java-output-plugin]] +=== How to write a Java output plugin + +beta[] + +// Pulls in shared section: Setting Up Environment +include::include/javapluginsetup.asciidoc[] + +[float] +=== Code the plugin + +The example output plugin prints events to the console using the event's +`toString` method. Let's look at the main class in the example output: + +[source,java] +----- +@LogstashPlugin(name = "java_output_example") +public class JavaOutputExample implements Output { + + public static final PluginConfigSpec PREFIX_CONFIG = + PluginConfigSpec.stringSetting("prefix", ""); + + private final String id; + private String prefix; + private PrintStream printer; + private final CountDownLatch done = new CountDownLatch(1); + private volatile boolean stopped = false; + + public JavaOutputExample(final String id, final Configuration configuration, final Context context) { + this(id, configuration, context, System.out); + } + + JavaOutputExample(final String id, final Configuration config, final Context context, OutputStream targetStream) { + this.id = id; + prefix = config.get(PREFIX_CONFIG); + printer = new PrintStream(targetStream); + } + + @Override + public void output(final Collection events) { + Iterator z = events.iterator(); + while (z.hasNext() && !stopped) { + String s = prefix + z.next(); + printer.println(s); + } + } + + @Override + public void stop() { + stopped = true; + done.countDown(); + } + + @Override + public void awaitStop() throws InterruptedException { + done.await(); + } + + @Override + public Collection> configSchema() { + return Collections.singletonList(PREFIX_CONFIG); + } + + @Override + public String getId() { + return id; + } +} +----- + +Let's step through and examine each part of that class. + +[float] +==== Class declaration + +[source,java] +----- +@LogstashPlugin(name="java_output_example") +public class JavaOutputExample implements Output { +----- + +Notes about the class declaration: + +* All Java plugins must be annotated with the `@LogstashPlugin` annotation. Additionally: +** The `name` property of the annotation must be supplied and defines the name of the plugin as it will be used + in the Logstash pipeline definition. For example, this output would be referenced in the output section of the + Logstash pipeline definition as `output { java_output_example => { .... } }` +** The value of the `name` property must match the name of the class excluding casing and underscores. +* The class must implement the `co.elastic.logstash.api.Output` interface. + +[float] +==== Plugin settings + +The snippet below contains both the setting definition and the method referencing it: + +[source,java] +----- +public static final PluginConfigSpec PREFIX_CONFIG = + PluginConfigSpec.stringSetting("prefix", ""); + +@Override +public Collection> configSchema() { + return Collections.singletonList(PREFIX_CONFIG); +} +----- + +The `PluginConfigSpec` class allows developers to specify the settings that a +plugin supports complete with setting name, data type, deprecation status, +required status, and default value. In this example, the `prefix` setting +defines an optional prefix to include in the output of the event. The setting is +not required and if it is not explicitly set, it defaults to the empty string. + +The `configSchema` method must return a list of all settings that the plugin +supports. In a future phase of the Java plugin project, the Logstash execution +engine will validate that all required settings are present and that no +unsupported settings are present. + +[float] +==== Constructor and initialization + +[source,java] +----- +private final String id; +private String prefix; +private PrintStream printer; + +public JavaOutputExample(final String id, final Configuration configuration, final Context context) { + this(configuration, context, System.out); +} + +JavaOutputExample(final String id, final Configuration config, final Context context, OutputStream targetStream) { + this.id = id; + prefix = config.get(PREFIX_CONFIG); + printer = new PrintStream(targetStream); +} +----- + +All Java output plugins must have a constructor taking a `String` id and a +`Configuration` and `Context` argument. This is the constructor that will be +used to instantiate them at runtime. The retrieval and validation of all plugin +settings should occur in this constructor. In this example, the values of the +`prefix` setting is retrieved and stored in a local variable for later use in +the `output` method. In this example, a second, pacakge private constructor is +defined that is useful for unit testing with a `Stream` other than `System.out`. + +Any additional initialization may occur in the constructor as well. If there are +any unrecoverable errors encountered in the configuration or initialization of +the output plugin, a descriptive exception should be thrown. The exception will +be logged and will prevent Logstash from starting. + +[float] +==== Output method + +[source,java] +----- +@Override +public void output(final Collection events) { + Iterator z = events.iterator(); + while (z.hasNext() && !stopped) { + String s = prefix + z.next(); + printer.println(s); + } +} +----- + +Outputs may send events to local sinks such as the console or a file or to remote systems such as Elasticsearch +or other external systems. In this example, the events are printed to the local console. + +[float] +==== Stop and awaitStop methods + +[source,java] +----- +private final CountDownLatch done = new CountDownLatch(1); +private volatile boolean stopped; + +@Override +public void stop() { + stopped = true; + done.countDown(); +} + +@Override +public void awaitStop() throws InterruptedException { + done.await(); +} +----- + +The `stop` method notifies the output to stop sending events. The stop mechanism +may be implemented in any way that honors the API contract though a `volatile +boolean` flag works well for many use cases. Because this output example is so +simple, its `output` method does not check for the stop flag. + +Outputs stop both asynchronously and cooperatively. Use the `awaitStop` method +to block until the output has completed the stop process. Note that this method +should **not** signal the output to stop as the `stop` method does. The +awaitStop mechanism may be implemented in any way that honors the API contract +though a `CountDownLatch` works well for many use cases. + +[float] +==== getId method + +[source,java] +----- +@Override +public String getId() { + return id; +} +----- + +For output plugins, the `getId` method should always return the id that was provided to the plugin through its +constructor at instantiation time. + +[float] +==== Unit tests + +Lastly, but certainly not least importantly, unit tests are strongly encouraged. +The example output plugin includes an +https://github.com/logstash-plugins/logstash-output-java_output_example/blob/master/src/test/java/org/logstash/javaapi/JavaOutputExampleTest.java[example unit +test] that you can use as a template for your own. + + +// Pulls in shared section about Packaging and Deploying +include::include/javapluginpkg.asciidoc[] + +[float] +=== Running Logstash with the Java output plugin + +The following is a minimal Logstash configuration that can be used to test that +the Java output plugin is correctly installed and functioning. + +[source,java] +----- +input { + generator { message => "Hello world!" count => 1 } +} +output { + java_output_example {} +} +----- + +Copy the above Logstash configuration to a file such as `java_output.conf`. +Logstash should then be started with: + +[source,txt] +----- +bin/logstash --java-execution -f /path/to/java_output.conf +----- + +Note that the `--java-execution` flag to enable the Java execution engine is +required as Java plugins are not supported in the Ruby execution engine. + +The expected Logstash output (excluding initialization) with the configuration +above is: + +[source,txt] +----- +{"@timestamp":"yyyy-MM-ddTHH:mm:ss.SSSZ","message":"Hello world!","@version":"1","host":"","sequence":0} +----- + +[float] +=== Feedback + +If you have any feedback on Java plugin support in Logstash, please comment on our +https://github.com/elastic/logstash/issues/9215[main Github issue] or post in the +https://discuss.elastic.co/c/logstash[Logstash forum]. + +:pluginrepo!: +:sversion!: +:plugintypecap!: +:pluginnamecap!: +:pluginname!: +:pluginclass!: +:plugintype!: From ebad88a358449df09dae97419c6802e6e5b967da Mon Sep 17 00:00:00 2001 From: Joao Duarte Date: Wed, 13 Mar 2019 12:00:38 +0000 Subject: [PATCH 0035/1126] make monitoring specs resilient to internal api number changes Fixes #10552 --- x-pack/qa/integration/spec_helper.rb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/x-pack/qa/integration/spec_helper.rb b/x-pack/qa/integration/spec_helper.rb index d93b3c26c..3c9bbc9b3 100644 --- a/x-pack/qa/integration/spec_helper.rb +++ b/x-pack/qa/integration/spec_helper.rb @@ -2,7 +2,7 @@ # or more contributor license agreements. Licensed under the Elastic License; # you may not use this file except in compliance with the Elastic License. -MONITORING_INDEXES = ".monitoring-logstash-2*,.monitoring-logstash-6*" +MONITORING_INDEXES = ".monitoring-logstash-*" require_relative "support/helpers" require_relative "support/shared_examples" From f6933dbe9a939c6d6fb484d2b493527b74cae937 Mon Sep 17 00:00:00 2001 From: Colin Surprenant Date: Wed, 13 Mar 2019 18:04:24 -0400 Subject: [PATCH 0036/1126] move download setup code inside the downloadEs task (#10549) 7.x clean backport of #10547 --- build.gradle | 91 ++++++++++++++++++++++++++-------------------------- 1 file changed, 45 insertions(+), 46 deletions(-) diff --git a/build.gradle b/build.gradle index 5ea084509..9724fdca0 100644 --- a/build.gradle +++ b/build.gradle @@ -423,57 +423,56 @@ bootstrap.dependsOn installTestGems runIntegrationTests.shouldRunAfter tasks.getByPath(":logstash-core:test") check.dependsOn runIntegrationTests -String artifactsVersionApi = "https://artifacts-api.elastic.co/v1/versions/" -String apiResponse = artifactsVersionApi.toURL().text -def dlVersions = new JsonSlurper().parseText(apiResponse) -// the version string can be either '7.0.0' or '7.0.0-alpha1', i.e. with the qualifier. -// in the normal PR type builds it is plain '7.0.0' -// in the build invoked by the release manager it is '7.0.0-alpha1' etc. -// the artifacts-api will return JSON like this: `{"versions":["5.6.13-SNAPSHOT","6.4.3-SNAPSHOT","6.5.0-SNAPSHOT","6.6.0-SNAPSHOT","7.0.0-alpha1-SNAPSHOT"]}` -String qualifiedVersion = dlVersions['versions'].grep(~/^${version}.*/)[0] - -String arch = "x86_64" -String osName = System.properties['os.name'] - -if (osName ==~ /Mac OS X/) { - osName = "darwin" -} else { - osName = "linux" -} - -String architecture = "${osName}-${arch}" - -String downloadedElasticsearchName = "elasticsearch-${qualifiedVersion}-${architecture}" -String unpackedElasticsearchName = "elasticsearch-${qualifiedVersion}" - -// find latest reference to last build -String buildsListApi = "https://artifacts-api.elastic.co/v1/versions/${qualifiedVersion}/builds/" -apiResponse = buildsListApi.toURL().text -def dlBuilds = new JsonSlurper().parseText(apiResponse) -String build = dlBuilds["builds"][0] - -// find url of build artifact -String artifactApiUrl = "https://artifacts-api.elastic.co/v1/versions/${qualifiedVersion}/builds/${build}/projects/elasticsearch/packages/${downloadedElasticsearchName}.tar.gz" -apiResponse = artifactApiUrl.toURL().text -def buildUrls = new JsonSlurper().parseText(apiResponse) - -String elasticsearchSnapshotURL = System.getenv("ELASTICSEARCH_SNAPSHOT_URL") ?: buildUrls["package"]["url"] -String elasticsearchDownloadLocation = "${projectDir}/build/${downloadedElasticsearchName}.tar.gz" - task downloadEs(type: Download) { description "Download ES Snapshot for current branch version: ${version}" - doFirst { - if (qualifiedVersion == "null") { - throw new GradleException("could not find the current artifact from the artifact-api for version: ${version}, api response was: ${apiResponse}") - } + + String artifactsVersionApi = "https://artifacts-api.elastic.co/v1/versions/" + String apiResponse = artifactsVersionApi.toURL().text + def dlVersions = new JsonSlurper().parseText(apiResponse) + // the version string can be either '7.0.0' or '7.0.0-alpha1', i.e. with the qualifier. + // in the normal PR type builds it is plain '7.0.0' + // in the build invoked by the release manager it is '7.0.0-alpha1' etc. + // the artifacts-api will return JSON like this: `{"versions":["5.6.13-SNAPSHOT","6.4.3-SNAPSHOT","6.5.0-SNAPSHOT","6.6.0-SNAPSHOT","7.0.0-alpha1-SNAPSHOT"]}` + String qualifiedVersion = dlVersions['versions'].grep(~/^${version}.*/)[0] + if (qualifiedVersion == "null") { + throw new GradleException("could not find the current artifact from the artifact-api for version: ${version}, api response was: ${apiResponse}") } + + String arch = "x86_64" + String osName = System.properties['os.name'] + + if (osName ==~ /Mac OS X/) { + osName = "darwin" + } else { + osName = "linux" + } + + String architecture = "${osName}-${arch}" + + String downloadedElasticsearchName = "elasticsearch-${qualifiedVersion}-${architecture}" + project.ext.set("unpackedElasticsearchName", "elasticsearch-${qualifiedVersion}") + + // find latest reference to last build + String buildsListApi = "https://artifacts-api.elastic.co/v1/versions/${qualifiedVersion}/builds/" + apiResponse = buildsListApi.toURL().text + def dlBuilds = new JsonSlurper().parseText(apiResponse) + String build = dlBuilds["builds"][0] + + // find url of build artifact + String artifactApiUrl = "https://artifacts-api.elastic.co/v1/versions/${qualifiedVersion}/builds/${build}/projects/elasticsearch/packages/${downloadedElasticsearchName}.tar.gz" + apiResponse = artifactApiUrl.toURL().text + def buildUrls = new JsonSlurper().parseText(apiResponse) + + String elasticsearchSnapshotURL = System.getenv("ELASTICSEARCH_SNAPSHOT_URL") ?: buildUrls["package"]["url"] + project.ext.set("elasticsearchDownloadLocation", "${projectDir}/build/${downloadedElasticsearchName}.tar.gz") + src elasticsearchSnapshotURL onlyIfNewer true inputs.file("${projectDir}/versions.yml") - outputs.file(elasticsearchDownloadLocation) - dest new File(elasticsearchDownloadLocation) + outputs.file(project.ext.elasticsearchDownloadLocation) + dest new File(project.ext.elasticsearchDownloadLocation) doLast { - System.out.println "Downloaded to ${elasticsearchDownloadLocation}" + System.out.println "Downloaded to ${project.ext.elasticsearchDownloadLocation}" } } @@ -482,10 +481,10 @@ task deleteLocalEs(type: Delete) { } task copyEs(type: Copy, dependsOn: [downloadEs, deleteLocalEs]) { - from tarTree(resources.gzip(elasticsearchDownloadLocation)) + from tarTree(resources.gzip(project.ext.elasticsearchDownloadLocation)) into "./build/" doLast { - file("./build/${unpackedElasticsearchName}").renameTo('./build/elasticsearch') + file("./build/${project.ext.unpackedElasticsearchName}").renameTo('./build/elasticsearch') } } From 8ec1d2276bcd0180c94813afa3e40aa68d4872e2 Mon Sep 17 00:00:00 2001 From: Colin Surprenant Date: Wed, 13 Mar 2019 18:08:19 -0400 Subject: [PATCH 0037/1126] correctly handle unexecuted downloadEs task (#10557) [7.x clean backport of #10555] --- build.gradle | 81 ++++++++++++++++++++++++++++++++-------------------- 1 file changed, 50 insertions(+), 31 deletions(-) diff --git a/build.gradle b/build.gradle index 9724fdca0..4738de743 100644 --- a/build.gradle +++ b/build.gradle @@ -423,10 +423,17 @@ bootstrap.dependsOn installTestGems runIntegrationTests.shouldRunAfter tasks.getByPath(":logstash-core:test") check.dependsOn runIntegrationTests +String artifactsVersionApi = "https://artifacts-api.elastic.co/v1/versions/" + task downloadEs(type: Download) { description "Download ES Snapshot for current branch version: ${version}" - String artifactsVersionApi = "https://artifacts-api.elastic.co/v1/versions/" + doFirst { + if (!project.ext.versionFound) { + throw new GradleException("could not find the current artifact from the artifact-api ${artifactsVersionApi} for version: ${version}") + } + } + String apiResponse = artifactsVersionApi.toURL().text def dlVersions = new JsonSlurper().parseText(apiResponse) // the version string can be either '7.0.0' or '7.0.0-alpha1', i.e. with the qualifier. @@ -434,43 +441,53 @@ task downloadEs(type: Download) { // in the build invoked by the release manager it is '7.0.0-alpha1' etc. // the artifacts-api will return JSON like this: `{"versions":["5.6.13-SNAPSHOT","6.4.3-SNAPSHOT","6.5.0-SNAPSHOT","6.6.0-SNAPSHOT","7.0.0-alpha1-SNAPSHOT"]}` String qualifiedVersion = dlVersions['versions'].grep(~/^${version}.*/)[0] - if (qualifiedVersion == "null") { - throw new GradleException("could not find the current artifact from the artifact-api for version: ${version}, api response was: ${apiResponse}") - } - - String arch = "x86_64" - String osName = System.properties['os.name'] - - if (osName ==~ /Mac OS X/) { - osName = "darwin" + if (qualifiedVersion == null) { + // the version is not found in the versions API, for now just set dummy values so the + // task parameters like src and dest below sees these dummy values but also set + // versionFound to false so that we can fail the task in the doFirst closure. + // this is somewhat convoluted and there is certainly a better way to do this but + // it seems to be an acceptable solution for now. + project.ext.set("versionFound", false) + project.ext.set("elasticsearchSnapshotURL", "http://elastic.co/invalid") + project.ext.set("elasticsearchDownloadLocation", "${projectDir}/build/invalid") } else { - osName = "linux" + project.ext.set("versionFound", true) + + String arch = "x86_64" + String osName = System.properties['os.name'] + + if (osName ==~ /Mac OS X/) { + osName = "darwin" + } else { + osName = "linux" + } + + String architecture = "${osName}-${arch}" + + String downloadedElasticsearchName = "elasticsearch-${qualifiedVersion}-${architecture}" + project.ext.set("unpackedElasticsearchName", "elasticsearch-${qualifiedVersion}") + + // find latest reference to last build + String buildsListApi = "https://artifacts-api.elastic.co/v1/versions/${qualifiedVersion}/builds/" + apiResponse = buildsListApi.toURL().text + def dlBuilds = new JsonSlurper().parseText(apiResponse) + String build = dlBuilds["builds"][0] + + // find url of build artifact + String artifactApiUrl = "https://artifacts-api.elastic.co/v1/versions/${qualifiedVersion}/builds/${build}/projects/elasticsearch/packages/${downloadedElasticsearchName}.tar.gz" + apiResponse = artifactApiUrl.toURL().text + def buildUrls = new JsonSlurper().parseText(apiResponse) + + project.ext.set("elasticsearchSnapshotURL", System.getenv("ELASTICSEARCH_SNAPSHOT_URL") ?: buildUrls["package"]["url"]) + project.ext.set("elasticsearchDownloadLocation", "${projectDir}/build/${downloadedElasticsearchName}.tar.gz") } - String architecture = "${osName}-${arch}" - - String downloadedElasticsearchName = "elasticsearch-${qualifiedVersion}-${architecture}" - project.ext.set("unpackedElasticsearchName", "elasticsearch-${qualifiedVersion}") - - // find latest reference to last build - String buildsListApi = "https://artifacts-api.elastic.co/v1/versions/${qualifiedVersion}/builds/" - apiResponse = buildsListApi.toURL().text - def dlBuilds = new JsonSlurper().parseText(apiResponse) - String build = dlBuilds["builds"][0] - - // find url of build artifact - String artifactApiUrl = "https://artifacts-api.elastic.co/v1/versions/${qualifiedVersion}/builds/${build}/projects/elasticsearch/packages/${downloadedElasticsearchName}.tar.gz" - apiResponse = artifactApiUrl.toURL().text - def buildUrls = new JsonSlurper().parseText(apiResponse) - - String elasticsearchSnapshotURL = System.getenv("ELASTICSEARCH_SNAPSHOT_URL") ?: buildUrls["package"]["url"] - project.ext.set("elasticsearchDownloadLocation", "${projectDir}/build/${downloadedElasticsearchName}.tar.gz") - - src elasticsearchSnapshotURL + src project.ext.elasticsearchSnapshotURL onlyIfNewer true inputs.file("${projectDir}/versions.yml") outputs.file(project.ext.elasticsearchDownloadLocation) dest new File(project.ext.elasticsearchDownloadLocation) + doLast { System.out.println "Downloaded to ${project.ext.elasticsearchDownloadLocation}" } @@ -483,8 +500,10 @@ task deleteLocalEs(type: Delete) { task copyEs(type: Copy, dependsOn: [downloadEs, deleteLocalEs]) { from tarTree(resources.gzip(project.ext.elasticsearchDownloadLocation)) into "./build/" + doLast { file("./build/${project.ext.unpackedElasticsearchName}").renameTo('./build/elasticsearch') + System.out.println "Unzipped ${project.ext.elasticsearchDownloadLocation} to ./build/elasticsearch" } } From 2543539910e5255bd7843642e61e6f1b477c72f9 Mon Sep 17 00:00:00 2001 From: Joao Duarte Date: Thu, 28 Feb 2019 11:22:48 +0000 Subject: [PATCH 0038/1126] cleanup many rakelib tasks that aren't used anymore * simplify the plugins-metadata.json file * sort and update the plugin list in the rakelib/plugins-metadata.json * remove dependency on twitter input for testing * sorted Gemfile.template (grouped by group) * remove default plugins from Gemfile.template Fixes #10509 --- Gemfile.template | 134 +-- build.gradle | 2 +- qa/integration/specs/cli/remove_spec.rb | 16 +- rakelib/default_plugins.rb | 5 - rakelib/dependency.rake | 34 - rakelib/package.rake | 10 - rakelib/plugin.rake | 17 +- rakelib/plugins-metadata.json | 1354 +++++++++-------------- rakelib/test.rake | 10 +- rakelib/vendor.rake | 1 - 10 files changed, 538 insertions(+), 1045 deletions(-) delete mode 100644 rakelib/package.rake diff --git a/Gemfile.template b/Gemfile.template index f7b5e56ae..8ad97c8c2 100644 --- a/Gemfile.template +++ b/Gemfile.template @@ -4,123 +4,25 @@ source "https://rubygems.org" gem "logstash-core", :path => "./logstash-core" gem "logstash-core-plugin-api", :path => "./logstash-core-plugin-api" -gem "paquet", "~> 0.2" -gem "ruby-progressbar", "~> 1" -gem "builder", "~> 3" -gem "ci_reporter_rspec", "~> 1", :group => :development -gem "rspec", "~> 3.5", :group => :development -gem "logstash-devutils", "~> 1", :group => :development -gem "benchmark-ips", :group => :development -gem "octokit", "~> 4", :group => :build -gem "stud", "~> 0.0.22", :group => :build -gem "rack-test", :require => "rack/test", :group => :development -gem "fpm", "~> 1.3.3", :group => :build -gem "childprocess", "~> 0.9", :group => :build -gem "rubyzip", "~> 1", :group => :build -gem "gems", "~> 1", :group => :build -gem "flores", "~> 0.0.6", :group => :development gem "atomic", "~> 1" -gem "belzebuth", :group => :development -gem "json-schema", "~> 2", :group => :development +gem "builder", "~> 3" +gem "json", "~> 1.8.3" +gem "paquet", "~> 0.2" gem "pleaserun", "~>0.0.28" gem "rake", "~> 12" +gem "ruby-progressbar", "~> 1" +gem "childprocess", "~> 0.9", :group => :build +gem "fpm", "~> 1.3.3", :group => :build +gem "gems", "~> 1", :group => :build +gem "octokit", "~> 4", :group => :build +gem "rubyzip", "~> 1", :group => :build +gem "stud", "~> 0.0.22", :group => :build +gem "belzebuth", :group => :development +gem "benchmark-ips", :group => :development +gem "ci_reporter_rspec", "~> 1", :group => :development +gem "flores", "~> 0.0.6", :group => :development +gem "json-schema", "~> 2", :group => :development +gem "logstash-devutils", "~> 1", :group => :development +gem "rack-test", :require => "rack/test", :group => :development +gem "rspec", "~> 3.5", :group => :development gem "webmock", "~> 3", :group => :development -gem "logstash-codec-cef" -gem "logstash-codec-collectd" -gem "logstash-codec-dots" -gem "logstash-codec-edn" -gem "logstash-codec-edn_lines" -gem "logstash-codec-es_bulk" -gem "logstash-codec-fluent" -gem "logstash-codec-graphite" -gem "logstash-codec-json" -gem "logstash-codec-json_lines" -gem "logstash-codec-line" -gem "logstash-codec-msgpack" -gem "logstash-codec-multiline" -gem "logstash-codec-netflow" -gem "logstash-codec-plain" -gem "logstash-codec-rubydebug" -gem "logstash-filter-aggregate" -gem "logstash-filter-anonymize" -gem "logstash-filter-cidr" -gem "logstash-filter-clone" -gem "logstash-filter-csv" -gem "logstash-filter-date" -gem "logstash-filter-de_dot" -gem "logstash-filter-dissect" -gem "logstash-filter-dns" -gem "logstash-filter-drop" -gem "logstash-filter-elasticsearch" -gem "logstash-filter-fingerprint" -gem "logstash-filter-geoip" -gem "logstash-filter-grok" -gem "logstash-filter-http" -gem "logstash-filter-jdbc_static" -gem "logstash-filter-jdbc_streaming" -gem "logstash-filter-json" -gem "logstash-filter-kv" -gem "logstash-filter-memcached" -gem "logstash-filter-metrics" -gem "logstash-filter-mutate" -gem "logstash-filter-ruby" -gem "logstash-filter-sleep" -gem "logstash-filter-split" -gem "logstash-filter-syslog_pri" -gem "logstash-filter-throttle" -gem "logstash-filter-translate" -gem "logstash-filter-truncate" -gem "logstash-filter-urldecode" -gem "logstash-filter-useragent" -gem "logstash-filter-xml" -gem "logstash-input-beats" -gem "logstash-input-azure_event_hubs" -gem "logstash-input-dead_letter_queue" -gem "logstash-input-elasticsearch" -gem "logstash-input-exec" -gem "logstash-input-file" -gem "logstash-input-ganglia" -gem "logstash-input-gelf" -gem "logstash-input-generator" -gem "logstash-input-graphite" -gem "logstash-input-heartbeat" -gem "logstash-input-http" -gem "logstash-input-http_poller" -gem "logstash-input-imap" -gem "logstash-input-jdbc" -gem "logstash-input-kafka" -gem "logstash-input-pipe" -gem "logstash-input-rabbitmq" -gem "logstash-input-redis" -gem "logstash-input-s3" -gem "logstash-input-snmp" -gem "logstash-input-snmptrap" -gem "logstash-input-sqs" -gem "logstash-input-stdin" -gem "logstash-input-syslog" -gem "logstash-input-tcp" -gem "logstash-input-twitter" -gem "logstash-input-udp" -gem "logstash-input-unix" -gem "logstash-output-elastic_app_search" -gem "logstash-output-cloudwatch" -gem "logstash-output-csv" -gem "logstash-output-elasticsearch" -gem "logstash-output-email" -gem "logstash-output-file" -gem "logstash-output-graphite" -gem "logstash-output-http" -gem "logstash-output-kafka" -gem "logstash-output-lumberjack" -gem "logstash-output-nagios" -gem "logstash-output-null" -gem "logstash-output-pipe" -gem "logstash-output-rabbitmq" -gem "logstash-output-redis" -gem "logstash-output-s3" -gem "logstash-output-sns" -gem "logstash-output-sqs" -gem "logstash-output-stdout" -gem "logstash-output-tcp" -gem "logstash-output-udp" -gem "logstash-output-webhdfs" diff --git a/build.gradle b/build.gradle index 4738de743..f3a13e0a5 100644 --- a/build.gradle +++ b/build.gradle @@ -253,7 +253,7 @@ task installTestGems(dependsOn: assemblyDeps) { doLast { rubyGradleUtils.gem("rake", "12.3.1", "${projectDir}/vendor/bundle/jruby/2.5.0") rubyGradleUtils.gem("json", "1.8.6", "${projectDir}/vendor/bundle/jruby/2.5.0") - rubyGradleUtils.rake('test:install-core') + rubyGradleUtils.rake('plugin:install-development-dependencies') } } diff --git a/qa/integration/specs/cli/remove_spec.rb b/qa/integration/specs/cli/remove_spec.rb index 2bce464ce..b9bdcefd0 100644 --- a/qa/integration/specs/cli/remove_spec.rb +++ b/qa/integration/specs/cli/remove_spec.rb @@ -26,16 +26,16 @@ describe "CLI > logstash-plugin remove" do context "when no other plugins depends on this plugin" do it "successfully remove the plugin" do - execute = @logstash_plugin.run_raw("#{offline_wrapper_cmd} bin/logstash-plugin remove logstash-input-twitter") + execute = @logstash_plugin.run_raw("#{offline_wrapper_cmd} bin/logstash-plugin remove logstash-filter-mutate") expect(execute.exit_code).to eq(0) - expect(execute.stderr_and_stdout).to match(/Successfully removed logstash-input-twitter/) + expect(execute.stderr_and_stdout).to match(/Successfully removed logstash-filter-mutate/) - presence_check = @logstash_plugin.list("logstash-input-twitter") + presence_check = @logstash_plugin.list("logstash-filter-mutate") expect(presence_check.exit_code).to eq(1) expect(presence_check.stderr_and_stdout).to match(/ERROR: No plugins found/) - @logstash_plugin.install("logstash-input-twitter") + @logstash_plugin.install("logstash-filter-mutate") end end @@ -59,16 +59,16 @@ describe "CLI > logstash-plugin remove" do else context "when no other plugins depends on this plugin" do it "successfully remove the plugin" do - execute = @logstash_plugin.remove("logstash-input-twitter") + execute = @logstash_plugin.remove("logstash-filter-mutate") expect(execute.exit_code).to eq(0) - expect(execute.stderr_and_stdout).to match(/Successfully removed logstash-input-twitter/) + expect(execute.stderr_and_stdout).to match(/Successfully removed logstash-filter-mutate/) - presence_check = @logstash_plugin.list("logstash-input-twitter") + presence_check = @logstash_plugin.list("logstash-filter-mutate") expect(presence_check.exit_code).to eq(1) expect(presence_check.stderr_and_stdout).to match(/ERROR: No plugins found/) - @logstash_plugin.install("logstash-input-twitter") + @logstash_plugin.install("logstash-filter-mutate") end end diff --git a/rakelib/default_plugins.rb b/rakelib/default_plugins.rb index 433acedd4..2600602c1 100644 --- a/rakelib/default_plugins.rb +++ b/rakelib/default_plugins.rb @@ -31,11 +31,6 @@ module LogStash # plugins required to run the logstash core specs CORE_SPECS_PLUGINS = self.fetch_plugins_for("core-specs").freeze - TEST_JAR_DEPENDENCIES_PLUGINS = self.fetch_plugins_for("test-jar-dependencies").freeze - - TEST_VENDOR_PLUGINS = self.fetch_plugins_for("test-vendor-plugin").freeze - ALL_PLUGINS_SKIP_LIST = Regexp.union(self.fetch_plugins_for("skip-list")).freeze - end end diff --git a/rakelib/dependency.rake b/rakelib/dependency.rake index f58617456..0671095bc 100644 --- a/rakelib/dependency.rake +++ b/rakelib/dependency.rake @@ -1,39 +1,5 @@ - namespace "dependency" do task "bundler" do Rake::Task["gem:require"].invoke("bundler", "~> 1.17.1") end - - task "clamp" do - Rake::Task["gem:require"].invoke("clamp", "~> 0.6") - end - - task "rbx-stdlib" do - Rake::Task["gem:require"].invoke("rubysl", ">= 0") - end # task rbx-stdlib - - task "archive-tar-minitar" do - Rake::Task["gem:require"].invoke("minitar", "0.6.1") - end # task archive-minitar - - task "stud" do - Rake::Task["gem:require"].invoke("stud", ">= 0") - end # task stud - - task "fpm" do - Rake::Task["gem:require"].invoke("fpm", "~> 1.3.3") - end # task stud - - task "rubyzip" do - Rake::Task["gem:require"].invoke("rubyzip", ">= 0") - end # task stud - - task "octokit" do - Rake::Task["gem:require"].invoke("octokit", ">= 0") - end # task octokit - - task "gems" do - Rake::Task["gem:require"].invoke("gems", ">= 0") - end # task gems - end # namespace dependency diff --git a/rakelib/package.rake b/rakelib/package.rake deleted file mode 100644 index 531a160fd..000000000 --- a/rakelib/package.rake +++ /dev/null @@ -1,10 +0,0 @@ -namespace "package" do - - task "bundle" do - system("bin/logstash-plugin", "pack") - raise(RuntimeError, $!.to_s) unless $?.success? - end - - desc "Build a package with the default plugins, including dependencies, to be installed offline" - task "plugins-default" => ["test:install-default", "bundle"] -end diff --git a/rakelib/plugin.rake b/rakelib/plugin.rake index f860dff27..21559e94a 100644 --- a/rakelib/plugin.rake +++ b/rakelib/plugin.rake @@ -9,8 +9,9 @@ namespace "plugin" do end task "install-development-dependencies" => "bootstrap" do - puts("[plugin:install-development-dependencies] Installing development dependencies of all installed plugins") + puts("[plugin:install-development-dependencies] Installing development dependencies") install_plugins("--development", "--preserve") + install_plugins("--preserve", *LogStash::RakeLib::CORE_SPECS_PLUGINS) task.reenable # Allow this task to be run again end @@ -30,20 +31,6 @@ namespace "plugin" do task.reenable # Allow this task to be run again end - task "install-core" => "bootstrap" do - puts("[plugin:install-core] Installing core plugins") - install_plugins("--no-verify", "--preserve", *LogStash::RakeLib::CORE_SPECS_PLUGINS) - - task.reenable # Allow this task to be run again - end - - task "install-jar-dependencies" => "bootstrap" do - puts("[plugin:install-jar-dependencies] Installing jar_dependencies plugins for testing") - install_plugins("--no-verify", "--preserve", *LogStash::RakeLib::TEST_JAR_DEPENDENCIES_PLUGINS) - - task.reenable # Allow this task to be run again - end - task "clean-local-core-gem", [:name, :path] do |task, args| name = args[:name] path = args[:path] diff --git a/rakelib/plugins-metadata.json b/rakelib/plugins-metadata.json index 467481c57..5181640ca 100644 --- a/rakelib/plugins-metadata.json +++ b/rakelib/plugins-metadata.json @@ -1,849 +1,509 @@ { - "logstash-input-heartbeat": { - "default-plugins": true, - "core-specs": false, - "test-jar-dependencies": false, - "test-vendor-plugins": false, - "skip-list": false - }, - "logstash-input-dead_letter_queue": { - "default-plugins": true, - "core-specs": false, - "test-jar-dependencies": false, - "test-vendor-plugins": false, - "skip-list": false - }, - "logstash-codec-collectd": { - "default-plugins": true, - "core-specs": false, - "test-jar-dependencies": false, - "test-vendor-plugins": true, - "skip-list": false - }, - "logstash-codec-dots": { - "default-plugins": true, - "core-specs": false, - "test-jar-dependencies": false, - "test-vendor-plugins": false, - "skip-list": false - }, - "logstash-codec-edn": { - "default-plugins": true, - "core-specs": false, - "test-jar-dependencies": false, - "test-vendor-plugins": false, - "skip-list": false - }, - "logstash-codec-edn_lines": { - "default-plugins": true, - "core-specs": false, - "test-jar-dependencies": false, - "test-vendor-plugins": false, - "skip-list": false - }, - "logstash-codec-fluent": { - "default-plugins": true, - "core-specs": false, - "test-jar-dependencies": false, - "test-vendor-plugins": false, - "skip-list": false - }, - "logstash-codec-es_bulk": { - "default-plugins": true, - "core-specs": false, - "test-jar-dependencies": false, - "test-vendor-plugins": false, - "skip-list": false - }, - "logstash-codec-graphite": { - "default-plugins": true, - "core-specs": false, - "test-jar-dependencies": false, - "test-vendor-plugins": false, - "skip-list": false - }, - "logstash-codec-json": { - "default-plugins": true, - "core-specs": false, - "test-jar-dependencies": false, - "test-vendor-plugins": false, - "skip-list": false - }, - "logstash-codec-json_lines": { - "default-plugins": true, - "core-specs": false, - "test-jar-dependencies": false, - "test-vendor-plugins": false, - "skip-list": false - }, - "logstash-codec-line": { - "default-plugins": true, - "core-specs": false, - "test-jar-dependencies": false, - "test-vendor-plugins": false, - "skip-list": false - }, - "logstash-codec-msgpack": { - "default-plugins": true, - "core-specs": false, - "test-jar-dependencies": false, - "test-vendor-plugins": false, - "skip-list": false - }, - "logstash-codec-multiline": { - "default-plugins": true, - "core-specs": false, - "test-jar-dependencies": false, - "test-vendor-plugins": false, - "skip-list": false - }, - "logstash-codec-netflow": { - "default-plugins": true, - "core-specs": false, - "test-jar-dependencies": false, - "test-vendor-plugins": false, - "skip-list": false - }, - "logstash-codec-plain": { - "default-plugins": true, - "core-specs": false, - "test-jar-dependencies": false, - "test-vendor-plugins": false, - "skip-list": false - }, - "logstash-codec-rubydebug": { - "default-plugins": true, - "core-specs": false, - "test-jar-dependencies": false, - "test-vendor-plugins": false, - "skip-list": false - }, - "logstash-filter-clone": { - "default-plugins": true, - "core-specs": true, - "test-jar-dependencies": false, - "test-vendor-plugins": false, - "skip-list": false - }, - "logstash-filter-cidr": { - "default-plugins": true, - "core-specs": true, - "test-jar-dependencies": false, - "test-vendor-plugins": false, - "skip-list": false - }, - "logstash-filter-csv": { - "default-plugins": true, - "core-specs": false, - "test-jar-dependencies": false, - "test-vendor-plugins": false, - "skip-list": false - }, - "logstash-filter-date": { - "default-plugins": true, - "core-specs": false, - "test-jar-dependencies": false, - "test-vendor-plugins": false, - "skip-list": false - }, - "logstash-filter-dissect": { - "default-plugins": true, - "core-specs": false, - "test-jar-dependencies": false, - "test-vendor-plugins": false, - "skip-list": false - }, - "logstash-filter-dns": { - "default-plugins": true, - "core-specs": false, - "test-jar-dependencies": false, - "test-vendor-plugins": false, - "skip-list": false - }, - "logstash-filter-drop": { - "default-plugins": true, - "core-specs": false, - "test-jar-dependencies": false, - "test-vendor-plugins": false, - "skip-list": false - }, - "logstash-filter-fingerprint": { - "default-plugins": true, - "core-specs": false, - "test-jar-dependencies": false, - "test-vendor-plugins": false, - "skip-list": false - }, - "logstash-filter-geoip": { - "default-plugins": true, - "core-specs": false, - "test-jar-dependencies": false, - "test-vendor-plugins": false, - "skip-list": false - }, - "logstash-filter-grok": { - "default-plugins": true, - "core-specs": false, - "test-jar-dependencies": false, - "test-vendor-plugins": false, - "skip-list": false - }, - "logstash-filter-http": { - "default-plugins": true, - "core-specs": false, - "test-jar-dependencies": false, - "test-vendor-plugins": false, - "skip-list": false - }, - "logstash-filter-json": { - "default-plugins": true, - "core-specs": false, - "test-jar-dependencies": false, - "test-vendor-plugins": false, - "skip-list": false - }, - "logstash-filter-kv": { - "default-plugins": true, - "core-specs": false, - "test-jar-dependencies": false, - "test-vendor-plugins": false, - "skip-list": false - }, - "logstash-filter-memcached": { - "default-plugins": true, - "core-specs": false, - "test-jar-dependencies": false, - "test-vendor-plugins": false, - "skip-list": false - }, - "logstash-filter-metrics": { - "default-plugins": true, - "core-specs": false, - "test-jar-dependencies": false, - "test-vendor-plugins": false, - "skip-list": false - }, - "logstash-filter-mutate": { - "default-plugins": true, - "core-specs": true, - "test-jar-dependencies": false, - "test-vendor-plugins": false, - "skip-list": false - }, - "logstash-filter-ruby": { - "default-plugins": true, - "core-specs": false, - "test-jar-dependencies": false, - "test-vendor-plugins": false, - "skip-list": false - }, - "logstash-filter-sleep": { - "default-plugins": true, - "core-specs": false, - "test-jar-dependencies": false, - "test-vendor-plugins": false, - "skip-list": false - }, - "logstash-filter-split": { - "default-plugins": true, - "core-specs": false, - "test-jar-dependencies": false, - "test-vendor-plugins": false, - "skip-list": false - }, - "logstash-filter-syslog_pri": { - "default-plugins": true, - "core-specs": false, - "test-jar-dependencies": false, - "test-vendor-plugins": false, - "skip-list": false - }, - "logstash-filter-throttle": { - "default-plugins": true, - "core-specs": false, - "test-jar-dependencies": false, - "test-vendor-plugins": false, - "skip-list": false - }, - "logstash-filter-translate": { - "default-plugins": true, - "core-specs": false, - "test-jar-dependencies": false, - "test-vendor-plugins": false, - "skip-list": false - }, - "logstash-filter-urldecode": { - "default-plugins": true, - "core-specs": false, - "test-jar-dependencies": false, - "test-vendor-plugins": false, - "skip-list": false - }, - "logstash-filter-useragent": { - "default-plugins": true, - "core-specs": false, - "test-jar-dependencies": false, - "test-vendor-plugins": false, - "skip-list": false - }, - "logstash-filter-xml": { - "default-plugins": true, - "core-specs": false, - "test-jar-dependencies": false, - "test-vendor-plugins": false, - "skip-list": false - }, - "logstash-input-azure_event_hubs": { - "default-plugins": true, - "core-specs": false, - "test-jar-dependencies": false, - "test-vendor-plugins": false, - "skip-list": false - }, - "logstash-input-elasticsearch": { - "default-plugins": true, - "core-specs": false, - "test-jar-dependencies": false, - "test-vendor-plugins": false, - "skip-list": false - }, - "logstash-input-exec": { - "default-plugins": true, - "core-specs": false, - "test-jar-dependencies": false, - "test-vendor-plugins": false, - "skip-list": false - }, - "logstash-input-file": { - "default-plugins": true, - "core-specs": false, - "test-jar-dependencies": false, - "test-vendor-plugins": false, - "skip-list": false - }, - "logstash-input-ganglia": { - "default-plugins": true, - "core-specs": false, - "test-jar-dependencies": false, - "test-vendor-plugins": false, - "skip-list": false - }, - "logstash-input-gelf": { - "default-plugins": true, - "core-specs": false, - "test-jar-dependencies": false, - "test-vendor-plugins": false, - "skip-list": false - }, - "logstash-input-generator": { - "default-plugins": true, - "core-specs": true, - "test-jar-dependencies": false, - "test-vendor-plugins": false, - "skip-list": false - }, - "logstash-input-graphite": { - "default-plugins": true, - "core-specs": false, - "test-jar-dependencies": false, - "test-vendor-plugins": false, - "skip-list": false - }, - "logstash-input-http": { - "default-plugins": true, - "core-specs": false, - "test-jar-dependencies": false, - "test-vendor-plugins": false, - "skip-list": false - }, - "logstash-input-http_poller": { - "default-plugins": true, - "core-specs": false, - "test-jar-dependencies": false, - "test-vendor-plugins": false, - "skip-list": false - }, - "logstash-input-imap": { - "default-plugins": true, - "core-specs": false, - "test-jar-dependencies": false, - "test-vendor-plugins": false, - "skip-list": false - }, - "logstash-input-jdbc": { - "default-plugins": true, - "core-specs": false, - "test-jar-dependencies": false, - "test-vendor-plugins": false, - "skip-list": true - }, - "logstash-input-pipe": { - "default-plugins": true, - "core-specs": false, - "test-jar-dependencies": false, - "test-vendor-plugins": false, - "skip-list": false - }, - "logstash-input-rabbitmq": { - "default-plugins": true, - "core-specs": false, - "test-jar-dependencies": false, - "test-vendor-plugins": false, - "skip-list": false - }, - "logstash-input-redis": { - "default-plugins": true, - "core-specs": false, - "test-jar-dependencies": false, - "test-vendor-plugins": false, - "skip-list": false - }, - "logstash-input-s3": { - "default-plugins": true, - "core-specs": false, - "test-jar-dependencies": false, - "test-vendor-plugins": false, - "skip-list": false - }, - "logstash-input-snmp": { - "default-plugins": true, - "core-specs": false, - "test-jar-dependencies": false, - "test-vendor-plugins": false, - "skip-list": false - }, - "logstash-input-snmptrap": { - "default-plugins": true, - "core-specs": false, - "test-jar-dependencies": false, - "test-vendor-plugins": false, - "skip-list": false - }, - "logstash-input-sqs": { - "default-plugins": true, - "core-specs": false, - "test-jar-dependencies": false, - "test-vendor-plugins": false, - "skip-list": false - }, - "logstash-input-stdin": { - "default-plugins": true, - "core-specs": true, - "test-jar-dependencies": false, - "test-vendor-plugins": false, - "skip-list": false - }, - "logstash-input-syslog": { - "default-plugins": true, - "core-specs": false, - "test-jar-dependencies": false, - "test-vendor-plugins": false, - "skip-list": false - }, - "logstash-input-tcp": { - "default-plugins": true, - "core-specs": true, - "test-jar-dependencies": false, - "test-vendor-plugins": false, - "skip-list": false - }, - "logstash-input-twitter": { - "default-plugins": true, - "core-specs": false, - "test-jar-dependencies": false, - "test-vendor-plugins": false, - "skip-list": false - }, - "logstash-input-udp": { - "default-plugins": true, - "core-specs": false, - "test-jar-dependencies": false, - "test-vendor-plugins": false, - "skip-list": false - }, - "logstash-input-unix": { - "default-plugins": true, - "core-specs": false, - "test-jar-dependencies": false, - "test-vendor-plugins": false, - "skip-list": false - }, - "logstash-input-kafka": { - "default-plugins": true, - "core-specs": false, - "test-jar-dependencies": true, - "test-vendor-plugins": false, - "skip-list": false - }, - "logstash-input-beats": { - "default-plugins": true, - "core-specs": false, - "test-jar-dependencies": false, - "test-vendor-plugins": false, - "skip-list": false - }, - "logstash-output-elastic_app_search": { - "default-plugins": true, - "core-specs": false, - "test-jar-dependencies": false, - "test-vendor-plugins": false, - "skip-list": false - }, - "logstash-output-cloudwatch": { - "default-plugins": true, - "core-specs": false, - "test-jar-dependencies": false, - "test-vendor-plugins": false, - "skip-list": false - }, - "logstash-output-csv": { - "default-plugins": true, - "core-specs": false, - "test-jar-dependencies": false, - "test-vendor-plugins": false, - "skip-list": false - }, - "logstash-output-elasticsearch": { - "default-plugins": true, - "core-specs": false, - "test-jar-dependencies": false, - "test-vendor-plugins": false, - "skip-list": false - }, - "logstash-output-file": { - "default-plugins": true, - "core-specs": false, - "test-jar-dependencies": false, - "test-vendor-plugins": false, - "skip-list": false - }, - "logstash-output-graphite": { - "default-plugins": true, - "core-specs": false, - "test-jar-dependencies": false, - "test-vendor-plugins": false, - "skip-list": false - }, - "logstash-output-http": { - "default-plugins": true, - "core-specs": false, - "test-jar-dependencies": false, - "test-vendor-plugins": false, - "skip-list": false - }, - "logstash-output-kafka": { - "default-plugins": true, - "core-specs": false, - "test-jar-dependencies": false, - "test-vendor-plugins": false, - "skip-list": false - }, - "logstash-output-nagios": { - "default-plugins": true, - "core-specs": false, - "test-jar-dependencies": false, - "test-vendor-plugins": false, - "skip-list": false - }, - "logstash-output-null": { - "default-plugins": true, - "core-specs": false, - "test-jar-dependencies": false, - "test-vendor-plugins": false, - "skip-list": false - }, - "logstash-output-pagerduty": { - "default-plugins": true, - "core-specs": false, - "test-jar-dependencies": false, - "test-vendor-plugins": false, - "skip-list": false - }, - "logstash-output-pipe": { - "default-plugins": true, - "core-specs": false, - "test-jar-dependencies": false, - "test-vendor-plugins": false, - "skip-list": false - }, - "logstash-output-rabbitmq": { - "default-plugins": true, - "core-specs": false, - "test-jar-dependencies": false, - "test-vendor-plugins": false, - "skip-list": false - }, - "logstash-output-redis": { - "default-plugins": true, - "core-specs": false, - "test-jar-dependencies": false, - "test-vendor-plugins": false, - "skip-list": false - }, - "logstash-output-s3": { - "default-plugins": true, - "core-specs": false, - "test-jar-dependencies": false, - "test-vendor-plugins": false, - "skip-list": false - }, - "logstash-output-sns": { - "default-plugins": true, - "core-specs": false, - "test-jar-dependencies": false, - "test-vendor-plugins": false, - "skip-list": false - }, - "logstash-output-sqs": { - "default-plugins": true, - "core-specs": false, - "test-jar-dependencies": false, - "test-vendor-plugins": false, - "skip-list": false - }, - "logstash-output-stdout": { - "default-plugins": true, - "core-specs": true, - "test-jar-dependencies": false, - "test-vendor-plugins": false, - "skip-list": false - }, - "logstash-output-tcp": { - "default-plugins": true, - "core-specs": false, - "test-jar-dependencies": false, - "test-vendor-plugins": false, - "skip-list": false - }, - "logstash-output-udp": { - "default-plugins": true, - "core-specs": false, - "test-jar-dependencies": false, - "test-vendor-plugins": false, - "skip-list": false - }, - "logstash-output-webhdfs": { - "default-plugins": true, - "core-specs": false, - "test-jar-dependencies": false, - "test-vendor-plugins": false, - "skip-list": true - }, - "logstash-filter-multiline": { - "default-plugins": false, - "core-specs": true, - "test-jar-dependencies": false, - "test-vendor-plugins": false, - "skip-list": false - }, - "logstash-filter-yaml": { - "default-plugins": false, - "core-specs": false, - "test-jar-dependencies": false, - "test-vendor-plugins": false, - "skip-list": true - }, - "logstash-input-example": { - "default-plugins": false, - "core-specs": false, - "test-jar-dependencies": false, - "test-vendor-plugins": false, - "skip-list": true - }, - "logstash-codec-example": { - "default-plugins": false, - "core-specs": false, - "test-jar-dependencies": false, - "test-vendor-plugins": false, - "skip-list": true - }, - "logstash-filter-example": { - "default-plugins": false, - "core-specs": false, - "test-jar-dependencies": false, - "test-vendor-plugins": false, - "skip-list": true - }, - "logstash-output-example": { - "default-plugins": false, - "core-specs": false, - "test-jar-dependencies": false, - "test-vendor-plugins": false, - "skip-list": true - }, - "logstash-input-drupal_dblog": { - "default-plugins": false, - "core-specs": false, - "test-jar-dependencies": false, - "test-vendor-plugins": false, - "skip-list": true - }, - "logstash-output-logentries": { - "default-plugins": false, - "core-specs": false, - "test-jar-dependencies": false, - "test-vendor-plugins": false, - "skip-list": true - }, - "logstash-output-newrelic": { - "default-plugins": false, - "core-specs": false, - "test-jar-dependencies": false, - "test-vendor-plugins": false, - "skip-list": true - }, - "logstash-output-slack": { - "default-plugins": false, - "core-specs": false, - "test-jar-dependencies": false, - "test-vendor-plugins": false, - "skip-list": true - }, - "logstash-input-neo4j": { - "default-plugins": false, - "core-specs": false, - "test-jar-dependencies": false, - "test-vendor-plugins": false, - "skip-list": true - }, - "logstash-output-neo4j": { - "default-plugins": false, - "core-specs": false, - "test-jar-dependencies": false, - "test-vendor-plugins": false, - "skip-list": true - }, - "logstash-input-perfmon": { - "default-plugins": false, - "core-specs": false, - "test-jar-dependencies": false, - "test-vendor-plugins": false, - "skip-list": true - }, - "logstash-input-rackspace": { - "default-plugins": false, - "core-specs": false, - "test-jar-dependencies": false, - "test-vendor-plugins": false, - "skip-list": true - }, - "logstash-output-rackspace": { - "default-plugins": false, - "core-specs": false, - "test-jar-dependencies": false, - "test-vendor-plugins": false, - "skip-list": true - }, - "logstash-input-dynamodb": { - "default-plugins": false, - "core-specs": false, - "test-jar-dependencies": false, - "test-vendor-plugins": false, - "skip-list": true - }, - "logstash-filter-language": { - "default-plugins": false, - "core-specs": false, - "test-jar-dependencies": false, - "test-vendor-plugins": false, - "skip-list": true - }, - "logstash-input-heroku": { - "default-plugins": false, - "core-specs": false, - "test-jar-dependencies": false, - "test-vendor-plugins": false, - "skip-list": true - }, - "logstash-output-google_cloud_storage": { - "default-plugins": false, - "core-specs": false, - "test-jar-dependencies": false, - "test-vendor-plugins": false, - "skip-list": true - }, - "logstash-input-journald": { - "default-plugins": false, - "core-specs": false, - "test-jar-dependencies": false, - "test-vendor-plugins": false, - "skip-list": true - }, - "logstash-input-log4j2": { - "default-plugins": false, - "core-specs": false, - "test-jar-dependencies": false, - "test-vendor-plugins": false, - "skip-list": true - }, - "logstash-codec-cloudtrail": { - "default-plugins": false, - "core-specs": false, - "test-jar-dependencies": false, - "test-vendor-plugins": false, - "skip-list": false - }, - "logstash-filter-aggregate": { - "default-plugins": true, - "core-specs": false, - "test-jar-dependencies": false, - "test-vendor-plugins": false, - "skip-list": false - }, - "logstash-filter-anonymize": { - "default-plugins": true, - "core-specs": false, - "test-jar-dependencies": false, - "test-vendor-plugins": false, - "skip-list": false - }, - "logstash-filter-de_dot": { - "default-plugins": true, - "core-specs": false, - "test-jar-dependencies": false, - "test-vendor-plugins": false, - "skip-list": false - }, - "logstash-filter-elasticsearch": { - "default-plugins": true, - "core-specs": false, - "test-jar-dependencies": false, - "test-vendor-plugins": false, - "skip-list": false - }, - "logstash-filter-jdbc_static": { - "default-plugins": true, - "core-specs": false, - "test-jar-dependencies": false, - "test-vendor-plugins": false, - "skip-list": false - }, - "logstash-filter-jdbc_streaming": { - "default-plugins": true, - "core-specs": false, - "test-jar-dependencies": false, - "test-vendor-plugins": false, - "skip-list": false - }, - "logstash-filter-truncate": { - "default-plugins": true, - "core-specs": false, - "test-jar-dependencies": false, - "test-vendor-plugins": false, - "skip-list": false - }, - "logstash-output-email": { - "default-plugins": true, - "core-specs": false, - "test-jar-dependencies": false, - "test-vendor-plugins": false, - "skip-list": false - }, - "logstash-output-lumberjack": { - "default-plugins": true, - "core-specs": false, - "test-jar-dependencies": false, - "test-vendor-plugins": false, - "skip-list": false - } + "logstash-codec-avro": { + "default-plugins": true, + "skip-list": false + }, + "logstash-codec-cef": { + "default-plugins": true, + "skip-list": false + }, + "logstash-codec-collectd": { + "default-plugins": true, + "skip-list": false + }, + "logstash-codec-dots": { + "default-plugins": true, + "skip-list": false + }, + "logstash-codec-edn": { + "default-plugins": true, + "skip-list": false + }, + "logstash-codec-edn_lines": { + "default-plugins": true, + "skip-list": false + }, + "logstash-codec-es_bulk": { + "default-plugins": true, + "skip-list": false + }, + "logstash-codec-example": { + "default-plugins": false, + "skip-list": true + }, + "logstash-codec-fluent": { + "default-plugins": true, + "skip-list": false + }, + "logstash-codec-graphite": { + "default-plugins": true, + "skip-list": false + }, + "logstash-codec-json": { + "default-plugins": true, + "skip-list": false + }, + "logstash-codec-json_lines": { + "default-plugins": true, + "skip-list": false + }, + "logstash-codec-line": { + "default-plugins": true, + "skip-list": false + }, + "logstash-codec-msgpack": { + "default-plugins": true, + "skip-list": false + }, + "logstash-codec-multiline": { + "default-plugins": true, + "skip-list": false + }, + "logstash-codec-netflow": { + "default-plugins": true, + "skip-list": false + }, + "logstash-codec-plain": { + "default-plugins": true, + "core-specs": true, + "skip-list": false + }, + "logstash-codec-rubydebug": { + "default-plugins": true, + "skip-list": false + }, + "logstash-filter-aggregate": { + "default-plugins": true, + "skip-list": false + }, + "logstash-filter-anonymize": { + "default-plugins": true, + "skip-list": false + }, + "logstash-filter-cidr": { + "default-plugins": true, + "skip-list": false + }, + "logstash-filter-clone": { + "default-plugins": true, + "core-specs": true, + "skip-list": false + }, + "logstash-filter-csv": { + "default-plugins": true, + "skip-list": false + }, + "logstash-filter-date": { + "default-plugins": true, + "core-specs": true, + "skip-list": false + }, + "logstash-filter-de_dot": { + "default-plugins": true, + "skip-list": false + }, + "logstash-filter-dissect": { + "default-plugins": true, + "skip-list": false + }, + "logstash-filter-dns": { + "default-plugins": true, + "skip-list": false + }, + "logstash-filter-drop": { + "default-plugins": true, + "core-specs": true, + "skip-list": false + }, + "logstash-filter-elasticsearch": { + "default-plugins": true, + "skip-list": false + }, + "logstash-filter-example": { + "default-plugins": false, + "skip-list": true + }, + "logstash-filter-fingerprint": { + "default-plugins": true, + "skip-list": false + }, + "logstash-filter-geoip": { + "default-plugins": true, + "skip-list": false + }, + "logstash-filter-grok": { + "default-plugins": true, + "skip-list": false + }, + "logstash-filter-http": { + "default-plugins": true, + "skip-list": false + }, + "logstash-filter-jdbc_static": { + "default-plugins": true, + "skip-list": false + }, + "logstash-filter-jdbc_streaming": { + "default-plugins": true, + "skip-list": false + }, + "logstash-filter-json": { + "default-plugins": true, + "skip-list": false + }, + "logstash-filter-kv": { + "default-plugins": true, + "skip-list": false + }, + "logstash-filter-language": { + "default-plugins": false, + "skip-list": true + }, + "logstash-filter-memcached": { + "default-plugins": true, + "skip-list": false + }, + "logstash-filter-metrics": { + "default-plugins": true, + "skip-list": false + }, + "logstash-filter-mutate": { + "default-plugins": true, + "core-specs": true, + "skip-list": false + }, + "logstash-filter-prune": { + "default-plugins": true, + "skip-list": false + }, + "logstash-filter-ruby": { + "default-plugins": true, + "core-specs": true, + "skip-list": false + }, + "logstash-filter-sleep": { + "default-plugins": true, + "skip-list": false + }, + "logstash-filter-split": { + "default-plugins": true, + "skip-list": false + }, + "logstash-filter-syslog_pri": { + "default-plugins": true, + "skip-list": false + }, + "logstash-filter-throttle": { + "default-plugins": true, + "skip-list": false + }, + "logstash-filter-translate": { + "default-plugins": true, + "skip-list": false + }, + "logstash-filter-truncate": { + "default-plugins": true, + "skip-list": false + }, + "logstash-filter-urldecode": { + "default-plugins": true, + "skip-list": false + }, + "logstash-filter-useragent": { + "default-plugins": true, + "skip-list": false + }, + "logstash-filter-uuid": { + "default-plugins": true, + "skip-list": false + }, + "logstash-filter-xml": { + "default-plugins": true, + "core-specs": true, + "skip-list": false + }, + "logstash-filter-yaml": { + "default-plugins": false, + "skip-list": true + }, + "logstash-input-azure_event_hubs": { + "default-plugins": true, + "skip-list": false + }, + "logstash-input-beats": { + "default-plugins": true, + "core-specs": true, + "skip-list": false + }, + "logstash-input-couchdb_changes": { + "default-plugins": true, + "skip-list": false + }, + "logstash-input-dead_letter_queue": { + "default-plugins": true, + "skip-list": false + }, + "logstash-input-drupal_dblog": { + "default-plugins": false, + "skip-list": true + }, + "logstash-input-dynamodb": { + "default-plugins": false, + "skip-list": true + }, + "logstash-input-elasticsearch": { + "default-plugins": true, + "skip-list": false + }, + "logstash-input-example": { + "default-plugins": false, + "skip-list": true + }, + "logstash-input-exec": { + "default-plugins": true, + "skip-list": false + }, + "logstash-input-file": { + "default-plugins": true, + "skip-list": false + }, + "logstash-input-ganglia": { + "default-plugins": true, + "skip-list": false + }, + "logstash-input-gelf": { + "default-plugins": true, + "skip-list": false + }, + "logstash-input-generator": { + "default-plugins": true, + "core-specs": true, + "skip-list": false + }, + "logstash-input-graphite": { + "default-plugins": true, + "skip-list": false + }, + "logstash-input-heartbeat": { + "default-plugins": true, + "skip-list": false + }, + "logstash-input-heroku": { + "default-plugins": false, + "skip-list": true + }, + "logstash-input-http": { + "default-plugins": true, + "skip-list": false + }, + "logstash-input-http_poller": { + "default-plugins": true, + "skip-list": false + }, + "logstash-input-imap": { + "default-plugins": true, + "skip-list": false + }, + "logstash-input-jdbc": { + "default-plugins": true, + "skip-list": false + }, + "logstash-input-journald": { + "default-plugins": false, + "skip-list": true + }, + "logstash-input-kafka": { + "default-plugins": true, + "skip-list": false + }, + "logstash-input-log4j2": { + "default-plugins": false, + "skip-list": true + }, + "logstash-input-neo4j": { + "default-plugins": false, + "skip-list": true + }, + "logstash-input-perfmon": { + "default-plugins": false, + "skip-list": true + }, + "logstash-input-pipe": { + "default-plugins": true, + "skip-list": false + }, + "logstash-input-rabbitmq": { + "default-plugins": true, + "skip-list": false + }, + "logstash-input-rackspace": { + "default-plugins": false, + "skip-list": true + }, + "logstash-input-redis": { + "default-plugins": true, + "skip-list": false + }, + "logstash-input-s3": { + "default-plugins": true, + "skip-list": false + }, + "logstash-input-snmp": { + "default-plugins": true, + "skip-list": false + }, + "logstash-input-snmptrap": { + "default-plugins": true, + "skip-list": false + }, + "logstash-input-sqs": { + "default-plugins": true, + "skip-list": false + }, + "logstash-input-stdin": { + "default-plugins": true, + "core-specs": true, + "skip-list": false + }, + "logstash-input-syslog": { + "default-plugins": true, + "skip-list": false + }, + "logstash-input-tcp": { + "default-plugins": true, + "core-specs": true, + "skip-list": false + }, + "logstash-input-twitter": { + "default-plugins": false, + "skip-list": false + }, + "logstash-input-udp": { + "default-plugins": true, + "skip-list": false + }, + "logstash-input-unix": { + "default-plugins": true, + "skip-list": false + }, + "logstash-output-cloudwatch": { + "default-plugins": true, + "skip-list": false + }, + "logstash-output-csv": { + "default-plugins": true, + "skip-list": false + }, + "logstash-output-elastic_app_search": { + "default-plugins": true, + "skip-list": false + }, + "logstash-output-elasticsearch": { + "default-plugins": true, + "core-specs": true, + "skip-list": false + }, + "logstash-output-email": { + "default-plugins": true, + "skip-list": false + }, + "logstash-output-example": { + "default-plugins": false, + "skip-list": true + }, + "logstash-output-file": { + "default-plugins": true, + "core-specs": true, + "skip-list": false + }, + "logstash-output-google_cloud_storage": { + "default-plugins": false, + "skip-list": true + }, + "logstash-output-graphite": { + "default-plugins": true, + "skip-list": false + }, + "logstash-output-http": { + "default-plugins": true, + "skip-list": false + }, + "logstash-output-kafka": { + "default-plugins": true, + "skip-list": false + }, + "logstash-output-logentries": { + "default-plugins": false, + "skip-list": true + }, + "logstash-output-lumberjack": { + "default-plugins": true, + "skip-list": false + }, + "logstash-output-nagios": { + "default-plugins": true, + "skip-list": false + }, + "logstash-output-neo4j": { + "default-plugins": false, + "skip-list": true + }, + "logstash-output-newrelic": { + "default-plugins": false, + "skip-list": true + }, + "logstash-output-null": { + "default-plugins": true, + "core-specs": true, + "skip-list": false + }, + "logstash-output-pipe": { + "default-plugins": true, + "skip-list": false + }, + "logstash-output-rabbitmq": { + "default-plugins": true, + "skip-list": false + }, + "logstash-output-rackspace": { + "default-plugins": false, + "skip-list": true + }, + "logstash-output-redis": { + "default-plugins": true, + "skip-list": false + }, + "logstash-output-s3": { + "default-plugins": true, + "skip-list": false + }, + "logstash-output-slack": { + "default-plugins": false, + "skip-list": true + }, + "logstash-output-sns": { + "default-plugins": true, + "skip-list": false + }, + "logstash-output-sqs": { + "default-plugins": true, + "skip-list": false + }, + "logstash-output-stdout": { + "default-plugins": true, + "core-specs": true, + "skip-list": false + }, + "logstash-output-tcp": { + "default-plugins": true, + "skip-list": false + }, + "logstash-output-udp": { + "default-plugins": true, + "skip-list": false + }, + "logstash-output-webhdfs": { + "default-plugins": true, + "skip-list": false + } } diff --git a/rakelib/test.rake b/rakelib/test.rake index a3260fb65..81f131452 100644 --- a/rakelib/test.rake +++ b/rakelib/test.rake @@ -58,17 +58,11 @@ namespace "test" do exit 1 unless system(*(["bin/rspec", "-fd", "--order", "rand"].concat(test_files))) end - desc "install core plugins and dev dependencies" - task "install-core" => ["bootstrap", "plugin:install-core", "plugin:install-development-dependencies"] + desc "install dev dependencies" + task "install-core" => ["bootstrap", "plugin:install-development-dependencies"] desc "install default plugins and dev dependencies" task "install-default" => ["bootstrap", "plugin:install-default", "plugin:install-development-dependencies"] - - desc "install vendor plugins and dev dependencies" - task "install-vendor-plugins" => ["bootstrap", "plugin:install-vendor", "plugin:install-development-dependencies"] - - desc "install jar dependencies and dev dependencies" - task "install-jar-dependencies-plugins" => ["bootstrap", "plugin:install-jar-dependencies", "plugin:install-development-dependencies"] end task "test" => [ "test:core" ] diff --git a/rakelib/vendor.rake b/rakelib/vendor.rake index 842640b70..e1848f5e3 100644 --- a/rakelib/vendor.rake +++ b/rakelib/vendor.rake @@ -14,7 +14,6 @@ namespace "vendor" do task "gems", [:bundle] do |task, args| require "bootstrap/environment" - Rake::Task["dependency:clamp"].invoke Rake::Task["dependency:bundler"].invoke puts("Invoking bundler install...") From 9eb2949ab75a0c70e1d33479c7cf5ee083102ba2 Mon Sep 17 00:00:00 2001 From: Ry Biesemeyer Date: Fri, 15 Mar 2019 18:13:44 +0000 Subject: [PATCH 0039/1126] fix events_count to return total Fixes #10564 --- x-pack/lib/monitoring/inputs/metrics/stats_event_factory.rb | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/x-pack/lib/monitoring/inputs/metrics/stats_event_factory.rb b/x-pack/lib/monitoring/inputs/metrics/stats_event_factory.rb index a946a6d5e..ae55808da 100644 --- a/x-pack/lib/monitoring/inputs/metrics/stats_event_factory.rb +++ b/x-pack/lib/monitoring/inputs/metrics/stats_event_factory.rb @@ -93,8 +93,6 @@ module LogStash; module Inputs; class Metrics; end def format_queue_stats(agent, stats) - events = 0 - pipelines_stats = stats.get_shallow(:stats, :pipelines) total_queued_events = 0 @@ -103,7 +101,7 @@ module LogStash; module Inputs; class Metrics; pipeline = agent.get_pipeline(pipeline_id) # Check if pipeline is nil to avoid race condition where metrics system refers pipeline that has been stopped already next if pipeline.nil? || pipeline.system? || type != 'persisted' - total_queued_events = p_stats[:queue][:events].value + total_queued_events += p_stats[:queue][:events].value end {:events_count => total_queued_events} From 1f29c7145d6aaa3294630fcb6bb04accdac429bb Mon Sep 17 00:00:00 2001 From: Jake Landis Date: Mon, 11 Mar 2019 13:47:38 -0500 Subject: [PATCH 0040/1126] monitoring: bump to system_api_version 7 Fixes #10562 --- x-pack/lib/monitoring/monitoring.rb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/x-pack/lib/monitoring/monitoring.rb b/x-pack/lib/monitoring/monitoring.rb index 4dbeefff0..15e0cef7f 100644 --- a/x-pack/lib/monitoring/monitoring.rb +++ b/x-pack/lib/monitoring/monitoring.rb @@ -83,7 +83,7 @@ module LogStash include LogStash::Util::Loggable, LogStash::Helpers::ElasticsearchOptions PIPELINE_ID = ".monitoring-logstash" - API_VERSION = 6 + API_VERSION = 7 def initialize # nothing to do here From 67e62a9c00e282d38fb0c376cabb69006d6455d2 Mon Sep 17 00:00:00 2001 From: Karen Metts Date: Thu, 27 Sep 2018 18:58:26 -0400 Subject: [PATCH 0041/1126] Add sample doc files to plugin generator Fixes #10029 --- .../codec-plugin/docs/index.asciidoc | 102 ++++++++++++++ .../filter-plugin/docs/index.asciidoc | 87 ++++++++++++ .../input-plugin/docs/index.asciidoc | 117 ++++++++++++++++ .../output-plugin/docs/index.asciidoc | 127 ++++++++++++++++++ 4 files changed, 433 insertions(+) create mode 100644 lib/pluginmanager/templates/codec-plugin/docs/index.asciidoc create mode 100644 lib/pluginmanager/templates/filter-plugin/docs/index.asciidoc create mode 100644 lib/pluginmanager/templates/input-plugin/docs/index.asciidoc create mode 100644 lib/pluginmanager/templates/output-plugin/docs/index.asciidoc diff --git a/lib/pluginmanager/templates/codec-plugin/docs/index.asciidoc b/lib/pluginmanager/templates/codec-plugin/docs/index.asciidoc new file mode 100644 index 000000000..e9c5cbb80 --- /dev/null +++ b/lib/pluginmanager/templates/codec-plugin/docs/index.asciidoc @@ -0,0 +1,102 @@ +:plugin: example +:type: codec +// Update header with plugin name + +/////////////////////////////////////////// +START - GENERATED VARIABLES, DO NOT EDIT! +/////////////////////////////////////////// +:version: %VERSION% +:release_date: %RELEASE_DATE% +:changelog_url: %CHANGELOG_URL% +:include_path: ../../../../logstash/docs/include +/////////////////////////////////////////// +END - GENERATED VARIABLES, DO NOT EDIT! +/////////////////////////////////////////// + +[id="plugins-{type}s-{plugin}"] + +=== Example codec plugin + +include::{include_path}/plugin_header.asciidoc[] + +==== Description + +Add plugin description here + +// Format anchors and links to support generated ids for versioning +// Sample anchor: [id="plugins-{type}s-{plugin}-setting_name"] +// Sample link: <> + +[id="plugins-{type}s-{plugin}-options"] +==== Example Codec Configuration Options + +[cols="<,<,<",options="header",] +|======================================================================= +|Setting |Input type|Required +| <> |<>|No +| <> |<>|No +| <> |<>|No +| <> |<>|No +| <> |<>|No +| <> |<>|No +| <> |<>|No +|======================================================================= + +[id="plugins-{type}s-{plugin}-a_setting_name"] +===== `a_setting_name` + + * Value type is <> + * Default value is `true` + +Add description here + +[id="plugins-{type}s-{plugin}-another_setting_name"] +===== `another_setting_name` + + * Value type is <> + * Default value is `{}` + +Add description here + +[id="plugins-{type}s-{plugin}-setting_name_3"] +===== `setting_name_3` + + * Value type is <> + * Default value is `{}` + +Add description here + +[id="plugins-{type}s-{plugin}-setting_name_4"] +===== `setting_name_4` + + * Value type is <> + * Default value is `0` + +Add description here + +[id="plugins-{type}s-{plugin}-setting_name_5"] +===== `setting_name_5` + + * Value type is <> + * Default value is {} + +Add description here + +[id="plugins-{type}s-{plugin}-setting_name_6"] +===== `setting_name_6` + + * Value type is <> + * Default value is {} + +Add description here + +[id="plugins-{type}s-{plugin}-setting_name_7"] +===== `setting_name_7` + + * Value type is <> + * Default value is {} + +Add description here + +// The full list of Value Types is here: +// https://www.elastic.co/guide/en/logstash/current/configuration-file-structure.html diff --git a/lib/pluginmanager/templates/filter-plugin/docs/index.asciidoc b/lib/pluginmanager/templates/filter-plugin/docs/index.asciidoc new file mode 100644 index 000000000..fca3730ac --- /dev/null +++ b/lib/pluginmanager/templates/filter-plugin/docs/index.asciidoc @@ -0,0 +1,87 @@ +:plugin: example +:type: filter +// Update header with plugin name + +/////////////////////////////////////////// +START - GENERATED VARIABLES, DO NOT EDIT! +/////////////////////////////////////////// +:version: %VERSION% +:release_date: %RELEASE_DATE% +:changelog_url: %CHANGELOG_URL% +:include_path: ../../../../logstash/docs/include +/////////////////////////////////////////// +END - GENERATED VARIABLES, DO NOT EDIT! +/////////////////////////////////////////// + +[id="plugins-{type}s-{plugin}"] + +=== Example filter plugin + +include::{include_path}/plugin_header.asciidoc[] + +==== Description + +Add plugin description here + +// Format anchors and links to support generated ids for versioning +// Sample anchor: [id="plugins-{type}s-{plugin}-setting_name"] +// Sample link: <> + +[id="plugins-{type}s-{plugin}-options"] +==== Example Filter Configuration Options + +[cols="<,<,<",options="header",] +|======================================================================= +|Setting |Input type|Required +| <> |<>|No +| <> |<>|No +| <> |<>|No +| <> |<>|No +| <> |<>|No +|======================================================================= + +[id="plugins-{type}s-{plugin}-a_setting_name"] +===== `a_setting_name` + + * Value type is <> + * Default value is `true` + +Add description here + +[id="plugins-{type}s-{plugin}-another_setting_name"] +===== `another_setting_name` + + * Value type is <> + * Default value is `{}` + +Add description here + +[id="plugins-{type}s-{plugin}-setting_name_3"] +===== `setting_name_3` + + * Value type is <> + * Default value is `{}` + +Add description here + +[id="plugins-{type}s-{plugin}-setting_name_4"] +===== `setting_name_4` + + * Value type is <> + * Default value is `0` + +Add description here + +[id="plugins-{type}s-{plugin}-setting_name_5"] +===== `setting_name_5` + + * Value type is <> + * Default value is {} + +Add description here + +// The full list of Value Types is here: +// https://www.elastic.co/guide/en/logstash/current/configuration-file-structure.html + +[id="plugins-{type}s-{plugin}-common-options"] +include::{include_path}/{type}.asciidoc[] diff --git a/lib/pluginmanager/templates/input-plugin/docs/index.asciidoc b/lib/pluginmanager/templates/input-plugin/docs/index.asciidoc new file mode 100644 index 000000000..cc47ac158 --- /dev/null +++ b/lib/pluginmanager/templates/input-plugin/docs/index.asciidoc @@ -0,0 +1,117 @@ +:plugin: example +:type: input +:default_codec: plain +// Update header with plugin name and default codec + +/////////////////////////////////////////// +START - GENERATED VARIABLES, DO NOT EDIT! +/////////////////////////////////////////// +:version: %VERSION% +:release_date: %RELEASE_DATE% +:changelog_url: %CHANGELOG_URL% +:include_path: ../../../../logstash/docs/include +/////////////////////////////////////////// +END - GENERATED VARIABLES, DO NOT EDIT! +/////////////////////////////////////////// + +[id="plugins-{type}s-{plugin}"] + +=== Example input plugin + +include::{include_path}/plugin_header.asciidoc[] + +==== Description + +Add plugin description here + +// Format anchors and links to support generated ids for versioning +// Sample anchor: [id="plugins-{type}s-{plugin}-setting_name"] +// Sample link: <> + +[id="plugins-{type}s-{plugin}-options"] +==== Example Input Configuration Options + +[cols="<,<,<",options="header",] +|======================================================================= +|Setting |Input type|Required +| <> |<>|No +| <> |<>|No +| <> |<>|No +| <> |<>|No +| <> |<>|No +| <> |<>|No +| <> |<>|No +| <> |<>|No +|======================================================================= + +[id="plugins-{type}s-{plugin}-a_setting_name"] +===== `a_setting_name` + + * Value type is <> + * Default value is `true` + +Add description here + +[id="plugins-{type}s-{plugin}-another_setting_name"] +===== `another_setting_name` + + * Value type is <> + * Default value is `{}` + +Add description here + +[id="plugins-{type}s-{plugin}-setting_name_3"] +===== `setting_name_3` + + * Value type is <> + * Default value is `{}` + +Add description here + +[id="plugins-{type}s-{plugin}-setting_name_4"] +===== `setting_name_4` + + * Value type is <> + * Default value is `0` + +Add description here + +[id="plugins-{type}s-{plugin}-setting_name_5"] +===== `setting_name_5` + + * Value type is <> + * Default value is {} + +Add description here + +[id="plugins-{type}s-{plugin}-setting_name_6"] +===== `setting_name_6` + + * Value type is <> + * Default value is {} + +Add description here + +[id="plugins-{type}s-{plugin}-setting_name_7"] +===== `setting_name_7` + + * Value type is <> + * Default value is {} + +Add description here + +[id="plugins-{type}s-{plugin}-setting_name_8"] +===== `setting_name_8` + + * Value type is <> + * Default value is {} + +Add description here + +// The full list of Value Types is here: +// https://www.elastic.co/guide/en/logstash/current/configuration-file-structure.html + +[id="plugins-{type}s-{plugin}-common-options"] +include::{include_path}/{type}.asciidoc[] + +:default_codec!: diff --git a/lib/pluginmanager/templates/output-plugin/docs/index.asciidoc b/lib/pluginmanager/templates/output-plugin/docs/index.asciidoc new file mode 100644 index 000000000..623a89d9a --- /dev/null +++ b/lib/pluginmanager/templates/output-plugin/docs/index.asciidoc @@ -0,0 +1,127 @@ +:plugin: example +:type: output +:default_codec: plain +// Update header with plugin name and default codec + +/////////////////////////////////////////// +START - GENERATED VARIABLES, DO NOT EDIT! +/////////////////////////////////////////// +:version: %VERSION% +:release_date: %RELEASE_DATE% +:changelog_url: %CHANGELOG_URL% +:include_path: ../../../../logstash/docs/include +/////////////////////////////////////////// +END - GENERATED VARIABLES, DO NOT EDIT! +/////////////////////////////////////////// + +[id="plugins-{type}s-{plugin}"] + +=== Example output plugin + +include::{include_path}/plugin_header.asciidoc[] + +==== Description + +Add plugin description here + +// Format anchors and links to support generated ids for versioning +// Sample anchor: [id="plugins-{type}s-{plugin}-setting_name"] +// Sample link: <> + +[id="plugins-{type}s-{plugin}-options"] +==== Example Output Configuration Options + +[cols="<,<,<",options="header",] +|======================================================================= +|Setting |Input type|Required +| <> |<>|No +| <> |<>|No +| <> |<>|No +| <> |<>|No +| <> |<>|No +| <> |<>|No +| <> |<>|No +| <> |<>|No +| <> |<>|No +|======================================================================= + +[id="plugins-{type}s-{plugin}-a_setting_name"] +===== `a_setting_name` + + * Value type is <> + * Default value is `true` + +Add description here + +[id="plugins-{type}s-{plugin}-another_setting_name"] +===== `another_setting_name` + + * Value type is <> + * Default value is `{}` + +Add description here + +[id="plugins-{type}s-{plugin}-setting_name_3"] +===== `setting_name_3` + + * Value type is <> + * Default value is `{}` + +Add description here + +[id="plugins-{type}s-{plugin}-setting_name_4"] +===== `setting_name_4` + + * Value type is <> + * Default value is `0` + +Add description here + +[id="plugins-{type}s-{plugin}-setting_name_5"] +===== `setting_name_5` + + * Value type is <> + * Default value is {} + +Add description here + +[id="plugins-{type}s-{plugin}-setting_name_6"] +===== `setting_name_6` + + * Value type is <> + * Default value is {} + +Add description here + +[id="plugins-{type}s-{plugin}-setting_name_7"] +===== `setting_name_7` + + * Value type is <> + * Default value is {} + +Add description here + +[id="plugins-{type}s-{plugin}-setting_name_8"] +===== `setting_name_8` + + * Value type is <> + * Default value is {} + +Add description here + + +[id="plugins-{type}s-{plugin}-setting_name_9"] +===== `setting_name_9` + + * Value type is <> + * Default value is {} + +Add description here + +// The full list of Value Types is here: +// https://www.elastic.co/guide/en/logstash/current/configuration-file-structure.html + +[id="plugins-{type}s-{plugin}-common-options"] +include::{include_path}/{type}.asciidoc[] + +:default_codec!: From 4d0255228dfe8e2c7f747623e2c788fe76243ba7 Mon Sep 17 00:00:00 2001 From: Karen Metts Date: Mon, 25 Mar 2019 18:51:26 -0400 Subject: [PATCH 0042/1126] Update supported java version and example Fixes #10584 --- docs/static/getting-started-with-logstash.asciidoc | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/docs/static/getting-started-with-logstash.asciidoc b/docs/static/getting-started-with-logstash.asciidoc index a8b57c70a..0354ad260 100644 --- a/docs/static/getting-started-with-logstash.asciidoc +++ b/docs/static/getting-started-with-logstash.asciidoc @@ -15,7 +15,7 @@ This section includes the following topics: [[installing-logstash]] === Installing Logstash -NOTE: Logstash requires Java 8. Java 9 is not supported. Use the +NOTE: Logstash requires Java 8 or Java 11. Use the http://www.oracle.com/technetwork/java/javase/downloads/index.html[official Oracle distribution] or an open-source distribution such as http://openjdk.java.net/[OpenJDK]. @@ -27,9 +27,11 @@ java -version On systems with Java installed, this command produces output similar to the following: [source,shell] -java version "1.8.0_65" -Java(TM) SE Runtime Environment (build 1.8.0_65-b17) -Java HotSpot(TM) 64-Bit Server VM (build 25.65-b01, mixed mode) +----- +java version "11.0.1" 2018-10-16 LTS +Java(TM) SE Runtime Environment 18.9 (build 11.0.1+13-LTS) +Java HotSpot(TM) 64-Bit Server VM 18.9 (build 11.0.1+13-LTS, mixed mode) +----- On some Linux systems, you may also need to have the `JAVA_HOME` environment exported before attempting the install, particularly if you installed Java from From 7bda524e2b32267db42e423288149159c96babc7 Mon Sep 17 00:00:00 2001 From: Karen Metts Date: Tue, 26 Mar 2019 16:40:32 -0400 Subject: [PATCH 0043/1126] Add note that pline-pline also supports files Fixes #10590 --- docs/static/pipeline-pipeline-config.asciidoc | 3 +++ 1 file changed, 3 insertions(+) diff --git a/docs/static/pipeline-pipeline-config.asciidoc b/docs/static/pipeline-pipeline-config.asciidoc index 9148fc68e..aa591fa9e 100644 --- a/docs/static/pipeline-pipeline-config.asciidoc +++ b/docs/static/pipeline-pipeline-config.asciidoc @@ -58,6 +58,9 @@ You can use the `pipeline` input and output to better organize code, streamline * <> * <> +NOTE: These examples use `config.string` to illustrate the flows. +You can also use configuration files for pipeline-to-pipeline communication. + [[distributor-pattern]] ===== The distributor pattern From 1cda518c14fa11d63b8f14d5383a2eda1445aa59 Mon Sep 17 00:00:00 2001 From: Dan Hermann Date: Thu, 28 Mar 2019 08:50:31 -0500 Subject: [PATCH 0044/1126] Update JRuby and Java prerequisites Fixes #10604 --- README.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index f77e47aca..2198bed2e 100644 --- a/README.md +++ b/README.md @@ -65,8 +65,8 @@ Logstash core will continue to exist under this repository and all related issue ### Prerequisites -* Install JDK version 8. Make sure to set the `JAVA_HOME` environment variable to the path to your JDK installation directory. For example `set JAVA_HOME=` -* Install JRuby 9.1.x It is recommended to use a Ruby version manager such as [RVM](https://rvm.io/) or [rbenv](https://github.com/sstephenson/rbenv). +* Install JDK version 8 or 11. Make sure to set the `JAVA_HOME` environment variable to the path to your JDK installation directory. For example `set JAVA_HOME=` +* Install JRuby 9.2.x It is recommended to use a Ruby version manager such as [RVM](https://rvm.io/) or [rbenv](https://github.com/sstephenson/rbenv). * Install `rake` and `bundler` tool using `gem install rake` and `gem install bundler` respectively. ### RVM install (optional) From 07eb8ea005150fe2cb7f1d8b71eb695840ec14c5 Mon Sep 17 00:00:00 2001 From: Rob Bavey Date: Thu, 28 Mar 2019 12:42:33 -0400 Subject: [PATCH 0045/1126] Update Kafka version to fix build Fixes #10608 --- qa/integration/services/kafka_setup.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/qa/integration/services/kafka_setup.sh b/qa/integration/services/kafka_setup.sh index 9e96527e5..7369ab309 100755 --- a/qa/integration/services/kafka_setup.sh +++ b/qa/integration/services/kafka_setup.sh @@ -10,7 +10,7 @@ if [ -n "${KAFKA_VERSION+1}" ]; then echo "KAFKA_VERSION is $KAFKA_VERSION" version=$KAFKA_VERSION else - version=2.0.1 + version=2.1.1 fi KAFKA_HOME=$INSTALL_DIR/kafka From 863a0c44e0f025e157c4084768d3b25c75b94c61 Mon Sep 17 00:00:00 2001 From: Yi Ou Date: Tue, 26 Mar 2019 23:12:13 +0100 Subject: [PATCH 0046/1126] Make the sample command easier to follow A tiny change suggestion due to: - `-SIGHUP` was mentioned in the previous text - `-SIGHUP` is easier to read than `-1` - `-1` can be easily mixed up with `-l` Fixes #10592 --- docs/static/reloading-config.asciidoc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/static/reloading-config.asciidoc b/docs/static/reloading-config.asciidoc index 1a16a379c..db225a102 100644 --- a/docs/static/reloading-config.asciidoc +++ b/docs/static/reloading-config.asciidoc @@ -25,7 +25,7 @@ process running Logstash. For example: [source,shell] ---------------------------------- -kill -1 14175 +kill -SIGHUP 14175 ---------------------------------- Where 14175 is the ID of the process running Logstash. From 4a79246dd103ab0b57cce10ef6567ab63127b07b Mon Sep 17 00:00:00 2001 From: Ry Biesemeyer Date: Tue, 2 Apr 2019 16:19:24 +0000 Subject: [PATCH 0047/1126] add `DeprecatedSetting` to ease 7.0 transition of xpack config renames Fixes #10623 --- logstash-core/lib/logstash/settings.rb | 28 +++++++++++++++++ .../settings/deprecated_and_renamed_spec.rb | 30 +++++++++++++++++++ x-pack/lib/config_management/extension.rb | 6 ++++ x-pack/lib/monitoring/monitoring.rb | 4 +++ .../spec/config_management/extension_spec.rb | 7 +++++ x-pack/spec/support/helpers.rb | 14 +++++++++ 6 files changed, 89 insertions(+) create mode 100644 logstash-core/spec/logstash/settings/deprecated_and_renamed_spec.rb diff --git a/logstash-core/lib/logstash/settings.rb b/logstash-core/lib/logstash/settings.rb index 94994dcaa..4288d882c 100644 --- a/logstash-core/lib/logstash/settings.rb +++ b/logstash-core/lib/logstash/settings.rb @@ -586,6 +586,34 @@ module LogStash coerce(value) end end + + ## + # Instances of `DeprecatedSetting` can be registered, but will fail with helpful guidance when encountering any + # configuration that attempts to explicitly set the value. They should be used in the Major version immediately + # following a deprecation to assist users who are porting forward configurations. + class DeprecatedSetting < Setting + def initialize(name, guidance='please remove the setting from your configuration and try again.') + super(name, Object) + @guidance = guidance + end + + def set(value) + fail(RuntimeError, "The setting `#{name}` has been deprecated and removed from Logstash; #{@guidance}") + end + + def value + fail(ArgumentError, "The setting `#{name}` has been deprecated and removed from Logstash") + end + end + + # Useful when a setting has been renamed but otherwise is semantically identical + class DeprecatedAndRenamed < DeprecatedSetting + attr_reader :new_name + def initialize(name, new_name) + super(name, "please update your configuration to use `#{new_name}` instead.") + @new_name = new_name + end + end end diff --git a/logstash-core/spec/logstash/settings/deprecated_and_renamed_spec.rb b/logstash-core/spec/logstash/settings/deprecated_and_renamed_spec.rb new file mode 100644 index 000000000..74ce828ee --- /dev/null +++ b/logstash-core/spec/logstash/settings/deprecated_and_renamed_spec.rb @@ -0,0 +1,30 @@ +# encoding: utf-8 +require 'spec_helper' +require 'logstash/settings' + +describe LogStash::Setting::DeprecatedAndRenamed do + subject(:setting) { described_class.new("option.deprecated", "option.current") } + let(:value) { Object.new } + + describe '#set' do + it 'fails with deprecation runtime error and helpful guidance' do + expect { setting.set(value) }.to raise_exception do |exception| + expect(exception).to be_a_kind_of(RuntimeError) + expect(exception.message).to match(/deprecated and removed/) + expect(exception.message).to include("option.deprecated") + expect(exception.message).to include("option.current") + end + end + end + + describe '#value' do + it 'fails with deprecation argument error' do + expect { setting.value }.to raise_exception do |exception| + expect(exception).to be_a_kind_of(ArgumentError) + expect(exception.message).to match(/deprecated and removed/) + expect(exception.message).to include("option.deprecated") + end + end + end + +end \ No newline at end of file diff --git a/x-pack/lib/config_management/extension.rb b/x-pack/lib/config_management/extension.rb index 06e55feaa..f71248065 100644 --- a/x-pack/lib/config_management/extension.rb +++ b/x-pack/lib/config_management/extension.rb @@ -34,6 +34,12 @@ module LogStash settings.register(LogStash::Setting::NullableString.new("xpack.management.elasticsearch.ssl.keystore.password")) settings.register(LogStash::Setting::String.new("xpack.management.elasticsearch.ssl.verification_mode", "certificate", true, ["none", "certificate"])) settings.register(LogStash::Setting::Boolean.new("xpack.management.elasticsearch.sniffing", false)) + + # These Settings were renamed and deprecated in 6.x timeframe and removed for 7.0; provide guidance to ease transition. + settings.register(LogStash::Setting::DeprecatedAndRenamed.new("xpack.management.elasticsearch.url", "xpack.management.elasticsearch.hosts")) + settings.register(LogStash::Setting::DeprecatedAndRenamed.new("xpack.management.elasticsearch.ssl.ca", "xpack.management.elasticsearch.ssl.certificate_authority")) + + rescue => e logger.error("Cannot register new settings", :message => e.message, :backtrace => e.backtrace) raise e diff --git a/x-pack/lib/monitoring/monitoring.rb b/x-pack/lib/monitoring/monitoring.rb index 15e0cef7f..0975d5386 100644 --- a/x-pack/lib/monitoring/monitoring.rb +++ b/x-pack/lib/monitoring/monitoring.rb @@ -184,6 +184,10 @@ module LogStash settings.register(LogStash::Setting::Boolean.new("xpack.monitoring.collection.pipeline.details.enabled", true)) settings.register(LogStash::Setting::Boolean.new("xpack.monitoring.collection.config.enabled", true)) + # These Settings were renamed and deprecated in 6.x timeframe and removed for 7.0; provide guidance to ease transition. + settings.register(LogStash::Setting::DeprecatedAndRenamed.new("xpack.monitoring.elasticsearch.url", "xpack.monitoring.elasticsearch.hosts")) + settings.register(LogStash::Setting::DeprecatedAndRenamed.new("xpack.monitoring.elasticsearch.ssl.ca", "xpack.monitoring.elasticsearch.ssl.certificate_authority")) + settings.register(LogStash::Setting::String.new("node.uuid", "")) rescue => e logger.error e.message diff --git a/x-pack/spec/config_management/extension_spec.rb b/x-pack/spec/config_management/extension_spec.rb index d25a87672..1ad4e9c0c 100644 --- a/x-pack/spec/config_management/extension_spec.rb +++ b/x-pack/spec/config_management/extension_spec.rb @@ -40,6 +40,13 @@ describe LogStash::ConfigManagement::Extension do "xpack.management.elasticsearch.ssl.keystore.path" => [LogStash::Setting::NullableString, nil], "xpack.management.elasticsearch.ssl.keystore.password" => [LogStash::Setting::NullableString, nil] ) + + describe 'deprecated and renamed settings' do + define_deprecated_and_renamed_settings( + "xpack.management.elasticsearch.url" => "xpack.management.elasticsearch.hosts", + "xpack.management.elasticsearch.ssl.ca" => "xpack.management.elasticsearch.ssl.certificate_authority" + ) + end end end end diff --git a/x-pack/spec/support/helpers.rb b/x-pack/spec/support/helpers.rb index eb26a1262..6e8ba7903 100644 --- a/x-pack/spec/support/helpers.rb +++ b/x-pack/spec/support/helpers.rb @@ -23,6 +23,20 @@ def define_settings(settings_options) end end +def define_deprecated_and_renamed_settings(settings_map) + settings_map.each do |deprecated_name, new_name| + it "define deprecated-and-renamed stub setting: `#{deprecated_name}` with guidance pointing to use `#{new_name}` instead" do + deprecated_setting = settings.get_setting(deprecated_name) + + expect(deprecated_setting).to be_kind_of(LogStash::Setting::DeprecatedAndRenamed) + expect(deprecated_setting.name).to eq(deprecated_name) + expect(deprecated_setting.new_name).to eq(new_name) + + expect { deprecated_setting.set(true) }.to raise_exception(ArgumentError, /deprecated and removed/) + end + end +end + def apply_settings(settings_values, settings = nil) settings = settings.nil? ? LogStash::SETTINGS.clone : settings From 4bb036f68a55b671e4a3ba746deb372911755259 Mon Sep 17 00:00:00 2001 From: Colin Surprenant Date: Tue, 2 Apr 2019 13:43:04 -0700 Subject: [PATCH 0048/1126] eliminate unnecessary add of whitespace Co-Authored-By: yaauie Fixes #10623 --- x-pack/lib/config_management/extension.rb | 1 - 1 file changed, 1 deletion(-) diff --git a/x-pack/lib/config_management/extension.rb b/x-pack/lib/config_management/extension.rb index f71248065..b98aee938 100644 --- a/x-pack/lib/config_management/extension.rb +++ b/x-pack/lib/config_management/extension.rb @@ -39,7 +39,6 @@ module LogStash settings.register(LogStash::Setting::DeprecatedAndRenamed.new("xpack.management.elasticsearch.url", "xpack.management.elasticsearch.hosts")) settings.register(LogStash::Setting::DeprecatedAndRenamed.new("xpack.management.elasticsearch.ssl.ca", "xpack.management.elasticsearch.ssl.certificate_authority")) - rescue => e logger.error("Cannot register new settings", :message => e.message, :backtrace => e.backtrace) raise e From 10301b40f7dee4f4615e8603256d41133a7e3866 Mon Sep 17 00:00:00 2001 From: Karen Metts Date: Mon, 1 Apr 2019 13:56:09 -0400 Subject: [PATCH 0049/1126] Update instructions for 7.0 upgrade Fixes #10621 --- docs/static/upgrading.asciidoc | 115 +++++++++++++++++++++++++-------- 1 file changed, 89 insertions(+), 26 deletions(-) diff --git a/docs/static/upgrading.asciidoc b/docs/static/upgrading.asciidoc index 6a7863d0f..cc0a4bddb 100644 --- a/docs/static/upgrading.asciidoc +++ b/docs/static/upgrading.asciidoc @@ -6,6 +6,7 @@ Before upgrading Logstash: * Consult the <> docs. +* Read the <>. * Test upgrades in a development environment before upgrading your production cluster. While upgrading Logstash: @@ -16,16 +17,15 @@ and becomes a new node in the monitoring data. =========================================== If you're upgrading other products in the stack, also read the -{stack-ref}/index.html[Elastic Stack Installation and Upgrade Guide]. Want an -upgrade list that's tailored to your stack? Try out our -{upgrade_guide}[Interactive Upgrade Guide]. +{stack-ref}/index.html[Elastic Stack Installation and Upgrade Guide]. See the following topics for information about upgrading Logstash: * <> * <> +* <> +* <> * <> -* <> [[upgrading-using-package-managers]] === Upgrading Using Package Managers @@ -33,12 +33,12 @@ See the following topics for information about upgrading Logstash: This procedure uses <> to upgrade Logstash. 1. Shut down your Logstash pipeline, including any inputs that send events to Logstash. -2. Using the directions in the _Package Repositories_ section, update your repository links to point to the 5.x repositories -instead of the previous version. +2. Using the directions in the <> section, update your repository +links to point to the 7.x repositories. 3. Run the `apt-get upgrade logstash` or `yum update logstash` command as appropriate for your operating system. 4. Test your configuration file with the `logstash --config.test_and_exit -f ` command. Configuration options for -some Logstash plugins have changed in the 5.x release. -5. Restart your Logstash pipeline after updating your configuration file. +some Logstash plugins have changed in the 7.x release. +5. Restart your Logstash pipeline after you have updated your configuration file. [[upgrading-using-direct-download]] === Upgrading Using a Direct Download @@ -48,12 +48,70 @@ This procedure downloads the relevant Logstash binaries directly from Elastic. 1. Shut down your Logstash pipeline, including any inputs that send events to Logstash. 2. Download the https://www.elastic.co/downloads/logstash[Logstash installation file] that matches your host environment. 3. Unpack the installation file into your Logstash directory. -4. Test your configuration file with the `logstash --config.test_and_exit -f ` command. Configuration options for -some Logstash plugins have changed in the 5.x release. +4. Test your configuration file with the `logstash --config.test_and_exit -f ` command. +Configuration options for +some Logstash plugins have changed in the 7.x release. 5. Restart your Logstash pipeline after updating your configuration file. + + +[[upgrading-minor-versions]] +=== Upgrading between minor versions + +As a general rule, you can upgrade between minor versions (for example, 7.x to +7.y, where x < y) by simply installing the new release and restarting {ls}. +{ls} typically maintains backwards compatibility for configuration +settings and exported fields. Please review the +<> for potential exceptions. + +Upgrading between non-consecutive major versions (5.x to 7.x, for example) is not +supported. + [[upgrading-logstash-pqs]] -=== Upgrading with Persistent Queues Enabled +=== Upgrading with the Persistent Queue Enabled + +If you have the persistent queue (PQ) enabled, please read the section that applies +for your upgrade scenario. + +* If you are upgrading from version 6.2.x or earlier, we recommend that you +<> before you upgrade. + +* If you are upgrading from version 6.3.0 or later, see +<> for information. + +[float] +[[drain-pq]] +==== Drain the Persistent Queue (version 6.2.x and earlier) + +The following applies only if you are upgrading from Logstash version 6.2.x or +earlier with the persistent queue (PQ) enabled. + +We strive to maintain backward compatibility within a given major release. +Serialization issues in Logstash 6.2.x and earlier required us to break +that compatibility in version 6.3.0 to ensure correctness of operation. For more +technical details, please check our tracking github issue for this +matter, https://github.com/elastic/logstash/issues/9494[#9494]. + +We strongly recommend that you drain or delete +the persistent queue before you upgrade from version 6.2.x and earlier. + +To drain the queue: + +. In the logstash.yml file, set `queue.drain:true`. +. Restart Logstash for this setting to take effect. +. Shutdown Logstash (using CTRL+C or SIGTERM), and wait for the queue to empty. + +When the queue is empty: + +. Complete the upgrade. +. Restart Logstash. + +We have resolved issues with data incompatibilities for version 6.3 and later. +These steps won’t be required for future upgrades. + +[float] +[[upgrading-logstash-pqs-6.3]] +==== Upgrading from version 6.3 (and later) with Persistent Queues Enabled Upgrading Logstash with persistent queues enabled is supported. The persistent queue directory is self-contained and can be read by a new Logstash instance @@ -66,37 +124,42 @@ Keep in mind that only one Logstash instance can write to `path.queue`. You cannot have the original instance and the new instance writing to the queue at the same time. -[[upgrading-logstash-5.0]] -=== Upgrading Logstash to 5.0 +[[upgrading-logstash-7.0]] +=== Upgrading Logstash to 7.0 -Before upgrading Logstash, remember to read the <>. +Before upgrading Logstash, remember to read the <> docs and the <>. If you are installing Logstash with other components in the Elastic Stack, also see the {stack-ref}/index.html[Elastic Stack installation and upgrade documentation]. +NOTE: Upgrading between non-consecutive major versions (5.x to 7.x, for example) is not +supported. We recommend that you upgrade to 6.x, and then upgrade to 7.x. + ==== When to Upgrade Fresh installations can and should start with the same version across the Elastic Stack. -Elasticsearch 5.0 does not require Logstash 5.0. An Elasticsearch 5.0 cluster will happily receive data from a -Logstash 2.x instance via the default HTTP communication layer. This provides some flexibility to decide when to upgrade -Logstash relative to an Elasticsearch upgrade. It may or may not be convenient for you to upgrade them together, and it -is -not required to be done at the same time as long as Elasticsearch is upgraded first. +Elasticsearch 7.0 does not require Logstash 7.0. An Elasticsearch 7.0 cluster +will happily receive data from earlier versions of Logstash via the default +HTTP communication layer. This provides some flexibility to decide when to +upgrade Logstash relative to an Elasticsearch upgrade. It may or may not be +convenient for you to upgrade them together, and it is not required to be done +at the same time as long as Elasticsearch is upgraded first. -You should upgrade in a timely manner to get the performance improvements that come with Logstash 5.0, but do so in +You should upgrade in a timely manner to get the performance improvements that come with Logstash 7.0, but do so in the way that makes the most sense for your environment. ==== When Not to Upgrade -If any Logstash plugin that you require is not compatible with Logstash 5.0, then you should wait until it is ready +If any Logstash plugin that you require is not compatible with Logstash 7.0, then you should wait until it is ready before upgrading. -Although we make great efforts to ensure compatibility, Logstash 5.0 is not completely backwards compatible. As noted -in the Elastic Stack upgrade guide, Logstash 5.0 should not be upgraded before Elasticsearch 5.0. This is both -practical and because some Logstash 5.0 plugins may attempt to use features of Elasticsearch 5.0 that did not exist -in earlier versions. For example, if you attempt to send the 5.x template to a cluster before Elasticsearch 5.0, then it -will not be able to use it and all indexing will fail likely fail. If you use your own, custom template with Logstash, +Although we make great efforts to ensure compatibility, Logstash 7.0 is not completely backwards compatible. As noted +in the Elastic Stack upgrade guide, Logstash 7.0 should not be upgraded before Elasticsearch 7.0. This is both +practical and because some Logstash 7.0 plugins may attempt to use features of Elasticsearch 7.0 that did not exist +in earlier versions. For example, if you attempt to send the 7.x template to a cluster before Elasticsearch 7.0, then +all indexing will fail likely fail. If you use your own custom template with Logstash, then this issue can be ignored. Note the Elasticsearch Output Index Template change in the <> documentation for further insight into From 3e0ac53e3af53793fc272746514b4648edb5fe6f Mon Sep 17 00:00:00 2001 From: Karen Metts <35154725+karenzone@users.noreply.github.com> Date: Tue, 2 Apr 2019 18:16:16 -0400 Subject: [PATCH 0050/1126] Removed note from earlier upgrade Fixes #10621 --- docs/static/upgrading.asciidoc | 3 --- 1 file changed, 3 deletions(-) diff --git a/docs/static/upgrading.asciidoc b/docs/static/upgrading.asciidoc index cc0a4bddb..db33342ef 100644 --- a/docs/static/upgrading.asciidoc +++ b/docs/static/upgrading.asciidoc @@ -161,6 +161,3 @@ practical and because some Logstash 7.0 plugins may attempt to use features of E in earlier versions. For example, if you attempt to send the 7.x template to a cluster before Elasticsearch 7.0, then all indexing will fail likely fail. If you use your own custom template with Logstash, then this issue can be ignored. - -Note the Elasticsearch Output Index Template change in the <> documentation for further insight into -this change and how it impacts operations. From f2b6fa35d45740a72f69c4e0208b560dac55b6f7 Mon Sep 17 00:00:00 2001 From: Karen Metts <35154725+karenzone@users.noreply.github.com> Date: Wed, 3 Apr 2019 09:30:56 -0400 Subject: [PATCH 0051/1126] Remove duplicate text Fixes #10621 --- docs/static/upgrading.asciidoc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/static/upgrading.asciidoc b/docs/static/upgrading.asciidoc index db33342ef..378660de2 100644 --- a/docs/static/upgrading.asciidoc +++ b/docs/static/upgrading.asciidoc @@ -159,5 +159,5 @@ Although we make great efforts to ensure compatibility, Logstash 7.0 is not comp in the Elastic Stack upgrade guide, Logstash 7.0 should not be upgraded before Elasticsearch 7.0. This is both practical and because some Logstash 7.0 plugins may attempt to use features of Elasticsearch 7.0 that did not exist in earlier versions. For example, if you attempt to send the 7.x template to a cluster before Elasticsearch 7.0, then -all indexing will fail likely fail. If you use your own custom template with Logstash, +all indexing likely fail. If you use your own custom template with Logstash, then this issue can be ignored. From 6913e62a3b49ee6689c7f2d8c1d481af674d1296 Mon Sep 17 00:00:00 2001 From: Dan Hermann Date: Wed, 3 Apr 2019 10:03:25 -0500 Subject: [PATCH 0052/1126] Call out requirement for Java execution in note Fixes #10630 --- docs/static/java-codec.asciidoc | 3 ++- docs/static/java-filter.asciidoc | 4 ++-- docs/static/java-input.asciidoc | 2 +- docs/static/java-output.asciidoc | 2 +- 4 files changed, 6 insertions(+), 5 deletions(-) diff --git a/docs/static/java-codec.asciidoc b/docs/static/java-codec.asciidoc index 5ed4d3c90..14172b5a0 100644 --- a/docs/static/java-codec.asciidoc +++ b/docs/static/java-codec.asciidoc @@ -374,8 +374,9 @@ To test the plugin, start Logstash with: echo "foo,bar" | bin/logstash --java-execution -e 'input { java_stdin { codec => java_codec_example } } }' ----- -Note that the `--java-execution` flag to enable the Java execution engine is required as Java plugins are not supported +NOTE: The `--java-execution` flag to enable the Java execution engine is required as Java plugins are not supported in the Ruby execution engine. + The expected Logstash output (excluding initialization) with the configuration above is: [source,txt] diff --git a/docs/static/java-filter.asciidoc b/docs/static/java-filter.asciidoc index 886b8a4d0..e2d2a05b0 100644 --- a/docs/static/java-filter.asciidoc +++ b/docs/static/java-filter.asciidoc @@ -207,7 +207,7 @@ reversed. public String getId() { return id; } ----- +----- For filter plugins, the `getId` method should always return the id that was provided to the plugin through its constructor at instantiation time. @@ -251,7 +251,7 @@ Start Logstash with: bin/logstash --java-execution -f /path/to/java_filter.conf ----- -Note that the `--java-execution` flag to enable the Java execution engine is +NOTE: The `--java-execution` flag to enable the Java execution engine is required as Java plugins are not supported in the Ruby execution engine. The expected Logstash output (excluding initialization) with the configuration diff --git a/docs/static/java-input.asciidoc b/docs/static/java-input.asciidoc index 917348275..06815c540 100644 --- a/docs/static/java-input.asciidoc +++ b/docs/static/java-input.asciidoc @@ -277,7 +277,7 @@ Start {ls} with: bin/logstash --java-execution -f /path/to/java_input.conf ----- -Note that the `--java-execution` flag to enable the Java execution engine is +NOTE: The `--java-execution` flag to enable the Java execution engine is required as Java plugins are not supported in the Ruby execution engine. The expected Logstash output (excluding initialization) with the configuration above is: diff --git a/docs/static/java-output.asciidoc b/docs/static/java-output.asciidoc index 0ea374768..15e57816d 100644 --- a/docs/static/java-output.asciidoc +++ b/docs/static/java-output.asciidoc @@ -261,7 +261,7 @@ Logstash should then be started with: bin/logstash --java-execution -f /path/to/java_output.conf ----- -Note that the `--java-execution` flag to enable the Java execution engine is +NOTE: The `--java-execution` flag to enable the Java execution engine is required as Java plugins are not supported in the Ruby execution engine. The expected Logstash output (excluding initialization) with the configuration From 9827ba8bbbd60e0526c3c4752a19757f3b587fb5 Mon Sep 17 00:00:00 2001 From: Karen Metts <35154725+karenzone@users.noreply.github.com> Date: Thu, 4 Apr 2019 04:46:18 -0400 Subject: [PATCH 0053/1126] Add note about issues with Java 11 and Debian or RPM (#10635) --- docs/static/getting-started-with-logstash.asciidoc | 3 +++ 1 file changed, 3 insertions(+) diff --git a/docs/static/getting-started-with-logstash.asciidoc b/docs/static/getting-started-with-logstash.asciidoc index 0354ad260..c70b85b27 100644 --- a/docs/static/getting-started-with-logstash.asciidoc +++ b/docs/static/getting-started-with-logstash.asciidoc @@ -41,6 +41,9 @@ automatically detect your environment and install the correct startup method JAVA_HOME environment variable during package installation time, you may get an error message, and Logstash will be unable to start properly. +IMPORTANT: Users have reported issues with Debian or RPM install packages and Java 11. +We are investigating and tracking in https://github.com/elastic/logstash/issues/10593[Issue #10593]. + [float] [[installing-binary]] === Installing from a Downloaded Binary From 0c4fe62a6d622fc2dbe74310df1d5e72149da97a Mon Sep 17 00:00:00 2001 From: Dan Hermann Date: Tue, 2 Apr 2019 18:29:11 -0500 Subject: [PATCH 0054/1126] Log successful shutdowns Fixes #10628 --- logstash-core/lib/logstash/runner.rb | 2 ++ 1 file changed, 2 insertions(+) diff --git a/logstash-core/lib/logstash/runner.rb b/logstash-core/lib/logstash/runner.rb index bc964a9dc..f03ac07c4 100644 --- a/logstash-core/lib/logstash/runner.rb +++ b/logstash-core/lib/logstash/runner.rb @@ -369,6 +369,8 @@ class LogStash::Runner < Clamp::StrictCommand @agent.shutdown + logger.info("Logstash shut down.") + # flush any outstanding log messages during shutdown org.apache.logging.log4j.LogManager.shutdown From 0921798a71379dc58162d5cf833188efb0d3d140 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jo=C3=A3o=20Duarte?= Date: Thu, 4 Apr 2019 11:27:06 +0100 Subject: [PATCH 0055/1126] build docker images from logstash repo (#10603) introduces two rake tasks: `rake artifact:docker_oss` and `rake artifact:docker`, which will create the docker images of the OSS and non OSS packages. These tasks depend on the tar artifacts being built. Also `rake artifact:all` has been modified to also call these two tasks. most code was moved from https://github.com/elastic/logstash-docker/ --- .gitignore | 2 +- docker/LICENSE | 201 ++++++++++++++++++ docker/Makefile | 133 ++++++++++++ docker/README.md | 39 ++++ docker/bin/elastic-version | 24 +++ docker/bin/pytest | 5 + docker/data/golang/Dockerfile | 4 + docker/data/logstash/bin/docker-entrypoint | 15 ++ docker/data/logstash/config/log4j2.properties | 16 ++ docker/data/logstash/config/logstash-full.yml | 2 + docker/data/logstash/config/logstash-oss.yml | 1 + docker/data/logstash/config/pipelines.yml | 6 + docker/data/logstash/env2yaml/env2yaml.go | 167 +++++++++++++++ docker/data/logstash/pipeline/default.conf | 12 ++ docker/docker-compose.yml | 1 + docker/examples/logstash.conf | 14 ++ docker/requirements.txt | 7 + docker/templates/Dockerfile.j2 | 72 +++++++ docker/templates/docker-compose.yml.j2 | 23 ++ docker/tests/__init__.py | 0 docker/tests/conftest.py | 25 +++ docker/tests/constants.py | 16 ++ docker/tests/docker-compose.yml | 5 + docker/tests/fixtures.py | 91 ++++++++ docker/tests/helpers.py | 8 + docker/tests/test_basics.py | 50 +++++ docker/tests/test_entrypoint.py | 14 ++ docker/tests/test_labels.py | 15 ++ docker/tests/test_process.py | 15 ++ docker/tests/test_settings.py | 71 +++++++ docker/tox.ini | 5 + docs/static/docker.asciidoc | 2 +- rakelib/artifacts.rake | 29 +++ 33 files changed, 1088 insertions(+), 2 deletions(-) create mode 100644 docker/LICENSE create mode 100644 docker/Makefile create mode 100644 docker/README.md create mode 100755 docker/bin/elastic-version create mode 100755 docker/bin/pytest create mode 100644 docker/data/golang/Dockerfile create mode 100755 docker/data/logstash/bin/docker-entrypoint create mode 100644 docker/data/logstash/config/log4j2.properties create mode 100644 docker/data/logstash/config/logstash-full.yml create mode 100644 docker/data/logstash/config/logstash-oss.yml create mode 100644 docker/data/logstash/config/pipelines.yml create mode 100644 docker/data/logstash/env2yaml/env2yaml.go create mode 100644 docker/data/logstash/pipeline/default.conf create mode 120000 docker/docker-compose.yml create mode 100644 docker/examples/logstash.conf create mode 100644 docker/requirements.txt create mode 100644 docker/templates/Dockerfile.j2 create mode 100644 docker/templates/docker-compose.yml.j2 create mode 100644 docker/tests/__init__.py create mode 100644 docker/tests/conftest.py create mode 100644 docker/tests/constants.py create mode 100644 docker/tests/docker-compose.yml create mode 100644 docker/tests/fixtures.py create mode 100644 docker/tests/helpers.py create mode 100644 docker/tests/test_basics.py create mode 100644 docker/tests/test_entrypoint.py create mode 100644 docker/tests/test_labels.py create mode 100644 docker/tests/test_process.py create mode 100644 docker/tests/test_settings.py create mode 100644 docker/tox.ini diff --git a/.gitignore b/.gitignore index 691ac83c2..3a87424ee 100644 --- a/.gitignore +++ b/.gitignore @@ -17,7 +17,7 @@ local test/setup/elasticsearch/elasticsearch-* vendor .sass-cache -data +/data .buildpath .project .DS_Store diff --git a/docker/LICENSE b/docker/LICENSE new file mode 100644 index 000000000..8dada3eda --- /dev/null +++ b/docker/LICENSE @@ -0,0 +1,201 @@ + Apache License + Version 2.0, January 2004 + http://www.apache.org/licenses/ + + TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION + + 1. Definitions. + + "License" shall mean the terms and conditions for use, reproduction, + and distribution as defined by Sections 1 through 9 of this document. + + "Licensor" shall mean the copyright owner or entity authorized by + the copyright owner that is granting the License. + + "Legal Entity" shall mean the union of the acting entity and all + other entities that control, are controlled by, or are under common + control with that entity. For the purposes of this definition, + "control" means (i) the power, direct or indirect, to cause the + direction or management of such entity, whether by contract or + otherwise, or (ii) ownership of fifty percent (50%) or more of the + outstanding shares, or (iii) beneficial ownership of such entity. + + "You" (or "Your") shall mean an individual or Legal Entity + exercising permissions granted by this License. + + "Source" form shall mean the preferred form for making modifications, + including but not limited to software source code, documentation + source, and configuration files. + + "Object" form shall mean any form resulting from mechanical + transformation or translation of a Source form, including but + not limited to compiled object code, generated documentation, + and conversions to other media types. + + "Work" shall mean the work of authorship, whether in Source or + Object form, made available under the License, as indicated by a + copyright notice that is included in or attached to the work + (an example is provided in the Appendix below). + + "Derivative Works" shall mean any work, whether in Source or Object + form, that is based on (or derived from) the Work and for which the + editorial revisions, annotations, elaborations, or other modifications + represent, as a whole, an original work of authorship. For the purposes + of this License, Derivative Works shall not include works that remain + separable from, or merely link (or bind by name) to the interfaces of, + the Work and Derivative Works thereof. + + "Contribution" shall mean any work of authorship, including + the original version of the Work and any modifications or additions + to that Work or Derivative Works thereof, that is intentionally + submitted to Licensor for inclusion in the Work by the copyright owner + or by an individual or Legal Entity authorized to submit on behalf of + the copyright owner. For the purposes of this definition, "submitted" + means any form of electronic, verbal, or written communication sent + to the Licensor or its representatives, including but not limited to + communication on electronic mailing lists, source code control systems, + and issue tracking systems that are managed by, or on behalf of, the + Licensor for the purpose of discussing and improving the Work, but + excluding communication that is conspicuously marked or otherwise + designated in writing by the copyright owner as "Not a Contribution." + + "Contributor" shall mean Licensor and any individual or Legal Entity + on behalf of whom a Contribution has been received by Licensor and + subsequently incorporated within the Work. + + 2. Grant of Copyright License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + copyright license to reproduce, prepare Derivative Works of, + publicly display, publicly perform, sublicense, and distribute the + Work and such Derivative Works in Source or Object form. + + 3. Grant of Patent License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + (except as stated in this section) patent license to make, have made, + use, offer to sell, sell, import, and otherwise transfer the Work, + where such license applies only to those patent claims licensable + by such Contributor that are necessarily infringed by their + Contribution(s) alone or by combination of their Contribution(s) + with the Work to which such Contribution(s) was submitted. If You + institute patent litigation against any entity (including a + cross-claim or counterclaim in a lawsuit) alleging that the Work + or a Contribution incorporated within the Work constitutes direct + or contributory patent infringement, then any patent licenses + granted to You under this License for that Work shall terminate + as of the date such litigation is filed. + + 4. Redistribution. You may reproduce and distribute copies of the + Work or Derivative Works thereof in any medium, with or without + modifications, and in Source or Object form, provided that You + meet the following conditions: + + (a) You must give any other recipients of the Work or + Derivative Works a copy of this License; and + + (b) You must cause any modified files to carry prominent notices + stating that You changed the files; and + + (c) You must retain, in the Source form of any Derivative Works + that You distribute, all copyright, patent, trademark, and + attribution notices from the Source form of the Work, + excluding those notices that do not pertain to any part of + the Derivative Works; and + + (d) If the Work includes a "NOTICE" text file as part of its + distribution, then any Derivative Works that You distribute must + include a readable copy of the attribution notices contained + within such NOTICE file, excluding those notices that do not + pertain to any part of the Derivative Works, in at least one + of the following places: within a NOTICE text file distributed + as part of the Derivative Works; within the Source form or + documentation, if provided along with the Derivative Works; or, + within a display generated by the Derivative Works, if and + wherever such third-party notices normally appear. The contents + of the NOTICE file are for informational purposes only and + do not modify the License. You may add Your own attribution + notices within Derivative Works that You distribute, alongside + or as an addendum to the NOTICE text from the Work, provided + that such additional attribution notices cannot be construed + as modifying the License. + + You may add Your own copyright statement to Your modifications and + may provide additional or different license terms and conditions + for use, reproduction, or distribution of Your modifications, or + for any such Derivative Works as a whole, provided Your use, + reproduction, and distribution of the Work otherwise complies with + the conditions stated in this License. + + 5. Submission of Contributions. Unless You explicitly state otherwise, + any Contribution intentionally submitted for inclusion in the Work + by You to the Licensor shall be under the terms and conditions of + this License, without any additional terms or conditions. + Notwithstanding the above, nothing herein shall supersede or modify + the terms of any separate license agreement you may have executed + with Licensor regarding such Contributions. + + 6. Trademarks. This License does not grant permission to use the trade + names, trademarks, service marks, or product names of the Licensor, + except as required for reasonable and customary use in describing the + origin of the Work and reproducing the content of the NOTICE file. + + 7. Disclaimer of Warranty. Unless required by applicable law or + agreed to in writing, Licensor provides the Work (and each + Contributor provides its Contributions) on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + implied, including, without limitation, any warranties or conditions + of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A + PARTICULAR PURPOSE. You are solely responsible for determining the + appropriateness of using or redistributing the Work and assume any + risks associated with Your exercise of permissions under this License. + + 8. Limitation of Liability. In no event and under no legal theory, + whether in tort (including negligence), contract, or otherwise, + unless required by applicable law (such as deliberate and grossly + negligent acts) or agreed to in writing, shall any Contributor be + liable to You for damages, including any direct, indirect, special, + incidental, or consequential damages of any character arising as a + result of this License or out of the use or inability to use the + Work (including but not limited to damages for loss of goodwill, + work stoppage, computer failure or malfunction, or any and all + other commercial damages or losses), even if such Contributor + has been advised of the possibility of such damages. + + 9. Accepting Warranty or Additional Liability. While redistributing + the Work or Derivative Works thereof, You may choose to offer, + and charge a fee for, acceptance of support, warranty, indemnity, + or other liability obligations and/or rights consistent with this + License. However, in accepting such obligations, You may act only + on Your own behalf and on Your sole responsibility, not on behalf + of any other Contributor, and only if You agree to indemnify, + defend, and hold each Contributor harmless for any liability + incurred by, or claims asserted against, such Contributor by reason + of your accepting any such warranty or additional liability. + + END OF TERMS AND CONDITIONS + + APPENDIX: How to apply the Apache License to your work. + + To apply the Apache License to your work, attach the following + boilerplate notice, with the fields enclosed by brackets "{}" + replaced with your own identifying information. (Don't include + the brackets!) The text should be enclosed in the appropriate + comment syntax for the file format. We also recommend that a + file or class name and description of purpose be included on the + same "printed page" as the copyright notice for easier + identification within third-party archives. + + Copyright {yyyy} {name of copyright owner} + + Licensed 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. diff --git a/docker/Makefile b/docker/Makefile new file mode 100644 index 000000000..bf5f74005 --- /dev/null +++ b/docker/Makefile @@ -0,0 +1,133 @@ +SHELL=/bin/bash +ELASTIC_REGISTRY ?= docker.elastic.co + +export PATH := ./bin:./venv/bin:$(PATH) + +# Determine the version to build. Override by setting ELASTIC_VERSION env var. +ELASTIC_VERSION := $(shell ./bin/elastic-version) + +ifdef STAGING_BUILD_NUM + VERSION_TAG := $(ELASTIC_VERSION)-$(STAGING_BUILD_NUM) +else + VERSION_TAG := $(ELASTIC_VERSION) +endif + +IMAGE_FLAVORS ?= oss full +DEFAULT_IMAGE_FLAVOR ?= full + +IMAGE_TAG := $(ELASTIC_REGISTRY)/logstash/logstash +HTTPD ?= logstash-docker-artifact-server + +FIGLET := pyfiglet -w 160 -f puffy + +all: build-from-local-artifacts build-from-local-oss-artifacts + +test: lint docker-compose + $(foreach FLAVOR, $(IMAGE_FLAVORS), \ + $(FIGLET) "test: $(FLAVOR)"; \ + ./bin/pytest tests --image-flavor=$(FLAVOR); \ + ) + +test-snapshot: + ELASTIC_VERSION=$(ELASTIC_VERSION)-SNAPSHOT make test + +lint: venv + flake8 tests + +# Build from artifacts on the local filesystem, using an http server (running +# in a container) to provide the artifacts to the Dockerfile. +build-from-local-artifacts: venv dockerfile docker-compose env2yaml + docker run --rm -d --name=$(HTTPD) \ + -p 8000:8000 --expose=8000 -v $(ARTIFACTS_DIR):/mnt \ + python:3 bash -c 'cd /mnt && python3 -m http.server' + gtimeout 120 bash -c 'until curl -s localhost:8000 > /dev/null; do sleep 1; done' + pyfiglet -f puffy -w 160 "Building: full"; \ + docker build --network=host -t $(IMAGE_TAG)-full:$(VERSION_TAG) -f $(ARTIFACTS_DIR)/Dockerfile-full data/logstash || \ + (docker kill $(HTTPD); false); \ + docker tag $(IMAGE_TAG)-full:$(VERSION_TAG) $(IMAGE_TAG):$(VERSION_TAG); + docker kill $(HTTPD) + +build-from-local-oss-artifacts: venv dockerfile docker-compose env2yaml + docker run --rm -d --name=$(HTTPD) \ + -p 8000:8000 --expose=8000 -v $(ARTIFACTS_DIR):/mnt \ + python:3 bash -c 'cd /mnt && python3 -m http.server' + gtimeout 120 bash -c 'until curl -s localhost:8000 > /dev/null; do sleep 1; done' + pyfiglet -f puffy -w 160 "Building: oss"; \ + docker build --network=host -t $(IMAGE_TAG)-oss:$(VERSION_TAG) -f $(ARTIFACTS_DIR)/Dockerfile-oss data/logstash || \ + (docker kill $(HTTPD); false); + -docker kill $(HTTPD) + +demo: docker-compose clean-demo + docker-compose up + +# Push the image to the dedicated push endpoint at "push.docker.elastic.co" +push: test + $(foreach FLAVOR, $(IMAGE_FLAVORS), \ + docker tag $(IMAGE_TAG)-$(FLAVOR):$(VERSION_TAG) push.$(IMAGE_TAG)-$(FLAVOR):$(VERSION_TAG); \ + docker push push.$(IMAGE_TAG)-$(FLAVOR):$(VERSION_TAG); \ + docker rmi push.$(IMAGE_TAG)-$(FLAVOR):$(VERSION_TAG); \ + ) + # Also push the default version, with no suffix like '-oss' or '-full' + docker tag $(IMAGE_TAG):$(VERSION_TAG) push.$(IMAGE_TAG):$(VERSION_TAG); + docker push push.$(IMAGE_TAG):$(VERSION_TAG); + docker rmi push.$(IMAGE_TAG):$(VERSION_TAG); + +# The tests are written in Python. Make a virtualenv to handle the dependencies. +venv: requirements.txt + @if [ -z $$PYTHON3 ]; then\ + PY3_MINOR_VER=`python3 --version 2>&1 | cut -d " " -f 2 | cut -d "." -f 2`;\ + if (( $$PY3_MINOR_VER < 5 )); then\ + echo "Couldn't find python3 in \$PATH that is >=3.5";\ + echo "Please install python3.5 or later or explicity define the python3 executable name with \$PYTHON3";\ + echo "Exiting here";\ + exit 1;\ + else\ + export PYTHON3="python3.$$PY3_MINOR_VER";\ + fi;\ + fi;\ + test -d venv || virtualenv --python=$$PYTHON3 venv;\ + pip install -r requirements.txt;\ + touch venv;\ + +# Make a Golang container that can compile our env2yaml tool. +golang: + docker build -t golang:env2yaml data/golang + +# Compile "env2yaml", the helper for configuring logstash.yml via environment +# variables. +env2yaml: golang + docker run --rm -i \ + -v $(PWD)/data/logstash/env2yaml:/usr/local/src/env2yaml:Z \ + golang:env2yaml + +# Generate the Dockerfiles from Jinja2 templates. +dockerfile: venv templates/Dockerfile.j2 + $(foreach FLAVOR, $(IMAGE_FLAVORS), \ + jinja2 \ + -D elastic_version='$(ELASTIC_VERSION)' \ + -D version_tag='$(VERSION_TAG)' \ + -D image_flavor='$(FLAVOR)' \ + -D artifacts_dir='$(ARTIFACTS_DIR)' \ + templates/Dockerfile.j2 > $(ARTIFACTS_DIR)/Dockerfile-$(FLAVOR); \ + ) + + +# Generate docker-compose files from Jinja2 templates. +docker-compose: venv + $(foreach FLAVOR, $(IMAGE_FLAVORS), \ + jinja2 \ + -D version_tag='$(VERSION_TAG)' \ + -D image_flavor='$(FLAVOR)' \ + templates/docker-compose.yml.j2 > docker-compose-$(FLAVOR).yml; \ + ) + ln -sf docker-compose-$(DEFAULT_IMAGE_FLAVOR).yml docker-compose.yml + +clean: clean-demo + rm -f ${ARTIFACTS_DIR}/env2yaml/env2yaml ${ARTIFACTS_DIR}/Dockerfile + rm -rf venv + +clean-demo: docker-compose + docker-compose down + docker-compose rm --force + +.PHONY: clean clean-demo demo push test diff --git a/docker/README.md b/docker/README.md new file mode 100644 index 000000000..4bd6af593 --- /dev/null +++ b/docker/README.md @@ -0,0 +1,39 @@ +## Description + +This repository contains the official [Logstash][logstash] Docker image from +[Elastic][elastic]. + +Documentation can be found on the [Elastic website](https://www.elastic.co/guide/en/logstash/current/docker.html). + +[logstash]: https://www.elastic.co/products/logstash +[elastic]: https://www.elastic.co/ + +## Supported Docker versions + +The images have been tested on Docker version 18.09.2, build 6247962 + +## Requirements +A full build and test requires: +* Docker +* GNU Make +* Python 3.5 with Virtualenv +* JRuby 9.1+ + +## Running a build +To build an image check out the corresponding branch for the version and run the rake task +Like this: +``` +git checkout 7.0 +rake artifact:docker +# and for the OSS package +rake artifact:docker_oss +``` + +## Contributing, issues and testing + +Acceptance tests for the image are located in the `test` directory, and can +be invoked with `make test`. + +This image is built on [Centos 7][centos-7]. + +[centos-7]: https://github.com/CentOS/sig-cloud-instance-images/blob/50281d86d6ed5c61975971150adfd0ede86423bb/docker/Dockerfile diff --git a/docker/bin/elastic-version b/docker/bin/elastic-version new file mode 100755 index 000000000..68790168d --- /dev/null +++ b/docker/bin/elastic-version @@ -0,0 +1,24 @@ +#!/usr/bin/env ruby +# +# Print the Elastic Stack version for the current branch, as defined in +# the 'version.json' file. +# +require 'yaml' + +def get_hard_coded_version + version_info = YAML::safe_load(IO.read('../versions.yml')) + version_info['logstash'] +end + +def qualify(version) + qualifier = ENV['VERSION_QUALIFIER'] + qualifier ? [version, qualifier].join("-") : version +end + +def get_version + version = get_hard_coded_version() + version = qualify(version) + ENV["RELEASE"] == "1" ? version : [version, "SNAPSHOT"].join("-") +end + +puts get_version diff --git a/docker/bin/pytest b/docker/bin/pytest new file mode 100755 index 000000000..90c52e1db --- /dev/null +++ b/docker/bin/pytest @@ -0,0 +1,5 @@ +#!/bin/bash +# +# A wrapper for `pytest` to handle the appropriate Testinfra arguments. + +./venv/bin/pytest --verbose --connection=docker --hosts=logstash-test $@ diff --git a/docker/data/golang/Dockerfile b/docker/data/golang/Dockerfile new file mode 100644 index 000000000..b23afaa8c --- /dev/null +++ b/docker/data/golang/Dockerfile @@ -0,0 +1,4 @@ +FROM golang:1.8 +RUN go get gopkg.in/yaml.v2 +WORKDIR /usr/local/src/env2yaml +CMD ["go", "build"] diff --git a/docker/data/logstash/bin/docker-entrypoint b/docker/data/logstash/bin/docker-entrypoint new file mode 100755 index 000000000..19165f149 --- /dev/null +++ b/docker/data/logstash/bin/docker-entrypoint @@ -0,0 +1,15 @@ +#!/bin/bash -e + +# Map environment variables to entries in logstash.yml. +# Note that this will mutate logstash.yml in place if any such settings are found. +# This may be undesirable, especially if logstash.yml is bind-mounted from the +# host system. +env2yaml /usr/share/logstash/config/logstash.yml + +export LS_JAVA_OPTS="-Dls.cgroup.cpuacct.path.override=/ -Dls.cgroup.cpu.path.override=/ $LS_JAVA_OPTS" + +if [[ -z $1 ]] || [[ ${1:0:1} == '-' ]] ; then + exec logstash "$@" +else + exec "$@" +fi diff --git a/docker/data/logstash/config/log4j2.properties b/docker/data/logstash/config/log4j2.properties new file mode 100644 index 000000000..36bc45143 --- /dev/null +++ b/docker/data/logstash/config/log4j2.properties @@ -0,0 +1,16 @@ +status = error +name = LogstashPropertiesConfig + +appender.console.type = Console +appender.console.name = plain_console +appender.console.layout.type = PatternLayout +appender.console.layout.pattern = [%d{ISO8601}][%-5p][%-25c] %m%n + +appender.json_console.type = Console +appender.json_console.name = json_console +appender.json_console.layout.type = JSONLayout +appender.json_console.layout.compact = true +appender.json_console.layout.eventEol = true + +rootLogger.level = ${sys:ls.log.level} +rootLogger.appenderRef.console.ref = ${sys:ls.log.format}_console diff --git a/docker/data/logstash/config/logstash-full.yml b/docker/data/logstash/config/logstash-full.yml new file mode 100644 index 000000000..58e1a35d0 --- /dev/null +++ b/docker/data/logstash/config/logstash-full.yml @@ -0,0 +1,2 @@ +http.host: "0.0.0.0" +xpack.monitoring.elasticsearch.hosts: [ "http://elasticsearch:9200" ] diff --git a/docker/data/logstash/config/logstash-oss.yml b/docker/data/logstash/config/logstash-oss.yml new file mode 100644 index 000000000..342d19af8 --- /dev/null +++ b/docker/data/logstash/config/logstash-oss.yml @@ -0,0 +1 @@ +http.host: "0.0.0.0" diff --git a/docker/data/logstash/config/pipelines.yml b/docker/data/logstash/config/pipelines.yml new file mode 100644 index 000000000..aed22ce73 --- /dev/null +++ b/docker/data/logstash/config/pipelines.yml @@ -0,0 +1,6 @@ +# This file is where you define your pipelines. You can define multiple. +# For more information on multiple pipelines, see the documentation: +# https://www.elastic.co/guide/en/logstash/current/multiple-pipelines.html + +- pipeline.id: main + path.config: "/usr/share/logstash/pipeline" diff --git a/docker/data/logstash/env2yaml/env2yaml.go b/docker/data/logstash/env2yaml/env2yaml.go new file mode 100644 index 000000000..507f73f0a --- /dev/null +++ b/docker/data/logstash/env2yaml/env2yaml.go @@ -0,0 +1,167 @@ +// env2yaml +// +// Merge environment variables into logstash.yml. +// For example, running Docker with: +// +// docker run -e pipeline.workers=6 +// +// or +// +// docker run -e PIPELINE_WORKERS=6 +// +// will cause logstash.yml to contain the line: +// +// pipeline.workers: 6 +// +package main + +import ( + "errors" + "gopkg.in/yaml.v2" + "io/ioutil" + "log" + "os" + "strings" +) + +// If the given string can be parsed as YAML, then do so and return the +// resulting entity. Otherwise, return the string unmodified. +func FromYamlIfPossible(str string) interface{} { + var entity interface{} + err := yaml.Unmarshal([]byte(str), &entity) + if err == nil { + return entity + } else { + return str + } +} + +// Given a setting name, return a downcased version with delimiters removed. +func squashSetting(setting string) string { + downcased := strings.ToLower(setting) + de_dotted := strings.Replace(downcased, ".", "", -1) + de_underscored := strings.Replace(de_dotted, "_", "", -1) + return de_underscored +} + +// Given a setting name like "pipeline.workers" or "PIPELINE_UNSAFE_SHUTDOWN", +// return the canonical setting name. eg. 'pipeline.unsafe_shutdown' +func normalizeSetting(setting string) (string, error) { + valid_settings := []string{ + "node.name", + "path.data", + "pipeline.id", + "pipeline.workers", + "pipeline.output.workers", + "pipeline.batch.size", + "pipeline.batch.delay", + "pipeline.unsafe_shutdown", + "pipeline.java_execution", + "path.config", + "config.string", + "config.test_and_exit", + "config.reload.automatic", + "config.reload.interval", + "config.debug", + "config.support_escapes", + "queue.type", + "path.queue", + "queue.page_capacity", + "queue.max_events", + "queue.max_bytes", + "queue.checkpoint.acks", + "queue.checkpoint.writes", + "queue.checkpoint.interval", + "queue.drain", + "dead_letter_queue.enable", + "dead_letter_queue.max_bytes", + "path.dead_letter_queue", + "http.host", + "http.port", + "log.level", + "log.format", + "modules", + "path.logs", + "path.plugins", + "xpack.monitoring.enabled", + "xpack.monitoring.collection.interval", + "xpack.monitoring.elasticsearch.hosts", + "xpack.monitoring.elasticsearch.username", + "xpack.monitoring.elasticsearch.password", + "xpack.monitoring.elasticsearch.ssl.certificate_authority", + "xpack.monitoring.elasticsearch.ssl.truststore.path", + "xpack.monitoring.elasticsearch.ssl.truststore.password", + "xpack.monitoring.elasticsearch.ssl.keystore.path", + "xpack.monitoring.elasticsearch.ssl.keystore.password", + "xpack.management.enabled", + "xpack.management.logstash.poll_interval", + "xpack.management.pipeline.id", + "xpack.management.elasticsearch.hosts", + "xpack.management.elasticsearch.username", + "xpack.management.elasticsearch.password", + "xpack.management.elasticsearch.ssl.certificate_authority", + "xpack.management.elasticsearch.ssl.truststore.path", + "xpack.management.elasticsearch.ssl.truststore.password", + "xpack.management.elasticsearch.ssl.keystore.path", + "xpack.management.elasticsearch.ssl.keystore.password", + "cloud.id", + "cloud.auth", + } + + for _, valid_setting := range valid_settings { + if squashSetting(setting) == squashSetting(valid_setting) { + return valid_setting, nil + } + } + return "", errors.New("Invalid setting: " + setting) +} + +func main() { + if len(os.Args) != 2 { + log.Fatalf("usage: env2yaml FILENAME") + } + settingsFilePath := os.Args[1] + + settingsFile, err := ioutil.ReadFile(settingsFilePath) + if err != nil { + log.Fatalf("error: %v", err) + } + + // Read the original settings file into a map. + settings := make(map[string]interface{}) + err = yaml.Unmarshal(settingsFile, &settings) + if err != nil { + log.Fatalf("error: %v", err) + } + + // Merge any valid settings found in the environment. + foundNewSettings := false + for _, line := range os.Environ() { + kv := strings.SplitN(line, "=", 2) + key := kv[0] + value := kv[1] + setting, err := normalizeSetting(key) + if err == nil { + foundNewSettings = true + log.Printf("Setting '%s' from environment.", setting) + settings[setting] = FromYamlIfPossible(value) + } + } + + if foundNewSettings { + output, err := yaml.Marshal(&settings) + if err != nil { + log.Fatalf("error: %v", err) + } + + stat, err := os.Stat(settingsFilePath) + if err != nil { + log.Fatalf("error: %v", err) + } + + err = ioutil.WriteFile(settingsFilePath, output, stat.Mode()) + if err != nil { + log.Fatalf("error: %v", err) + } + } +} diff --git a/docker/data/logstash/pipeline/default.conf b/docker/data/logstash/pipeline/default.conf new file mode 100644 index 000000000..11ce14cdf --- /dev/null +++ b/docker/data/logstash/pipeline/default.conf @@ -0,0 +1,12 @@ +input { + beats { + port => 5044 + } +} + +output { + stdout { + codec => rubydebug + } +} + diff --git a/docker/docker-compose.yml b/docker/docker-compose.yml new file mode 120000 index 000000000..574078f66 --- /dev/null +++ b/docker/docker-compose.yml @@ -0,0 +1 @@ +docker-compose-full.yml \ No newline at end of file diff --git a/docker/examples/logstash.conf b/docker/examples/logstash.conf new file mode 100644 index 000000000..4c20d126d --- /dev/null +++ b/docker/examples/logstash.conf @@ -0,0 +1,14 @@ +input { + heartbeat { + interval => 5 + message => 'Hello from Logstash 💓' + } +} + +output { + elasticsearch { + hosts => [ 'elasticsearch' ] + user => 'elastic' + password => 'changeme' + } +} diff --git a/docker/requirements.txt b/docker/requirements.txt new file mode 100644 index 000000000..eb42e8a6b --- /dev/null +++ b/docker/requirements.txt @@ -0,0 +1,7 @@ +docker-compose==1.11.2 +flake8==3.4.1 +jinja2-cli[yaml]==0.6.0 +jinja2==2.9.5 +retrying==1.3.3 +testinfra==1.6.0 +pyfiglet diff --git a/docker/templates/Dockerfile.j2 b/docker/templates/Dockerfile.j2 new file mode 100644 index 000000000..0bbf5ae84 --- /dev/null +++ b/docker/templates/Dockerfile.j2 @@ -0,0 +1,72 @@ +# This Dockerfile was generated from templates/Dockerfile.j2 +{% if image_flavor == 'oss' -%} + {% set tarball = 'logstash-oss-%s.tar.gz' % elastic_version -%} +{% else -%} + {% set tarball = 'logstash-%s.tar.gz' % elastic_version -%} +{% endif -%} + + +FROM centos:7 + +# Install Java and the "which" command, which is needed by Logstash's shell +# scripts. +RUN yum update -y && yum install -y java-1.8.0-openjdk-devel which && \ + yum clean all + +# Provide a non-root user to run the process. +RUN groupadd --gid 1000 logstash && \ + adduser --uid 1000 --gid 1000 \ + --home-dir /usr/share/logstash --no-create-home \ + logstash + +# Add Logstash itself. +RUN curl -Lo - 'http://localhost:8000/'{{ tarball }} | \ + tar zxf - -C /usr/share && \ + mv /usr/share/logstash-{{ elastic_version }} /usr/share/logstash && \ + chown --recursive logstash:logstash /usr/share/logstash/ && \ + chown -R logstash:root /usr/share/logstash && \ + chmod -R g=u /usr/share/logstash && \ + find /usr/share/logstash -type d -exec chmod g+s {} \; && \ + ln -s /usr/share/logstash /opt/logstash + +WORKDIR /usr/share/logstash + +ENV ELASTIC_CONTAINER true +ENV PATH=/usr/share/logstash/bin:$PATH + +# Provide a minimal configuration, so that simple invocations will provide +# a good experience. +ADD config/pipelines.yml config/pipelines.yml +ADD config/logstash-{{ image_flavor }}.yml config/logstash.yml +ADD config/log4j2.properties config/ +ADD pipeline/default.conf pipeline/logstash.conf +RUN chown --recursive logstash:root config/ pipeline/ + +# Ensure Logstash gets a UTF-8 locale by default. +ENV LANG='en_US.UTF-8' LC_ALL='en_US.UTF-8' + +# Place the startup wrapper script. +ADD bin/docker-entrypoint /usr/local/bin/ +RUN chmod 0755 /usr/local/bin/docker-entrypoint + +USER 1000 + +ADD env2yaml/env2yaml /usr/local/bin/ + +EXPOSE 9600 5044 + + +LABEL org.label-schema.schema-version="1.0" \ + org.label-schema.vendor="Elastic" \ + org.label-schema.name="logstash" \ + org.label-schema.version="{{ elastic_version }}" \ + org.label-schema.url="https://www.elastic.co/products/logstash" \ + org.label-schema.vcs-url="https://github.com/elastic/logstash" \ +{% if image_flavor == 'oss' -%} + license="Apache-2.0" +{% else -%} + license="Elastic License" +{% endif -%} + + +ENTRYPOINT ["/usr/local/bin/docker-entrypoint"] diff --git a/docker/templates/docker-compose.yml.j2 b/docker/templates/docker-compose.yml.j2 new file mode 100644 index 000000000..e228dd545 --- /dev/null +++ b/docker/templates/docker-compose.yml.j2 @@ -0,0 +1,23 @@ +--- +version: '3.0' +services: + logstash: + image: docker.elastic.co/logstash/logstash:{{ version_tag }} + volumes: + - ./examples/logstash.conf/:/usr/share/logstash/pipeline/logstash.conf + networks: + - elastic-stack + + elasticsearch: + image: docker.elastic.co/elasticsearch/elasticsearch-platinum:{{ version_tag }} + networks: + - elastic-stack + + kibana: + image: docker.elastic.co/kibana/kibana:{{ version_tag }} + ports: [ '5601:5601' ] + networks: + - elastic-stack + +networks: + elastic-stack: diff --git a/docker/tests/__init__.py b/docker/tests/__init__.py new file mode 100644 index 000000000..e69de29bb diff --git a/docker/tests/conftest.py b/docker/tests/conftest.py new file mode 100644 index 000000000..b0bc563ec --- /dev/null +++ b/docker/tests/conftest.py @@ -0,0 +1,25 @@ +from subprocess import run +import pytest +from .constants import container_name, version +import docker + +docker_engine = docker.from_env() + + +def pytest_addoption(parser): + """Customize testinfra with config options via cli args""" + # Let us specify which docker-compose-(image_flavor).yml file to use + parser.addoption('--image-flavor', action='store', default='full', + help='Docker image flavor; the suffix used in docker-compose-.yml') + + +@pytest.fixture(scope='session', autouse=True) +def start_container(): + image = 'docker.elastic.co/logstash/logstash-%s:%s' % (pytest.config.getoption('--image-flavor'), version) + docker_engine.containers.run(image, name=container_name, detach=True, stdin_open=False) + + +def pytest_unconfigure(config): + container = docker_engine.containers.get(container_name) + container.stop() + container.remove() diff --git a/docker/tests/constants.py b/docker/tests/constants.py new file mode 100644 index 000000000..e0996dc5b --- /dev/null +++ b/docker/tests/constants.py @@ -0,0 +1,16 @@ +import os +import pytest +from subprocess import run, PIPE + +version = run('./bin/elastic-version', stdout=PIPE).stdout.decode().strip() +version_number = version.split('-')[0] # '7.0.0-alpha1-SNAPSHOT' -> '7.0.0' +logstash_version_string = 'logstash %s' % version_number # eg. 'logstash 7.0.0' + + +try: + if len(os.environ['STAGING_BUILD_NUM']) > 0: + version += '-%s' % os.environ['STAGING_BUILD_NUM'] # eg. '5.3.0-d5b30bd7' +except KeyError: + pass + +container_name = 'logstash-test' diff --git a/docker/tests/docker-compose.yml b/docker/tests/docker-compose.yml new file mode 100644 index 000000000..fc7939532 --- /dev/null +++ b/docker/tests/docker-compose.yml @@ -0,0 +1,5 @@ +--- +version: '3' +services: + logstash: + container_name: logstash-test diff --git a/docker/tests/fixtures.py b/docker/tests/fixtures.py new file mode 100644 index 000000000..8d6f1d776 --- /dev/null +++ b/docker/tests/fixtures.py @@ -0,0 +1,91 @@ +import json +import os +import yaml +from pytest import config, fixture +from .constants import container_name, version +from retrying import retry +from subprocess import run, PIPE +from time import sleep + +retry_settings = { + 'wait_fixed': 1000, + 'stop_max_attempt_number': 60 +} + + +@fixture +def logstash(host): + class Logstash: + def __init__(self): + self.version = version + self.name = container_name + self.process = host.process.get(comm='java') + self.settings_file = host.file('/usr/share/logstash/config/logstash.yml') + self.image_flavor = config.getoption('--image-flavor') + self.image = 'docker.elastic.co/logstash/logstash-%s:%s' % (self.image_flavor, version) + + if 'STAGING_BUILD_NUM' in os.environ: + self.tag = '%s-%s' % (self.version, os.environ['STAGING_BUILD_NUM']) + else: + self.tag = self.version + + self.docker_metadata = json.loads( + run(['docker', 'inspect', self.image], stdout=PIPE).stdout.decode())[0] + + def start(self, args=None): + if args: + arg_array = args.split(' ') + else: + arg_array = [] + run(['docker', 'run', '-d', '--name', self.name] + arg_array + [self.image]) + + def stop(self): + run(['docker', 'kill', self.name]) + run(['docker', 'rm', self.name]) + + def restart(self, args=None): + self.stop() + self.start(args) + + @retry(**retry_settings) + def get_node_info(self): + """Return the contents of Logstash's node info API. + + It retries for a while, since Logstash may still be coming up. + Refer: https://www.elastic.co/guide/en/logstash/master/node-info-api.html + """ + result = json.loads(host.command.check_output('curl -s http://localhost:9600/_node')) + assert 'workers' in result['pipelines']['main'] + return result + + def get_settings(self): + return yaml.load(self.settings_file.content_string) + + def run(self, command): + return host.run(command) + + def stdout_of(self, command): + return host.run(command).stdout.strip() + + def stderr_of(self, command): + return host.run(command).stderr.strip() + + def environment(self, varname): + environ = {} + for line in self.run('env').stdout.strip().split("\n"): + var, value = line.split('=') + environ[var] = value + return environ[varname] + + def get_docker_log(self): + return run(['docker', 'logs', self.name], stdout=PIPE).stdout.decode() + + @retry(**retry_settings) + def assert_in_log(self, string): + assert string in self.get_docker_log() + + @retry(**retry_settings) + def assert_not_in_log(self, string): + assert string not in self.get_docker_log() + + return Logstash() diff --git a/docker/tests/helpers.py b/docker/tests/helpers.py new file mode 100644 index 000000000..a68eb8765 --- /dev/null +++ b/docker/tests/helpers.py @@ -0,0 +1,8 @@ +import subprocess +import os +from .constants import image, version + +try: + version += '-%s' % os.environ['STAGING_BUILD_NUM'] +except KeyError: + pass diff --git a/docker/tests/test_basics.py b/docker/tests/test_basics.py new file mode 100644 index 000000000..7ae50d930 --- /dev/null +++ b/docker/tests/test_basics.py @@ -0,0 +1,50 @@ +from .fixtures import logstash +from .constants import logstash_version_string + + +def test_logstash_is_the_correct_version(logstash): + assert logstash_version_string in logstash.stdout_of('logstash --version') + + +def test_the_default_user_is_logstash(logstash): + assert logstash.stdout_of('whoami') == 'logstash' + + +def test_that_the_user_home_directory_is_usr_share_logstash(logstash): + assert logstash.environment('HOME') == '/usr/share/logstash' + + +def test_locale_variables_are_set_correctly(logstash): + assert logstash.environment('LANG') == 'en_US.UTF-8' + assert logstash.environment('LC_ALL') == 'en_US.UTF-8' + + +def test_opt_logstash_is_a_symlink_to_usr_share_logstash(logstash): + assert logstash.stdout_of('realpath /opt/logstash') == '/usr/share/logstash' + + +def test_all_logstash_files_are_owned_by_logstash(logstash): + assert logstash.stdout_of('find /usr/share/logstash ! -user logstash') == '' + + +def test_logstash_user_is_uid_1000(logstash): + assert logstash.stdout_of('id -u logstash') == '1000' + + +def test_logstash_user_is_gid_1000(logstash): + assert logstash.stdout_of('id -g logstash') == '1000' + + +def test_logging_config_does_not_log_to_files(logstash): + assert logstash.stdout_of('grep RollingFile /logstash/config/log4j2.properties') == '' + + +# REF: https://docs.openshift.com/container-platform/3.5/creating_images/guidelines.html +def test_all_files_in_logstash_directory_are_gid_zero(logstash): + bad_files = logstash.stdout_of('find /usr/share/logstash ! -gid 0').split() + assert len(bad_files) is 0 + + +def test_all_directories_in_logstash_directory_are_setgid(logstash): + bad_dirs = logstash.stdout_of('find /usr/share/logstash -type d ! -perm /g+s').split() + assert len(bad_dirs) is 0 diff --git a/docker/tests/test_entrypoint.py b/docker/tests/test_entrypoint.py new file mode 100644 index 000000000..f17f50f61 --- /dev/null +++ b/docker/tests/test_entrypoint.py @@ -0,0 +1,14 @@ +from .fixtures import logstash +import pytest + + +@pytest.mark.xfail +def test_whitespace_in_config_string_cli_flag(logstash): + config = 'input{heartbeat{}} output{stdout{}}' + assert logstash.run("-t -e '%s'" % config).rc == 0 + + +def test_running_an_arbitrary_command(logstash): + result = logstash.run('uname --all') + assert result.rc == 0 + assert 'GNU/Linux' in str(result.stdout) diff --git a/docker/tests/test_labels.py b/docker/tests/test_labels.py new file mode 100644 index 000000000..97d8ff59d --- /dev/null +++ b/docker/tests/test_labels.py @@ -0,0 +1,15 @@ +from .fixtures import logstash + + +def test_labels(logstash): + labels = logstash.docker_metadata['Config']['Labels'] + assert labels['org.label-schema.name'] == 'logstash' + assert labels['org.label-schema.schema-version'] == '1.0' + assert labels['org.label-schema.url'] == 'https://www.elastic.co/products/logstash' + assert labels['org.label-schema.vcs-url'] == 'https://github.com/elastic/logstash' + assert labels['org.label-schema.vendor'] == 'Elastic' + assert labels['org.label-schema.version'] == logstash.tag + if logstash.image_flavor == 'oss': + assert labels['license'] == 'Apache-2.0' + else: + assert labels['license'] == 'Elastic License' diff --git a/docker/tests/test_process.py b/docker/tests/test_process.py new file mode 100644 index 000000000..574fcd46e --- /dev/null +++ b/docker/tests/test_process.py @@ -0,0 +1,15 @@ +from .fixtures import logstash + + +def test_process_is_pid_1(logstash): + assert logstash.process.pid == 1 + + +def test_process_is_running_as_the_correct_user(logstash): + assert logstash.process.user == 'logstash' + + +def test_process_is_running_with_cgroup_override_flags(logstash): + # REF: https://github.com/elastic/logstash-docker/pull/97 + assert '-Dls.cgroup.cpu.path.override=/' in logstash.process.args + assert '-Dls.cgroup.cpuacct.path.override=/' in logstash.process.args diff --git a/docker/tests/test_settings.py b/docker/tests/test_settings.py new file mode 100644 index 000000000..885296648 --- /dev/null +++ b/docker/tests/test_settings.py @@ -0,0 +1,71 @@ +from .fixtures import logstash +from retrying import retry +import time + + +def test_setting_pipeline_workers_from_environment(logstash): + logstash.restart(args='-e pipeline.workers=6') + assert logstash.get_node_info()['pipelines']['main']['workers'] == 6 + + +def test_setting_pipeline_batch_size_from_environment(logstash): + logstash.restart(args='-e pipeline.batch.size=123') + assert logstash.get_node_info()['pipelines']['main']['batch_size'] == 123 + + +def test_setting_pipeline_batch_delay_from_environment(logstash): + logstash.restart(args='-e pipeline.batch.delay=36') + assert logstash.get_node_info()['pipelines']['main']['batch_delay'] == 36 + + +def test_setting_pipeline_unsafe_shutdown_from_environment(logstash): + logstash.restart(args='-e pipeline.unsafe_shutdown=true') + assert logstash.get_settings()['pipeline.unsafe_shutdown'] is True + + +def test_setting_pipeline_unsafe_shutdown_with_shell_style_variable(logstash): + logstash.restart(args='-e PIPELINE_UNSAFE_SHUTDOWN=true') + assert logstash.get_settings()['pipeline.unsafe_shutdown'] is True + + +def test_setting_things_with_upcased_and_underscored_env_vars(logstash): + logstash.restart(args='-e PIPELINE_BATCH_DELAY=24') + assert logstash.get_node_info()['pipelines']['main']['batch_delay'] == 24 + + +def test_disabling_xpack_monitoring_via_environment(logstash): + logstash.restart(args='-e xpack.monitoring.enabled=false') + assert logstash.get_settings()['xpack.monitoring.enabled'] is False + + +def test_enabling_java_execution_via_environment(logstash): + logstash.restart(args='-e pipeline.java_execution=true') + logstash.assert_in_log('logstash.javapipeline') + + +def test_disabling_java_execution_via_environment(logstash): + logstash.restart(args='-e pipeline.java_execution=true') + logstash.assert_not_in_log('logstash.javapipeline') + + +def test_setting_elasticsearch_urls_as_an_array(logstash): + setting_string = '["http://node1:9200","http://node2:9200"]' + logstash.restart(args='-e xpack.monitoring.elasticsearch.hosts=%s' % setting_string) + live_setting = logstash.get_settings()['xpack.monitoring.elasticsearch.hosts'] + assert type(live_setting) is list + assert 'http://node1:9200' in live_setting + assert 'http://node2:9200' in live_setting + + +def test_invalid_settings_in_environment_are_ignored(logstash): + logstash.restart(args='-e cheese.ftw=true') + assert not logstash.settings_file.contains('cheese.ftw') + + +def test_settings_file_is_untouched_when_no_settings_in_env(logstash): + original_timestamp = logstash.settings_file.mtime + original_hash = logstash.settings_file.sha256sum + logstash.restart() + time.sleep(1) # since mtime() has one second resolution + assert logstash.settings_file.mtime == original_timestamp + assert logstash.settings_file.sha256sum == original_hash diff --git a/docker/tox.ini b/docker/tox.ini new file mode 100644 index 000000000..1105ab911 --- /dev/null +++ b/docker/tox.ini @@ -0,0 +1,5 @@ +# pytest fixtures (which are wonderful) trigger false positives for these +# pyflakes checks. +[flake8] +ignore = F401,F811 +max-line-length = 120 diff --git a/docs/static/docker.asciidoc b/docs/static/docker.asciidoc index e0f76d114..ce49a3e40 100644 --- a/docs/static/docker.asciidoc +++ b/docs/static/docker.asciidoc @@ -5,7 +5,7 @@ registry. The base image is https://hub.docker.com/_/centos/[centos:7]. A list of all published Docker images and tags is available at https://www.docker.elastic.co[www.docker.elastic.co]. The source code is in -https://github.com/elastic/logstash-docker/tree/{branch}[GitHub]. +https://github.com/elastic/logstash/tree/{branch}[GitHub]. These images are free to use under the Elastic license. They contain open source and free commercial features and access to paid commercial features. diff --git a/rakelib/artifacts.rake b/rakelib/artifacts.rake index dd5792b29..646affd0a 100644 --- a/rakelib/artifacts.rake +++ b/rakelib/artifacts.rake @@ -167,6 +167,18 @@ namespace "artifact" do build_tar('ELASTIC-LICENSE', "-all-plugins") end + desc "Build docker image" + task "docker" => ["prepare", "generate_build_metadata", "tar"] do + puts("[docker] Building docker image") + build_docker(false) + end + + desc "Build OSS docker image" + task "docker_oss" => ["prepare", "generate_build_metadata", "tar_oss"] do + puts("[docker_oss] Building OSS docker image") + build_docker(true) + end + # Auxiliary tasks task "build" => [:generate_build_metadata] do Rake::Task["artifact:gems"].invoke unless SNAPSHOT_BUILD @@ -178,6 +190,8 @@ namespace "artifact" do Rake::Task["artifact:zip_oss"].invoke Rake::Task["artifact:tar"].invoke Rake::Task["artifact:tar_oss"].invoke + Rake::Task["artifact:docker"].invoke + Rake::Task["artifact:docker_oss"].invoke end task "generate_build_metadata" do @@ -499,4 +513,19 @@ namespace "artifact" do out.cleanup end end # def package + + def build_docker(oss = false) + env = { + "ARTIFACTS_DIR" => ::File.join(Dir.pwd, "build"), + "RELEASE" => ENV["RELEASE"], + "VERSION_QUALIFIER" => VERSION_QUALIFIER + } + Dir.chdir("docker") do |dir| + if oss + system(env, "make build-from-local-oss-artifacts") + else + system(env, "make build-from-local-artifacts") + end + end + end end From a335f2e4b79b2167c51f06111e04f8c4d4b0a084 Mon Sep 17 00:00:00 2001 From: Joao Duarte Date: Thu, 4 Apr 2019 15:29:53 +0100 Subject: [PATCH 0056/1126] remove docker-compose symlink Fixes #10645 --- docker/docker-compose.yml | 1 - 1 file changed, 1 deletion(-) delete mode 120000 docker/docker-compose.yml diff --git a/docker/docker-compose.yml b/docker/docker-compose.yml deleted file mode 120000 index 574078f66..000000000 --- a/docker/docker-compose.yml +++ /dev/null @@ -1 +0,0 @@ -docker-compose-full.yml \ No newline at end of file From 6ed7b4bc5c34a1b915dfcf72239957e1ebf929aa Mon Sep 17 00:00:00 2001 From: Joao Duarte Date: Thu, 4 Apr 2019 16:17:27 +0100 Subject: [PATCH 0057/1126] disable docker img generation on artifact:all Fixes #10647 --- rakelib/artifacts.rake | 2 -- 1 file changed, 2 deletions(-) diff --git a/rakelib/artifacts.rake b/rakelib/artifacts.rake index 646affd0a..d8ae1455a 100644 --- a/rakelib/artifacts.rake +++ b/rakelib/artifacts.rake @@ -190,8 +190,6 @@ namespace "artifact" do Rake::Task["artifact:zip_oss"].invoke Rake::Task["artifact:tar"].invoke Rake::Task["artifact:tar_oss"].invoke - Rake::Task["artifact:docker"].invoke - Rake::Task["artifact:docker_oss"].invoke end task "generate_build_metadata" do From 3ce3b96e300406eefd4072d00340f479e72b35e3 Mon Sep 17 00:00:00 2001 From: Dan Hermann Date: Mon, 1 Apr 2019 11:39:43 -0500 Subject: [PATCH 0058/1126] Handle duplicate config entries Fixes #10619 --- logstash-core/lib/logstash/compiler/lscl.rb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/logstash-core/lib/logstash/compiler/lscl.rb b/logstash-core/lib/logstash/compiler/lscl.rb index 277c3ef27..b4cdb4d0d 100644 --- a/logstash-core/lib/logstash/compiler/lscl.rb +++ b/logstash-core/lib/logstash/compiler/lscl.rb @@ -115,7 +115,7 @@ module LogStashCompilerLSCLGrammar; module LogStash; module Compiler; module LSC elsif existing.kind_of?(::Array) hash[k] = existing.push(*v) else - hash[k] = existing + v + hash[k] = [existing, v] unless v == existing end hash end From 30dd8243d2cb2fd09606e0eb599f2fc6ebab6b06 Mon Sep 17 00:00:00 2001 From: Dan Hermann Date: Fri, 29 Mar 2019 13:06:15 -0500 Subject: [PATCH 0059/1126] Move Gradle wrappers around Ruby operations to a separate file to facilitate sharing of common operations with Java plugins Fixes #10642 --- Dockerfile | 2 +- build.gradle | 140 ++-------- buildSrc/build.gradle | 12 - .../logstash/gradle/RubyGradleUtils.groovy | 103 -------- .../logstash/gradle/ExecLogOutputStream.java | 29 --- rubyUtils.gradle | 246 ++++++++++++++++++ 6 files changed, 267 insertions(+), 265 deletions(-) delete mode 100644 buildSrc/build.gradle delete mode 100644 buildSrc/src/main/groovy/org/logstash/gradle/RubyGradleUtils.groovy delete mode 100644 buildSrc/src/main/java/org/logstash/gradle/ExecLogOutputStream.java create mode 100644 rubyUtils.gradle diff --git a/Dockerfile b/Dockerfile index 56dc10b8f..233f91d3d 100644 --- a/Dockerfile +++ b/Dockerfile @@ -22,7 +22,6 @@ LABEL retention="keep" ADD gradlew /opt/logstash/gradlew ADD gradle/wrapper /opt/logstash/gradle/wrapper -ADD buildSrc /opt/logstash/buildSrc RUN /opt/logstash/gradlew wrapper ADD versions.yml /opt/logstash/versions.yml @@ -33,6 +32,7 @@ ADD CONTRIBUTORS /opt/logstash/CONTRIBUTORS ADD Gemfile.template /opt/logstash/Gemfile.template ADD Rakefile /opt/logstash/Rakefile ADD build.gradle /opt/logstash/build.gradle +ADD rubyUtils.gradle /opt/logstash/rubyUtils.gradle ADD rakelib /opt/logstash/rakelib ADD config /opt/logstash/config ADD spec /opt/logstash/spec diff --git a/build.gradle b/build.gradle index f3a13e0a5..734cdc17b 100644 --- a/build.gradle +++ b/build.gradle @@ -6,7 +6,6 @@ buildscript { } } dependencies { - classpath 'org.yaml:snakeyaml:1.23' classpath "gradle.plugin.com.github.jk1:gradle-license-report:0.7.1" } } @@ -16,16 +15,11 @@ plugins { } apply plugin: 'de.undercouch.download' +apply from: "rubyUtils.gradle" import de.undercouch.gradle.tasks.download.Download -import de.undercouch.gradle.tasks.download.Verify import groovy.json.JsonSlurper -import org.logstash.gradle.RubyGradleUtils -import org.yaml.snakeyaml.Yaml - -import java.nio.file.Files -import java.nio.file.Paths allprojects { group = 'org.logstash' @@ -100,29 +94,12 @@ subprojects { } // fetch version from Logstash's master versions.yml file -def versionMap = (Map) (new Yaml()).load(new File("${projectDir}/versions.yml").text) version = versionMap['logstash-core'] def versionQualifier = System.getenv('VERSION_QUALIFIER') if (versionQualifier) { version = "$version-$versionQualifier" } -String jRubyURL -String jRubyVersion -String jRubySha1 -Boolean doChecksum - -if (versionMap["jruby-runtime-override"]) { - jRubyVersion = versionMap["jruby-runtime-override"]["version"] - jRubyURL = versionMap["jruby-runtime-override"]["url"] - doChecksum = false -} else { - jRubyVersion = versionMap["jruby"]["version"] - jRubySha1 = versionMap["jruby"]["sha1"] - jRubyURL = "https://repo1.maven.org/maven2/org/jruby/jruby-dist/${jRubyVersion}/jruby-dist-${jRubyVersion}-bin.tar.gz" - doChecksum = true -} - // Tasks clean { @@ -138,8 +115,6 @@ clean { task bootstrap {} -RubyGradleUtils rubyGradleUtils = new RubyGradleUtils(buildDir, projectDir) - project(":logstash-core") { ["rubyTests", "test"].each { tsk -> tasks.getByPath(":logstash-core:" + tsk).configure { @@ -148,81 +123,6 @@ project(":logstash-core") { } } -def jrubyTarPath = "${projectDir}/vendor/_/jruby-dist-${jRubyVersion}-bin.tar.gz" - -def customJRubyDir = project.hasProperty("custom.jruby.path") ? project.property("custom.jruby.path") : "" -def customJRubyVersion = customJRubyDir == "" ? "" : Files.readAllLines(Paths.get(customJRubyDir, "VERSION")).get(0).trim() -def customJRubyTar = customJRubyDir == "" ? "" : (customJRubyDir + "/maven/jruby-dist/target/jruby-dist-${customJRubyVersion}-bin.tar.gz") - -task downloadJRuby(type: Download) { - description "Download JRuby artifact from this specific URL: ${jRubyURL}" - src jRubyURL - onlyIfNewer true - inputs.file("${projectDir}/versions.yml") - outputs.file(jrubyTarPath) - dest new File("${projectDir}/vendor/_", "jruby-dist-${jRubyVersion}-bin.tar.gz") -} - -downloadJRuby.onlyIf { customJRubyDir == "" } - -task verifyFile(dependsOn: downloadJRuby, type: Verify) { - description "Verify the SHA1 of the download JRuby artifact" - inputs.file(jrubyTarPath) - outputs.file(jrubyTarPath) - src new File(jrubyTarPath) - algorithm 'SHA-1' - checksum jRubySha1 -} - -verifyFile.onlyIf { customJRubyDir == "" } - -task buildCustomJRuby(type: Exec) { - description "Build tar.gz and .jar artifacts from JRuby source directory" - workingDir (customJRubyDir == "" ? "./" : customJRubyDir) - commandLine './mvnw', 'clean', 'install', '-Pdist', '-Pcomplete' - standardOutput = new ByteArrayOutputStream() - errorOutput = new ByteArrayOutputStream() - ext.output = { - standardOutput.toString() + errorOutput.toString() - } -} - -buildCustomJRuby.onlyIf { customJRubyDir != "" } - -task installCustomJRuby(dependsOn: buildCustomJRuby, type: Copy) { - description "Install custom built JRuby in the vendor directory" - inputs.file(customJRubyTar) - outputs.dir("${projectDir}/vendor/jruby") - from tarTree(customJRubyTar == "" ? jrubyTarPath : customJRubyTar) - eachFile { f -> - f.path = f.path.replaceFirst("^jruby-${customJRubyVersion}", '') - } - exclude "**/stdlib/rdoc/**" - includeEmptyDirs = false - into "${projectDir}/vendor/jruby" -} - -installCustomJRuby.onlyIf { customJRubyDir != "" } - -task downloadAndInstallJRuby(dependsOn: [verifyFile, installCustomJRuby], type: Copy) { - description "Install JRuby in the vendor directory" - inputs.file(jrubyTarPath) - outputs.dir("${projectDir}/vendor/jruby") - from tarTree(downloadJRuby.dest) - eachFile { f -> - f.path = f.path.replaceFirst("^jruby-${jRubyVersion}", '') - } - exclude "**/stdlib/rdoc/**" - includeEmptyDirs = false - into "${projectDir}/vendor/jruby" - doLast { - rubyGradleUtils.gem("rake", "12.3.1", "${projectDir}/vendor/bundle/jruby/2.5.0") - rubyGradleUtils.gem("json", "1.8.6", "${projectDir}/vendor/bundle/jruby/2.5.0") - } -} - -downloadAndInstallJRuby.onlyIf { customJRubyDir == "" } - task installDefaultGems(dependsOn: downloadAndInstallJRuby) { inputs.files file("${projectDir}/Gemfile.template") inputs.files fileTree("${projectDir}/rakelib") @@ -232,9 +132,9 @@ task installDefaultGems(dependsOn: downloadAndInstallJRuby) { outputs.dir("${projectDir}/logstash-core/lib/jars") outputs.dir("${projectDir}/vendor/bundle/jruby/2.5.0") doLast { - rubyGradleUtils.gem("rake", "12.3.1", "${projectDir}/vendor/bundle/jruby/2.5.0") - rubyGradleUtils.gem("json", "1.8.6", "${projectDir}/vendor/bundle/jruby/2.5.0") - rubyGradleUtils.rake('plugin:install-default') + gem(projectDir, buildDir, "rake", "12.3.1", "${projectDir}/vendor/bundle/jruby/2.5.0") + gem(projectDir, buildDir, "json", "1.8.6", "${projectDir}/vendor/bundle/jruby/2.5.0") + rake(projectDir, buildDir, 'plugin:install-default') } } @@ -251,9 +151,9 @@ task installTestGems(dependsOn: assemblyDeps) { outputs.dir("${projectDir}/logstash-core/lib/jars") outputs.dir("${projectDir}/vendor/bundle/jruby/2.5.0") doLast { - rubyGradleUtils.gem("rake", "12.3.1", "${projectDir}/vendor/bundle/jruby/2.5.0") - rubyGradleUtils.gem("json", "1.8.6", "${projectDir}/vendor/bundle/jruby/2.5.0") - rubyGradleUtils.rake('plugin:install-development-dependencies') + gem(projectDir, buildDir, "rake", "12.3.1", "${projectDir}/vendor/bundle/jruby/2.5.0") + gem(projectDir, buildDir, "json", "1.8.6", "${projectDir}/vendor/bundle/jruby/2.5.0") + rake(projectDir, buildDir, 'plugin:install-development-dependencies') } } @@ -269,8 +169,8 @@ task assembleTarDistribution(dependsOn: assemblyDeps) { inputs.files fileTree("${projectDir}/x-pack") outputs.files file("${buildDir}/logstash-${project.version}-SNAPSHOT.tar.gz") doLast { - rubyGradleUtils.gem("rake", "12.3.1", "${projectDir}/vendor/bundle/jruby/2.5.0") - rubyGradleUtils.rake('artifact:tar') + gem(projectDir, buildDir, "rake", "12.3.1", "${projectDir}/vendor/bundle/jruby/2.5.0") + rake(projectDir, buildDir, 'artifact:tar') } } @@ -284,7 +184,7 @@ task assembleOssTarDistribution(dependsOn: assemblyDeps) { inputs.files fileTree("${projectDir}/logstash-core/lib") inputs.files fileTree("${projectDir}/logstash-core/src") doLast { - rubyGradleUtils.rake('artifact:tar_oss') + rake(projectDir, buildDir, 'artifact:tar_oss') } } @@ -300,7 +200,7 @@ task assembleZipDistribution(dependsOn: assemblyDeps) { inputs.files fileTree("${projectDir}/x-pack") outputs.files file("${buildDir}/logstash-${project.version}.zip") doLast { - rubyGradleUtils.rake('artifact:zip') + rake(projectDir, buildDir, 'artifact:zip') } } @@ -315,7 +215,8 @@ task assembleOssZipDistribution(dependsOn: assemblyDeps) { inputs.files fileTree("${projectDir}/logstash-core/src") outputs.files file("${buildDir}/logstash-${project.version}.zip") doLast { - rubyGradleUtils.rake('artifact:zip_oss') + rake(projectDir, buildDir, 'artifact:zip_oss') + } } @@ -336,7 +237,7 @@ def qaBundleBin = "${qaBundledGemPath}/bin/bundle" task installIntegrationTestBundler(dependsOn: unpackTarDistribution) { outputs.files fileTree("${qaBundledGemPath}/gems/bundler-1.17.1") doLast { - rubyGradleUtils.gem("bundler", "1.17.1", qaBundledGemPath) + gem(projectDir, buildDir, "bundler", "1.17.1", qaBundledGemPath) } } @@ -349,10 +250,11 @@ task installIntegrationTestGems(dependsOn: installIntegrationTestBundler) { outputs.files fileTree("${qaVendorPath}") outputs.files file("${projectDir}/qa/integration/Gemfile.lock") doLast { - rubyGradleUtils.bundle( - "${projectDir}/qa/integration", qaBundleBin, ['install', '--path', qaVendorPath], - [LS_GEM_PATH: qaBundledGemPath, LS_GEM_HOME: qaBundledGemPath] - ) + bundleWithEnv( + projectDir, buildDir, + "${projectDir}/qa/integration", qaBundleBin, ['install', '--path', qaVendorPath], + [LS_GEM_PATH: qaBundledGemPath, LS_GEM_HOME: qaBundledGemPath] + ) } } @@ -412,12 +314,10 @@ task generateLicenseReportInputs() { task generatePluginsVersion(dependsOn: bootstrap) { doLast { - rubyGradleUtils.rake('generate_plugins_version') + rake(projectDir, buildDir, 'generate_plugins_version') } } -// If you are running a JRuby snapshot we will skip the integrity check. -verifyFile.onlyIf { doChecksum } bootstrap.dependsOn installTestGems runIntegrationTests.shouldRunAfter tasks.getByPath(":logstash-core:test") diff --git a/buildSrc/build.gradle b/buildSrc/build.gradle deleted file mode 100644 index d41a08344..000000000 --- a/buildSrc/build.gradle +++ /dev/null @@ -1,12 +0,0 @@ -apply plugin: 'java' -apply plugin: 'groovy' - -group = 'org.logstash.gradle' - -repositories { - mavenCentral() -} - -dependencies { - compile group: 'org.jruby', name: 'jruby-complete', version: '9.2.6.0' -} diff --git a/buildSrc/src/main/groovy/org/logstash/gradle/RubyGradleUtils.groovy b/buildSrc/src/main/groovy/org/logstash/gradle/RubyGradleUtils.groovy deleted file mode 100644 index 53d26e45b..000000000 --- a/buildSrc/src/main/groovy/org/logstash/gradle/RubyGradleUtils.groovy +++ /dev/null @@ -1,103 +0,0 @@ -package org.logstash.gradle - -import org.jruby.Ruby -import org.jruby.embed.PathType -import org.jruby.embed.ScriptingContainer - -final class RubyGradleUtils { - - private final File buildDir - - private final File projectDir - - RubyGradleUtils(File buildDir, File projectDir) { - this.buildDir = buildDir - this.projectDir = projectDir - } - - /** - * Executes a bundler bin script with given parameters. - * @param pwd Current worker directory to execute in - * @param bundleBin Bundler Bin Script - * @param args CLI Args to Use with Bundler - */ - void bundle(String pwd, String bundleBin, Iterable args) { - bundle(pwd, bundleBin, args, Collections.emptyMap()) - } - - /** - * Executes a bundler bin script with given parameters. - * @param pwd Current worker directory to execute in - * @param bundleBin Bundler Bin Script - * @param args CLI Args to Use with Bundler - * @param env Environment Variables to Set - */ - void bundle(String pwd, String bundleBin, Iterable args, Map env) { - executeJruby { ScriptingContainer jruby -> - jruby.environment.putAll(env) - jruby.currentDirectory = pwd - jruby.argv = args.toList().toArray() - jruby.runScriptlet(PathType.ABSOLUTE, bundleBin) - } - } - - /** - * Installs a Gem with the given version to the given path. - * @param gem Gem Name - * @param version Version to Install - * @param path Path to Install to - */ - void gem(String gem, String version, String path) { - executeJruby { ScriptingContainer jruby -> - jruby.currentDirectory = projectDir - jruby.runScriptlet( - "require 'rubygems/commands/install_command'\n" + - "cmd = Gem::Commands::InstallCommand.new\n" + - "cmd.handle_options [\"--no-ri\", \"--no-rdoc\", '${gem}', '-v', '${version}', '-i', '${path}']\n" + - "begin \n" + - " cmd.execute\n" + - "rescue Gem::SystemExitException => e\n" + - " raise e unless e.exit_code == 0\n" + - "end" - ) - } - } - - /** - * Executes RSpec for a given plugin. - * @param plugin Plugin to run specs for - * @param args CLI arguments to pass to rspec - */ - void rake(String task) { - executeJruby { ScriptingContainer jruby -> - jruby.currentDirectory = projectDir - jruby.runScriptlet("require 'rake'") - jruby.runScriptlet( - "rake = Rake.application\n" + - "rake.init\n" + - "rake.load_rakefile\n" + - "rake['${task}'].invoke" - ) - } - } - - /** - * Executes Closure using a fresh JRuby environment, safely tearing it down afterwards. - * @param block Closure to run - */ - Object executeJruby(Closure block) { - def jruby = new ScriptingContainer() - def env = jruby.environment - def gemDir = "${projectDir}/vendor/bundle/jruby/2.5.0".toString() - env.put "USE_RUBY", "1" - env.put "GEM_HOME", gemDir - env.put "GEM_SPEC_CACHE", "${buildDir}/cache".toString() - env.put "GEM_PATH", gemDir - try { - return block(jruby) - } finally { - jruby.terminate() - Ruby.clearGlobalRuntime() - } - } -} diff --git a/buildSrc/src/main/java/org/logstash/gradle/ExecLogOutputStream.java b/buildSrc/src/main/java/org/logstash/gradle/ExecLogOutputStream.java deleted file mode 100644 index 2f39436bb..000000000 --- a/buildSrc/src/main/java/org/logstash/gradle/ExecLogOutputStream.java +++ /dev/null @@ -1,29 +0,0 @@ -package org.logstash.gradle; - -import java.io.ByteArrayOutputStream; -import java.io.PrintStream; - -/** - * Stream that can be used to forward Gradle Exec task output to an arbitrary {@link PrintStream}. - */ -public final class ExecLogOutputStream extends ByteArrayOutputStream { - - /** - * Underlying {@link PrintStream} to flush output to. - */ - private final PrintStream stream; - - /** - * Ctor. - * @param stream PrintStream to flush to - */ - public ExecLogOutputStream(final PrintStream stream) { - this.stream = stream; - } - - @Override - public synchronized void flush() { - stream.print(toString()); - reset(); - } -} diff --git a/rubyUtils.gradle b/rubyUtils.gradle new file mode 100644 index 000000000..603a3356c --- /dev/null +++ b/rubyUtils.gradle @@ -0,0 +1,246 @@ + +buildscript { + repositories { + mavenCentral() + } + dependencies { + classpath 'org.yaml:snakeyaml:1.23' + classpath "de.undercouch:gradle-download-task:3.2.0" + classpath "org.jruby:jruby-complete:9.2.6.0" + } +} + +import de.undercouch.gradle.tasks.download.Download +import de.undercouch.gradle.tasks.download.Verify +import org.yaml.snakeyaml.Yaml + + +import org.jruby.Ruby +import org.jruby.embed.PathType +import org.jruby.embed.ScriptingContainer + +import java.nio.file.Files +import java.nio.file.Paths + +ext { + bundle = this.&bundle + bundleWithEnv = this.&bundleWithEnv + gem = this.&gem + buildGem = this.&buildGem + rake = this.&rake + versionMap = new HashMap() +} + +/** + * Executes a bundler bin script with given parameters. + * @param projectDir Gradle projectDir + * @param buildDir Gradle buildDir + * @param pwd Current worker directory to execute in + * @param bundleBin Bundler Bin Script + * @param args CLI Args to Use with Bundler + */ +void bundle(File projectDir, File buildDir, String pwd, String bundleBin, Iterable args) { + bundleWithEnv(projectDir, buildDir, pwd, bundleBin, args, Collections.emptyMap()) +} + +/** + * Executes a bundler bin script with given parameters. + * @param projectDir Gradle projectDir + * @param buildDir Gradle buildDir + * @param pwd Current worker directory to execute in + * @param bundleBin Bundler Bin Script + * @param args CLI Args to Use with Bundler + * @param env Environment Variables to Set + */ +void bundleWithEnv(File projectDir, File buildDir, String pwd, String bundleBin, Iterable args, Map env) { + executeJruby projectDir, buildDir, { ScriptingContainer jruby -> + jruby.environment.putAll(env) + jruby.currentDirectory = pwd + jruby.argv = args.toList().toArray() + jruby.runScriptlet(PathType.ABSOLUTE, bundleBin) + } +} + +/** + * Installs a Gem with the given version to the given path. + * @param projectDir Gradle projectDir + * @param buildDir Gradle buildDir + * @param gem Gem Name + * @param version Version to Install + * @param path Path to Install to + */ +void gem(File projectDir, File buildDir, String gem, String version, String path) { + executeJruby projectDir, buildDir, { ScriptingContainer jruby -> + jruby.currentDirectory = projectDir + jruby.runScriptlet(""" + require 'rubygems/commands/install_command' + cmd = Gem::Commands::InstallCommand.new + cmd.handle_options ['--no-ri', '--no-rdoc', '${gem}', '-v', '${version}', '-i', '${path}'] + begin + cmd.execute + rescue Gem::SystemExitException => e + raise e unless e.exit_code == 0 + end + """ + ) + } +} + +void buildGem(File projectDir, File buildDir, String gemspec) { + executeJruby projectDir, buildDir, { ScriptingContainer jruby -> + jruby.currentDirectory = projectDir + jruby.runScriptlet(""" + require 'rubygems/commands/build_command' + cmd = Gem::Commands::BuildCommand.new + cmd.handle_options ['${gemspec}'] + begin + cmd.execute + rescue Gem::SystemExitException => e + raise e unless e.exit_code == 0 + end + """ + ) + } +} + +/** + * Executes RSpec for a given plugin. + * @param projectDir Gradle projectDir + * @param buildDir Gradle buildDir + * @param plugin Plugin to run specs for + * @param args CLI arguments to pass to rspec + */ +void rake(File projectDir, File buildDir, String task) { + executeJruby projectDir, buildDir, { ScriptingContainer jruby -> + jruby.currentDirectory = projectDir + jruby.runScriptlet("require 'rake'") + jruby.runScriptlet(""" + rake = Rake.application + rake.init + rake.load_rakefile + rake['${task}'].invoke + """ + ) + } +} + +/** + * Executes Closure using a fresh JRuby environment, safely tearing it down afterwards. + * @param projectDir Gradle projectDir + * @param buildDir Gradle buildDir + * @param block Closure to run + */ +Object executeJruby(File projectDir, File buildDir, Closure /* Object*/ block) { + def jruby = new ScriptingContainer() + def env = jruby.environment + def gemDir = "${projectDir}/vendor/bundle/jruby/2.5.0".toString() + env.put "USE_RUBY", "1" + env.put "GEM_HOME", gemDir + env.put "GEM_SPEC_CACHE", "${buildDir}/cache".toString() + env.put "GEM_PATH", gemDir + try { + block(jruby) + } finally { + jruby.terminate() + Ruby.clearGlobalRuntime() + } +} + +//=============================================================================== +// Ruby variables +//=============================================================================== + +def versionsPath = project.hasProperty("LOGSTASH_CORE_PATH") ? LOGSTASH_CORE_PATH + "/../versions.yml" : "${projectDir}/versions.yml" +versionMap = (Map) (new Yaml()).load(new File("${versionsPath}").text) + +String jRubyURL +String jRubyVersion +String jRubySha1 +Boolean doChecksum + +if (versionMap["jruby-runtime-override"]) { + jRubyVersion = versionMap["jruby-runtime-override"]["version"] + jRubyURL = versionMap["jruby-runtime-override"]["url"] + doChecksum = false +} else { + jRubyVersion = versionMap["jruby"]["version"] + jRubySha1 = versionMap["jruby"]["sha1"] + jRubyURL = "https://repo1.maven.org/maven2/org/jruby/jruby-dist/${jRubyVersion}/jruby-dist-${jRubyVersion}-bin.tar.gz" + doChecksum = true +} +def jrubyTarPath = "${projectDir}/vendor/_/jruby-dist-${jRubyVersion}-bin.tar.gz" + +def customJRubyDir = project.hasProperty("custom.jruby.path") ? project.property("custom.jruby.path") : "" +def customJRubyVersion = customJRubyDir == "" ? "" : Files.readAllLines(Paths.get(customJRubyDir, "VERSION")).get(0).trim() +def customJRubyTar = customJRubyDir == "" ? "" : (customJRubyDir + "/maven/jruby-dist/target/jruby-dist-${customJRubyVersion}-bin.tar.gz") + +task downloadJRuby(type: Download) { + description "Download JRuby artifact from this specific URL: ${jRubyURL}" + src jRubyURL + onlyIfNewer true + inputs.file("${projectDir}/versions.yml") + outputs.file(jrubyTarPath) + dest new File("${projectDir}/vendor/_", "jruby-dist-${jRubyVersion}-bin.tar.gz") +} + +downloadJRuby.onlyIf { customJRubyDir == "" } + +task verifyFile(dependsOn: downloadJRuby, type: Verify) { + description "Verify the SHA1 of the download JRuby artifact" + inputs.file(jrubyTarPath) + outputs.file(jrubyTarPath) + src new File(jrubyTarPath) + algorithm 'SHA-1' + checksum jRubySha1 +} + +verifyFile.onlyIf { customJRubyDir == "" } +verifyFile.onlyIf { doChecksum } + +task buildCustomJRuby(type: Exec) { + description "Build tar.gz and .jar artifacts from JRuby source directory" + workingDir (customJRubyDir == "" ? "./" : customJRubyDir) + commandLine './mvnw', 'clean', 'install', '-Pdist', '-Pcomplete' + standardOutput = new ByteArrayOutputStream() + errorOutput = new ByteArrayOutputStream() + ext.output = { + standardOutput.toString() + errorOutput.toString() + } +} + +buildCustomJRuby.onlyIf { customJRubyDir != "" } + +task installCustomJRuby(dependsOn: buildCustomJRuby, type: Copy) { + description "Install custom built JRuby in the vendor directory" + inputs.file(customJRubyTar) + outputs.dir("${projectDir}/vendor/jruby") + from tarTree(customJRubyTar == "" ? jrubyTarPath : customJRubyTar) + eachFile { f -> + f.path = f.path.replaceFirst("^jruby-${customJRubyVersion}", '') + } + exclude "**/stdlib/rdoc/**" + includeEmptyDirs = false + into "${projectDir}/vendor/jruby" +} + +installCustomJRuby.onlyIf { customJRubyDir != "" } + + +task downloadAndInstallJRuby(dependsOn: [verifyFile, installCustomJRuby], type: Copy) { + description "Install JRuby in the vendor directory" + inputs.file(jrubyTarPath) + outputs.dir("${projectDir}/vendor/jruby") + from tarTree(downloadJRuby.dest) + eachFile { f -> + f.path = f.path.replaceFirst("^jruby-${jRubyVersion}", '') + } + exclude "**/stdlib/rdoc/**" + includeEmptyDirs = false + into "${projectDir}/vendor/jruby" + doLast { + gem(projectDir, buildDir, "rake", "12.3.1", "${projectDir}/vendor/bundle/jruby/2.5.0") + gem(projectDir, buildDir, "json", "1.8.6", "${projectDir}/vendor/bundle/jruby/2.5.0") + } +} + +downloadAndInstallJRuby.onlyIf { customJRubyDir == "" } From aaac050098816c142250f988ed9d974902c03f6a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jo=C3=A3o=20Duarte?= Date: Fri, 5 Apr 2019 12:19:30 +0100 Subject: [PATCH 0060/1126] prevent DeprecatedRemovedSetting from fatally stopping logstash (#10657) --- logstash-core/lib/logstash/settings.rb | 6 +----- .../settings/deprecated_and_renamed_spec.rb | 15 ++------------- 2 files changed, 3 insertions(+), 18 deletions(-) diff --git a/logstash-core/lib/logstash/settings.rb b/logstash-core/lib/logstash/settings.rb index 4288d882c..ecdac5885 100644 --- a/logstash-core/lib/logstash/settings.rb +++ b/logstash-core/lib/logstash/settings.rb @@ -598,11 +598,7 @@ module LogStash end def set(value) - fail(RuntimeError, "The setting `#{name}` has been deprecated and removed from Logstash; #{@guidance}") - end - - def value - fail(ArgumentError, "The setting `#{name}` has been deprecated and removed from Logstash") + fail(ArgumentError, "The setting `#{name}` has been deprecated and removed from Logstash; #{@guidance}") end end diff --git a/logstash-core/spec/logstash/settings/deprecated_and_renamed_spec.rb b/logstash-core/spec/logstash/settings/deprecated_and_renamed_spec.rb index 74ce828ee..fd9faf351 100644 --- a/logstash-core/spec/logstash/settings/deprecated_and_renamed_spec.rb +++ b/logstash-core/spec/logstash/settings/deprecated_and_renamed_spec.rb @@ -9,22 +9,11 @@ describe LogStash::Setting::DeprecatedAndRenamed do describe '#set' do it 'fails with deprecation runtime error and helpful guidance' do expect { setting.set(value) }.to raise_exception do |exception| - expect(exception).to be_a_kind_of(RuntimeError) + expect(exception).to be_a_kind_of(ArgumentError) expect(exception.message).to match(/deprecated and removed/) expect(exception.message).to include("option.deprecated") expect(exception.message).to include("option.current") end end end - - describe '#value' do - it 'fails with deprecation argument error' do - expect { setting.value }.to raise_exception do |exception| - expect(exception).to be_a_kind_of(ArgumentError) - expect(exception.message).to match(/deprecated and removed/) - expect(exception.message).to include("option.deprecated") - end - end - end - -end \ No newline at end of file +end From 563fa8117cf75b2aab99cfa67ed31a920bb270f9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jo=C3=A3o=20Duarte?= Date: Fri, 5 Apr 2019 15:37:55 +0100 Subject: [PATCH 0061/1126] work around jruby-5642 during package installation on jdk11 (#10658) fixes #10593 --- lib/systeminstall/pleasewrap.rb | 23 +++++++++++++++++++++++ 1 file changed, 23 insertions(+) diff --git a/lib/systeminstall/pleasewrap.rb b/lib/systeminstall/pleasewrap.rb index f7ee00bd4..0eb05dd4a 100755 --- a/lib/systeminstall/pleasewrap.rb +++ b/lib/systeminstall/pleasewrap.rb @@ -8,5 +8,28 @@ Gem.use_paths(LogStash::Environment.logstash_gem_home) #libdir = File.expand_path("../lib", File.dirname(__FILE__)) #$LOAD_PATH << libdir if File.exist?(File.join(libdir, "pleaserun", "cli.rb")) + +require 'open3' + +# Work around for https://github.com/elastic/logstash/issues/10593 +# Issue on JRUBY https://github.com/jruby/jruby/issues/5642 +# Workaround retrieved from https://github.com/jruby/jruby/issues/5642#issuecomment-479671017 +if RUBY_ENGINE_VERSION != "9.2.6.0" + raise "A workaround is in place for JRUBY-5642 that should be applied only to JRuby 9.2.6.0, but found #{RUBY_ENGINE_VERSION}" +end +if java.lang.System.getProperty("java.version").start_with?("11") + class IO + def self.pipe + readwrite = Java::int[2].new + JRuby.runtime.posix.pipe(readwrite) + return readwrite.map do |fd| + io = IO.for_fd(fd) + io.close_on_exec = true + io + end + end + end +end + require "pleaserun/cli" exit(PleaseRun::CLI.run || 0) From 6e0658fbf75f67f33f1567ab41b67d283d7f9e52 Mon Sep 17 00:00:00 2001 From: Lisa Cawley Date: Mon, 8 Apr 2019 09:09:34 -0700 Subject: [PATCH 0062/1126] [DOCS] Adds tagged region for notable breaking changes (#10654) (#10661) --- docs/static/breaking-changes.asciidoc | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/docs/static/breaking-changes.asciidoc b/docs/static/breaking-changes.asciidoc index 803cc8005..e37f63a50 100644 --- a/docs/static/breaking-changes.asciidoc +++ b/docs/static/breaking-changes.asciidoc @@ -20,6 +20,12 @@ See these topics for a description of breaking changes: See also <>. +//NOTE: The notable-breaking-changes tagged regions are re-used in the +//Installation and Upgrade Guide +// tag::notable-breaking-changes[] + +// end::notable-breaking-changes[] + [float] [[breaking-pq]] === Breaking change across PQ versions prior to Logstash 6.3.0 From 336ba7dfec8df77a50912cc404a18e089375ca00 Mon Sep 17 00:00:00 2001 From: Karen Metts Date: Wed, 3 Apr 2019 11:04:38 -0400 Subject: [PATCH 0063/1126] Refine upgrade instructions for 7.0 Add recommendation to upgrade to 6.7 before 7.0 Fixes #10634 --- docs/static/upgrading.asciidoc | 113 +++++++++++++++++++++------------ 1 file changed, 74 insertions(+), 39 deletions(-) diff --git a/docs/static/upgrading.asciidoc b/docs/static/upgrading.asciidoc index 378660de2..24292d736 100644 --- a/docs/static/upgrading.asciidoc +++ b/docs/static/upgrading.asciidoc @@ -27,6 +27,36 @@ See the following topics for information about upgrading Logstash: * <> * <> +[float] +==== When to Upgrade + +Fresh installations can and should start with the same version across the Elastic Stack. + +Elasticsearch 7.0 does not require Logstash 7.0. An Elasticsearch 7.0 cluster +will happily receive data from earlier versions of Logstash via the default +HTTP communication layer. This provides some flexibility to decide when to +upgrade Logstash relative to an Elasticsearch upgrade. It may or may not be +convenient for you to upgrade them together, and it is not required to be done +at the same time as long as Elasticsearch is upgraded first. + +You should upgrade in a timely manner to get the performance improvements that +come with Logstash 7.0, but do so in the way that makes the most sense for your +environment. + +[float] +==== When Not to Upgrade + +If any Logstash plugin that you require is not compatible with Logstash 7.0, then you should wait until it is ready +before upgrading. + +Although we make great efforts to ensure compatibility, Logstash 7.0 is not completely backwards compatible. As noted +in the Elastic Stack upgrade guide, Logstash 7.0 should not be upgraded before Elasticsearch 7.0. This is both +practical and because some Logstash 7.0 plugins may attempt to use features of Elasticsearch 7.0 that did not exist +in earlier versions. For example, if you attempt to send the 7.x template to a cluster before Elasticsearch 7.0, then +all indexing likely fail. If you use your own custom template with Logstash, +then this issue can be ignored. + + [[upgrading-using-package-managers]] === Upgrading Using Package Managers @@ -53,8 +83,6 @@ Configuration options for some Logstash plugins have changed in the 7.x release. 5. Restart your Logstash pipeline after updating your configuration file. - - [[upgrading-minor-versions]] === Upgrading between minor versions @@ -67,6 +95,50 @@ settings and exported fields. Please review the Upgrading between non-consecutive major versions (5.x to 7.x, for example) is not supported. + +[[upgrading-logstash-7.0]] +=== Upgrading Logstash to 7.0 + +coming[7.0.0] + +Before upgrading Logstash: + +* Read the <>. +* Read the <> docs. ++ +There you can find info on these topics and more: + +** Java execution engine enabled by default +** Field parser is more strict and how that affects processing +** Beats conforms to the Elastic Common Schema (ECS) and how that impacts {ls} + +//TO DO: ^^ Add links <> and <> and <> after breaking changes are merged + +If you are installing Logstash with other components in the Elastic Stack, also see the +{stack-ref}/index.html[Elastic Stack installation and upgrade documentation]. + +NOTE: Upgrading between non-consecutive major versions (5.x to 7.x, for example) is not +supported. We recommend that you upgrade to 6.x, and then upgrade to 7.x. + +[float] +[[upgrade-to-6.7-rec]] +==== Upgrade to {ls} 6.7 before upgrading to 7.0 + +If you haven't already, upgrade to version 6.7 before you upgrade to 7.0. If +you're using other products in the {stack}, upgrade {ls} as part of the +{stack-ref}/upgrading-elastic-stack.html[{stack} upgrade process]. + +TIP: Upgrading to {ls} 6.7 will give you a head-start on new 7.0 features, including +the java execution engine and the strict field reference parser, while you're still running 6.x. +This step helps reduce risk and makes roll backs easier if you hit +a snag. + +//TO DO: Add links [[field-ref-strict]] and [[java-exec-default]] after upgrade docs are merged + +Upgrading to 6.7 is required because the {es} index template was modified to +be compatible with {es} 7.0 (the `_type` setting changed from `doc` to `_doc`). + + [[upgrading-logstash-pqs]] === Upgrading with the Persistent Queue Enabled @@ -124,40 +196,3 @@ Keep in mind that only one Logstash instance can write to `path.queue`. You cannot have the original instance and the new instance writing to the queue at the same time. -[[upgrading-logstash-7.0]] -=== Upgrading Logstash to 7.0 - -Before upgrading Logstash, remember to read the <> docs and the <>. - -If you are installing Logstash with other components in the Elastic Stack, also see the -{stack-ref}/index.html[Elastic Stack installation and upgrade documentation]. - -NOTE: Upgrading between non-consecutive major versions (5.x to 7.x, for example) is not -supported. We recommend that you upgrade to 6.x, and then upgrade to 7.x. - -==== When to Upgrade - -Fresh installations can and should start with the same version across the Elastic Stack. - -Elasticsearch 7.0 does not require Logstash 7.0. An Elasticsearch 7.0 cluster -will happily receive data from earlier versions of Logstash via the default -HTTP communication layer. This provides some flexibility to decide when to -upgrade Logstash relative to an Elasticsearch upgrade. It may or may not be -convenient for you to upgrade them together, and it is not required to be done -at the same time as long as Elasticsearch is upgraded first. - -You should upgrade in a timely manner to get the performance improvements that come with Logstash 7.0, but do so in -the way that makes the most sense for your environment. - -==== When Not to Upgrade - -If any Logstash plugin that you require is not compatible with Logstash 7.0, then you should wait until it is ready -before upgrading. - -Although we make great efforts to ensure compatibility, Logstash 7.0 is not completely backwards compatible. As noted -in the Elastic Stack upgrade guide, Logstash 7.0 should not be upgraded before Elasticsearch 7.0. This is both -practical and because some Logstash 7.0 plugins may attempt to use features of Elasticsearch 7.0 that did not exist -in earlier versions. For example, if you attempt to send the 7.x template to a cluster before Elasticsearch 7.0, then -all indexing likely fail. If you use your own custom template with Logstash, -then this issue can be ignored. From ce7e3107b1f5f5bbb80ecfd0ba2a119b0c69652a Mon Sep 17 00:00:00 2001 From: Karen Metts <35154725+karenzone@users.noreply.github.com> Date: Mon, 8 Apr 2019 16:02:37 -0400 Subject: [PATCH 0064/1126] Update breaking changes doc for 7.0 (#10632) * Update breaking changes doc for 7.0 Update structure to allow for previous and current changes * Update docs/static/breaking-changes.asciidoc Adds info about field reference parser Co-Authored-By: karenzone <35154725+karenzone@users.noreply.github.com> * Populate content for plugin changes Co-Authored-By: karenzone <35154725+karenzone@users.noreply.github.com> * Fix asciidoc formatting * Incorporate review comments and new content * Minor change for clarity * add anchors for linking * Add anchor for ecs-beats * Incorporate review comments * [DOCS] Adds tagged region for notable breaking changes * Incorporate review comments Remove link Fixes #10666 --- docs/static/breaking-changes.asciidoc | 220 ++++++++++++++++++++++++-- 1 file changed, 210 insertions(+), 10 deletions(-) diff --git a/docs/static/breaking-changes.asciidoc b/docs/static/breaking-changes.asciidoc index e37f63a50..aabc6c585 100644 --- a/docs/static/breaking-changes.asciidoc +++ b/docs/static/breaking-changes.asciidoc @@ -1,20 +1,21 @@ [[breaking-changes]] == Breaking Changes -We strive to maintain backward compatibility between minor versions (6.x to 6.y, +We strive to maintain backward compatibility between minor versions (7.x to 7.y, for example) so that you can upgrade without changing any configuration files. -Breaking changes are usually introduced only between major versions (such as 5.x -to 6.y). On occasion, we are forced to break compatibility within a given major release +Breaking changes are usually introduced only between major versions (such as 6.x +to 7.y). On occasion, we are forced to break compatibility within a given major release to ensure correctness of operation. This section covers the changes that you need to be aware of when migrating to -Logstash 6.0.0 and later. +Logstash 7.0.0 and later. -NOTE: Migrating directly between non-consecutive major versions (1.x to -6.x) is not recommended. +NOTE: Migrating directly between non-consecutive major versions (5.x to +7.x) is not recommended. See these topics for a description of breaking changes: +* <> * <> * <> @@ -22,11 +23,210 @@ See also <>. //NOTE: The notable-breaking-changes tagged regions are re-used in the //Installation and Upgrade Guide + +[[breaking-7.0]] +=== Breaking changes in 7.0 + +coming[7.0.0] + +Here are the breaking changes for {ls} 7.0. + // tag::notable-breaking-changes[] +[float] +==== Changes in Logstash Core + +These changes can affect any instance of Logstash that uses impacted features. +Changes to Logstash Core are plugin agnostic. + +[float] +[[java-exec-default]] +===== Java execution engine enabled by default + +The new Java execution engine is enabled by default. It features faster +performance, reduced memory usage, and lower config startup and reload times. + +For more information, see the blog post about the +https://www.elastic.co/blog/meet-the-new-logstash-java-execution-engine[initial +release of the Java execution engine]. + +We went to considerable lengths to make this change seamless. Still, it's a big +change. If you notice different behaviors that might be related, please +https://github.com/elastic/logstash/issues[open a GitHub issue] to let us +know. + +[float] +[[beats-ecs]] +===== Beats conform to the Elastic Common Schema (ECS) + +As of 7.0, Beats fields conform to the {ecs-ref}/index.html[Elastic Common +Schema (ECS)]. + +If you upgrade Logstash before you upgrade Beats, the payloads continue to use +the pre-ECS schema. If you upgrade your Beats before you upgrade Logstash, then +you'll get payloads with the ECS schema in advance of any Logstash upgrade. + +If you see mapping conflicts after upgrade, that is an indication that the +Beats/ECS change is influencing the data reaching existing indices. + +See the *{beats} Platform Reference* for more information on +{beats-ref}/upgrading-6-to-7.html#enable-ecs-compatibility[Beats and ECS]. + +[float] +[[field-ref-strict]] +===== Field Reference parser is more strict + +The Field Reference parser, which is used to interpret references to fields in +your pipelines and plugins, was made to be more strict and will now reject +inputs that are either ambiguous or illegal. Since 6.4, Logstash has emitted +warnings when encountering input that is ambiguous, and allowed an early opt-in +of strict-mode parsing either by providing the command-line flag +`--field-reference-parser STRICT` or by adding `config.field_reference.parser: +STRICT` to `logstash.yml`. + +Here's an example. + +*Before* + +[source,txt] +----- +logstash-6.7.0 % echo "hello"| bin/logstash -e 'filter { mutate { replace => { "message" => "%{[[]]message]} you" } } }' +[2019-04-05T16:52:18,691][WARN ][org.logstash.FieldReference] Detected ambiguous Field Reference `[[]]message]`, which we expanded to the path `[message]`; in a future release of Logstash, ambiguous Field References will not be expanded. +{ + "message" => "hello you", + "@version" => "1", + "@timestamp" => 2019-04-05T15:52:18.546Z, + "type" => "stdin", + "host" => "overcraft.lan" +} +----- + +*After* + +[source,txt] +----- +logstash-7.0.0 % echo "hello"| bin/logstash -e 'filter { mutate { replace => { "message" => "%{[[]]message]} you" } } }' +[2019-04-05T16:48:09,135][FATAL][logstash.runner ] An unexpected error occurred! {:error=>java.lang.IllegalStateException: org.logstash.FieldReference$IllegalSyntaxException: Invalid FieldReference: `[[]]message]` +[2019-04-05T16:48:09,167][ERROR][org.logstash.Logstash ] java.lang.IllegalStateException: Logstash stopped processing because of an error: (SystemExit) exit +----- + + +[float] +==== Changes in Logstash Plugins + +With 7.0.0, we have taken the opportunity to upgrade a number of bundled plugins +to their newest major version, absorbing their breaking changes into the +Logstash distribution. + +While these upgrades included new features and important fixes, only the +breaking changes are called out below. + +NOTE: The majority of the changes to plugins are the removal of previously-deprecated +and now-obsolete options. Please ensure that your pipeline +configurations do not use these removed options before upgrading. + +[float] +===== Codec Plugins + +Here are the breaking changes for codec plugins. + +*CEF Codec* + +* Removed obsolete `sev` option +* Removed obsolete `deprecated_v1_fields` option + +*Netflow Codec* + +* Changed decoding of application_id to implement RFC6759; the format changes from a pair of colon-separated ids (e.g. `0:40567`) to a variable number of double-dot-separated ids (e.g. `0..12356..40567`). + +[float] +===== Filter Plugins + +Here are the breaking changes for filter plugins. + +*Clone Filter* + +* Make `clones` a required option + +*Geoip Filter* + +* Removed obsolete `lru_cache_size` option + +*HTTP Filter* + +* Removed obsolete `ssl_certificate_verify` option + +[float] +===== Input Plugins + +Here are the breaking changes for input plugins. + +*Beats Input* + +* Removed obsolete `congestion_threshold` option +* Removed obsolete `target_field_for_codec` option +* Changed default value of `add_hostname` to false + +NOTE: In Beats 7.0.0, the fields exported by Beats _to_ the Logstash Beats Input +conform to the {ecs-ref}/index.html[Elastic Common Schema (ECS)]. Many of the +exported fields have been renamed, so you may need to modify your pipeline +configurations to access them at their new locations prior to upgrading your +Beats. See {beats-ref}/breaking-changes-7.0.html[Beats Breaking changes in 7.0] +for the full list of changed names. + +*HTTP Input* + +* Removed obsolete `ssl_certificate_verify` option + +*HTTP Poller Input* + +* Removed obsolete `interval` option +* Removed obsolete `ssl_certificate_verify` option + +*Tcp Input* + +* Removed obsolete `data_timeout` option +* Removed obsolete `ssl_cacert` option + +[float] +===== Output Plugins + +Here are the breaking changes for output plugins. + +*Elasticsearch Output* + +* {es} {ref}/index-lifecycle-management.html[Index lifecycle management (ILM)] is +auto-detected and enabled by default if your {es} cluster supports it. +* Remove support for parent/child (still support join data type) since we don't +support multiple document types any more +* Removed obsolete `flush_size` option +* Removed obsolete `idle_flush_time` option + +*HTTP Output* + +* Removed obsolete `ssl_certificate_verify` option + +*Kafka Output* + +* Removed obsolete `block_on_buffer_full` option +* Removed obsolete `ssl` option +* Removed obsolete `timeout_ms` option + +*Redis Output* + +* Removed obsolete `queue` option +* Removed obsolete `name` option + +*Sqs Output* + +* Removed obsolete `batch` option +* Removed obsolete `batch_timeout` option + +*Tcp Output* + +* Removed obsolete `message_format` option // end::notable-breaking-changes[] -[float] [[breaking-pq]] === Breaking change across PQ versions prior to Logstash 6.3.0 @@ -35,7 +235,6 @@ and have the persistent queue enabled, we strongly recommend that you drain or delete the persistent queue before you upgrade. See <> for information and instructions. -[float] [[breaking-6.0]] === Breaking changes in 6.0 @@ -44,7 +243,8 @@ Here are the breaking changes for 6.0. [float] ==== Changes in Logstash Core -These changes can impact any instance of Logstash and are plugin agnostic, but only if you are using the features that are impacted. +These changes can affect any instance of Logstash that uses impacted features. +Changes to Logstash Core are plugin agnostic. [float] ===== Application Settings @@ -68,7 +268,7 @@ These changes can impact any instance of Logstash and are plugin agnostic, but o [float] ===== List of plugins bundled with Logstash -The following plugins were removed from the 5.0 default bundle based on usage data. You can still install these plugins manually: +The following plugins were removed from the default bundle based on usage data. You can still install these plugins manually: * logstash-codec-oldlogstashjson * logstash-input-couchdb_changes From 12133e3a3d6e61009d4fc78257dbb7525ffb9fe5 Mon Sep 17 00:00:00 2001 From: Colin Surprenant Date: Fri, 5 Apr 2019 01:12:25 -0400 Subject: [PATCH 0065/1126] add 7.0.0 alpha1, alpha2 and beta1 release notes (#10665) cleanup plugins changes for alpha1, alpha2, beta1 Fixes #10665 --- docs/static/releasenotes.asciidoc | 166 ++++++++++++++++++++++++++++-- 1 file changed, 156 insertions(+), 10 deletions(-) diff --git a/docs/static/releasenotes.asciidoc b/docs/static/releasenotes.asciidoc index 149579ee5..2104db220 100644 --- a/docs/static/releasenotes.asciidoc +++ b/docs/static/releasenotes.asciidoc @@ -10,21 +10,167 @@ This section summarizes the changes in the following releases: [[logstash-7-0-0-beta1]] === Logstash 7.0.0-beta1 Release Notes -Placeholder for release notes +* Update Java dependencies https://github.com/elastic/logstash/pull/10340[#10340] +* Remove pipeline output workers setting https://github.com/elastic/logstash/pull/10358[#10358] +* Cleanup Ruby gems dependencies https://github.com/elastic/logstash/pull/10171[#10171] +* Ensure compatibility of module data with ES and Kibana 7.0 https://github.com/elastic/logstash/pull/10356[#10356] +* Rename x-pack monitoring and management config option .url and .ca to .hosts and .certificate_authority https://github.com/elastic/logstash/pull/10380[#10380] +* BUGFIX: building of deb and rpm artifacts https://github.com/elastic/logstash/pull/10396[#10396] +* logstash-codec-cef + - Removed obsolete `sev` and `deprecated_v1_fields` fields + - Fixed minor doc inconsistencies (added reverse_mapping to options table, moved it to alpha order in option descriptions, fixed typo) + [#60](https://github.com/logstash-plugins/logstash-codec-cef/pull/60) +* logstash-codec-es_bulk + - Add documentation about use with http input +* logstash-codec-netflow + - Fix sub-second timestamp math +* logstash-filter-clone + - Make 'clones' a required option + - Added a warning when 'clones' is empty since that results in a no-op https://github.com/logstash-plugins/logstash-filter-clone/issues/14 +* logstash-filter-de_dot + - fix failure of fieldnames with boolean value "false" +* logstash-filter-geoip + - Removed obsolete lru_cache_size field +* logstash-filter-http + - Fixed minor documentation issues [#9](https://github.com/logstash-plugins/logstash-filter-http/pull/9) + - Minor documentation fixes +* logstash-filter-jdbc_streaming + - [#11](https://github.com/logstash-plugins/logstash-filter-jdbc_streaming/pull/11) Swap out mysql for postgresql for testing +* logstash-filter-json + - Updated documentation with some clarifications and fixes +* logstash-filter-memcached + - Updated to 1.0.0 + - The plugin common options (e.g., `add_field`, `add_tag`, etc.) are now correctly only invoked when the plugin successfully gets one or more values from, or sets one or more values to memcached (#4) + - Fix links to argument types in documentation (#3) +* logstash-filter-metrics + - Fixed two minor typos in documentation +* logstash-filter-mutate + - Added ability to directly convert from integer and float to boolean [#127](https://github.com/logstash-plugins/logstash-filter-mutate/pull/127) +* logstash-filter-split + - Fixed numeric values, optimized @target verification, cleanups and specs [36](https://github.com/logstash-plugins/logstash-filter-split/pull/36) +* logstash-input-azure_event_hubs + - Updated Azure event hub library dependencies[#27](https://github.com/logstash-plugins/logstash-input-azure_event_hubs/pull/27) +* logstash-input-beats + - Removed obsolete setting congestion_threshold and target_field_for_codec + - Changed default value of `add_hostname` to false +* logstash-input-elasticsearch + - Added managed slice scrolling with `slices` option +* logstash-input-http + - Added configurable response code option [#103](https://github.com/logstash-plugins/logstash-input-http/pull/103) + - Added explanation about operation order of codec and additional_codecs [#104](https://github.com/logstash-plugins/logstash-input-http/pull/104) +* logstash-input-http_poller + - Fixed minor doc and doc formatting issues [#107](https://github.com/logstash-plugins/logstash-input-http_poller/pull/107) + - Removed obsolete field `interval` + - Changed `schedule` entry to show that it is required + [#102](https://github.com/logstash-plugins/logstash-input-http_poller/pull/102) +* logstash-input-kafka + - Removed obsolete `ssl` option +* logstash-input-tcp + - Removed obsolete `data_timeout` and `ssl_cacert` options +* logstash-mixin-http_client + - Removed obsolete ssl_certificate_verify option +* logstash-output-elasticsearch + - Remove support for parent child (still support join data type) since we don't support multiple document types any more + - Removed obsolete `flush_size` and `idle_flush_time` + - Added 'auto' setting for ILM with default of 'auto' [#838](https://github.com/logstash-plugins/logstash-output-elasticsearch/pull/838) + - Fixed sniffing support for 7.x [#827](https://github.com/logstash-plugins/logstash-output-elasticsearch/pull/827) + - Fixed issue with escaping index names which was causing writing aliases for ILM to fail [#831](https://github.com/logstash-plugins/logstash-output-elasticsearch/pull/831) +* logstash-output-file + - Removed JRuby check when using FIFOs [#75](https://github.com/logstash-plugins/logstash-output-file/pull/75) +* logstash-output-http + - Relax dependency on http_client mixin since current major works on both +* logstash-output-kafka + - Removed obsolete `block_on_buffer_full`, `ssl` and `timeout_ms` options +* logstash-output-pagerduty + - Update _development_ dependency webmock to latest version to prevent conflicts in logstash core's dependency matrix. +* logstash-output-redis + - Removed obsolete fields `queue` and `name` + - Changed major version of redis library dependency to 4.x +* logstash-output-sqs + - Removed obsolete fields `batch` and `batch_timeout` + - Removed workaround to JRuby bug (see more [here](https://github.com/jruby/jruby/issues/3645)) +* logstash-output-tcp + - Removed obsolete field `message_format` + - Removed requirement to have a certificate/key pair when enabling ssl [[logstash-7-0-0-alpha2]] === Logstash 7.0.0-alpha2 Release Notes -Placeholder for release notes +* logstash-filter-elasticsearch + - Add support for extracting hits total from Elasticsearch 7.x responses + - Added connection check during register to avoid failures during processing + - Changed Elasticsearch Client transport to use Manticore + - Changed amount of logging details during connection failure +* logstash-filter-fingerprint + - Fixed concurrent SHA fingerprinting by making the instances thread local +* NEW: logstash-filter-http + - Beta version of HTTP filter plugin based on @lucashenning's [REST filter](https://github.com/lucashenning/logstash-filter-rest). +* NEW: logstash-filter-memcached +* logstash-input-beats + - Loosen jar-dependencies manager gem dependency to allow plugin to work with JRubies that include a later version + - Updated jar dependencies to reflect newer releases +* logstash-input-file + - Fixed issue where logs were being spammed with needless error messages [#224](https://github.com/logstash-plugins/logstash-input-file/pull/224) + - Fixed problem in tail and read modes where the read loop could get stuck if an IO error occurs in the loop. + The file appears to be being read but it is not, suspected with file truncation schemes. + [Issue #205](https://github.com/logstash-plugins/logstash-input-file/issues/205) +* logstash-input-gelf + - Fixed shutdown handling, robustness in socket closing and restarting, json parsing, code DRYing and cleanups [62](https://github.com/logstash-plugins/logstash-input-gelf/pull/62) +* logstash-input-http + - Loosen jar-dependencies manager gem dependency to allow plugin to work with JRubies that include a later version. + - Changed jar dependencies to reflect newer versions +* logstash-input-kafka + - Added support for kafka property ssl.endpoint.identification.algorithm #302(https://github.com/logstash-plugins/logstash-input-kafka/pull/302) + - Changed Kafka client version to 2.1.0 + - Changed Kafka client version to 2.0.1 [#295](https://github.com/logstash-plugins/logstash-input-kafka/pull/295) +* logstash-output-elasticsearch + - Adds support for Index Lifecycle Management for Elasticsearch 6.6.0 and above, running with at least a Basic License(Beta) [#805](https://github.com/logstash-plugins/logstash-output-elasticsearch/pull/805) + - Fixed support for Elasticsearch 7.x [#812](https://github.com/logstash-plugins/logstash-output-elasticsearch/pull/812) +* logstash-output-http + - Fixed handling of empty `retryable_codes` [#99](https://github.com/logstash-plugins/logstash-output-http/pull/99) +* logstash-output-kafka + - Added support for kafka property `ssl.endpoint.identification.algorithm` [#213](https://github.com/logstash-plugins/logstash-output-kafka/pull/213) + - Changed Kafka client to version 2.1.0 + - Changed Kafka client to version 2.0.1 [#209](https://github.com/logstash-plugins/logstash-output-kafka/pull/209) [[logstash-7-0-0-alpha1]] === Logstash 7.0.0-alpha1 Release Notes -Placeholder for release notes - - - - - - - +* Make Java execution the default https://github.com/elastic/logstash/pull/8649[#8649] +* Field-reference parsing is now strict by default https://github.com/elastic/logstash/pull/9543[#9543] +* Improvements to core Javaification +* BUGFIX: Support for Byte, Short and Date type conversions as seen in the rabbitmq input plugin https://github.com/elastic/logstash/pull/9984[#9984] +* logstash-codec-netflow + - BREAKING: Added support for RFC6759 decoding of application_id. This is a breaking change to the way application_id is decoded. The format changes from e.g. 0:40567 to 0..12356..40567 + - Fixed IPFIX options template parsing for Juniper MX240 JunOS 15.1 + - Fixed incorrect parsing of zero-filled Netflow 9 packets from Palo Alto + - Added support for Netflow v9 devices with VarString fields (H3C Netstream) + - Reduced complexity of creating, persisting, loading an retrieving template caches + - Fixed issue where TTL in template registry was not being respected + - Added Cisco ACI to list of known working Netflow v9 exporters + - Added support for IXIA Packet Broker IPFIX + - Fixed issue with Procera float fields +* logstash-filter-aggregate + - new feature: add ability to dynamically define a custom `timeout` or `inactivity_timeout` in `code` block (fix issues [#91](https://github.com/logstash-plugins/logstash-filter-aggregate/issues/91) and [#92](https://github.com/logstash-plugins/logstash-filter-aggregate/issues/92)) + - new feature: add meta informations available in `code` block through `map_meta` variable + - new feature: add Logstash metrics, specific to aggregate plugin: aggregate_maps, pushed_events, task_timeouts, code_errors, timeout_code_errors + - new feature: validate at startup that `map_action` option equals to 'create', 'update' or 'create_or_update' +* logstash-filter-jdbc_static + - Added info to documentation to emphasize significance of table order [36](https://github.com/logstash-plugins/logstash-filter-jdbc_static/pull/36) +* logstash-filter-xml + - Fixed creation of empty arrays when xpath failed [#59](https://github.com/logstash-plugins/logstash-filter-xml/pull/59) + - Fixed force_array behavior with nested elements [#57](https://github.com/logstash-plugins/logstash-filter-xml/pull/57) +* logstash-input-file + - Fixed problem in rotation handling where the target file being rotated was + subjected to the start_position setting when it must always start from the beginning. + [Issue #214](https://github.com/logstash-plugins/logstash-input-file/issues/214) +* logstash-input-snmp + - Added no_codec condition to the documentation and bumped version [#39](https://github.com/logstash-plugins/logstash-input-snmp/pull/39) + - Changed docs to improve options layout [#38](https://github.com/logstash-plugins/logstash-input-snmp/pull/38) +* logstash-input-sqs + - Added support for multiple events inside same message from SQS [#48](https://github.com/logstash-plugins/logstash-input-sqs/pull/48/files) +* logstash-output-elasticsearch + - Tweaked logging statements to reduce verbosity + - Fixed numerous issues relating to builds on Travis [#799](https://github.com/logstash-plugins/logstash-output-elasticsearch/pull/799) +* logstash-output-s3 + - Fixed issue where on restart, 0 byte files could erroneously be uploaded to s3 [#195](https://github.com/logstash-plugins/logstash-output-s3/issues/195) From d4e6236dd77f08ee06b0c0c07b2f1f2889258537 Mon Sep 17 00:00:00 2001 From: Karen Metts <35154725+karenzone@users.noreply.github.com> Date: Sun, 7 Apr 2019 21:15:02 -0400 Subject: [PATCH 0066/1126] Fix asciidoc formatting for links in release notes (#10665) Added placeholders and coming label for 7.0.0 Add entry/link for 7.0.0 and clean up asciidoc Fixes #10665 --- docs/static/releasenotes.asciidoc | 106 +++++++++++++++++++----------- 1 file changed, 68 insertions(+), 38 deletions(-) diff --git a/docs/static/releasenotes.asciidoc b/docs/static/releasenotes.asciidoc index 2104db220..802731619 100644 --- a/docs/static/releasenotes.asciidoc +++ b/docs/static/releasenotes.asciidoc @@ -3,10 +3,40 @@ This section summarizes the changes in the following releases: +* <> +* <> +* <> * <> * <> * <> +[[logstash-7-0-0]] +=== Logstash 7.0.0 Release Notes + +coming[7.0.0] + +The list combines release notes from the 7.0.0-alpha1, -alpha2, -beta1, -rc1 and -rc2 releases. + + + +[[logstash-7-0-0-rc2]] +=== Logstash 7.0.0-rc2 Release Notes + +* No user-facing changes + +[[logstash-7-0-0-rc1]] +=== Logstash 7.0.0-rc1 Release Notes + +* BUGFIX: Correctly count total queued items across multiple pipelines https://github.com/elastic/logstash/pull/10564[#10564] +* BUGFIX: Fix issue setting 'enable_metric => false' https://github.com/elastic/logstash/pull/10538[#10538] +* BUGFIX: Prevent concurrent convergence of pipeline actions https://github.com/elastic/logstash/pull/10537[#10537] +* Monitoring: Change internal document type to push "_doc" instead of "doc" https://github.com/elastic/logstash/pull/10533[#10533] +* BUGFIX: Allow explicitly-specified Java codecs https://github.com/elastic/logstash/pull/10520[#10520] +* Central management typeless API https://github.com/elastic/logstash/pull/10421[#10421] +* Improve docs about using Filebeat modules with Logstash https://github.com/elastic/logstash/pull/10438[#10438] +* Bump JRuby to 9.2.6.0 https://github.com/elastic/logstash/pull/10425[#10425] +* BUGFIX: Remove exclusive lock for Ruby pipeline initialization https://github.com/elastic/logstash/pull/10462[#10462] + [[logstash-7-0-0-beta1]] === Logstash 7.0.0-beta1 Release Notes @@ -19,23 +49,23 @@ This section summarizes the changes in the following releases: * logstash-codec-cef - Removed obsolete `sev` and `deprecated_v1_fields` fields - Fixed minor doc inconsistencies (added reverse_mapping to options table, moved it to alpha order in option descriptions, fixed typo) - [#60](https://github.com/logstash-plugins/logstash-codec-cef/pull/60) + https://github.com/logstash-plugins/logstash-codec-cef/pull/60[#60] * logstash-codec-es_bulk - Add documentation about use with http input * logstash-codec-netflow - Fix sub-second timestamp math * logstash-filter-clone - Make 'clones' a required option - - Added a warning when 'clones' is empty since that results in a no-op https://github.com/logstash-plugins/logstash-filter-clone/issues/14 + - Added a warning when 'clones' is empty since that results in a no-op https://github.com/logstash-plugins/logstash-filter-clone/issues/14[#14] * logstash-filter-de_dot - fix failure of fieldnames with boolean value "false" * logstash-filter-geoip - Removed obsolete lru_cache_size field * logstash-filter-http - - Fixed minor documentation issues [#9](https://github.com/logstash-plugins/logstash-filter-http/pull/9) + - Fixed minor documentation issues https://github.com/logstash-plugins/logstash-filter-http/pull/9[#9] - Minor documentation fixes * logstash-filter-jdbc_streaming - - [#11](https://github.com/logstash-plugins/logstash-filter-jdbc_streaming/pull/11) Swap out mysql for postgresql for testing + - Swap out mysql for postgresql for testing https://github.com/logstash-plugins/logstash-filter-jdbc_streaming/pull/11[#11] * logstash-filter-json - Updated documentation with some clarifications and fixes * logstash-filter-memcached @@ -45,24 +75,24 @@ This section summarizes the changes in the following releases: * logstash-filter-metrics - Fixed two minor typos in documentation * logstash-filter-mutate - - Added ability to directly convert from integer and float to boolean [#127](https://github.com/logstash-plugins/logstash-filter-mutate/pull/127) + - Added ability to directly convert from integer and float to boolean https://github.com/logstash-plugins/logstash-filter-mutate/pull/127[#127] * logstash-filter-split - - Fixed numeric values, optimized @target verification, cleanups and specs [36](https://github.com/logstash-plugins/logstash-filter-split/pull/36) + - Fixed numeric values, optimized @target verification, cleanups and specs https://github.com/logstash-plugins/logstash-filter-split/pull/36[#36] * logstash-input-azure_event_hubs - - Updated Azure event hub library dependencies[#27](https://github.com/logstash-plugins/logstash-input-azure_event_hubs/pull/27) -* logstash-input-beats + - Updated Azure event hub library dependencies https://github.com/logstash-plugins/logstash-input-azure_event_hubs/pull/27[#27] +* logstash-input-beats - Removed obsolete setting congestion_threshold and target_field_for_codec - Changed default value of `add_hostname` to false * logstash-input-elasticsearch - Added managed slice scrolling with `slices` option * logstash-input-http - - Added configurable response code option [#103](https://github.com/logstash-plugins/logstash-input-http/pull/103) - - Added explanation about operation order of codec and additional_codecs [#104](https://github.com/logstash-plugins/logstash-input-http/pull/104) + - Added configurable response code option https://github.com/logstash-plugins/logstash-input-http/pull/103[#103] + - Added explanation about operation order of codec and additional_codecs https://github.com/logstash-plugins/logstash-input-http/pull/104[#104] * logstash-input-http_poller - - Fixed minor doc and doc formatting issues [#107](https://github.com/logstash-plugins/logstash-input-http_poller/pull/107) + - Fixed minor doc and doc formatting issues https://github.com/logstash-plugins/logstash-input-http_poller/pull/107[#107] - Removed obsolete field `interval` - Changed `schedule` entry to show that it is required - [#102](https://github.com/logstash-plugins/logstash-input-http_poller/pull/102) + https://github.com/logstash-plugins/logstash-input-http_poller/pull/102[#102] * logstash-input-kafka - Removed obsolete `ssl` option * logstash-input-tcp @@ -72,11 +102,11 @@ This section summarizes the changes in the following releases: * logstash-output-elasticsearch - Remove support for parent child (still support join data type) since we don't support multiple document types any more - Removed obsolete `flush_size` and `idle_flush_time` - - Added 'auto' setting for ILM with default of 'auto' [#838](https://github.com/logstash-plugins/logstash-output-elasticsearch/pull/838) - - Fixed sniffing support for 7.x [#827](https://github.com/logstash-plugins/logstash-output-elasticsearch/pull/827) - - Fixed issue with escaping index names which was causing writing aliases for ILM to fail [#831](https://github.com/logstash-plugins/logstash-output-elasticsearch/pull/831) + - Added 'auto' setting for ILM with default of 'auto' https://github.com/logstash-plugins/logstash-output-elasticsearch/pull/838[#838] + - Fixed sniffing support for 7.x https://github.com/logstash-plugins/logstash-output-elasticsearch/pull/827[#827] + - Fixed issue with escaping index names which was causing writing aliases for ILM to fail https://github.com/logstash-plugins/logstash-output-elasticsearch/pull/831[#831] * logstash-output-file - - Removed JRuby check when using FIFOs [#75](https://github.com/logstash-plugins/logstash-output-file/pull/75) + - Removed JRuby check when using FIFOs https://github.com/logstash-plugins/logstash-output-file/pull/75[#75] * logstash-output-http - Relax dependency on http_client mixin since current major works on both * logstash-output-kafka @@ -88,7 +118,7 @@ This section summarizes the changes in the following releases: - Changed major version of redis library dependency to 4.x * logstash-output-sqs - Removed obsolete fields `batch` and `batch_timeout` - - Removed workaround to JRuby bug (see more [here](https://github.com/jruby/jruby/issues/3645)) + - Removed workaround to JRuby bug https://github.com/jruby/jruby/issues/3645[#3645] * logstash-output-tcp - Removed obsolete field `message_format` - Removed requirement to have a certificate/key pair when enabling ssl @@ -104,34 +134,34 @@ This section summarizes the changes in the following releases: * logstash-filter-fingerprint - Fixed concurrent SHA fingerprinting by making the instances thread local * NEW: logstash-filter-http - - Beta version of HTTP filter plugin based on @lucashenning's [REST filter](https://github.com/lucashenning/logstash-filter-rest). + - Beta version of HTTP filter plugin based on @lucashenning's https://github.com/lucashenning/logstash-filter-rest[REST filter]. * NEW: logstash-filter-memcached * logstash-input-beats - Loosen jar-dependencies manager gem dependency to allow plugin to work with JRubies that include a later version - Updated jar dependencies to reflect newer releases * logstash-input-file - - Fixed issue where logs were being spammed with needless error messages [#224](https://github.com/logstash-plugins/logstash-input-file/pull/224) + - Fixed issue where logs were being spammed with needless error messages https://github.com/logstash-plugins/logstash-input-file/pull/224[#224] - Fixed problem in tail and read modes where the read loop could get stuck if an IO error occurs in the loop. The file appears to be being read but it is not, suspected with file truncation schemes. - [Issue #205](https://github.com/logstash-plugins/logstash-input-file/issues/205) + https://github.com/logstash-plugins/logstash-input-file/issues/205[#205] * logstash-input-gelf - - Fixed shutdown handling, robustness in socket closing and restarting, json parsing, code DRYing and cleanups [62](https://github.com/logstash-plugins/logstash-input-gelf/pull/62) + - Fixed shutdown handling, robustness in socket closing and restarting, json parsing, code DRYing and cleanups https://github.com/logstash-plugins/logstash-input-gelf/pull/62[#62] * logstash-input-http - Loosen jar-dependencies manager gem dependency to allow plugin to work with JRubies that include a later version. - Changed jar dependencies to reflect newer versions * logstash-input-kafka - - Added support for kafka property ssl.endpoint.identification.algorithm #302(https://github.com/logstash-plugins/logstash-input-kafka/pull/302) + - Added support for kafka property ssl.endpoint.identification.algorithm https://github.com/logstash-plugins/logstash-input-kafka/pull/302[#302] - Changed Kafka client version to 2.1.0 - - Changed Kafka client version to 2.0.1 [#295](https://github.com/logstash-plugins/logstash-input-kafka/pull/295) + - Changed Kafka client version to 2.0.1 https://github.com/logstash-plugins/logstash-input-kafka/pull/295[#295] * logstash-output-elasticsearch - - Adds support for Index Lifecycle Management for Elasticsearch 6.6.0 and above, running with at least a Basic License(Beta) [#805](https://github.com/logstash-plugins/logstash-output-elasticsearch/pull/805) - - Fixed support for Elasticsearch 7.x [#812](https://github.com/logstash-plugins/logstash-output-elasticsearch/pull/812) + - Adds support for Index Lifecycle Management for Elasticsearch 6.6.0 and above, running with at least a Basic License(Beta) https://github.com/logstash-plugins/logstash-output-elasticsearch/pull/805[#805] + - Fixed support for Elasticsearch 7.x https://github.com/logstash-plugins/logstash-output-elasticsearch/pull/812[#812] * logstash-output-http - - Fixed handling of empty `retryable_codes` [#99](https://github.com/logstash-plugins/logstash-output-http/pull/99) + - Fixed handling of empty `retryable_codes` https://github.com/logstash-plugins/logstash-output-http/pull/99[#99] * logstash-output-kafka - - Added support for kafka property `ssl.endpoint.identification.algorithm` [#213](https://github.com/logstash-plugins/logstash-output-kafka/pull/213) + - Added support for kafka property `ssl.endpoint.identification.algorithm` https://github.com/logstash-plugins/logstash-output-kafka/pull/213[#213] - Changed Kafka client to version 2.1.0 - - Changed Kafka client to version 2.0.1 [#209](https://github.com/logstash-plugins/logstash-output-kafka/pull/209) + - Changed Kafka client to version 2.0.1 https://github.com/logstash-plugins/logstash-output-kafka/pull/209[#209] [[logstash-7-0-0-alpha1]] === Logstash 7.0.0-alpha1 Release Notes @@ -151,26 +181,26 @@ This section summarizes the changes in the following releases: - Added support for IXIA Packet Broker IPFIX - Fixed issue with Procera float fields * logstash-filter-aggregate - - new feature: add ability to dynamically define a custom `timeout` or `inactivity_timeout` in `code` block (fix issues [#91](https://github.com/logstash-plugins/logstash-filter-aggregate/issues/91) and [#92](https://github.com/logstash-plugins/logstash-filter-aggregate/issues/92)) + - new feature: add ability to dynamically define a custom `timeout` or `inactivity_timeout` in `code` block (fix issues https://github.com/logstash-plugins/logstash-filter-aggregate/issues/91[#91] and https://github.com/logstash-plugins/logstash-filter-aggregate/issues/92[#92]) - new feature: add meta informations available in `code` block through `map_meta` variable - new feature: add Logstash metrics, specific to aggregate plugin: aggregate_maps, pushed_events, task_timeouts, code_errors, timeout_code_errors - new feature: validate at startup that `map_action` option equals to 'create', 'update' or 'create_or_update' * logstash-filter-jdbc_static - - Added info to documentation to emphasize significance of table order [36](https://github.com/logstash-plugins/logstash-filter-jdbc_static/pull/36) + - Added info to documentation to emphasize significance of table order https://github.com/logstash-plugins/logstash-filter-jdbc_static/pull/36[36] * logstash-filter-xml - - Fixed creation of empty arrays when xpath failed [#59](https://github.com/logstash-plugins/logstash-filter-xml/pull/59) - - Fixed force_array behavior with nested elements [#57](https://github.com/logstash-plugins/logstash-filter-xml/pull/57) + - Fixed creation of empty arrays when xpath failed https://github.com/logstash-plugins/logstash-filter-xml/pull/59[#59] + - Fixed force_array behavior with nested elements https://github.com/logstash-plugins/logstash-filter-xml/pull/57[#57] * logstash-input-file - Fixed problem in rotation handling where the target file being rotated was subjected to the start_position setting when it must always start from the beginning. - [Issue #214](https://github.com/logstash-plugins/logstash-input-file/issues/214) + https://github.com/logstash-plugins/logstash-input-file/issues/214[#214] * logstash-input-snmp - - Added no_codec condition to the documentation and bumped version [#39](https://github.com/logstash-plugins/logstash-input-snmp/pull/39) - - Changed docs to improve options layout [#38](https://github.com/logstash-plugins/logstash-input-snmp/pull/38) + - Added no_codec condition to the documentation and bumped version https://github.com/logstash-plugins/logstash-input-snmp/pull/39[#39] + - Changed docs to improve options layout https://github.com/logstash-plugins/logstash-input-snmp/pull/38[#38] * logstash-input-sqs - - Added support for multiple events inside same message from SQS [#48](https://github.com/logstash-plugins/logstash-input-sqs/pull/48/files) + - Added support for multiple events inside same message from SQS https://github.com/logstash-plugins/logstash-input-sqs/pull/48[#48] * logstash-output-elasticsearch - Tweaked logging statements to reduce verbosity - - Fixed numerous issues relating to builds on Travis [#799](https://github.com/logstash-plugins/logstash-output-elasticsearch/pull/799) + - Fixed numerous issues relating to builds on Travis https://github.com/logstash-plugins/logstash-output-elasticsearch/pull/799[#799] * logstash-output-s3 - - Fixed issue where on restart, 0 byte files could erroneously be uploaded to s3 [#195](https://github.com/logstash-plugins/logstash-output-s3/issues/195) + - Fixed issue where on restart, 0 byte files could erroneously be uploaded to s3 https://github.com/logstash-plugins/logstash-output-s3/issues/195[#195] From 68517090418c9970a2f11046f134ab849345fa1f Mon Sep 17 00:00:00 2001 From: Colin Surprenant Date: Sun, 7 Apr 2019 22:59:02 -0400 Subject: [PATCH 0067/1126] add 7.0.0 rc1 and rc2 release notes (#10665) Fixes #10665 --- docs/static/releasenotes.asciidoc | 25 ++++++++++++++++++++++--- 1 file changed, 22 insertions(+), 3 deletions(-) diff --git a/docs/static/releasenotes.asciidoc b/docs/static/releasenotes.asciidoc index 802731619..1bceeab1d 100644 --- a/docs/static/releasenotes.asciidoc +++ b/docs/static/releasenotes.asciidoc @@ -17,12 +17,12 @@ coming[7.0.0] The list combines release notes from the 7.0.0-alpha1, -alpha2, -beta1, -rc1 and -rc2 releases. - - [[logstash-7-0-0-rc2]] === Logstash 7.0.0-rc2 Release Notes -* No user-facing changes +* logstash-input-snmp + - Added support for querying SNMP tables + - Changed three error messages in the base_client to include the target address for clarity in the logs. [[logstash-7-0-0-rc1]] === Logstash 7.0.0-rc1 Release Notes @@ -36,6 +36,25 @@ The list combines release notes from the 7.0.0-alpha1, -alpha2, -beta1, -rc1 and * Improve docs about using Filebeat modules with Logstash https://github.com/elastic/logstash/pull/10438[#10438] * Bump JRuby to 9.2.6.0 https://github.com/elastic/logstash/pull/10425[#10425] * BUGFIX: Remove exclusive lock for Ruby pipeline initialization https://github.com/elastic/logstash/pull/10462[#10462] +* logstash-filter-dns + - Fixed issue where unqualified domains would fail to resolve when running this plugin with Logstash 5.x https://github.com/logstash-plugins/logstash-filter-dns/pull/48[#48] + - Fixed crash that could occur when encountering certain classes of invalid inputs https://github.com/logstash-plugins/logstash-filter-dns/pull/49[#49] +* logstash-filter-kv + - Added a timeout enforcer which prevents inputs that are pathological against the generated parser from blocking + the pipeline. By default, timeout is a generous 30s, but can be configured or disabled entirely with the new + `timeout_millis` and `tag_on_timeout` directives https://github.com/logstash-plugins/logstash-filter-kv/pull/79[#79] + - Made error-handling configurable with `tag_on_failure` directive. +* logstash-filter-xml + - Fixed creation of empty arrays when xpath failed https://github.com/logstash-plugins/logstash-filter-xml/pull/59[#59] +* logstash-input-file + - Fixed problem in Windows where some paths would fail to return an identifier ("inode"). Make path into a C style String before encoding to UTF-16LE. https://github.com/logstash-plugins/logstash-input-file/issues/232[#232] +* logstash-input-tcp + - Fixed race condition where data would be accepted before queue was configured + - Support multiple certificates per file https://github.com/logstash-plugins/logstash-input-tcp/pull/140[#140] +* logstash-output-kafka + - Fixed issue with unnecessary sleep after retries exhausted https://github.com/logstash-plugins/logstash-output-kafka/pull/216[#216] +* logstash-output-s3 + - Add support for setting mutipart upload threshold https://github.com/logstash-plugins/logstash-output-s3/pull/202[#202] [[logstash-7-0-0-beta1]] === Logstash 7.0.0-beta1 Release Notes From 476e503936ba3006e5418401dea9dd7601dc5b74 Mon Sep 17 00:00:00 2001 From: Karen Metts Date: Mon, 8 Apr 2019 17:41:47 -0400 Subject: [PATCH 0068/1126] Added core and plugin headings Combine plugins from alphas, betas, and rcs to make 7.0 release notes Fixes #10667 --- docs/static/releasenotes.asciidoc | 220 ++++++++++++++++++++++++++++-- 1 file changed, 210 insertions(+), 10 deletions(-) diff --git a/docs/static/releasenotes.asciidoc b/docs/static/releasenotes.asciidoc index 1bceeab1d..57d9d13d2 100644 --- a/docs/static/releasenotes.asciidoc +++ b/docs/static/releasenotes.asciidoc @@ -17,16 +17,7 @@ coming[7.0.0] The list combines release notes from the 7.0.0-alpha1, -alpha2, -beta1, -rc1 and -rc2 releases. -[[logstash-7-0-0-rc2]] -=== Logstash 7.0.0-rc2 Release Notes - -* logstash-input-snmp - - Added support for querying SNMP tables - - Changed three error messages in the base_client to include the target address for clarity in the logs. - -[[logstash-7-0-0-rc1]] -=== Logstash 7.0.0-rc1 Release Notes - +==== Logstash core * BUGFIX: Correctly count total queued items across multiple pipelines https://github.com/elastic/logstash/pull/10564[#10564] * BUGFIX: Fix issue setting 'enable_metric => false' https://github.com/elastic/logstash/pull/10538[#10538] * BUGFIX: Prevent concurrent convergence of pipeline actions https://github.com/elastic/logstash/pull/10537[#10537] @@ -36,6 +27,208 @@ The list combines release notes from the 7.0.0-alpha1, -alpha2, -beta1, -rc1 and * Improve docs about using Filebeat modules with Logstash https://github.com/elastic/logstash/pull/10438[#10438] * Bump JRuby to 9.2.6.0 https://github.com/elastic/logstash/pull/10425[#10425] * BUGFIX: Remove exclusive lock for Ruby pipeline initialization https://github.com/elastic/logstash/pull/10462[#10462] +* Update Java dependencies https://github.com/elastic/logstash/pull/10340[#10340] +* Remove pipeline output workers setting https://github.com/elastic/logstash/pull/10358[#10358] +* Cleanup Ruby gems dependencies https://github.com/elastic/logstash/pull/10171[#10171] +* Ensure compatibility of module data with ES and Kibana 7.0 https://github.com/elastic/logstash/pull/10356[#10356] +* Rename x-pack monitoring and management config option .url and .ca to .hosts and .certificate_authority https://github.com/elastic/logstash/pull/10380[#10380] +* BUGFIX: building of deb and rpm artifacts https://github.com/elastic/logstash/pull/10396[#10396] +* Make Java execution the default https://github.com/elastic/logstash/pull/8649[#8649] +* Field-reference parsing is now strict by default https://github.com/elastic/logstash/pull/9543[#9543] +* Improvements to core Javaification +* BUGFIX: Support for Byte, Short and Date type conversions as seen in the rabbitmq input plugin https://github.com/elastic/logstash/pull/9984[#9984] + +==== Plugins +Here are the plugin changes. + +===== Codec plugins +* logstash-codec-cef + - Removed obsolete `sev` and `deprecated_v1_fields` fields + - Fixed minor doc inconsistencies (added reverse_mapping to options table, moved it to alpha order in option descriptions, fixed typo) + https://github.com/logstash-plugins/logstash-codec-cef/pull/60[#60] +* logstash-codec-es_bulk + - Add documentation about use with http input +* logstash-codec-netflow + - Fix sub-second timestamp math + - BREAKING: Added support for RFC6759 decoding of application_id. This is a breaking change to the way application_id is decoded. The format changes from e.g. 0:40567 to 0..12356..40567 + - Fixed IPFIX options template parsing for Juniper MX240 JunOS 15.1 + - Fixed incorrect parsing of zero-filled Netflow 9 packets from Palo Alto + - Added support for Netflow v9 devices with VarString fields (H3C Netstream) + - Reduced complexity of creating, persisting, loading an retrieving template caches + - Fixed issue where TTL in template registry was not being respected + - Added Cisco ACI to list of known working Netflow v9 exporters + - Added support for IXIA Packet Broker IPFIX + - Fixed issue with Procera float fields + +===== Filter plugins +* logstash-filter-aggregate + - new feature: add ability to dynamically define a custom `timeout` or `inactivity_timeout` in `code` block (fix issues https://github.com/logstash-plugins/logstash-filter-aggregate/issues/91[#91] and https://github.com/logstash-plugins/logstash-filter-aggregate/issues/92[#92]) + - new feature: add meta informations available in `code` block through `map_meta` variable + - new feature: add Logstash metrics, specific to aggregate plugin: aggregate_maps, pushed_events, task_timeouts, code_errors, timeout_code_errors + - new feature: validate at startup that `map_action` option equals to 'create', 'update' or 'create_or_update' +* logstash-filter-clone + - Make 'clones' a required option + - Added a warning when 'clones' is empty since that results in a no-op https://github.com/logstash-plugins/logstash-filter-clone/issues/14[#14] +* logstash-filter-de_dot + - fix failure of fieldnames with boolean value "false" +* logstash-filter-dns + - Fixed issue where unqualified domains would fail to resolve when running this plugin with Logstash 5.x https://github.com/logstash-plugins/logstash-filter-dns/pull/48[#48] + - Fixed crash that could occur when encountering certain classes of invalid inputs https://github.com/logstash-plugins/logstash-filter-dns/pull/49[#49] +* logstash-filter-elasticsearch + - Add support for extracting hits total from Elasticsearch 7.x responses + - Added connection check during register to avoid failures during processing + - Changed Elasticsearch Client transport to use Manticore + - Changed amount of logging details during connection failure +* logstash-filter-fingerprint + - Fixed concurrent SHA fingerprinting by making the instances thread local +* logstash-filter-geoip + - Removed obsolete lru_cache_size field +* NEW: logstash-filter-http + - Beta version of HTTP filter plugin based on @lucashenning's https://github.com/lucashenning/logstash-filter-rest[REST filter]. + - Fixed minor documentation issues https://github.com/logstash-plugins/logstash-filter-http/pull/9[#9] + - Minor documentation fixes +* logstash-filter-jdbc_static + - Added info to documentation to emphasize significance of table order https://github.com/logstash-plugins/logstash-filter-jdbc_static/pull/36[36] +* logstash-filter-jdbc_streaming + - Swap out mysql for postgresql for testing https://github.com/logstash-plugins/logstash-filter-jdbc_streaming/pull/11[#11] +* logstash-filter-json + - Updated documentation with some clarifications and fixes +* logstash-filter-kv + - Added a timeout enforcer which prevents inputs that are pathological against the generated parser from blocking + the pipeline. By default, timeout is a generous 30s, but can be configured or disabled entirely with the new + `timeout_millis` and `tag_on_timeout` directives https://github.com/logstash-plugins/logstash-filter-kv/pull/79[#79] + - Made error-handling configurable with `tag_on_failure` directive. +* NEW: logstash-filter-memcached + - Updated to 1.0.0 + - The plugin common options (e.g., `add_field`, `add_tag`, etc.) are now correctly only invoked when the plugin successfully gets one or more values from, or sets one or more values to memcached (#4) + - Fix links to argument types in documentation (#3) +* logstash-filter-metrics + - Fixed two minor typos in documentation +* logstash-filter-mutate + - Added ability to directly convert from integer and float to boolean https://github.com/logstash-plugins/logstash-filter-mutate/pull/127[#127] +* logstash-filter-split + - Fixed numeric values, optimized @target verification, cleanups and specs https://github.com/logstash-plugins/logstash-filter-split/pull/36[#36] +* logstash-filter-xml + - Fixed creation of empty arrays when xpath failed https://github.com/logstash-plugins/logstash-filter-xml/pull/59[#59] + - Fixed force_array behavior with nested elements https://github.com/logstash-plugins/logstash-filter-xml/pull/57[#57] + +===== Input plugins +* logstash-input-azure_event_hubs + - Updated Azure event hub library dependencies https://github.com/logstash-plugins/logstash-input-azure_event_hubs/pull/27[#27] +* logstash-input-beats + - Removed obsolete setting congestion_threshold and target_field_for_codec + - Changed default value of `add_hostname` to false + - Loosen jar-dependencies manager gem dependency to allow plugin to work with JRubies that include a later version + - Updated jar dependencies to reflect newer releases +* logstash-input-elasticsearch + - Added managed slice scrolling with `slices` option +* logstash-input-file + - Fixed problem in Windows where some paths would fail to return an identifier ("inode"). Make path into a C style String before encoding to UTF-16LE. https://github.com/logstash-plugins/logstash-input-file/issues/232[#232] + - Fixed issue where logs were being spammed with needless error messages https://github.com/logstash-plugins/logstash-input-file/pull/224[#224] + - Fixed problem in tail and read modes where the read loop could get stuck if an IO error occurs in the loop. + The file appears to be being read but it is not, suspected with file truncation schemes. + https://github.com/logstash-plugins/logstash-input-file/issues/205[#205] + - Fixed problem in rotation handling where the target file being rotated was + subjected to the start_position setting when it must always start from the beginning. + https://github.com/logstash-plugins/logstash-input-file/issues/214[#214] +* logstash-input-gelf + - Fixed shutdown handling, robustness in socket closing and restarting, json parsing, code DRYing and cleanups https://github.com/logstash-plugins/logstash-input-gelf/pull/62[#62] +* logstash-input-http + - Added configurable response code option https://github.com/logstash-plugins/logstash-input-http/pull/103[#103] + - Added explanation about operation order of codec and additional_codecs https://github.com/logstash-plugins/logstash-input-http/pull/104[#104] + - Added configurable response code option https://github.com/logstash-plugins/logstash-input-http/pull/103[#103] + - Added explanation about operation order of codec and additional_codecs https://github.com/logstash-plugins/logstash-input-http/pull/104[#104] + - Loosen jar-dependencies manager gem dependency to allow plugin to work with JRubies that include a later version. + - Changed jar dependencies to reflect newer versions +* logstash-input-http_poller + - Fixed minor doc and doc formatting issues https://github.com/logstash-plugins/logstash-input-http_poller/pull/107[#107] + - Removed obsolete field `interval` + - Changed `schedule` entry to show that it is required + https://github.com/logstash-plugins/logstash-input-http_poller/pull/102[#102] +* logstash-input-kafka + - Removed obsolete `ssl` option + - Added support for kafka property ssl.endpoint.identification.algorithm https://github.com/logstash-plugins/logstash-input-kafka/pull/302[#302] + - Changed Kafka client version to 2.1.0 + - Changed Kafka client version to 2.0.1 https://github.com/logstash-plugins/logstash-input-kafka/pull/295[#295] +* logstash-input-snmp + - Added no_codec condition to the documentation and bumped version https://github.com/logstash-plugins/logstash-input-snmp/pull/39[#39] + - Changed docs to improve options layout https://github.com/logstash-plugins/logstash-input-snmp/pull/38[#38] + - Added support for querying SNMP tables + - Changed three error messages in the base_client to include the target address for clarity in the logs. +* logstash-input-sqs + - Added support for multiple events inside same message from SQS https://github.com/logstash-plugins/logstash-input-sqs/pull/48[#48] +* logstash-input-tcp + - Removed obsolete `data_timeout` and `ssl_cacert` options + - Fixed race condition where data would be accepted before queue was configured + - Support multiple certificates per file https://github.com/logstash-plugins/logstash-input-tcp/pull/140[#140] + +===== Output plugins +* logstash-output-elasticsearch + - Remove support for parent child (still support join data type) since we don't support multiple document types any more + - Removed obsolete `flush_size` and `idle_flush_time` + - Added 'auto' setting for ILM with default of 'auto' https://github.com/logstash-plugins/logstash-output-elasticsearch/pull/838[#838] + - Fixed sniffing support for 7.x https://github.com/logstash-plugins/logstash-output-elasticsearch/pull/827[#827] + - Fixed issue with escaping index names which was causing writing aliases for ILM to fail https://github.com/logstash-plugins/logstash-output-elasticsearch/pull/831[#831] + - Adds support for Index Lifecycle Management for Elasticsearch 6.6.0 and above, running with at least a Basic License(Beta) https://github.com/logstash-plugins/logstash-output-elasticsearch/pull/805[#805] + - Fixed support for Elasticsearch 7.x https://github.com/logstash-plugins/logstash-output-elasticsearch/pull/812[#812] + - Tweaked logging statements to reduce verbosity + - Fixed numerous issues relating to builds on Travis https://github.com/logstash-plugins/logstash-output-elasticsearch/pull/799[#799] +* logstash-output-file + - Removed JRuby check when using FIFOs https://github.com/logstash-plugins/logstash-output-file/pull/75[#75] +* logstash-output-http + - Relax dependency on http_client mixin since current major works on both + - Fixed handling of empty `retryable_codes` https://github.com/logstash-plugins/logstash-output-http/pull/99[#99] +* logstash-output-kafka + - Fixed issue with unnecessary sleep after retries exhausted https://github.com/logstash-plugins/logstash-output-kafka/pull/216[#216] + - Removed obsolete `block_on_buffer_full`, `ssl` and `timeout_ms` options + - Added support for kafka property `ssl.endpoint.identification.algorithm` https://github.com/logstash-plugins/logstash-output-kafka/pull/213[#213] + - Changed Kafka client to version 2.1.0 + - Changed Kafka client to version 2.0.1 https://github.com/logstash-plugins/logstash-output-kafka/pull/209[#209] +* logstash-output-pagerduty + - Update _development_ dependency webmock to latest version to prevent conflicts in logstash core's dependency matrix. +* logstash-output-redis + - Removed obsolete fields `queue` and `name` + - Changed major version of redis library dependency to 4.x +* logstash-output-s3 + - Add support for setting mutipart upload threshold https://github.com/logstash-plugins/logstash-output-s3/pull/202[#202] + - Fixed issue where on restart, 0 byte files could erroneously be uploaded to s3 https://github.com/logstash-plugins/logstash-output-s3/issues/195[#195] +* logstash-output-sqs + - Removed obsolete fields `batch` and `batch_timeout` + - Removed workaround to JRuby bug https://github.com/jruby/jruby/issues/3645[#3645] +* logstash-output-tcp + - Removed obsolete field `message_format` + - Removed requirement to have a certificate/key pair when enabling ssl + + +* logstash-mixin-http_client + - Removed obsolete ssl_certificate_verify option + + + + +[[logstash-7-0-0-rc2]] +=== Logstash 7.0.0-rc2 Release Notes + +==== Plugins +* logstash-input-snmp + - Added support for querying SNMP tables + - Changed three error messages in the base_client to include the target address for clarity in the logs. + +[[logstash-7-0-0-rc1]] +=== Logstash 7.0.0-rc1 Release Notes + +==== Logstash core +* BUGFIX: Correctly count total queued items across multiple pipelines https://github.com/elastic/logstash/pull/10564[#10564] +* BUGFIX: Fix issue setting 'enable_metric => false' https://github.com/elastic/logstash/pull/10538[#10538] +* BUGFIX: Prevent concurrent convergence of pipeline actions https://github.com/elastic/logstash/pull/10537[#10537] +* Monitoring: Change internal document type to push "_doc" instead of "doc" https://github.com/elastic/logstash/pull/10533[#10533] +* BUGFIX: Allow explicitly-specified Java codecs https://github.com/elastic/logstash/pull/10520[#10520] +* Central management typeless API https://github.com/elastic/logstash/pull/10421[#10421] +* Improve docs about using Filebeat modules with Logstash https://github.com/elastic/logstash/pull/10438[#10438] +* Bump JRuby to 9.2.6.0 https://github.com/elastic/logstash/pull/10425[#10425] +* BUGFIX: Remove exclusive lock for Ruby pipeline initialization https://github.com/elastic/logstash/pull/10462[#10462] + +==== Plugins * logstash-filter-dns - Fixed issue where unqualified domains would fail to resolve when running this plugin with Logstash 5.x https://github.com/logstash-plugins/logstash-filter-dns/pull/48[#48] - Fixed crash that could occur when encountering certain classes of invalid inputs https://github.com/logstash-plugins/logstash-filter-dns/pull/49[#49] @@ -59,12 +252,15 @@ The list combines release notes from the 7.0.0-alpha1, -alpha2, -beta1, -rc1 and [[logstash-7-0-0-beta1]] === Logstash 7.0.0-beta1 Release Notes +==== Logstash core * Update Java dependencies https://github.com/elastic/logstash/pull/10340[#10340] * Remove pipeline output workers setting https://github.com/elastic/logstash/pull/10358[#10358] * Cleanup Ruby gems dependencies https://github.com/elastic/logstash/pull/10171[#10171] * Ensure compatibility of module data with ES and Kibana 7.0 https://github.com/elastic/logstash/pull/10356[#10356] * Rename x-pack monitoring and management config option .url and .ca to .hosts and .certificate_authority https://github.com/elastic/logstash/pull/10380[#10380] * BUGFIX: building of deb and rpm artifacts https://github.com/elastic/logstash/pull/10396[#10396] + +==== Plugins * logstash-codec-cef - Removed obsolete `sev` and `deprecated_v1_fields` fields - Fixed minor doc inconsistencies (added reverse_mapping to options table, moved it to alpha order in option descriptions, fixed typo) @@ -145,6 +341,7 @@ The list combines release notes from the 7.0.0-alpha1, -alpha2, -beta1, -rc1 and [[logstash-7-0-0-alpha2]] === Logstash 7.0.0-alpha2 Release Notes +==== Plugins * logstash-filter-elasticsearch - Add support for extracting hits total from Elasticsearch 7.x responses - Added connection check during register to avoid failures during processing @@ -185,10 +382,13 @@ The list combines release notes from the 7.0.0-alpha1, -alpha2, -beta1, -rc1 and [[logstash-7-0-0-alpha1]] === Logstash 7.0.0-alpha1 Release Notes +==== Logstash core * Make Java execution the default https://github.com/elastic/logstash/pull/8649[#8649] * Field-reference parsing is now strict by default https://github.com/elastic/logstash/pull/9543[#9543] * Improvements to core Javaification * BUGFIX: Support for Byte, Short and Date type conversions as seen in the rabbitmq input plugin https://github.com/elastic/logstash/pull/9984[#9984] + +==== Plugins * logstash-codec-netflow - BREAKING: Added support for RFC6759 decoding of application_id. This is a breaking change to the way application_id is decoded. The format changes from e.g. 0:40567 to 0..12356..40567 - Fixed IPFIX options template parsing for Juniper MX240 JunOS 15.1 From f9e2f2369d9ab0cb76a2cbd066dfcbd62bb9fd84 Mon Sep 17 00:00:00 2001 From: Karen Metts Date: Mon, 8 Apr 2019 19:20:56 -0400 Subject: [PATCH 0069/1126] Add links to particular breaking changes Fixes #10668 --- docs/static/upgrading.asciidoc | 8 +++----- 1 file changed, 3 insertions(+), 5 deletions(-) diff --git a/docs/static/upgrading.asciidoc b/docs/static/upgrading.asciidoc index 24292d736..61528d1ff 100644 --- a/docs/static/upgrading.asciidoc +++ b/docs/static/upgrading.asciidoc @@ -108,11 +108,9 @@ Before upgrading Logstash: + There you can find info on these topics and more: -** Java execution engine enabled by default -** Field parser is more strict and how that affects processing -** Beats conforms to the Elastic Common Schema (ECS) and how that impacts {ls} - -//TO DO: ^^ Add links <> and <> and <> after breaking changes are merged +** <> +** <> +** <> If you are installing Logstash with other components in the Elastic Stack, also see the {stack-ref}/index.html[Elastic Stack installation and upgrade documentation]. From d1e41f3908238695c1c5f7143dfe2bc5f4f38453 Mon Sep 17 00:00:00 2001 From: lcawl Date: Wed, 10 Apr 2019 08:57:51 -0700 Subject: [PATCH 0070/1126] [DOCS] Removes coming tags --- docs/static/breaking-changes.asciidoc | 2 -- docs/static/releasenotes.asciidoc | 2 -- docs/static/upgrading.asciidoc | 2 -- 3 files changed, 6 deletions(-) diff --git a/docs/static/breaking-changes.asciidoc b/docs/static/breaking-changes.asciidoc index aabc6c585..8fc007239 100644 --- a/docs/static/breaking-changes.asciidoc +++ b/docs/static/breaking-changes.asciidoc @@ -27,8 +27,6 @@ See also <>. [[breaking-7.0]] === Breaking changes in 7.0 -coming[7.0.0] - Here are the breaking changes for {ls} 7.0. // tag::notable-breaking-changes[] diff --git a/docs/static/releasenotes.asciidoc b/docs/static/releasenotes.asciidoc index 57d9d13d2..684348ea3 100644 --- a/docs/static/releasenotes.asciidoc +++ b/docs/static/releasenotes.asciidoc @@ -13,8 +13,6 @@ This section summarizes the changes in the following releases: [[logstash-7-0-0]] === Logstash 7.0.0 Release Notes -coming[7.0.0] - The list combines release notes from the 7.0.0-alpha1, -alpha2, -beta1, -rc1 and -rc2 releases. ==== Logstash core diff --git a/docs/static/upgrading.asciidoc b/docs/static/upgrading.asciidoc index 61528d1ff..b46d7891d 100644 --- a/docs/static/upgrading.asciidoc +++ b/docs/static/upgrading.asciidoc @@ -99,8 +99,6 @@ supported. [[upgrading-logstash-7.0]] === Upgrading Logstash to 7.0 -coming[7.0.0] - Before upgrading Logstash: * Read the <>. From 25158bdddd7e6946b09027243c8eaf85d714f51f Mon Sep 17 00:00:00 2001 From: Dan Hermann Date: Wed, 10 Apr 2019 08:43:10 -0500 Subject: [PATCH 0071/1126] Correctly sets the default codec to java_line. Fixes buffer handling for events whose encodings do not fit into the buffer. Fixes #10673 --- .../org/logstash/plugins/outputs/Stdout.java | 4 ++-- .../logstash/plugins/outputs/StdoutTest.java | 21 +++++++++++++++++++ 2 files changed, 23 insertions(+), 2 deletions(-) diff --git a/logstash-core/src/main/java/org/logstash/plugins/outputs/Stdout.java b/logstash-core/src/main/java/org/logstash/plugins/outputs/Stdout.java index 20e998d27..c124fbf4c 100644 --- a/logstash-core/src/main/java/org/logstash/plugins/outputs/Stdout.java +++ b/logstash-core/src/main/java/org/logstash/plugins/outputs/Stdout.java @@ -20,7 +20,7 @@ import java.util.concurrent.CountDownLatch; public class Stdout implements Output { public static final PluginConfigSpec CODEC_CONFIG = - PluginConfigSpec.codecSetting("codec", "java-line"); + PluginConfigSpec.codecSetting("codec", "java_line"); private Codec codec; private OutputStream outputStream; @@ -57,7 +57,7 @@ public class Stdout implements Output { do { encodeCompleted = codec.encode(e, encodeBuffer); outputStream.write(encodeBuffer.array(), encodeBuffer.position(), encodeBuffer.limit()); - encodeBuffer.flip(); + encodeBuffer.clear(); } while (!encodeCompleted); } diff --git a/logstash-core/src/test/java/org/logstash/plugins/outputs/StdoutTest.java b/logstash-core/src/test/java/org/logstash/plugins/outputs/StdoutTest.java index 9744b6bb8..9f243c474 100644 --- a/logstash-core/src/test/java/org/logstash/plugins/outputs/StdoutTest.java +++ b/logstash-core/src/test/java/org/logstash/plugins/outputs/StdoutTest.java @@ -2,6 +2,7 @@ package org.logstash.plugins.outputs; import co.elastic.logstash.api.Event; import com.fasterxml.jackson.core.JsonProcessingException; +import org.junit.Assert; import org.junit.Test; import org.logstash.plugins.ConfigurationImpl; import org.logstash.plugins.TestContext; @@ -69,4 +70,24 @@ public class StdoutTest { e3.setField("myField", "event3"); return Arrays.asList(e1, e2, e3); } + + @Test + public void testEventLargerThanBuffer() { + StringBuilder message = new StringBuilder(); + String repeatedMessage = "foo"; + for (int k = 0; k < (16 * 1024 / repeatedMessage.length()); k++) { + message.append("foo"); + } + + org.logstash.Event e = new org.logstash.Event(); + e.setField("message", message.toString()); + + OutputStream dummyOutputStream = new ByteArrayOutputStream(17 * 1024); + Stdout stdout = new Stdout(ID, new ConfigurationImpl(Collections.emptyMap(), new TestPluginFactory()), + new TestContext(), dummyOutputStream); + stdout.output(Collections.singletonList(e)); + stdout.stop(); + + Assert.assertTrue(dummyOutputStream.toString().contains(message.toString())); + } } From 42515508268b96e47fba72b4a160bd02fc551d1d Mon Sep 17 00:00:00 2001 From: Jordan Johnson-Doyle Date: Fri, 29 Mar 2019 00:04:23 +0000 Subject: [PATCH 0072/1126] Collect and expose metrics from Java codecs Fixes #10614 --- .../lib/logstash/api/commands/stats.rb | 1 + .../ir/compiler/JavaCodecDelegator.java | 130 ++++++++++++++++++ .../logstash/plugins/PluginFactoryExt.java | 3 +- 3 files changed, 133 insertions(+), 1 deletion(-) create mode 100644 logstash-core/src/main/java/org/logstash/config/ir/compiler/JavaCodecDelegator.java diff --git a/logstash-core/lib/logstash/api/commands/stats.rb b/logstash-core/lib/logstash/api/commands/stats.rb index 2c6790667..3e43501a4 100644 --- a/logstash-core/lib/logstash/api/commands/stats.rb +++ b/logstash-core/lib/logstash/api/commands/stats.rb @@ -115,6 +115,7 @@ module LogStash :events => stats[:events], :plugins => { :inputs => plugin_stats(stats, :inputs), + :codecs => plugin_stats(stats, :codecs), :filters => plugin_stats(stats, :filters), :outputs => plugin_stats(stats, :outputs) }, diff --git a/logstash-core/src/main/java/org/logstash/config/ir/compiler/JavaCodecDelegator.java b/logstash-core/src/main/java/org/logstash/config/ir/compiler/JavaCodecDelegator.java new file mode 100644 index 000000000..f47e4068b --- /dev/null +++ b/logstash-core/src/main/java/org/logstash/config/ir/compiler/JavaCodecDelegator.java @@ -0,0 +1,130 @@ +package org.logstash.config.ir.compiler; + +import co.elastic.logstash.api.Codec; +import co.elastic.logstash.api.Event; +import co.elastic.logstash.api.PluginConfigSpec; +import org.jruby.RubySymbol; +import org.jruby.runtime.ThreadContext; +import org.logstash.RubyUtil; +import org.logstash.instrument.metrics.AbstractNamespacedMetricExt; +import org.logstash.instrument.metrics.MetricKeys; +import org.logstash.instrument.metrics.counter.LongCounter; + +import java.nio.ByteBuffer; +import java.util.Collection; +import java.util.Map; +import java.util.concurrent.TimeUnit; +import java.util.function.Consumer; + +public class JavaCodecDelegator implements Codec { + + public static final RubySymbol ENCODE_KEY = RubyUtil.RUBY.newSymbol("encode"); + public static final RubySymbol DECODE_KEY = RubyUtil.RUBY.newSymbol("decode"); + public static final RubySymbol IN_KEY = RubyUtil.RUBY.newSymbol("writes_in"); + + private final String configName; + + private final String id; + + private final Codec codec; + + protected final AbstractNamespacedMetricExt metricEncode; + + protected final AbstractNamespacedMetricExt metricDecode; + + protected final LongCounter encodeMetricIn; + + protected final LongCounter encodeMetricTime; + + protected final LongCounter decodeMetricIn; + + protected final LongCounter decodeMetricOut; + + protected final LongCounter decodeMetricTime; + + + public JavaCodecDelegator(final String configName, final String id, + final AbstractNamespacedMetricExt metric, + final Codec codec) { + this.configName = configName; + this.id = id; + this.codec = codec; + + final ThreadContext context = RubyUtil.RUBY.getCurrentContext(); + final AbstractNamespacedMetricExt namespacedMetric = + metric.namespace(context, RubyUtil.RUBY.newSymbol(codec.getId())); + synchronized(namespacedMetric.getMetric()) { + metricEncode = namespacedMetric.namespace(context, ENCODE_KEY); + encodeMetricIn = LongCounter.fromRubyBase(metricEncode, IN_KEY); + encodeMetricTime = LongCounter.fromRubyBase(metricEncode, MetricKeys.DURATION_IN_MILLIS_KEY); + + metricDecode = namespacedMetric.namespace(context, DECODE_KEY); + decodeMetricIn = LongCounter.fromRubyBase(metricDecode, IN_KEY); + decodeMetricOut = LongCounter.fromRubyBase(metricDecode, MetricKeys.OUT_KEY); + decodeMetricTime = LongCounter.fromRubyBase(metricDecode, MetricKeys.DURATION_IN_MILLIS_KEY); + + namespacedMetric.gauge(context, MetricKeys.NAME_KEY, RubyUtil.RUBY.newString(configName)); + } + } + + @Override + public void decode(final ByteBuffer buffer, final Consumer> eventConsumer) { + decodeMetricIn.increment(); + + final long start = System.nanoTime(); + + codec.decode(buffer, (event) -> { + decodeMetricOut.increment(); + eventConsumer.accept(event); + }); + + decodeMetricTime.increment(TimeUnit.MILLISECONDS.convert(System.nanoTime() - start, TimeUnit.NANOSECONDS)); + } + + @Override + public void flush(final ByteBuffer buffer, final Consumer> eventConsumer) { + decodeMetricIn.increment(); + + final long start = System.nanoTime(); + + codec.flush(buffer, (event) -> { + decodeMetricOut.increment(); + eventConsumer.accept(event); + }); + + decodeMetricTime.increment(TimeUnit.MILLISECONDS.convert(System.nanoTime() - start, TimeUnit.NANOSECONDS)); + } + + @Override + public boolean encode(final Event event, final ByteBuffer buffer) throws EncodeException { + encodeMetricIn.increment(); + + final long start = System.nanoTime(); + + final boolean ret = codec.encode(event, buffer); + + decodeMetricTime.increment(TimeUnit.MILLISECONDS.convert(System.nanoTime() - start, TimeUnit.NANOSECONDS)); + + return ret; + } + + @Override + public Codec cloneCodec() { + return codec.cloneCodec(); + } + + @Override + public Collection> configSchema() { + return codec.configSchema(); + } + + @Override + public String getName() { + return codec.getName(); + } + + @Override + public String getId() { + return codec.getId(); + } +} diff --git a/logstash-core/src/main/java/org/logstash/plugins/PluginFactoryExt.java b/logstash-core/src/main/java/org/logstash/plugins/PluginFactoryExt.java index 1176058fa..790c9b0e5 100644 --- a/logstash-core/src/main/java/org/logstash/plugins/PluginFactoryExt.java +++ b/logstash-core/src/main/java/org/logstash/plugins/PluginFactoryExt.java @@ -26,6 +26,7 @@ import org.logstash.config.ir.PipelineIR; import org.logstash.config.ir.compiler.AbstractFilterDelegatorExt; import org.logstash.config.ir.compiler.AbstractOutputDelegatorExt; import org.logstash.config.ir.compiler.FilterDelegatorExt; +import org.logstash.config.ir.compiler.JavaCodecDelegator; import org.logstash.config.ir.compiler.JavaFilterDelegatorExt; import org.logstash.config.ir.compiler.JavaInputDelegatorExt; import org.logstash.config.ir.compiler.JavaOutputDelegatorExt; @@ -338,7 +339,7 @@ public final class PluginFactoryExt { } if (codec != null) { - return JavaUtil.convertJavaToRuby(RubyUtil.RUBY, codec); + return JavaUtil.convertJavaToRuby(RubyUtil.RUBY, new JavaCodecDelegator(name, id, typeScopedMetric, codec)); } else { throw new IllegalStateException("Unable to instantiate codec: " + pluginClass); } From b53e3132022690da508d61a82b4264611fa78ced Mon Sep 17 00:00:00 2001 From: Jordan Johnson-Doyle Date: Sat, 30 Mar 2019 17:27:38 +0000 Subject: [PATCH 0073/1126] Collect and expose metrics from Ruby codecs Fixes #10614 --- .../lib/logstash/codecs/delegator.rb | 52 +++++++++++++++++++ logstash-core/lib/logstash/config/mixin.rb | 3 +- logstash-core/lib/logstash/inputs/base.rb | 7 +++ logstash-core/lib/logstash/outputs/base.rb | 7 +++ .../metrics/AbstractNamespacedMetricExt.java | 5 ++ 5 files changed, 73 insertions(+), 1 deletion(-) create mode 100644 logstash-core/lib/logstash/codecs/delegator.rb diff --git a/logstash-core/lib/logstash/codecs/delegator.rb b/logstash-core/lib/logstash/codecs/delegator.rb new file mode 100644 index 000000000..2cbb440c5 --- /dev/null +++ b/logstash-core/lib/logstash/codecs/delegator.rb @@ -0,0 +1,52 @@ +module LogStash::Codecs + class Delegator < SimpleDelegator + def initialize(obj) + super(obj) + @encode_metric = LogStash::Instrument::NamespacedNullMetric.new + @decode_metric = LogStash::Instrument::NamespacedNullMetric.new + end + + def class + __getobj__.class + end + + def metric=(metric) + __getobj__.metric = metric + + __getobj__.metric.gauge(:name, __getobj__.class.config_name) + + @encode_metric = __getobj__.metric.namespace(:encode) + @encode_metric.counter(:writes_in) + @encode_metric.report_time(:duration_in_millis, 0) + + @decode_metric = __getobj__.metric.namespace(:decode) + @decode_metric.counter(:writes_in) + @decode_metric.counter(:out) + @decode_metric.report_time(:duration_in_millis, 0) + end + + def encode(event) + @encode_metric.increment(:writes_in) + @encode_metric.time(:duration_in_millis) do + __getobj__.encode(event) + end + end + + def multi_encode(events) + @encode_metric.increment(:writes_in, events.length) + @encode_metric.time(:duration_in_millis) do + __getobj__.multi_encode(events) + end + end + + def decode(data) + @decode_metric.increment(:writes_in) + @decode_metric.time(:duration_in_millis) do + __getobj__.decode(data) do |event| + @decode_metric.increment(:out) + yield event + end + end + end + end +end diff --git a/logstash-core/lib/logstash/config/mixin.rb b/logstash-core/lib/logstash/config/mixin.rb index 30fb44d75..621ef9e0c 100644 --- a/logstash-core/lib/logstash/config/mixin.rb +++ b/logstash-core/lib/logstash/config/mixin.rb @@ -4,6 +4,7 @@ require "logstash/util/safe_uri" require "logstash/version" require "logstash/environment" require "logstash/util/plugin_version" +require "logstash/codecs/delegator" require "filesize" LogStash::Environment.load_locale! @@ -410,7 +411,7 @@ module LogStash::Config::Mixin case validator when :codec if value.first.is_a?(String) - value = LogStash::Plugin.lookup("codec", value.first).new + value = LogStash::Codecs::Delegator.new LogStash::Plugin.lookup("codec", value.first).new return true, value else value = value.first diff --git a/logstash-core/lib/logstash/inputs/base.rb b/logstash-core/lib/logstash/inputs/base.rb index 2a8ee97e7..50878ffff 100644 --- a/logstash-core/lib/logstash/inputs/base.rb +++ b/logstash-core/lib/logstash/inputs/base.rb @@ -99,6 +99,13 @@ class LogStash::Inputs::Base < LogStash::Plugin cloned end + def metric=(metric) + super + # Hack to create a new metric namespace using 'plugins' as the root + @codec.metric = metric.root.namespace(metric.namespace_name[0...-2].push(:codecs, codec.id)) + metric + end + def execution_context=(context) super # There is no easy way to propage an instance variable into the codec, because the codec diff --git a/logstash-core/lib/logstash/outputs/base.rb b/logstash-core/lib/logstash/outputs/base.rb index 1efc8b079..34abe972c 100644 --- a/logstash-core/lib/logstash/outputs/base.rb +++ b/logstash-core/lib/logstash/outputs/base.rb @@ -102,6 +102,13 @@ class LogStash::Outputs::Base < LogStash::Plugin self.class.concurrency end + def metric=(metric) + super + # Hack to create a new metric namespace using 'plugins' as the root + @codec.metric = metric.root.namespace(metric.namespace_name[0...-2].push(:codecs, codec.id)) + metric + end + def execution_context=(context) super # There is no easy way to propage an instance variable into the codec, because the codec diff --git a/logstash-core/src/main/java/org/logstash/instrument/metrics/AbstractNamespacedMetricExt.java b/logstash-core/src/main/java/org/logstash/instrument/metrics/AbstractNamespacedMetricExt.java index 414b05b99..5d1051e82 100644 --- a/logstash-core/src/main/java/org/logstash/instrument/metrics/AbstractNamespacedMetricExt.java +++ b/logstash-core/src/main/java/org/logstash/instrument/metrics/AbstractNamespacedMetricExt.java @@ -56,6 +56,11 @@ public abstract class AbstractNamespacedMetricExt extends AbstractMetricExt { return getNamespaceName(context); } + @JRubyMethod(name = "root") + public AbstractMetricExt root(final ThreadContext context) { + return getMetric(); + } + protected abstract IRubyObject getGauge(ThreadContext context, IRubyObject key, IRubyObject value); From 81f7e421958ce1bfcc29a88eb55c7adbd1bf9497 Mon Sep 17 00:00:00 2001 From: Jordan Johnson-Doyle Date: Mon, 1 Apr 2019 12:37:57 +0100 Subject: [PATCH 0074/1126] Add tests for JavaCodecDelegator Fixes #10614 --- logstash-core/build.gradle | 2 + .../ir/compiler/JavaCodecDelegator.java | 11 +- .../logstash/plugins/PluginFactoryExt.java | 2 +- .../logstash/config/ir/RubyEnvTestCase.java | 3 + .../ir/compiler/JavaCodecDelegatorTest.java | 243 ++++++++++++++++++ .../ir/compiler/OutputDelegatorTest.java | 58 +---- .../ir/compiler/PluginDelegatorTestCase.java | 71 +++++ 7 files changed, 329 insertions(+), 61 deletions(-) create mode 100644 logstash-core/src/test/java/org/logstash/config/ir/compiler/JavaCodecDelegatorTest.java create mode 100644 logstash-core/src/test/java/org/logstash/config/ir/compiler/PluginDelegatorTestCase.java diff --git a/logstash-core/build.gradle b/logstash-core/build.gradle index d3e26879c..307ef48ec 100644 --- a/logstash-core/build.gradle +++ b/logstash-core/build.gradle @@ -69,6 +69,7 @@ task javaTests(type: Test) { exclude '/org/logstash/config/ir/ConfigCompilerTest.class' exclude '/org/logstash/config/ir/CompiledPipelineTest.class' exclude '/org/logstash/config/ir/compiler/OutputDelegatorTest.class' + exclude '/org/logstash/config/ir/compiler/JavaCodecDelegatorTest.class' } task rubyTests(type: Test) { @@ -79,6 +80,7 @@ task rubyTests(type: Test) { include '/org/logstash/config/ir/ConfigCompilerTest.class' include '/org/logstash/config/ir/CompiledPipelineTest.class' include '/org/logstash/config/ir/compiler/OutputDelegatorTest.class' + include '/org/logstash/config/ir/compiler/JavaCodecDelegatorTest.class' } test { diff --git a/logstash-core/src/main/java/org/logstash/config/ir/compiler/JavaCodecDelegator.java b/logstash-core/src/main/java/org/logstash/config/ir/compiler/JavaCodecDelegator.java index f47e4068b..e65ce23ef 100644 --- a/logstash-core/src/main/java/org/logstash/config/ir/compiler/JavaCodecDelegator.java +++ b/logstash-core/src/main/java/org/logstash/config/ir/compiler/JavaCodecDelegator.java @@ -22,10 +22,6 @@ public class JavaCodecDelegator implements Codec { public static final RubySymbol DECODE_KEY = RubyUtil.RUBY.newSymbol("decode"); public static final RubySymbol IN_KEY = RubyUtil.RUBY.newSymbol("writes_in"); - private final String configName; - - private final String id; - private final Codec codec; protected final AbstractNamespacedMetricExt metricEncode; @@ -43,11 +39,8 @@ public class JavaCodecDelegator implements Codec { protected final LongCounter decodeMetricTime; - public JavaCodecDelegator(final String configName, final String id, - final AbstractNamespacedMetricExt metric, + public JavaCodecDelegator(final AbstractNamespacedMetricExt metric, final Codec codec) { - this.configName = configName; - this.id = id; this.codec = codec; final ThreadContext context = RubyUtil.RUBY.getCurrentContext(); @@ -63,7 +56,7 @@ public class JavaCodecDelegator implements Codec { decodeMetricOut = LongCounter.fromRubyBase(metricDecode, MetricKeys.OUT_KEY); decodeMetricTime = LongCounter.fromRubyBase(metricDecode, MetricKeys.DURATION_IN_MILLIS_KEY); - namespacedMetric.gauge(context, MetricKeys.NAME_KEY, RubyUtil.RUBY.newString(configName)); + namespacedMetric.gauge(context, MetricKeys.NAME_KEY, RubyUtil.RUBY.newString(codec.getName())); } } diff --git a/logstash-core/src/main/java/org/logstash/plugins/PluginFactoryExt.java b/logstash-core/src/main/java/org/logstash/plugins/PluginFactoryExt.java index 790c9b0e5..15453c5de 100644 --- a/logstash-core/src/main/java/org/logstash/plugins/PluginFactoryExt.java +++ b/logstash-core/src/main/java/org/logstash/plugins/PluginFactoryExt.java @@ -339,7 +339,7 @@ public final class PluginFactoryExt { } if (codec != null) { - return JavaUtil.convertJavaToRuby(RubyUtil.RUBY, new JavaCodecDelegator(name, id, typeScopedMetric, codec)); + return JavaUtil.convertJavaToRuby(RubyUtil.RUBY, new JavaCodecDelegator(typeScopedMetric, codec)); } else { throw new IllegalStateException("Unable to instantiate codec: " + pluginClass); } diff --git a/logstash-core/src/test/java/org/logstash/config/ir/RubyEnvTestCase.java b/logstash-core/src/test/java/org/logstash/config/ir/RubyEnvTestCase.java index 4470c8cd8..ed954bcc5 100644 --- a/logstash-core/src/test/java/org/logstash/config/ir/RubyEnvTestCase.java +++ b/logstash-core/src/test/java/org/logstash/config/ir/RubyEnvTestCase.java @@ -3,10 +3,13 @@ package org.logstash.config.ir; import java.nio.file.Path; import java.nio.file.Paths; import org.jruby.RubyHash; +import org.jruby.runtime.builtin.IRubyObject; import org.jruby.runtime.load.LoadService; import org.junit.BeforeClass; import org.logstash.RubyUtil; +import static org.logstash.RubyUtil.RUBY; + public abstract class RubyEnvTestCase { @BeforeClass diff --git a/logstash-core/src/test/java/org/logstash/config/ir/compiler/JavaCodecDelegatorTest.java b/logstash-core/src/test/java/org/logstash/config/ir/compiler/JavaCodecDelegatorTest.java new file mode 100644 index 000000000..aef26ccd3 --- /dev/null +++ b/logstash-core/src/test/java/org/logstash/config/ir/compiler/JavaCodecDelegatorTest.java @@ -0,0 +1,243 @@ +package org.logstash.config.ir.compiler; + +import co.elastic.logstash.api.Codec; +import co.elastic.logstash.api.Event; +import co.elastic.logstash.api.PluginConfigSpec; +import com.google.common.collect.ImmutableMap; +import org.jruby.RubyHash; +import org.junit.Before; +import org.junit.Test; +import org.mockito.Mockito; + +import java.nio.ByteBuffer; +import java.util.Collection; +import java.util.Map; +import java.util.function.Consumer; + +import static org.junit.Assert.assertEquals; + +public class JavaCodecDelegatorTest extends PluginDelegatorTestCase { + private Codec codec; + + @Before + public void setup() { + this.codec = Mockito.mock(AbstractCodec.class); + Mockito.when(this.codec.getId()).thenCallRealMethod(); + Mockito.when(this.codec.getName()).thenCallRealMethod(); + + super.setup(); + } + + @Override + protected String getBaseMetricsPath() { + return "codec/foo"; + } + + @Test + public void plainCodecDelegatorInitializesCleanly() { + constructCodecDelegator(); + } + + @Test + public void plainCodecPluginPushesPluginNameToMetric() { + constructCodecDelegator(); + final RubyHash metricStore = getMetricStore(new String[]{"codec", "foo"}); + final String pluginName = getMetricStringValue(metricStore, "name"); + + assertEquals(codec.getName(), pluginName); + } + + @Test + public void delegatesClone() { + final JavaCodecDelegator codecDelegator = constructCodecDelegator(); + codecDelegator.cloneCodec(); + Mockito.verify(codec, Mockito.times(1)).cloneCodec(); + } + + @Test + public void delegatesConfigSchema() { + final JavaCodecDelegator codecDelegator = constructCodecDelegator(); + codecDelegator.configSchema(); + Mockito.verify(codec, Mockito.times(1)).configSchema(); + } + + @Test + public void delegatesGetName() { + Mockito.when(codec.getName()).thenReturn("MyLogstashPluginName"); + final JavaCodecDelegator codecDelegator = constructCodecDelegator(); + assertEquals("MyLogstashPluginName", codecDelegator.getName()); + } + + @Test + public void delegatesGetId() { + Mockito.when(codec.getId()).thenReturn("MyLogstashPluginId"); + final JavaCodecDelegator codecDelegator = constructCodecDelegator(); + assertEquals("MyLogstashPluginId", codecDelegator.getId()); + } + + @Test + public void decodeDelegatesCall() { + final Map ret = ImmutableMap.of("message", "abcdef"); + + codec = Mockito.spy(new AbstractCodec() { + @Override + public void decode(final ByteBuffer buffer, final Consumer> eventConsumer) { + eventConsumer.accept(ret); + } + }); + + final JavaCodecDelegator codecDelegator = constructCodecDelegator(); + + final ByteBuffer buf = ByteBuffer.wrap(new byte[] {1, 2, 3}); + @SuppressWarnings("unchecked") + final Consumer> consumer = (Consumer>) Mockito.mock(Consumer.class); + + codecDelegator.decode(buf, consumer); + + Mockito.verify(codec, Mockito.times(1)).decode(Mockito.eq(buf), Mockito.any()); + Mockito.verify(consumer, Mockito.times(1)).accept(ret); + } + + @Test + public void decodeIncrementsEventCount() { + codec = new AbstractCodec() { + @Override + public void decode(final ByteBuffer buffer, final Consumer> eventConsumer) { + eventConsumer.accept(ImmutableMap.of("message", "abcdef")); + eventConsumer.accept(ImmutableMap.of("message", "1234567")); + } + }; + + final JavaCodecDelegator codecDelegator = constructCodecDelegator(); + + codecDelegator.decode(ByteBuffer.wrap(new byte[] {1, 2, 3}), (e) -> {}); + + assertEquals(1, getMetricLongValue("decode", "writes_in")); + assertEquals(2, getMetricLongValue("decode", "out")); + } + + @Test + public void flushDelegatesCall() { + final Map ret = ImmutableMap.of("message", "abcdef"); + + codec = Mockito.spy(new AbstractCodec() { + @Override + public void flush(final ByteBuffer buffer, final Consumer> eventConsumer) { + eventConsumer.accept(ret); + } + }); + + final JavaCodecDelegator codecDelegator = constructCodecDelegator(); + + final ByteBuffer buf = ByteBuffer.wrap(new byte[] {1, 2, 3}); + @SuppressWarnings("unchecked") + final Consumer> consumer = (Consumer>) Mockito.mock(Consumer.class); + + codecDelegator.flush(buf, consumer); + + Mockito.verify(codec, Mockito.times(1)).flush(Mockito.eq(buf), Mockito.any()); + Mockito.verify(consumer, Mockito.times(1)).accept(ret); + } + + @Test + public void flushIncrementsEventCount() { + codec = new AbstractCodec() { + @Override + public void flush(final ByteBuffer buffer, final Consumer> eventConsumer) { + eventConsumer.accept(ImmutableMap.of("message", "abcdef")); + eventConsumer.accept(ImmutableMap.of("message", "1234567")); + } + }; + + final JavaCodecDelegator codecDelegator = constructCodecDelegator(); + + codecDelegator.flush(ByteBuffer.wrap(new byte[] {1, 2, 3}), (e) -> {}); + + assertEquals(1, getMetricLongValue("decode", "writes_in")); + assertEquals(2, getMetricLongValue("decode", "out")); + } + + @Test + public void encodeDelegatesCall() throws Codec.EncodeException { + codec = Mockito.spy(new AbstractCodec() { + @Override + public boolean encode(final Event event, final ByteBuffer buffer) { + return true; + } + }); + + final JavaCodecDelegator codecDelegator = constructCodecDelegator(); + + final Event e = new org.logstash.Event(); + final ByteBuffer b = ByteBuffer.wrap(new byte[] {}); + + codecDelegator.encode(e, b); + + Mockito.verify(codec, Mockito.times(1)).encode(e, b); + } + + @Test + public void encodeIncrementsEventCount() throws Codec.EncodeException { + codec = new AbstractCodec() { + @Override + public boolean encode(final Event event, final ByteBuffer buffer) { + return true; + } + }; + + final JavaCodecDelegator codecDelegator = constructCodecDelegator(); + + codecDelegator.encode(new org.logstash.Event(), ByteBuffer.wrap(new byte[] {})); + + assertEquals(1, getMetricLongValue("encode", "writes_in")); + } + + private RubyHash getMetricStore(final String type) { + return getMetricStore(new String[]{"codec", "foo", type}); + } + + private long getMetricLongValue(final String type, final String symbolName) { + return getMetricLongValue(getMetricStore(type), symbolName); + } + + private JavaCodecDelegator constructCodecDelegator() { + return new JavaCodecDelegator(metric, codec); + } + + private abstract class AbstractCodec implements Codec { + @Override + public void decode(final ByteBuffer buffer, final Consumer> eventConsumer) { + throw new UnsupportedOperationException(); + } + + @Override + public void flush(final ByteBuffer buffer, final Consumer> eventConsumer) { + throw new UnsupportedOperationException(); + } + + @Override + public boolean encode(final Event event, final ByteBuffer buffer) throws EncodeException { + throw new UnsupportedOperationException(); + } + + @Override + public Codec cloneCodec() { + throw new UnsupportedOperationException(); + } + + @Override + public Collection> configSchema() { + throw new UnsupportedOperationException(); + } + + @Override + public String getId() { + return "foo"; + } + + @Override + public String getName() { + return "bar"; + } + } +} diff --git a/logstash-core/src/test/java/org/logstash/config/ir/compiler/OutputDelegatorTest.java b/logstash-core/src/test/java/org/logstash/config/ir/compiler/OutputDelegatorTest.java index 8c098f806..f2ecf3957 100644 --- a/logstash-core/src/test/java/org/logstash/config/ir/compiler/OutputDelegatorTest.java +++ b/logstash-core/src/test/java/org/logstash/config/ir/compiler/OutputDelegatorTest.java @@ -4,33 +4,23 @@ import javax.annotation.concurrent.NotThreadSafe; import org.assertj.core.data.Percentage; import org.jruby.RubyArray; import org.jruby.RubyClass; -import org.jruby.RubyFixnum; import org.jruby.RubyHash; -import org.jruby.RubyString; import org.jruby.RubySymbol; -import org.jruby.java.proxies.ConcreteJavaProxy; import org.jruby.runtime.ThreadContext; import org.jruby.runtime.builtin.IRubyObject; import org.junit.Before; import org.junit.Test; import org.logstash.Event; -import org.logstash.config.ir.RubyEnvTestCase; -import org.logstash.execution.ExecutionContextExt; -import org.logstash.instrument.metrics.NamespacedMetricExt; import static org.assertj.core.api.Assertions.assertThat; import static org.junit.Assert.assertEquals; -import static org.logstash.RubyUtil.EXECUTION_CONTEXT_CLASS; -import static org.logstash.RubyUtil.NAMESPACED_METRIC_CLASS; import static org.logstash.RubyUtil.RUBY; import static org.logstash.RubyUtil.RUBY_OUTPUT_DELEGATOR_CLASS; @SuppressWarnings("rawtypes") @NotThreadSafe -public class OutputDelegatorTest extends RubyEnvTestCase { +public class OutputDelegatorTest extends PluginDelegatorTestCase { - private NamespacedMetricExt metric; - private ExecutionContextExt executionContext; private RubyHash pluginArgs; private RubyArray events; private static final int EVENT_COUNT = 7; @@ -43,25 +33,21 @@ public class OutputDelegatorTest extends RubyEnvTestCase { @Before public void setup() { + super.setup(); events = RUBY.newArray(EVENT_COUNT); for (int k = 0; k < EVENT_COUNT; k++) { events.add(k, new Event()); } - final ThreadContext context = RUBY.getCurrentContext(); - RubyArray namespaces = RubyArray.newArray(RUBY, 1); - namespaces.add(0, RubySymbol.newSymbol(RUBY, "output")); - IRubyObject metricWithCollector = - runRubyScript("require \"logstash/instrument/collector\"\n" + - "metricWithCollector = LogStash::Instrument::Metric.new(LogStash::Instrument::Collector.new)"); - - metric = new NamespacedMetricExt(RUBY, NAMESPACED_METRIC_CLASS) - .initialize(context, metricWithCollector, namespaces); - executionContext = new ExecutionContextExt(RUBY, EXECUTION_CONTEXT_CLASS); pluginArgs = RubyHash.newHash(RUBY); pluginArgs.put("id", "foo"); pluginArgs.put("arg1", "val1"); } + @Override + protected String getBaseMetricsPath() { + return "output/foo"; + } + @Test public void plainOutputPluginInitializesCleanly() { constructOutputDelegator(); @@ -183,11 +169,6 @@ public class OutputDelegatorTest extends RubyEnvTestCase { } - private static IRubyObject runRubyScript(String script) { - IRubyObject m = RUBY.evalScriptlet(script); - return m; - } - private OutputDelegatorExt constructOutputDelegator() { return new OutputDelegatorExt(RUBY, RUBY_OUTPUT_DELEGATOR_CLASS).initialize(RUBY.getCurrentContext(), new IRubyObject[]{ FAKE_OUT_CLASS, @@ -202,35 +183,10 @@ public class OutputDelegatorTest extends RubyEnvTestCase { return getMetricStore(new String[]{"output", "foo", "events"}); } - private RubyHash getMetricStore(String[] path) { - RubyHash metricStore = (RubyHash) metric.collector(RUBY.getCurrentContext()) - .callMethod(RUBY.getCurrentContext(), "snapshot_metric") - .callMethod(RUBY.getCurrentContext(), "metric_store") - .callMethod(RUBY.getCurrentContext(), "get_with_path", new IRubyObject[]{RUBY.newString("output/foo")}); - - RubyHash rh = metricStore; - for (String p : path) { - rh = (RubyHash) rh.op_aref(RUBY.getCurrentContext(), RUBY.newSymbol(p)); - } - return rh; - } - - private String getMetricStringValue(RubyHash metricStore, String symbolName) { - ConcreteJavaProxy counter = (ConcreteJavaProxy) metricStore.op_aref(RUBY.getCurrentContext(), RUBY.newSymbol(symbolName)); - RubyString value = (RubyString) counter.callMethod("value"); - return value.asJavaString(); - } - private long getMetricLongValue(String symbolName) { return getMetricLongValue(getMetricStore(), symbolName); } - private long getMetricLongValue(RubyHash metricStore, String symbolName) { - ConcreteJavaProxy counter = (ConcreteJavaProxy) metricStore.op_aref(RUBY.getCurrentContext(), RUBY.newSymbol(symbolName)); - RubyFixnum count = (RubyFixnum) counter.callMethod("value"); - return count.getLongValue(); - } - private static class StrategyPair { RubySymbol symbol; Class klazz; diff --git a/logstash-core/src/test/java/org/logstash/config/ir/compiler/PluginDelegatorTestCase.java b/logstash-core/src/test/java/org/logstash/config/ir/compiler/PluginDelegatorTestCase.java new file mode 100644 index 000000000..d3d282ab6 --- /dev/null +++ b/logstash-core/src/test/java/org/logstash/config/ir/compiler/PluginDelegatorTestCase.java @@ -0,0 +1,71 @@ +package org.logstash.config.ir.compiler; + +import org.jruby.RubyArray; +import org.jruby.RubyFixnum; +import org.jruby.RubyHash; +import org.jruby.RubyString; +import org.jruby.RubySymbol; +import org.jruby.java.proxies.ConcreteJavaProxy; +import org.jruby.runtime.ThreadContext; +import org.jruby.runtime.builtin.IRubyObject; +import org.junit.Before; +import org.logstash.config.ir.RubyEnvTestCase; +import org.logstash.execution.ExecutionContextExt; +import org.logstash.instrument.metrics.AbstractNamespacedMetricExt; +import org.logstash.instrument.metrics.NamespacedMetricExt; + +import static org.logstash.RubyUtil.EXECUTION_CONTEXT_CLASS; +import static org.logstash.RubyUtil.NAMESPACED_METRIC_CLASS; +import static org.logstash.RubyUtil.RUBY; + +public abstract class PluginDelegatorTestCase extends RubyEnvTestCase { + protected AbstractNamespacedMetricExt metric; + protected ExecutionContextExt executionContext; + + @Before + public void setup() { + final ThreadContext context = RUBY.getCurrentContext(); + @SuppressWarnings("rawtypes") + final RubyArray namespaces = RubyArray.newArray(RUBY, 1); + namespaces.add(0, RubySymbol.newSymbol(RUBY, getBaseMetricsPath().split("/")[0])); + IRubyObject metricWithCollector = + runRubyScript("require \"logstash/instrument/collector\"\n" + + "metricWithCollector = LogStash::Instrument::Metric.new(LogStash::Instrument::Collector.new)"); + + metric = new NamespacedMetricExt(RUBY, NAMESPACED_METRIC_CLASS) + .initialize(context, metricWithCollector, namespaces); + executionContext = new ExecutionContextExt(RUBY, EXECUTION_CONTEXT_CLASS); + } + + protected static IRubyObject runRubyScript(String script) { + IRubyObject m = RUBY.evalScriptlet(script); + return m; + } + + protected RubyHash getMetricStore(String[] path) { + RubyHash metricStore = (RubyHash) metric.collector(RUBY.getCurrentContext()) + .callMethod(RUBY.getCurrentContext(), "snapshot_metric") + .callMethod(RUBY.getCurrentContext(), "metric_store") + .callMethod(RUBY.getCurrentContext(), "get_with_path", new IRubyObject[]{RUBY.newString(getBaseMetricsPath())}); + + RubyHash rh = metricStore; + for (String p : path) { + rh = (RubyHash) rh.op_aref(RUBY.getCurrentContext(), RUBY.newSymbol(p)); + } + return rh; + } + + protected abstract String getBaseMetricsPath(); + + protected String getMetricStringValue(RubyHash metricStore, String symbolName) { + ConcreteJavaProxy counter = (ConcreteJavaProxy) metricStore.op_aref(RUBY.getCurrentContext(), RUBY.newSymbol(symbolName)); + RubyString value = (RubyString) counter.callMethod("value"); + return value.asJavaString(); + } + + protected long getMetricLongValue(RubyHash metricStore, String symbolName) { + ConcreteJavaProxy counter = (ConcreteJavaProxy) metricStore.op_aref(RUBY.getCurrentContext(), RUBY.newSymbol(symbolName)); + RubyFixnum count = (RubyFixnum) counter.callMethod("value"); + return count.getLongValue(); + } +} From d332bc33aaa4d959a0dfb436659af6974b1f3551 Mon Sep 17 00:00:00 2001 From: Jordan Johnson-Doyle Date: Mon, 1 Apr 2019 13:18:25 +0100 Subject: [PATCH 0075/1126] Add tests for LogStash::Codec::Delegator Fixes #10614 --- .../spec/logstash/codecs/delegator_spec.rb | 85 +++++++++++++++++++ 1 file changed, 85 insertions(+) create mode 100644 logstash-core/spec/logstash/codecs/delegator_spec.rb diff --git a/logstash-core/spec/logstash/codecs/delegator_spec.rb b/logstash-core/spec/logstash/codecs/delegator_spec.rb new file mode 100644 index 000000000..c5702ee94 --- /dev/null +++ b/logstash-core/spec/logstash/codecs/delegator_spec.rb @@ -0,0 +1,85 @@ +# encoding: utf-8 +require "spec_helper" + +class LogStash::Codecs::MockCodec < LogStash::Codecs::Base + config_name "my_name" + + def multi_encode(e) + end + + def encode(e) + end + + def decode(e) + for i in e.split('|') + yield i + end + end +end + +describe LogStash::Codecs::Delegator do + let(:collector) { LogStash::Instrument::Collector.new } + let(:metric) { LogStash::Instrument::Metric.new(collector) } + let(:codec) { LogStash::Codecs::MockCodec.new } + + subject do + delegator = described_class.new(codec) + delegator.metric = metric.namespace([:stats, :pipelines, :main, :plugins, :codecs, :my_id]) + delegator + end + + let(:snapshot_store) { collector.snapshot_metric.metric_store } + + let(:snapshot_metric) { snapshot_store.get_shallow(:stats) } + + describe "#encode" do + it "should delegate call to codec" do + expect(codec).to receive(:encode).with("abcdef") + subject.encode("abcdef") + end + + it "should increment metrics" do + subject.encode("test") + expect(snapshot_metric[:pipelines][:main][:plugins][:codecs][:my_id][:encode][:writes_in].value).to eq(1) + end + end + + describe "#multi_encode" do + it "should delegate call to codec" do + expect(codec).to receive(:multi_encode).with(%w(ay laa)) + subject.multi_encode(%w(ay laa)) + end + + it "should increment metrics" do + subject.multi_encode(%w(ay test)) + expect(snapshot_metric[:pipelines][:main][:plugins][:codecs][:my_id][:encode][:writes_in].value).to eq(2) + end + end + + describe "#decode" do + it "should delegate call to codec" do + expect(codec).to receive(:decode).with("ayooooo") + subject.decode("ayooooo") + end + + it "should increment metrics" do + subject.decode("bird|law") {} + expect(snapshot_metric[:pipelines][:main][:plugins][:codecs][:my_id][:decode][:writes_in].value).to eq(1) + expect(snapshot_metric[:pipelines][:main][:plugins][:codecs][:my_id][:decode][:out].value).to eq(2) + end + end + + describe "#close" do + it "should delegate call to codec" do + expect(codec).to receive(:close) + subject.close + end + end + + describe "#plugin_type" do + it "should delegate call to codec" do + expect(codec).to receive(:plugin_type) + subject.plugin_type + end + end +end \ No newline at end of file From 78ea83ec07f390b0c487aff0dc93ad802201bdc8 Mon Sep 17 00:00:00 2001 From: Jordan Johnson-Doyle Date: Tue, 9 Apr 2019 16:34:23 +0100 Subject: [PATCH 0076/1126] Inputs expect a NamespacedMetric, not the root metric instance Fixes #10614 --- x-pack/spec/monitoring/inputs/metrics_spec.rb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/x-pack/spec/monitoring/inputs/metrics_spec.rb b/x-pack/spec/monitoring/inputs/metrics_spec.rb index 5ca0e9ac4..873ca282f 100644 --- a/x-pack/spec/monitoring/inputs/metrics_spec.rb +++ b/x-pack/spec/monitoring/inputs/metrics_spec.rb @@ -81,7 +81,7 @@ describe LogStash::Inputs::Metrics do wait(60).for { agent.get_pipeline(:main) }.to_not be_nil - metrics_input.metric = agent.metric + metrics_input.metric = agent.metric.namespace(:test) metrics_input.register metrics_input.run(queue) From f39e4a94462f621d7990e85e28520d60625a4f12 Mon Sep 17 00:00:00 2001 From: Colin Surprenant Date: Thu, 11 Apr 2019 17:23:48 -0400 Subject: [PATCH 0077/1126] download exact version artifact for release build otherwise download snapshot (#10664) --- build.gradle | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/build.gradle b/build.gradle index 734cdc17b..8f5e1e3b4 100644 --- a/build.gradle +++ b/build.gradle @@ -99,6 +99,9 @@ def versionQualifier = System.getenv('VERSION_QUALIFIER') if (versionQualifier) { version = "$version-$versionQualifier" } +// a release build will try to download the exact version artifact and not append -SNAPSHOT to it see +// the downloadEs task below +def isReleaseBuild = System.getenv('RELEASE') == "1" || versionQualifier // Tasks @@ -330,7 +333,7 @@ task downloadEs(type: Download) { doFirst { if (!project.ext.versionFound) { - throw new GradleException("could not find the current artifact from the artifact-api ${artifactsVersionApi} for version: ${version}") + throw new GradleException("could not find the current artifact from the artifact-api ${artifactsVersionApi} for " + (isReleaseBuild ? "release" : "snapshot") + " version: ${version}") } } @@ -340,7 +343,9 @@ task downloadEs(type: Download) { // in the normal PR type builds it is plain '7.0.0' // in the build invoked by the release manager it is '7.0.0-alpha1' etc. // the artifacts-api will return JSON like this: `{"versions":["5.6.13-SNAPSHOT","6.4.3-SNAPSHOT","6.5.0-SNAPSHOT","6.6.0-SNAPSHOT","7.0.0-alpha1-SNAPSHOT"]}` - String qualifiedVersion = dlVersions['versions'].grep(~/^${version}.*/)[0] + + String qualifiedVersion = dlVersions['versions'].grep(isReleaseBuild ? ~/^${version}$/ : ~/^${version}-SNAPSHOT/)[0] + if (qualifiedVersion == null) { // the version is not found in the versions API, for now just set dummy values so the // task parameters like src and dest below sees these dummy values but also set From 62f8282a3be5c51b81a0f74c7283bf2357ff231b Mon Sep 17 00:00:00 2001 From: Joao Duarte Date: Wed, 10 Apr 2019 14:52:59 +0100 Subject: [PATCH 0078/1126] bump jruby to 9.2.7.0 Revert "work around jruby-5642 during package installation on jdk11 (#10658)" This reverts commit 033c8963301ab887037334d12b3d0968cf2ee5a8. skip the bundler-1.16.6 files when unpacking jruby Fixes #10674 --- lib/systeminstall/pleasewrap.rb | 23 ----------------------- rubyUtils.gradle | 7 ++++++- versions.yml | 4 ++-- 3 files changed, 8 insertions(+), 26 deletions(-) diff --git a/lib/systeminstall/pleasewrap.rb b/lib/systeminstall/pleasewrap.rb index 0eb05dd4a..f7ee00bd4 100755 --- a/lib/systeminstall/pleasewrap.rb +++ b/lib/systeminstall/pleasewrap.rb @@ -8,28 +8,5 @@ Gem.use_paths(LogStash::Environment.logstash_gem_home) #libdir = File.expand_path("../lib", File.dirname(__FILE__)) #$LOAD_PATH << libdir if File.exist?(File.join(libdir, "pleaserun", "cli.rb")) - -require 'open3' - -# Work around for https://github.com/elastic/logstash/issues/10593 -# Issue on JRUBY https://github.com/jruby/jruby/issues/5642 -# Workaround retrieved from https://github.com/jruby/jruby/issues/5642#issuecomment-479671017 -if RUBY_ENGINE_VERSION != "9.2.6.0" - raise "A workaround is in place for JRUBY-5642 that should be applied only to JRuby 9.2.6.0, but found #{RUBY_ENGINE_VERSION}" -end -if java.lang.System.getProperty("java.version").start_with?("11") - class IO - def self.pipe - readwrite = Java::int[2].new - JRuby.runtime.posix.pipe(readwrite) - return readwrite.map do |fd| - io = IO.for_fd(fd) - io.close_on_exec = true - io - end - end - end -end - require "pleaserun/cli" exit(PleaseRun::CLI.run || 0) diff --git a/rubyUtils.gradle b/rubyUtils.gradle index 603a3356c..d208c9671 100644 --- a/rubyUtils.gradle +++ b/rubyUtils.gradle @@ -6,7 +6,7 @@ buildscript { dependencies { classpath 'org.yaml:snakeyaml:1.23' classpath "de.undercouch:gradle-download-task:3.2.0" - classpath "org.jruby:jruby-complete:9.2.6.0" + classpath "org.jruby:jruby-complete:9.2.7.0" } } @@ -235,6 +235,11 @@ task downloadAndInstallJRuby(dependsOn: [verifyFile, installCustomJRuby], type: f.path = f.path.replaceFirst("^jruby-${jRubyVersion}", '') } exclude "**/stdlib/rdoc/**" + exclude "**/stdlib/bundler/**" + exclude "**/stdlib/bundler.rb" + exclude "**/bundler-1.16.6/*" + exclude "**/bundler-1.16.6.*" + includeEmptyDirs = false into "${projectDir}/vendor/jruby" doLast { diff --git a/versions.yml b/versions.yml index cfa505279..7d730b9c4 100644 --- a/versions.yml +++ b/versions.yml @@ -7,8 +7,8 @@ logstash-core-plugin-api: 2.1.16 # jruby must reference a *released* version of jruby which can be downloaded from the official download url # *and* for which jars artifacts are published for compile-time jruby: - version: 9.2.6.0 - sha1: 3c13ec3966f6cc44966f3978c96325b9e56174f1 + version: 9.2.7.0 + sha1: dc35f9bb991f526f058bf6b9591c460f98cffe9e # jruby-runtime-override, if specified, will override the jruby version installed in vendor/jruby for logstash runtime only, # not for the compile-time jars From 86cae085471d3afd5597b8956d010169ac62c495 Mon Sep 17 00:00:00 2001 From: Joao Duarte Date: Fri, 12 Apr 2019 15:40:54 +0100 Subject: [PATCH 0079/1126] updated bundler to 1.17.3 Fixes #10685 --- build.gradle | 4 ++-- lib/bootstrap/bundler.rb | 6 +++--- rakelib/dependency.rake | 2 +- 3 files changed, 6 insertions(+), 6 deletions(-) diff --git a/build.gradle b/build.gradle index 8f5e1e3b4..da1de07f3 100644 --- a/build.gradle +++ b/build.gradle @@ -238,9 +238,9 @@ def qaBundledGemPath = "${qaVendorPath}/jruby/2.5.0" def qaBundleBin = "${qaBundledGemPath}/bin/bundle" task installIntegrationTestBundler(dependsOn: unpackTarDistribution) { - outputs.files fileTree("${qaBundledGemPath}/gems/bundler-1.17.1") + outputs.files fileTree("${qaBundledGemPath}/gems/bundler-1.17.3") doLast { - gem(projectDir, buildDir, "bundler", "1.17.1", qaBundledGemPath) + gem(projectDir, buildDir, "bundler", "1.17.3", qaBundledGemPath) } } diff --git a/lib/bootstrap/bundler.rb b/lib/bootstrap/bundler.rb index 305fbdc0f..88fe8a3a8 100644 --- a/lib/bootstrap/bundler.rb +++ b/lib/bootstrap/bundler.rb @@ -15,10 +15,10 @@ module LogStash end end - # In recent versions (currently 1.17.1) Bundler calls reset_paths! early during - # Bundler::CLI.start (https://github.com/bundler/bundler/blob/v1.17.1/lib/bundler/cli.rb#L39) + # In recent versions (currently 1.17.3) Bundler calls reset_paths! early during + # Bundler::CLI.start (https://github.com/bundler/bundler/blob/v1.17.3/lib/bundler/cli.rb#L39) # This breaks our setting up of gemfile and bundle paths, the without group setting etc - # We need to tone down this very aggressive resetter (https://github.com/bundler/bundler/blob/v1.17.1/lib/bundler.rb#L487-L500) + # We need to tone down this very aggressive resetter (https://github.com/bundler/bundler/blob/v1.17.3/lib/bundler.rb#L487-L500) # So we reimplement it here to only nullify the definition object, so that it can be computed # again if necessary with all the configuration in place. ::Bundler.module_exec do diff --git a/rakelib/dependency.rake b/rakelib/dependency.rake index 0671095bc..717f7a421 100644 --- a/rakelib/dependency.rake +++ b/rakelib/dependency.rake @@ -1,5 +1,5 @@ namespace "dependency" do task "bundler" do - Rake::Task["gem:require"].invoke("bundler", "~> 1.17.1") + Rake::Task["gem:require"].invoke("bundler", "~> 1.17.3") end end # namespace dependency From 97704dc35d501912b660abffcb5f762fe47df2e3 Mon Sep 17 00:00:00 2001 From: Joao Duarte Date: Fri, 12 Apr 2019 15:31:14 +0100 Subject: [PATCH 0080/1126] properly exclude bundler 1.16.6 Fixes #10684 --- rubyUtils.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/rubyUtils.gradle b/rubyUtils.gradle index d208c9671..c350b64ee 100644 --- a/rubyUtils.gradle +++ b/rubyUtils.gradle @@ -237,7 +237,7 @@ task downloadAndInstallJRuby(dependsOn: [verifyFile, installCustomJRuby], type: exclude "**/stdlib/rdoc/**" exclude "**/stdlib/bundler/**" exclude "**/stdlib/bundler.rb" - exclude "**/bundler-1.16.6/*" + exclude "**/bundler-1.16.6/**" exclude "**/bundler-1.16.6.*" includeEmptyDirs = false From de6ef0c04a8c3b3a2985455f6083011827cb620e Mon Sep 17 00:00:00 2001 From: Joao Duarte Date: Fri, 15 Mar 2019 17:17:04 +0000 Subject: [PATCH 0081/1126] moved to openjdk 11 in docker testing - also fix javadoc warning when building on jdk11 Fixes #10563 --- Dockerfile | 4 ++-- Dockerfile.base | 4 ++-- build.gradle | 3 +++ docker/templates/Dockerfile.j2 | 2 +- 4 files changed, 8 insertions(+), 5 deletions(-) diff --git a/Dockerfile b/Dockerfile index 233f91d3d..ee654201d 100644 --- a/Dockerfile +++ b/Dockerfile @@ -1,8 +1,8 @@ -FROM ubuntu:xenial +FROM ubuntu:bionic RUN apt-get update && \ apt-get install -y zlib1g-dev build-essential vim rake git curl libssl-dev libreadline-dev libyaml-dev \ - libxml2-dev libxslt-dev openjdk-8-jdk-headless curl iputils-ping netcat && \ + libxml2-dev libxslt-dev openjdk-11-jdk-headless curl iputils-ping netcat && \ apt-get clean WORKDIR /root diff --git a/Dockerfile.base b/Dockerfile.base index a33c1bfd2..a9c189500 100644 --- a/Dockerfile.base +++ b/Dockerfile.base @@ -1,9 +1,9 @@ #logstash-base image, use ci/docker_update_base_image.sh to push updates -FROM ubuntu:xenial +FROM ubuntu:bionic RUN apt-get update && \ apt-get install -y zlib1g-dev build-essential vim rake git curl libssl-dev libreadline-dev libyaml-dev \ - libxml2-dev libxslt-dev openjdk-8-jdk-headless curl iputils-ping netcat && \ + libxml2-dev libxslt-dev openjdk-11-jdk-headless curl iputils-ping netcat && \ apt-get clean WORKDIR /root diff --git a/build.gradle b/build.gradle index da1de07f3..5b2275e6c 100644 --- a/build.gradle +++ b/build.gradle @@ -38,6 +38,9 @@ allprojects { tasks.withType(Javadoc) { options.addStringOption("Xwerror", "-quiet") + if (JavaVersion.current().compareTo(JavaVersion.VERSION_1_9) > 0) { + options.addBooleanOption("html5", true) + } } clean { diff --git a/docker/templates/Dockerfile.j2 b/docker/templates/Dockerfile.j2 index 0bbf5ae84..66a823c16 100644 --- a/docker/templates/Dockerfile.j2 +++ b/docker/templates/Dockerfile.j2 @@ -10,7 +10,7 @@ FROM centos:7 # Install Java and the "which" command, which is needed by Logstash's shell # scripts. -RUN yum update -y && yum install -y java-1.8.0-openjdk-devel which && \ +RUN yum update -y && yum install -y java-11-openjdk-devel which && \ yum clean all # Provide a non-root user to run the process. From db80baf62c106b07a8c21a818b167cfb743ec507 Mon Sep 17 00:00:00 2001 From: Dan Hermann Date: Mon, 22 Apr 2019 07:48:51 -0500 Subject: [PATCH 0082/1126] Correct the docs for the settings file to note that Java execution defaults to true Fixes #10701 --- docs/static/settings-file.asciidoc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/static/settings-file.asciidoc b/docs/static/settings-file.asciidoc index 306f23e04..837741b6d 100644 --- a/docs/static/settings-file.asciidoc +++ b/docs/static/settings-file.asciidoc @@ -83,7 +83,7 @@ The `logstash.yml` file includes the following settings. If you are using X-Pack | `pipeline.java_execution` | Use the Java execution engine. -| false +| true | `pipeline.workers` | The number of workers that will, in parallel, execute the filter and output stages of the pipeline. From 96d2d59ab7265258e1dda9ef42dce92a5912867e Mon Sep 17 00:00:00 2001 From: Dan Hermann Date: Thu, 11 Apr 2019 11:07:56 -0500 Subject: [PATCH 0083/1126] Corrects the description of codec behavior in the output stage of Logstash pipelines Fixes #10682 --- docs/static/java-codec.asciidoc | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/docs/static/java-codec.asciidoc b/docs/static/java-codec.asciidoc index 14172b5a0..45933ab18 100644 --- a/docs/static/java-codec.asciidoc +++ b/docs/static/java-codec.asciidoc @@ -335,9 +335,10 @@ public Codec cloneCodec() { ----- The `cloneCodec` method should return an identical instance of the codec with the exception of its ID. Because codecs -may be stateful, a separate instance of each codec must be supplied to each worker thread in a pipeline. For all -pipelines with more than one worker, the `cloneCodec` method is called by the Logstash execution engine to create all -codec instances beyond the first. In the example above, the codec is cloned with the same delimiter but a different ID. +may be stateful across calls to their `decode` methods, input plugins that are multi-threaded should use a separate +instance of each codec via the `cloneCodec` method for each of their threads. Because a single codec instance is shared +across all pipeline workers in the output stage of the Logstash pipeline, codecs should _not_ retain state across calls +to their `encode` methods. In the example above, the codec is cloned with the same delimiter but a different ID. [float] ==== getId method From 71d7b7c1fbf03e6ecd868381d89b443931526068 Mon Sep 17 00:00:00 2001 From: Joao Duarte Date: Wed, 17 Apr 2019 14:28:26 +0100 Subject: [PATCH 0084/1126] rake task to generate dockerfile MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * dont include docker tasks in artifact:all * don't rebuild tar/zip if source hasn't changed * allow SKIP_PREPARE to avoid tar creation if no modifications * don't need a tarball to generate the dockerfile * remove docker tests as they weren't working anymore This commit adds a task to produce all necessary files to generate a docker image. ``` % RELEASE=1 rake artifact:dockerfile .... Dockerfile created in /tmp/elastic/logstash/build/docker % tree /tmp/elastic/logstash/build/docker /tmp/elastic/logstash/build/docker ├── Dockerfile ├── bin │   └── docker-entrypoint ├── config │   ├── log4j2.properties │   ├── logstash-full.yml │   └── pipelines.yml ├── env2yaml │   └── env2yaml └── pipeline └── default.conf % docker build --rm . ..... Step 19/20 : LABEL org.label-schema.schema-version="1.0" org.label-schema.vendor="Elastic" org.label-schema.name="logstash" org.label-schema.version="7.0.0" org.label-schema.url="https://www.elastic.co/products/logstash" org.label-schema.vcs-url="https://github.com/elastic/logstash" license="Elastic License" ---> Using cache ---> f622d7555220 Step 20/20 : ENTRYPOINT ["/usr/local/bin/docker-entrypoint"] ---> Using cache ---> b6feba7f4934 Successfully built b6feba7f4934 ``` This task works only for releases (not snapshots). This commit also adds a few tweaks to the artifacts building: Using `SKIP_PREPARE=1` in `rake artifact:tar` or `rake artifact:tar_oss` will make a check to not rebuild the tarball if there are no code modifications. These two changes are made since docker image build is new and we want to keep it out of artifact:all for a while. And if we're running these separately, we want to ensure the tarball built is used in the docker image (versus building a new one for each `rake artifact:tar` ) This means that, to generate all artifacts including docker images and dockerfile, it's necessary to run: ``` RELEASE=1 rake artifact:all SKIP_PREPARE=1 RELEASE=1 rake artifact:docker SKIP_PREPARE=1 RELEASE=1 rake artifact:docker_oss RELEASE=1 rake artifact:dockerfile ``` --- docker/Makefile | 73 +++++++++++---------- docker/README.md | 7 +- docker/requirements.txt | 1 - docker/templates/Dockerfile.j2 | 8 ++- docker/templates/docker-compose.yml.j2 | 23 ------- docker/tests/__init__.py | 0 docker/tests/conftest.py | 25 ------- docker/tests/constants.py | 16 ----- docker/tests/docker-compose.yml | 5 -- docker/tests/fixtures.py | 91 -------------------------- docker/tests/helpers.py | 8 --- docker/tests/test_basics.py | 50 -------------- docker/tests/test_entrypoint.py | 14 ---- docker/tests/test_labels.py | 15 ----- docker/tests/test_process.py | 15 ----- docker/tests/test_settings.py | 71 -------------------- rakelib/artifacts.rake | 36 ++++++++++ 17 files changed, 81 insertions(+), 377 deletions(-) delete mode 100644 docker/templates/docker-compose.yml.j2 delete mode 100644 docker/tests/__init__.py delete mode 100644 docker/tests/conftest.py delete mode 100644 docker/tests/constants.py delete mode 100644 docker/tests/docker-compose.yml delete mode 100644 docker/tests/fixtures.py delete mode 100644 docker/tests/helpers.py delete mode 100644 docker/tests/test_basics.py delete mode 100644 docker/tests/test_entrypoint.py delete mode 100644 docker/tests/test_labels.py delete mode 100644 docker/tests/test_process.py delete mode 100644 docker/tests/test_settings.py diff --git a/docker/Makefile b/docker/Makefile index bf5f74005..dd6653b74 100644 --- a/docker/Makefile +++ b/docker/Makefile @@ -3,8 +3,8 @@ ELASTIC_REGISTRY ?= docker.elastic.co export PATH := ./bin:./venv/bin:$(PATH) -# Determine the version to build. Override by setting ELASTIC_VERSION env var. -ELASTIC_VERSION := $(shell ./bin/elastic-version) +# Determine the version to build. +ELASTIC_VERSION := $(shell ../vendor/jruby/bin/jruby bin/elastic-version) ifdef STAGING_BUILD_NUM VERSION_TAG := $(ELASTIC_VERSION)-$(STAGING_BUILD_NUM) @@ -20,48 +20,64 @@ HTTPD ?= logstash-docker-artifact-server FIGLET := pyfiglet -w 160 -f puffy -all: build-from-local-artifacts build-from-local-oss-artifacts - -test: lint docker-compose - $(foreach FLAVOR, $(IMAGE_FLAVORS), \ - $(FIGLET) "test: $(FLAVOR)"; \ - ./bin/pytest tests --image-flavor=$(FLAVOR); \ - ) - -test-snapshot: - ELASTIC_VERSION=$(ELASTIC_VERSION)-SNAPSHOT make test +all: build-from-local-artifacts build-from-local-oss-artifacts public-dockerfile lint: venv flake8 tests # Build from artifacts on the local filesystem, using an http server (running # in a container) to provide the artifacts to the Dockerfile. -build-from-local-artifacts: venv dockerfile docker-compose env2yaml +build-from-local-artifacts: venv dockerfile env2yaml docker run --rm -d --name=$(HTTPD) \ -p 8000:8000 --expose=8000 -v $(ARTIFACTS_DIR):/mnt \ python:3 bash -c 'cd /mnt && python3 -m http.server' - gtimeout 120 bash -c 'until curl -s localhost:8000 > /dev/null; do sleep 1; done' + timeout 120 bash -c 'until curl -s localhost:8000 > /dev/null; do sleep 1; done' pyfiglet -f puffy -w 160 "Building: full"; \ docker build --network=host -t $(IMAGE_TAG)-full:$(VERSION_TAG) -f $(ARTIFACTS_DIR)/Dockerfile-full data/logstash || \ (docker kill $(HTTPD); false); \ docker tag $(IMAGE_TAG)-full:$(VERSION_TAG) $(IMAGE_TAG):$(VERSION_TAG); docker kill $(HTTPD) -build-from-local-oss-artifacts: venv dockerfile docker-compose env2yaml +build-from-local-oss-artifacts: venv dockerfile env2yaml docker run --rm -d --name=$(HTTPD) \ -p 8000:8000 --expose=8000 -v $(ARTIFACTS_DIR):/mnt \ python:3 bash -c 'cd /mnt && python3 -m http.server' - gtimeout 120 bash -c 'until curl -s localhost:8000 > /dev/null; do sleep 1; done' + timeout 120 bash -c 'until curl -s localhost:8000 > /dev/null; do sleep 1; done' pyfiglet -f puffy -w 160 "Building: oss"; \ docker build --network=host -t $(IMAGE_TAG)-oss:$(VERSION_TAG) -f $(ARTIFACTS_DIR)/Dockerfile-oss data/logstash || \ (docker kill $(HTTPD); false); -docker kill $(HTTPD) -demo: docker-compose clean-demo - docker-compose up +COPY_FILES = $(ARTIFACTS_DIR)/docker/config/pipelines.yml $(ARTIFACTS_DIR)/docker/config/logstash-full.yml $(ARTIFACTS_DIR)/docker/config/log4j2.properties $(ARTIFACTS_DIR)/docker/pipeline/default.conf $(ARTIFACTS_DIR)/docker/bin/docker-entrypoint $(ARTIFACTS_DIR)/docker/env2yaml/env2yaml + +$(ARTIFACTS_DIR)/docker/config/pipelines.yml: data/logstash/config/pipelines.yml +$(ARTIFACTS_DIR)/docker/config/logstash-full.yml: data/logstash/config/logstash-full.yml +$(ARTIFACTS_DIR)/docker/config/log4j2.properties: data/logstash/config/log4j2.properties +$(ARTIFACTS_DIR)/docker/pipeline/default.conf: data/logstash/pipeline/default.conf +$(ARTIFACTS_DIR)/docker/bin/docker-entrypoint: data/logstash/bin/docker-entrypoint +$(ARTIFACTS_DIR)/docker/env2yaml/env2yaml: data/logstash/env2yaml/env2yaml + +$(ARTIFACTS_DIR)/docker/%: + cp -f $< $@ + +docker_paths: + mkdir -p $(ARTIFACTS_DIR)/docker/ + mkdir -p $(ARTIFACTS_DIR)/docker/bin + mkdir -p $(ARTIFACTS_DIR)/docker/config + mkdir -p $(ARTIFACTS_DIR)/docker/env2yaml + mkdir -p $(ARTIFACTS_DIR)/docker/pipeline + +public-dockerfile: venv templates/Dockerfile.j2 docker_paths $(COPY_FILES) + jinja2 \ + -D elastic_version='$(ELASTIC_VERSION)' \ + -D version_tag='$(VERSION_TAG)' \ + -D image_flavor='full' \ + -D artifacts_dir='$(ARTIFACTS_DIR)' \ + -D release='$(RELEASE)' \ + templates/Dockerfile.j2 > $(ARTIFACTS_DIR)/docker/Dockerfile # Push the image to the dedicated push endpoint at "push.docker.elastic.co" -push: test +push: $(foreach FLAVOR, $(IMAGE_FLAVORS), \ docker tag $(IMAGE_TAG)-$(FLAVOR):$(VERSION_TAG) push.$(IMAGE_TAG)-$(FLAVOR):$(VERSION_TAG); \ docker push push.$(IMAGE_TAG)-$(FLAVOR):$(VERSION_TAG); \ @@ -111,23 +127,8 @@ dockerfile: venv templates/Dockerfile.j2 templates/Dockerfile.j2 > $(ARTIFACTS_DIR)/Dockerfile-$(FLAVOR); \ ) - -# Generate docker-compose files from Jinja2 templates. -docker-compose: venv - $(foreach FLAVOR, $(IMAGE_FLAVORS), \ - jinja2 \ - -D version_tag='$(VERSION_TAG)' \ - -D image_flavor='$(FLAVOR)' \ - templates/docker-compose.yml.j2 > docker-compose-$(FLAVOR).yml; \ - ) - ln -sf docker-compose-$(DEFAULT_IMAGE_FLAVOR).yml docker-compose.yml - -clean: clean-demo +clean: rm -f ${ARTIFACTS_DIR}/env2yaml/env2yaml ${ARTIFACTS_DIR}/Dockerfile rm -rf venv -clean-demo: docker-compose - docker-compose down - docker-compose rm --force - -.PHONY: clean clean-demo demo push test +.PHONY: clean push diff --git a/docker/README.md b/docker/README.md index 4bd6af593..ae2edfd7f 100644 --- a/docker/README.md +++ b/docker/README.md @@ -13,7 +13,7 @@ Documentation can be found on the [Elastic website](https://www.elastic.co/guide The images have been tested on Docker version 18.09.2, build 6247962 ## Requirements -A full build and test requires: +A full build requires: * Docker * GNU Make * Python 3.5 with Virtualenv @@ -29,11 +29,6 @@ rake artifact:docker rake artifact:docker_oss ``` -## Contributing, issues and testing - -Acceptance tests for the image are located in the `test` directory, and can -be invoked with `make test`. - This image is built on [Centos 7][centos-7]. [centos-7]: https://github.com/CentOS/sig-cloud-instance-images/blob/50281d86d6ed5c61975971150adfd0ede86423bb/docker/Dockerfile diff --git a/docker/requirements.txt b/docker/requirements.txt index eb42e8a6b..b75870b5b 100644 --- a/docker/requirements.txt +++ b/docker/requirements.txt @@ -1,4 +1,3 @@ -docker-compose==1.11.2 flake8==3.4.1 jinja2-cli[yaml]==0.6.0 jinja2==2.9.5 diff --git a/docker/templates/Dockerfile.j2 b/docker/templates/Dockerfile.j2 index 66a823c16..11694d50b 100644 --- a/docker/templates/Dockerfile.j2 +++ b/docker/templates/Dockerfile.j2 @@ -1,4 +1,10 @@ # This Dockerfile was generated from templates/Dockerfile.j2 +{% if release -%} +{% set url_root = 'https://artifacts.elastic.co/downloads/logstash' -%} +{% else -%} +{% set url_root = 'http://localhost:8000' -%} +{% endif -%} + {% if image_flavor == 'oss' -%} {% set tarball = 'logstash-oss-%s.tar.gz' % elastic_version -%} {% else -%} @@ -20,7 +26,7 @@ RUN groupadd --gid 1000 logstash && \ logstash # Add Logstash itself. -RUN curl -Lo - 'http://localhost:8000/'{{ tarball }} | \ +RUN curl -Lo - {{ url_root }}/{{ tarball }} | \ tar zxf - -C /usr/share && \ mv /usr/share/logstash-{{ elastic_version }} /usr/share/logstash && \ chown --recursive logstash:logstash /usr/share/logstash/ && \ diff --git a/docker/templates/docker-compose.yml.j2 b/docker/templates/docker-compose.yml.j2 deleted file mode 100644 index e228dd545..000000000 --- a/docker/templates/docker-compose.yml.j2 +++ /dev/null @@ -1,23 +0,0 @@ ---- -version: '3.0' -services: - logstash: - image: docker.elastic.co/logstash/logstash:{{ version_tag }} - volumes: - - ./examples/logstash.conf/:/usr/share/logstash/pipeline/logstash.conf - networks: - - elastic-stack - - elasticsearch: - image: docker.elastic.co/elasticsearch/elasticsearch-platinum:{{ version_tag }} - networks: - - elastic-stack - - kibana: - image: docker.elastic.co/kibana/kibana:{{ version_tag }} - ports: [ '5601:5601' ] - networks: - - elastic-stack - -networks: - elastic-stack: diff --git a/docker/tests/__init__.py b/docker/tests/__init__.py deleted file mode 100644 index e69de29bb..000000000 diff --git a/docker/tests/conftest.py b/docker/tests/conftest.py deleted file mode 100644 index b0bc563ec..000000000 --- a/docker/tests/conftest.py +++ /dev/null @@ -1,25 +0,0 @@ -from subprocess import run -import pytest -from .constants import container_name, version -import docker - -docker_engine = docker.from_env() - - -def pytest_addoption(parser): - """Customize testinfra with config options via cli args""" - # Let us specify which docker-compose-(image_flavor).yml file to use - parser.addoption('--image-flavor', action='store', default='full', - help='Docker image flavor; the suffix used in docker-compose-.yml') - - -@pytest.fixture(scope='session', autouse=True) -def start_container(): - image = 'docker.elastic.co/logstash/logstash-%s:%s' % (pytest.config.getoption('--image-flavor'), version) - docker_engine.containers.run(image, name=container_name, detach=True, stdin_open=False) - - -def pytest_unconfigure(config): - container = docker_engine.containers.get(container_name) - container.stop() - container.remove() diff --git a/docker/tests/constants.py b/docker/tests/constants.py deleted file mode 100644 index e0996dc5b..000000000 --- a/docker/tests/constants.py +++ /dev/null @@ -1,16 +0,0 @@ -import os -import pytest -from subprocess import run, PIPE - -version = run('./bin/elastic-version', stdout=PIPE).stdout.decode().strip() -version_number = version.split('-')[0] # '7.0.0-alpha1-SNAPSHOT' -> '7.0.0' -logstash_version_string = 'logstash %s' % version_number # eg. 'logstash 7.0.0' - - -try: - if len(os.environ['STAGING_BUILD_NUM']) > 0: - version += '-%s' % os.environ['STAGING_BUILD_NUM'] # eg. '5.3.0-d5b30bd7' -except KeyError: - pass - -container_name = 'logstash-test' diff --git a/docker/tests/docker-compose.yml b/docker/tests/docker-compose.yml deleted file mode 100644 index fc7939532..000000000 --- a/docker/tests/docker-compose.yml +++ /dev/null @@ -1,5 +0,0 @@ ---- -version: '3' -services: - logstash: - container_name: logstash-test diff --git a/docker/tests/fixtures.py b/docker/tests/fixtures.py deleted file mode 100644 index 8d6f1d776..000000000 --- a/docker/tests/fixtures.py +++ /dev/null @@ -1,91 +0,0 @@ -import json -import os -import yaml -from pytest import config, fixture -from .constants import container_name, version -from retrying import retry -from subprocess import run, PIPE -from time import sleep - -retry_settings = { - 'wait_fixed': 1000, - 'stop_max_attempt_number': 60 -} - - -@fixture -def logstash(host): - class Logstash: - def __init__(self): - self.version = version - self.name = container_name - self.process = host.process.get(comm='java') - self.settings_file = host.file('/usr/share/logstash/config/logstash.yml') - self.image_flavor = config.getoption('--image-flavor') - self.image = 'docker.elastic.co/logstash/logstash-%s:%s' % (self.image_flavor, version) - - if 'STAGING_BUILD_NUM' in os.environ: - self.tag = '%s-%s' % (self.version, os.environ['STAGING_BUILD_NUM']) - else: - self.tag = self.version - - self.docker_metadata = json.loads( - run(['docker', 'inspect', self.image], stdout=PIPE).stdout.decode())[0] - - def start(self, args=None): - if args: - arg_array = args.split(' ') - else: - arg_array = [] - run(['docker', 'run', '-d', '--name', self.name] + arg_array + [self.image]) - - def stop(self): - run(['docker', 'kill', self.name]) - run(['docker', 'rm', self.name]) - - def restart(self, args=None): - self.stop() - self.start(args) - - @retry(**retry_settings) - def get_node_info(self): - """Return the contents of Logstash's node info API. - - It retries for a while, since Logstash may still be coming up. - Refer: https://www.elastic.co/guide/en/logstash/master/node-info-api.html - """ - result = json.loads(host.command.check_output('curl -s http://localhost:9600/_node')) - assert 'workers' in result['pipelines']['main'] - return result - - def get_settings(self): - return yaml.load(self.settings_file.content_string) - - def run(self, command): - return host.run(command) - - def stdout_of(self, command): - return host.run(command).stdout.strip() - - def stderr_of(self, command): - return host.run(command).stderr.strip() - - def environment(self, varname): - environ = {} - for line in self.run('env').stdout.strip().split("\n"): - var, value = line.split('=') - environ[var] = value - return environ[varname] - - def get_docker_log(self): - return run(['docker', 'logs', self.name], stdout=PIPE).stdout.decode() - - @retry(**retry_settings) - def assert_in_log(self, string): - assert string in self.get_docker_log() - - @retry(**retry_settings) - def assert_not_in_log(self, string): - assert string not in self.get_docker_log() - - return Logstash() diff --git a/docker/tests/helpers.py b/docker/tests/helpers.py deleted file mode 100644 index a68eb8765..000000000 --- a/docker/tests/helpers.py +++ /dev/null @@ -1,8 +0,0 @@ -import subprocess -import os -from .constants import image, version - -try: - version += '-%s' % os.environ['STAGING_BUILD_NUM'] -except KeyError: - pass diff --git a/docker/tests/test_basics.py b/docker/tests/test_basics.py deleted file mode 100644 index 7ae50d930..000000000 --- a/docker/tests/test_basics.py +++ /dev/null @@ -1,50 +0,0 @@ -from .fixtures import logstash -from .constants import logstash_version_string - - -def test_logstash_is_the_correct_version(logstash): - assert logstash_version_string in logstash.stdout_of('logstash --version') - - -def test_the_default_user_is_logstash(logstash): - assert logstash.stdout_of('whoami') == 'logstash' - - -def test_that_the_user_home_directory_is_usr_share_logstash(logstash): - assert logstash.environment('HOME') == '/usr/share/logstash' - - -def test_locale_variables_are_set_correctly(logstash): - assert logstash.environment('LANG') == 'en_US.UTF-8' - assert logstash.environment('LC_ALL') == 'en_US.UTF-8' - - -def test_opt_logstash_is_a_symlink_to_usr_share_logstash(logstash): - assert logstash.stdout_of('realpath /opt/logstash') == '/usr/share/logstash' - - -def test_all_logstash_files_are_owned_by_logstash(logstash): - assert logstash.stdout_of('find /usr/share/logstash ! -user logstash') == '' - - -def test_logstash_user_is_uid_1000(logstash): - assert logstash.stdout_of('id -u logstash') == '1000' - - -def test_logstash_user_is_gid_1000(logstash): - assert logstash.stdout_of('id -g logstash') == '1000' - - -def test_logging_config_does_not_log_to_files(logstash): - assert logstash.stdout_of('grep RollingFile /logstash/config/log4j2.properties') == '' - - -# REF: https://docs.openshift.com/container-platform/3.5/creating_images/guidelines.html -def test_all_files_in_logstash_directory_are_gid_zero(logstash): - bad_files = logstash.stdout_of('find /usr/share/logstash ! -gid 0').split() - assert len(bad_files) is 0 - - -def test_all_directories_in_logstash_directory_are_setgid(logstash): - bad_dirs = logstash.stdout_of('find /usr/share/logstash -type d ! -perm /g+s').split() - assert len(bad_dirs) is 0 diff --git a/docker/tests/test_entrypoint.py b/docker/tests/test_entrypoint.py deleted file mode 100644 index f17f50f61..000000000 --- a/docker/tests/test_entrypoint.py +++ /dev/null @@ -1,14 +0,0 @@ -from .fixtures import logstash -import pytest - - -@pytest.mark.xfail -def test_whitespace_in_config_string_cli_flag(logstash): - config = 'input{heartbeat{}} output{stdout{}}' - assert logstash.run("-t -e '%s'" % config).rc == 0 - - -def test_running_an_arbitrary_command(logstash): - result = logstash.run('uname --all') - assert result.rc == 0 - assert 'GNU/Linux' in str(result.stdout) diff --git a/docker/tests/test_labels.py b/docker/tests/test_labels.py deleted file mode 100644 index 97d8ff59d..000000000 --- a/docker/tests/test_labels.py +++ /dev/null @@ -1,15 +0,0 @@ -from .fixtures import logstash - - -def test_labels(logstash): - labels = logstash.docker_metadata['Config']['Labels'] - assert labels['org.label-schema.name'] == 'logstash' - assert labels['org.label-schema.schema-version'] == '1.0' - assert labels['org.label-schema.url'] == 'https://www.elastic.co/products/logstash' - assert labels['org.label-schema.vcs-url'] == 'https://github.com/elastic/logstash' - assert labels['org.label-schema.vendor'] == 'Elastic' - assert labels['org.label-schema.version'] == logstash.tag - if logstash.image_flavor == 'oss': - assert labels['license'] == 'Apache-2.0' - else: - assert labels['license'] == 'Elastic License' diff --git a/docker/tests/test_process.py b/docker/tests/test_process.py deleted file mode 100644 index 574fcd46e..000000000 --- a/docker/tests/test_process.py +++ /dev/null @@ -1,15 +0,0 @@ -from .fixtures import logstash - - -def test_process_is_pid_1(logstash): - assert logstash.process.pid == 1 - - -def test_process_is_running_as_the_correct_user(logstash): - assert logstash.process.user == 'logstash' - - -def test_process_is_running_with_cgroup_override_flags(logstash): - # REF: https://github.com/elastic/logstash-docker/pull/97 - assert '-Dls.cgroup.cpu.path.override=/' in logstash.process.args - assert '-Dls.cgroup.cpuacct.path.override=/' in logstash.process.args diff --git a/docker/tests/test_settings.py b/docker/tests/test_settings.py deleted file mode 100644 index 885296648..000000000 --- a/docker/tests/test_settings.py +++ /dev/null @@ -1,71 +0,0 @@ -from .fixtures import logstash -from retrying import retry -import time - - -def test_setting_pipeline_workers_from_environment(logstash): - logstash.restart(args='-e pipeline.workers=6') - assert logstash.get_node_info()['pipelines']['main']['workers'] == 6 - - -def test_setting_pipeline_batch_size_from_environment(logstash): - logstash.restart(args='-e pipeline.batch.size=123') - assert logstash.get_node_info()['pipelines']['main']['batch_size'] == 123 - - -def test_setting_pipeline_batch_delay_from_environment(logstash): - logstash.restart(args='-e pipeline.batch.delay=36') - assert logstash.get_node_info()['pipelines']['main']['batch_delay'] == 36 - - -def test_setting_pipeline_unsafe_shutdown_from_environment(logstash): - logstash.restart(args='-e pipeline.unsafe_shutdown=true') - assert logstash.get_settings()['pipeline.unsafe_shutdown'] is True - - -def test_setting_pipeline_unsafe_shutdown_with_shell_style_variable(logstash): - logstash.restart(args='-e PIPELINE_UNSAFE_SHUTDOWN=true') - assert logstash.get_settings()['pipeline.unsafe_shutdown'] is True - - -def test_setting_things_with_upcased_and_underscored_env_vars(logstash): - logstash.restart(args='-e PIPELINE_BATCH_DELAY=24') - assert logstash.get_node_info()['pipelines']['main']['batch_delay'] == 24 - - -def test_disabling_xpack_monitoring_via_environment(logstash): - logstash.restart(args='-e xpack.monitoring.enabled=false') - assert logstash.get_settings()['xpack.monitoring.enabled'] is False - - -def test_enabling_java_execution_via_environment(logstash): - logstash.restart(args='-e pipeline.java_execution=true') - logstash.assert_in_log('logstash.javapipeline') - - -def test_disabling_java_execution_via_environment(logstash): - logstash.restart(args='-e pipeline.java_execution=true') - logstash.assert_not_in_log('logstash.javapipeline') - - -def test_setting_elasticsearch_urls_as_an_array(logstash): - setting_string = '["http://node1:9200","http://node2:9200"]' - logstash.restart(args='-e xpack.monitoring.elasticsearch.hosts=%s' % setting_string) - live_setting = logstash.get_settings()['xpack.monitoring.elasticsearch.hosts'] - assert type(live_setting) is list - assert 'http://node1:9200' in live_setting - assert 'http://node2:9200' in live_setting - - -def test_invalid_settings_in_environment_are_ignored(logstash): - logstash.restart(args='-e cheese.ftw=true') - assert not logstash.settings_file.contains('cheese.ftw') - - -def test_settings_file_is_untouched_when_no_settings_in_env(logstash): - original_timestamp = logstash.settings_file.mtime - original_hash = logstash.settings_file.sha256sum - logstash.restart() - time.sleep(1) # since mtime() has one second resolution - assert logstash.settings_file.mtime == original_timestamp - assert logstash.settings_file.sha256sum == original_hash diff --git a/rakelib/artifacts.rake b/rakelib/artifacts.rake index d8ae1455a..9c38cd3df 100644 --- a/rakelib/artifacts.rake +++ b/rakelib/artifacts.rake @@ -92,6 +92,18 @@ namespace "artifact" do end.flatten.uniq end + def source_modified_since?(time, excluder=nil) + skip_list = ["logstash-core-plugin-api/versions-gem-copy.yml", "logstash-core/versions-gem-copy.yml"] + result = false + files(excluder).each do |file| + next if File.mtime(file) < time || skip_list.include?(file) + puts "file modified #{file}" + result = true + break + end + result + end + desc "Generate rpm, deb, tar and zip artifacts" task "all" => ["prepare", "build"] @@ -179,6 +191,12 @@ namespace "artifact" do build_docker(true) end + desc "Generate Dockerfile for default image" + task "dockerfile" => ["prepare", "generate_build_metadata"] do + puts("[dockerfile] Building Dockerfile") + build_dockerfile + end + # Auxiliary tasks task "build" => [:generate_build_metadata] do Rake::Task["artifact:gems"].invoke unless SNAPSHOT_BUILD @@ -190,6 +208,8 @@ namespace "artifact" do Rake::Task["artifact:zip_oss"].invoke Rake::Task["artifact:tar"].invoke Rake::Task["artifact:tar_oss"].invoke + #Rake::Task["artifact:docker"].invoke + #Rake::Task["artifact:docker_oss"].invoke end task "generate_build_metadata" do @@ -271,6 +291,10 @@ namespace "artifact" do require "archive/tar/minitar" ensure_logstash_version_constant_defined tarpath = "build/logstash#{tar_suffix}-#{LOGSTASH_VERSION}#{PACKAGE_SUFFIX}.tar.gz" + if File.exist?(tarpath) && ENV['SKIP_PREPARE'] == "1" && !source_modified_since?(File.mtime(tarpath)) + puts("[artifact:tar] Source code not modified. Skipping build of #{tarpath}") + return + end puts("[artifact:tar] building #{tarpath}") gz = Zlib::GzipWriter.new(File.new(tarpath, "wb"), Zlib::BEST_COMPRESSION) tar = Archive::Tar::Minitar::Output.new(gz) @@ -526,4 +550,16 @@ namespace "artifact" do end end end + + def build_dockerfile + env = { + "ARTIFACTS_DIR" => ::File.join(Dir.pwd, "build"), + "RELEASE" => ENV["RELEASE"], + "VERSION_QUALIFIER" => VERSION_QUALIFIER + } + Dir.chdir("docker") do |dir| + system(env, "make public-dockerfile") + puts "Dockerfile created in #{::File.join(env['ARTIFACTS_DIR'], 'docker')}" + end + end end From 14c71227028cb8a6db3129eb2ed9b53faf5972eb Mon Sep 17 00:00:00 2001 From: Dan Hermann Date: Tue, 23 Apr 2019 09:10:20 -0500 Subject: [PATCH 0085/1126] Correction on Java execution in docs on command-line arguments Fixes #10710 --- docs/static/running-logstash-command-line.asciidoc | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/docs/static/running-logstash-command-line.asciidoc b/docs/static/running-logstash-command-line.asciidoc index f0e839197..876a82d5f 100644 --- a/docs/static/running-logstash-command-line.asciidoc +++ b/docs/static/running-logstash-command-line.asciidoc @@ -69,7 +69,8 @@ With this command, Logstash concatenates three config files, `/tmp/one`, `/tmp/t The default is nil. *`--java-execution`*:: - Use the Java execution engine instead of the default Ruby execution engine. + Specify `false` for this option to revert to the legacy Ruby execution engine instead + of the default Java execution engine. *`--modules`*:: Launch the named module. Works in conjunction with the `-M` option to assign values to From a44cb9ebf38084b97a8978bfa005c85b65a3d30c Mon Sep 17 00:00:00 2001 From: urso Date: Fri, 12 Oct 2018 19:17:41 +0100 Subject: [PATCH 0086/1126] Rename filebeat.prospectors to filebeat.inputs In filebeat prospectors settings have been renamed to inputs. When prospectors is used a deprecation warning is printed. With 7.0 `filebeat.prospectors` will be removed. This change updates all uses of prospectors with inputs. For now filebeat events report `prospector.type` and `input.type` for compatibility reasons. Fixes #10711 --- docs/static/advanced-pipeline.asciidoc | 16 ++++++++++++++-- qa/integration/specs/beats_input_spec.rb | 6 +++--- 2 files changed, 17 insertions(+), 5 deletions(-) diff --git a/docs/static/advanced-pipeline.asciidoc b/docs/static/advanced-pipeline.asciidoc index da442a497..c5e209c5b 100644 --- a/docs/static/advanced-pipeline.asciidoc +++ b/docs/static/advanced-pipeline.asciidoc @@ -40,7 +40,7 @@ directory, and replace the contents with the following lines. Make sure `paths` [source,yaml] -------------------------------------------------------------------------------- -filebeat.prospectors: +filebeat.inputs: - type: log paths: - /path/to/file/logstash-tutorial.log <1> @@ -172,6 +172,9 @@ If your pipeline is working correctly, you should see a series of events like th "host" => "My-MacBook-Pro.local", "prospector" => { "type" => "log" + }, + "input" => { + "type" => "log" }, "source" => "/path/to/file/logstash-tutorial.log", "message" => "83.149.9.216 - - [04/Jan/2015:05:13:42 +0000] \"GET /presentations/logstash-monitorama-2013/images/kibana-search.png HTTP/1.1\" 200 203023 \"http://semicomplete.com/presentations/logstash-monitorama-2013/\" \"Mozilla/5.0 (Macintosh; Intel Mac OS X 10_9_1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/32.0.1700.77 Safari/537.36\"", @@ -295,6 +298,9 @@ After Logstash applies the grok pattern, the events will have the following JSON "verb" => "GET", "prospector" => { "type" => "log" + }, + "input" => { + "type" => "log" }, "source" => "/path/to/file/logstash-tutorial.log", "message" => "83.149.9.216 - - [04/Jan/2015:05:13:42 +0000] \"GET /presentations/logstash-monitorama-2013/images/kibana-search.png HTTP/1.1\" 200 203023 \"http://semicomplete.com/presentations/logstash-monitorama-2013/\" \"Mozilla/5.0 (Macintosh; Intel Mac OS X 10_9_1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/32.0.1700.77 Safari/537.36\"", @@ -534,6 +540,9 @@ You should get multiple hits back. For example: "prospector": { "type": "log" }, + "input": { + "type": "log" + }, "source": "/path/to/file/logstash-tutorial.log", "message": """83.149.9.216 - - [04/Jan/2015:05:13:45 +0000] "GET /presentations/logstash-monitorama-2013/images/frontend-response-codes.png HTTP/1.1" 200 52878 "http://semicomplete.com/presentations/logstash-monitorama-2013/" "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_9_1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/32.0.1700.77 Safari/537.36"""", "tags": [ @@ -618,6 +627,9 @@ A few log entries come from Buffalo, so the query produces the following respons "prospector": { "type": "log" }, + "input": { + "type": "log" + }, "source": "/path/to/file/logstash-tutorial.log", "message": """198.46.149.143 - - [04/Jan/2015:05:29:13 +0000] "GET /blog/geekery/disabling-battery-in-ubuntu-vms.html?utm_source=feedburner&utm_medium=feed&utm_campaign=Feed%3A+semicomplete%2Fmain+%28semicomplete.com+-+Jordan+Sissel%29 HTTP/1.1" 200 9316 "-" "Tiny Tiny RSS/1.11 (http://tt-rss.org/)"""", "tags": [ @@ -711,7 +723,7 @@ directory, and replace the contents with the following lines. Make sure `paths` [source,shell] -------------------------------------------------------------------------------- -filebeat.prospectors: +filebeat.inputs: - type: log paths: - /var/log/*.log <1> diff --git a/qa/integration/specs/beats_input_spec.rb b/qa/integration/specs/beats_input_spec.rb index 1ecfaed6c..39a521a9e 100644 --- a/qa/integration/specs/beats_input_spec.rb +++ b/qa/integration/specs/beats_input_spec.rb @@ -67,7 +67,7 @@ describe "Beat Input" do let(:filebeat_config) do { "filebeat" => { - "prospectors" => [{ "paths" => [log_path], "input_type" => "log" }], + "inputs" => [{ "paths" => [log_path], "input_type" => "log" }], "registry_file" => registry_file, "scan_frequency" => "1s" }, @@ -92,7 +92,7 @@ describe "Beat Input" do let(:filebeat_config) do { "filebeat" => { - "prospectors" => [{ "paths" => [log_path], "input_type" => "log" }], + "inputs" => [{ "paths" => [log_path], "input_type" => "log" }], "registry_file" => registry_file, "scan_frequency" => "1s" }, @@ -119,7 +119,7 @@ describe "Beat Input" do let(:filebeat_config) do { "filebeat" => { - "prospectors" => [{ "paths" => [log_path], "input_type" => "log" }], + "inputs" => [{ "paths" => [log_path], "input_type" => "log" }], "registry_file" => registry_file, "scan_frequency" => "1s" }, From f9a5876b3cf824c57b8a148ef96d295f6965520e Mon Sep 17 00:00:00 2001 From: Dan Hermann Date: Wed, 24 Apr 2019 11:09:37 -0500 Subject: [PATCH 0087/1126] Clarify that Java codecs work only with Java inputs and outputs Fixes #10716 --- docs/static/java-codec.asciidoc | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/docs/static/java-codec.asciidoc b/docs/static/java-codec.asciidoc index 45933ab18..a68fde22e 100644 --- a/docs/static/java-codec.asciidoc +++ b/docs/static/java-codec.asciidoc @@ -17,10 +17,14 @@ //:methodheader: Logstash codecs must implement the `register` method, and the `decode` method or the `encode` method (or both). [[java-codec-plugin]] + === How to write a Java codec plugin beta[] +NOTE: Java codecs are currently supported only for Java input and output plugins. They will not work with Ruby +input or output plugins. + // Pulls in shared section: Setting Up Environment include::include/javapluginsetup.asciidoc[] From 122adbd22ec8c9d32b847ae958c77193624afe7a Mon Sep 17 00:00:00 2001 From: Ry Biesemeyer Date: Thu, 4 Apr 2019 00:09:01 +0000 Subject: [PATCH 0088/1126] adds LogStash::PluginMetadata for simple key/value plugin metadata We need a way for a plugin to register simple metadata about external resources it connects to in order to implement a Monitoring feature in which an Elasticsearch Output Plugin can store the connected cluster's uuid (#10602) Here, we add a generic `LogStash::PluginMetadata` along with a registry, and expose an accessor on `LogStash::Plugin#plugin_metadata` so that instances can access their own metadata object. Fixes #10691 --- logstash-core/lib/logstash/plugin.rb | 20 ++++ logstash-core/lib/logstash/plugin_metadata.rb | 108 ++++++++++++++++++ logstash-core/spec/logstash/plugin_spec.rb | 63 ++++++++++ logstash-core/spec/plugin_metadata_spec.rb | 98 ++++++++++++++++ 4 files changed, 289 insertions(+) create mode 100644 logstash-core/lib/logstash/plugin_metadata.rb create mode 100644 logstash-core/spec/plugin_metadata_spec.rb diff --git a/logstash-core/lib/logstash/plugin.rb b/logstash-core/lib/logstash/plugin.rb index 59fa8a9dc..eb4db8fc9 100644 --- a/logstash-core/lib/logstash/plugin.rb +++ b/logstash-core/lib/logstash/plugin.rb @@ -3,6 +3,8 @@ require "logstash/config/mixin" require "concurrent" require "securerandom" +require_relative 'plugin_metadata' + class LogStash::Plugin include LogStash::Util::Loggable @@ -136,4 +138,22 @@ class LogStash::Plugin require "logstash/plugins/registry" LogStash::PLUGIN_REGISTRY.lookup_pipeline_plugin(type, name) end + + ## + # Returns this plugin's metadata key/value store. + # + # @see LogStash::PluginMetadata for restrictions and caveats. + # @since 7.1 + # + # @usage: + # ~~~ + # if defined?(plugin_metadata) + # plugin_metadata.set(:foo, 'value') + # end + # ~~~ + # + # @return [LogStash::PluginMetadata] + def plugin_metadata + LogStash::PluginMetadata.for_plugin(self.id) + end end # class LogStash::Plugin diff --git a/logstash-core/lib/logstash/plugin_metadata.rb b/logstash-core/lib/logstash/plugin_metadata.rb new file mode 100644 index 000000000..24cb9802d --- /dev/null +++ b/logstash-core/lib/logstash/plugin_metadata.rb @@ -0,0 +1,108 @@ +# encoding: utf-8 + +require 'thread_safe/cache' + +module LogStash + ## + # `PluginMetadata` provides a space to store key/value metadata about a plugin, typically metadata about + # external resources that can be gleaned during plugin registration. + # + # Data is persisted across pipeline reloads, and no effort is made to clean up metadata from pipelines + # that no longer exist after a pipeline reload. + # + # - It MUST NOT be used to store processing state + # - It SHOULD NOT be updated frequently. + # - Individual metadata keys MUST be Symbols and SHOULD NOT be dynamically generated + # + # USAGE FROM PLUGINS + # ------------------ + # + # Since we allow plugins to be updated, it is important to introduce bindings to new Logstash features in a way + # that doesn't break when installed onto a Logstash that doesn't have those features, e.g.: + # + # ~~~ + # if defined?(LogStash::PluginMetadata) + # LogStash::PluginMetadata.set(id, :foo, bar) + # end + # ~~~ + # + # @since 7.1 + class PluginMetadata + Thread.exclusive do + @registry = ThreadSafe::Cache.new unless defined?(@registry) + end + + class << self + ## + # Get the PluginMetadata object corresponding to the given plugin id + # + # @param plugin_id [String] + # + # @return [PluginMetadata]: the metadata object for the provided `plugin_id`; if no + # metadata object exists, it will be created. + def for_plugin(plugin_id) + @registry.compute_if_absent(plugin_id) { PluginMetadata.new } + end + + ## + # Determine if we have an existing PluginMetadata object for the given plugin id + # This allows us to avoid creating a metadata object if we don't already have one. + # + # @param plugin_id [String] + # + # @return [Boolean] + def exists?(plugin_id) + @registry.key?(plugin_id) + end + + ## + # @api private + def reset! + @registry.clear + end + end + + ## + # @see [LogStash::PluginMetadata#for_plugin(String)] + # @api private + def initialize + @datastore = ThreadSafe::Cache.new + end + + ## + # Set the metadata key for this plugin, returning the previous value (if any) + # + # @param key [Symbol] + # @param value [Object] + # + # @return [Object] + def set(key, value) + if value.nil? + @datastore.delete(key) + else + @datastore.get_and_set(key, value) + end + end + + ## + # Get the metadata value for the given key on this plugin + # + # @param key [Symbol] + # + # @return [Object]: the value object associated with the given key on this + # plugin, or nil if no value is associated + def get(key) + @datastore.get(key) + end + + ## + # Determine whether specific key/value metadata exists for this plugin + # + # @param key [Symbol]: the key + # + # @return [Boolean]: true if the plugin includes metadata for the key + def set?(key) + @datastore.key?(key) + end + end +end \ No newline at end of file diff --git a/logstash-core/spec/logstash/plugin_spec.rb b/logstash-core/spec/logstash/plugin_spec.rb index fb7f3c1c7..302f4017a 100644 --- a/logstash-core/spec/logstash/plugin_spec.rb +++ b/logstash-core/spec/logstash/plugin_spec.rb @@ -267,6 +267,69 @@ describe LogStash::Plugin do end end + describe "#plugin_metadata" do + plugin_types = [ + LogStash::Filters::Base, + LogStash::Codecs::Base, + LogStash::Outputs::Base, + LogStash::Inputs::Base + ] + + before(:each) { LogStash::PluginMetadata::reset! } + + plugin_types.each do |plugin_type| + let(:plugin) do + Class.new(plugin_type) do + config_name "simple_plugin" + + config :host, :validate => :string + config :export, :validate => :boolean + + def register; end + end + end + + let(:config) do + { + "host" => "127.0.0.1", + "export" => true + } + end + + subject(:plugin_instance) { plugin.new(config) } + + context "plugin type is #{plugin_type}" do + { + 'when there is not ID configured for the plugin' => {}, + 'when a user provide an ID for the plugin' => { 'id' => 'ABC' }, + }.each do |desc, config_override| + + + context(desc) do + let(:config) { super.merge(config_override) } + + it "has a PluginMetadata" do + expect(plugin_instance.plugin_metadata).to be_a_kind_of(LogStash::PluginMetadata) + end + + if config_override.include?('id') + it "will be shared between instance of plugins" do + expect(plugin_instance.plugin_metadata).to equal(plugin.new(config).plugin_metadata) + end + end + + it 'stores metadata' do + new_value = 'foo' + old_value = plugin_instance.plugin_metadata.set(:foo, new_value) + expect(old_value).to be_nil + expect(plugin_instance.plugin_metadata.get(:foo)).to eq(new_value) + end + end + end + end + end + end + describe "#id" do let(:plugin) do Class.new(LogStash::Filters::Base,) do diff --git a/logstash-core/spec/plugin_metadata_spec.rb b/logstash-core/spec/plugin_metadata_spec.rb new file mode 100644 index 000000000..bedc7c0db --- /dev/null +++ b/logstash-core/spec/plugin_metadata_spec.rb @@ -0,0 +1,98 @@ +# encoding: utf-8 + +require 'spec_helper' +require 'logstash/plugin_metadata' +require 'securerandom' + +describe LogStash::PluginMetadata do + + let(:registry) { described_class } + before(:each) { registry.reset! } + + let(:plugin_id) { SecureRandom.uuid } + + describe 'registry' do + describe '#for_plugin' do + it 'returns the same instance when given the same id' do + expect(registry.for_plugin(plugin_id)).to be(registry.for_plugin(plugin_id)) + end + it 'returns different instances when given different ids' do + expect(registry.for_plugin(plugin_id)).to_not equal(registry.for_plugin(plugin_id.next)) + end + end + describe '#exists?' do + context 'when the plugin has not yet been registered' do + it 'returns false' do + expect(registry.exists?(plugin_id)).to be false + end + end + context 'when the plugin has already been registered' do + before(:each) { registry.for_plugin(plugin_id).set(:foo, 'bar') } + it 'returns true' do + expect(registry.exists?(plugin_id)).to be true + end + end + end + end + + describe 'instance' do + let(:instance) { registry.for_plugin(plugin_id) } + + describe '#set' do + context 'when the key is not set' do + it 'sets the new value' do + instance.set(:foo, 'bar') + expect(instance.get(:foo)).to eq('bar') + end + it 'returns the nil' do + expect(instance.set(:foo, 'bar')).to be_nil + end + end + context 'when the key is set' do + before(:each) { instance.set(:foo, 'bananas') } + + it 'sets the new value' do + instance.set(:foo, 'bar') + expect(instance.get(:foo)).to eq('bar') + end + it 'returns the previous associated value' do + expect(instance.set(:foo, 'bar')).to eq('bananas') + end + context 'when the new value is nil' do + it 'unsets the value' do + instance.set(:foo, nil) + expect(instance.set?(:foo)).to be false + end + end + end + end + + describe '#get' do + context 'when the key is set' do + before(:each) { instance.set(:foo, 'bananas') } + it 'returns the associated value' do + expect(instance.get(:foo)).to eq('bananas') + end + end + context 'when the key is not set' do + it 'returns nil' do + expect(instance.get(:foo)).to be_nil + end + end + end + + describe '#set?' do + context 'when the key is set' do + before(:each) { instance.set(:foo, 'bananas')} + it 'returns true' do + expect(instance.set?(:foo)).to be true + end + end + context 'when the key is not set' do + it 'returns false' do + expect(instance.set?(:foo)).to be false + end + end + end + end +end \ No newline at end of file From 2e2a00270e9d83620e9bd21ed35658908fe6bb53 Mon Sep 17 00:00:00 2001 From: Rob Bavey Date: Mon, 15 Apr 2019 16:37:39 -0400 Subject: [PATCH 0089/1126] Add methods to clear PluginMetadata repositories Fixes #10691 --- logstash-core/lib/logstash/plugin_metadata.rb | 36 +++++++++++- logstash-core/spec/logstash/plugin_spec.rb | 4 ++ logstash-core/spec/plugin_metadata_spec.rb | 57 ++++++++++++++++++- 3 files changed, 92 insertions(+), 5 deletions(-) diff --git a/logstash-core/lib/logstash/plugin_metadata.rb b/logstash-core/lib/logstash/plugin_metadata.rb index 24cb9802d..99bbbd32e 100644 --- a/logstash-core/lib/logstash/plugin_metadata.rb +++ b/logstash-core/lib/logstash/plugin_metadata.rb @@ -21,13 +21,14 @@ module LogStash # that doesn't break when installed onto a Logstash that doesn't have those features, e.g.: # # ~~~ - # if defined?(LogStash::PluginMetadata) - # LogStash::PluginMetadata.set(id, :foo, bar) - # end + # + # plugin_metadata.set(:foo, bar) if defined?(plugin_metadata?) + # # ~~~ # # @since 7.1 class PluginMetadata + Thread.exclusive do @registry = ThreadSafe::Cache.new unless defined?(@registry) end @@ -55,6 +56,17 @@ module LogStash @registry.key?(plugin_id) end + ## + # Deletes, and then clears the contents of an existing PluginMetadata object for the given plugin id if one exists + # + # @param plugin_id [String] + # + # @return [Boolean] + def delete_for_plugin(plugin_id) + old_registry = @registry.delete(plugin_id) + old_registry.clear unless old_registry.nil? + end + ## # @api private def reset! @@ -104,5 +116,23 @@ module LogStash def set?(key) @datastore.key?(key) end + + ## + # Delete the metadata key for this plugin, returning the previous value (if any) + # + # @param key [Symbol] + # + # @return [Object] + def delete(key) + @datastore.delete(key) + end + + ## + # Clear all metadata keys for this plugin + # + # @return [Object] + def clear + @datastore.clear + end end end \ No newline at end of file diff --git a/logstash-core/spec/logstash/plugin_spec.rb b/logstash-core/spec/logstash/plugin_spec.rb index 302f4017a..4b2e2ad19 100644 --- a/logstash-core/spec/logstash/plugin_spec.rb +++ b/logstash-core/spec/logstash/plugin_spec.rb @@ -312,6 +312,10 @@ describe LogStash::Plugin do expect(plugin_instance.plugin_metadata).to be_a_kind_of(LogStash::PluginMetadata) end + it "PluginMetadata is defined" do + expect(defined?(plugin_instance.plugin_metadata)).to be_truthy + end + if config_override.include?('id') it "will be shared between instance of plugins" do expect(plugin_instance.plugin_metadata).to equal(plugin.new(config).plugin_metadata) diff --git a/logstash-core/spec/plugin_metadata_spec.rb b/logstash-core/spec/plugin_metadata_spec.rb index bedc7c0db..b2d165efa 100644 --- a/logstash-core/spec/plugin_metadata_spec.rb +++ b/logstash-core/spec/plugin_metadata_spec.rb @@ -33,6 +33,20 @@ describe LogStash::PluginMetadata do end end end + describe '#delete_for_plugin' do + before(:each) { registry.for_plugin(plugin_id).set(:foo, 'bar') } + it 'deletes the registry' do + expect(registry.exists?(plugin_id)).to be true + registry.delete_for_plugin(plugin_id) + expect(registry.exists?(plugin_id)).to be false + end + it 'deletes the data inside the registry' do + plugin_registry = registry.for_plugin(plugin_id) + registry.delete_for_plugin(plugin_id) + expect(plugin_registry.set?(:foo)).to be false + end + end + end describe 'instance' do @@ -49,14 +63,15 @@ describe LogStash::PluginMetadata do end end context 'when the key is set' do - before(:each) { instance.set(:foo, 'bananas') } + let (:val) { 'bananas'} + before(:each) { instance.set(:foo, val) } it 'sets the new value' do instance.set(:foo, 'bar') expect(instance.get(:foo)).to eq('bar') end it 'returns the previous associated value' do - expect(instance.set(:foo, 'bar')).to eq('bananas') + expect(instance.set(:foo, 'bar')).to eq(val) end context 'when the new value is nil' do it 'unsets the value' do @@ -94,5 +109,43 @@ describe LogStash::PluginMetadata do end end end + + describe '#delete' do + context 'when the key is set' do + let (:val) { 'bananas' } + before(:each) { instance.set(:foo, val)} + it 'returns the value' do + expect(instance.delete(:foo)).to be val + end + it 'removes the key' do + instance.delete(:foo) + expect(instance.set?(:foo)).to be false + end + end + context 'when the key is not set' do + it 'returns nil' do + expect(instance.delete(:foo)).to be nil + end + + it 'should not be set' do + instance.delete(:foo) + expect(instance.set?(:foo)).to be false + end + end + end + + describe '#clear' do + context 'when the key is set' do + before(:each) do + instance.set(:foo, 'bananas') + instance.set(:bar, 'more bananas') + end + it 'removes all keys' do + instance.clear + expect(instance.set?(:foo)).to be false + expect(instance.set?(:bar)).to be false + end + end + end end end \ No newline at end of file From 8d60ab5c4d48cebf551c9b58e0333aceb55309ff Mon Sep 17 00:00:00 2001 From: Rob Bavey Date: Mon, 15 Apr 2019 16:38:08 -0400 Subject: [PATCH 0090/1126] Adds cleanup after shutdown of plugin Fixes #10691 --- logstash-core/lib/logstash/plugin.rb | 6 +++++- logstash-core/lib/logstash/plugin_metadata.rb | 5 +++-- logstash-core/spec/logstash/plugin_spec.rb | 8 ++++++++ 3 files changed, 16 insertions(+), 3 deletions(-) diff --git a/logstash-core/lib/logstash/plugin.rb b/logstash-core/lib/logstash/plugin.rb index eb4db8fc9..e332f6c00 100644 --- a/logstash-core/lib/logstash/plugin.rb +++ b/logstash-core/lib/logstash/plugin.rb @@ -72,7 +72,11 @@ class LogStash::Plugin # main task terminates def do_close @logger.debug("Closing", :plugin => self.class.name) - close + begin + close + ensure + LogStash::PluginMetadata.delete_for_plugin(self.id) + end end # Subclasses should implement this close method if you need to perform any diff --git a/logstash-core/lib/logstash/plugin_metadata.rb b/logstash-core/lib/logstash/plugin_metadata.rb index 99bbbd32e..a0bab9c99 100644 --- a/logstash-core/lib/logstash/plugin_metadata.rb +++ b/logstash-core/lib/logstash/plugin_metadata.rb @@ -7,8 +7,7 @@ module LogStash # `PluginMetadata` provides a space to store key/value metadata about a plugin, typically metadata about # external resources that can be gleaned during plugin registration. # - # Data is persisted across pipeline reloads, and no effort is made to clean up metadata from pipelines - # that no longer exist after a pipeline reload. + # Data should not be persisted across pipeline reloads, and should be cleaned up after a pipeline reload # # - It MUST NOT be used to store processing state # - It SHOULD NOT be updated frequently. @@ -28,6 +27,7 @@ module LogStash # # @since 7.1 class PluginMetadata + include LogStash::Util::Loggable Thread.exclusive do @registry = ThreadSafe::Cache.new unless defined?(@registry) @@ -63,6 +63,7 @@ module LogStash # # @return [Boolean] def delete_for_plugin(plugin_id) + logger.debug("Removing metadata for plugin #{plugin_id}") old_registry = @registry.delete(plugin_id) old_registry.clear unless old_registry.nil? end diff --git a/logstash-core/spec/logstash/plugin_spec.rb b/logstash-core/spec/logstash/plugin_spec.rb index 4b2e2ad19..48497f09e 100644 --- a/logstash-core/spec/logstash/plugin_spec.rb +++ b/logstash-core/spec/logstash/plugin_spec.rb @@ -328,6 +328,14 @@ describe LogStash::Plugin do expect(old_value).to be_nil expect(plugin_instance.plugin_metadata.get(:foo)).to eq(new_value) end + + it 'removes metadata when the plugin is closed' do + new_value = 'foo' + plugin_instance.plugin_metadata.set(:foo, new_value) + expect(plugin_instance.plugin_metadata.get(:foo)).to eq(new_value) + plugin_instance.do_close + expect(plugin_instance.plugin_metadata.set?(:foo)).to be_falsey + end end end end From 89be09907f895180bba426ac52e17eae23b17dd1 Mon Sep 17 00:00:00 2001 From: Rob Bavey Date: Tue, 16 Apr 2019 13:49:16 -0400 Subject: [PATCH 0091/1126] Move plugin cleanup before retry Previously the `do_close` method would never be called on a failing plugin, because the retry call stops the code under `ensure` from ever being called. Fixes #10691 --- logstash-core/lib/logstash/java_pipeline.rb | 9 +++++++-- logstash-core/lib/logstash/pipeline.rb | 9 +++++++-- 2 files changed, 14 insertions(+), 4 deletions(-) diff --git a/logstash-core/lib/logstash/java_pipeline.rb b/logstash-core/lib/logstash/java_pipeline.rb index 8de8197d9..8305f6c08 100644 --- a/logstash-core/lib/logstash/java_pipeline.rb +++ b/logstash-core/lib/logstash/java_pipeline.rb @@ -313,9 +313,14 @@ module LogStash; class JavaPipeline < JavaBasePipeline # Assuming the failure that caused this exception is transient, # let's sleep for a bit and execute #run again sleep(1) + begin + plugin.do_close + rescue => close_exception + @logger.debug("Input plugin raised exception while closing, ignoring", + default_logging_keys(:plugin => plugin.class.config_name, :exception => close_exception.message, + :backtrace => close_exception.backtrace)) + end retry - ensure - plugin.do_close end end # def inputworker diff --git a/logstash-core/lib/logstash/pipeline.rb b/logstash-core/lib/logstash/pipeline.rb index 283f6327c..2ce46b1fc 100644 --- a/logstash-core/lib/logstash/pipeline.rb +++ b/logstash-core/lib/logstash/pipeline.rb @@ -442,9 +442,14 @@ module LogStash; class Pipeline < BasePipeline # Assuming the failure that caused this exception is transient, # let's sleep for a bit and execute #run again sleep(1) + begin + plugin.do_close + rescue => close_exception + @logger.debug("Input plugin raised exception while closing, ignoring", + default_logging_keys(:plugin => plugin.class.config_name, :exception => close_exception.message, + :backtrace => close_exception.backtrace)) + end retry - ensure - plugin.do_close end end # def inputworker From 92dd9a932ff6aec7c2649dfc2eb5c8d52648edf3 Mon Sep 17 00:00:00 2001 From: Karen Metts Date: Wed, 25 Jul 2018 14:06:53 -0400 Subject: [PATCH 0092/1126] Add guidelines for writing plugin doc Fix link formatting Fixes #9861 --- docs/index.asciidoc | 5 ++ docs/static/contributing-to-logstash.asciidoc | 24 +++--- docs/static/doc-for-plugin.asciidoc | 76 +++++++++++++++++++ docs/static/include/pluginbody.asciidoc | 55 +++----------- 4 files changed, 101 insertions(+), 59 deletions(-) create mode 100644 docs/static/doc-for-plugin.asciidoc diff --git a/docs/index.asciidoc b/docs/index.asciidoc index 0a42808b8..8f979c708 100644 --- a/docs/index.asciidoc +++ b/docs/index.asciidoc @@ -235,6 +235,11 @@ include::static/codec.asciidoc[] include::static/filter.asciidoc[] include::static/output.asciidoc[] +// Plugin doc guidelines + +:edit_url: https://github.com/elastic/logstash/edit/{branch}/docs/static/doc-for-plugin.asciidoc +include::static/doc-for-plugin.asciidoc[] + // Contributing a Patch to a Logstash Plugin :edit_url: https://github.com/elastic/logstash/edit/{branch}/docs/static/contributing-patch.asciidoc diff --git a/docs/static/contributing-to-logstash.asciidoc b/docs/static/contributing-to-logstash.asciidoc index 5c7206201..96a45c601 100644 --- a/docs/static/contributing-to-logstash.asciidoc +++ b/docs/static/contributing-to-logstash.asciidoc @@ -1,24 +1,21 @@ [[contributing-to-logstash]] == Contributing to Logstash -Before version 1.5, Logstash included all plugins in each release. This made it -easy to make use of any plugin, but it complicated plugin development--a new -release of Logstash became necessary if a plugin needed patching. Since version -1.5, all plugins are independent of the Logstash core. Now you can add your own -input, codec, filter, or output plugins to Logstash much more easily! +You can add your own input, codec, filter, or output plugins to Logstash. [float] === Adding plugins -Since plugins can now be developed and deployed independently of the Logstash -core, there are documents which guide you through the process of coding and -deploying your own plugins: +Plugins can be developed and deployed independently of the Logstash +core. Here are some documents to guide you through the process of coding and +deploying your own plugin: * <> -* http://www.elasticsearch.org/guide/en/logstash/current/_how_to_write_a_logstash_input_plugin.html[How to write a Logstash input plugin] -* http://www.elasticsearch.org/guide/en/logstash/current/_how_to_write_a_logstash_codec_plugin.html[How to write a Logstash codec plugin] -* http://www.elasticsearch.org/guide/en/logstash/current/_how_to_write_a_logstash_filter_plugin.html[How to write a Logstash filter plugin] -* http://www.elasticsearch.org/guide/en/logstash/current/_how_to_write_a_logstash_output_plugin.html[How to write a Logstash output plugin] +* <> +* <> +* <> +* <> +* <> * <> * <> * <> @@ -26,8 +23,7 @@ deploying your own plugins: [float] ==== Plugin Shutdown APIs -Starting in Logstash 2.0, we changed how input plugins shut down to increase shutdown reliability. There are three methods -for plugin shutdown: `stop`, `stop?`, and `close`. +You have three options for shutting down a plugin: `stop`, `stop?`, and `close`. * Call the `stop` method from outside the plugin thread. This method signals the plugin to stop. * The `stop?` method returns `true` when the `stop` method has already been called for that plugin. diff --git a/docs/static/doc-for-plugin.asciidoc b/docs/static/doc-for-plugin.asciidoc new file mode 100644 index 000000000..f72dae1b7 --- /dev/null +++ b/docs/static/doc-for-plugin.asciidoc @@ -0,0 +1,76 @@ +[[plugin-doc]] +=== Documenting your plugin + +Quality documentation with good examples contributes to the adoption of your plugin. + +The documentation for your plugin will be generated and published in the +{logstash-ref}/index.html[Logstash Reference] and the +{lsplugindocs}[Versioned plugin docs]. + +[[plugin-doc-file]] +==== Documentation file + +Documentation should be included in your plugin structure as a single file called 'docs/index.asciidoc'. + +[[heading-ids]] +==== Heading IDs + +Heading IDs must be in a format that supports generated IDs. This approach +creates unique IDs when the +{lsplugindocs}[Versioned plugin docs] are generated. + +*Example* + +Don't hardcode a heading ID like this: `[[config_models]]` + +Instead, define it like this: + +[source,txt] +---------------------------------- +[id="plugins-{type}s-{plugin}-config_models"] +==== Configuration models +---------------------------------- + +If you hardcode an ID, the versioned plugin docs will build correctly the +first time. The second time the doc build runs, the ID will be flagged as +a duplicate, and the build will fail. + +[[format-code]] +==== Code samples + +We all love code samples. Asciidoc supports code blocks and config examples. +To include Ruby code, use the asciidoc `[source,ruby]` directive. + +Note that the hash marks (#) are present to make the example render correctly. +Don't include the hash marks in your asciidoc file. + +[source,txt] +[subs="attributes"] +---------------------------------- +# [source,ruby] +# ---------------------------------- +# match => { +# "field1" => "value1" +# "field2" => "value2" +# ... +# } +# ---------------------------------- +---------------------------------- + +This sample renders in the documentation like this: +[source,ruby] +---------------------------------- +match => { + "field1" => "value1" + "field2" => "value2" + ... +} +---------------------------------- + + +==== Resources + +For more asciidoc formatting tips, see the excellent reference at +https://github.com/elastic/docs#asciidoc-guide + + diff --git a/docs/static/include/pluginbody.asciidoc b/docs/static/include/pluginbody.asciidoc index 88e14779f..3a0a3ddeb 100644 --- a/docs/static/include/pluginbody.asciidoc +++ b/docs/static/include/pluginbody.asciidoc @@ -1,4 +1,4 @@ - +[id="{plugintype}-new-plugin"] === How to write a Logstash {plugintype} plugin @@ -344,49 +344,14 @@ them here along with these Logstash dependencies. Let's go through the various elements of the plugin itself. -==== Inline Documentation -Logstash provides infrastructure to automatically generate documentation for -plugins. We use the asciidoc format to write documentation so _any_ comments in -the source code will be first converted into asciidoc and then into html. +==== Documentation for your plugin +Documentation is an important part of your plugin. All plugin documentation is +rendered and placed in the +http://www.elasticsearch.org/guide/en/logstash/current/index.html[Logstash +Reference] and the {lsplugindocs}[Versioned plugin docs]. -All plugin documentation is then rendered and placed in -http://www.elasticsearch.org/guide/en/logstash/current/index.html[the Logstash section of the Elasticsearch Guide]. +See <> for tips and guidelines. -The inline documentation can include code blocks and config examples! To include -Ruby code, use the asciidoc `[source,ruby]` directive: - -[source,txt] -[subs="attributes"] ----------------------------------- -# Using hashes: -# [source,ruby] -# ---------------------------------- -# match => { -# "field1" => "value1" -# "field2" => "value2" -# ... -# } -# ---------------------------------- ----------------------------------- - -In the rendered HTML document, this block would look like: - -[] -========================= -Using hashes: -[source,ruby] ----------------------------------- -match => { - "field1" => "value1" - "field2" => "value2" - ... - } ----------------------------------- -========================= - - -TIP: For more asciidoc formatting tips, see the excellent reference at -https://github.com/elastic/docs#asciidoc-guide ==== `class` Declaration The {plugintype} plugin class should be a subclass of @@ -1275,11 +1240,11 @@ we always welcome new plugins! Some of the many benefits of having your plugin in the logstash-plugins repository are: -* **Discovery** Your plugin will appear in the http://www.elasticsearch.org/guide/en/logstash/current/index.html[Logstash Reference], +* **Discovery.** Your plugin will appear in the http://www.elasticsearch.org/guide/en/logstash/current/index.html[Logstash Reference], where Logstash users look first for plugins and documentation. -* **Documentation** Your plugin documentation will automatically be added to the +* **Documentation.** Your plugin documentation will automatically be added to the http://www.elasticsearch.org/guide/en/logstash/current/index.html[Logstash Reference]. -* **Testing** With our testing infrastructure, your plugin will be continuously +* **Testing.** With our testing infrastructure, your plugin will be continuously tested against current and future releases of Logstash. As a result, users will have the assurance that if incompatibilities arise, they will be quickly discovered and corrected. From b83d8a0deed95030bfddeea727cfb52a449c46b4 Mon Sep 17 00:00:00 2001 From: Karen Metts Date: Thu, 2 Aug 2018 11:03:22 -0400 Subject: [PATCH 0093/1126] Incorporate review comments Fixes #9861 --- docs/static/doc-for-plugin.asciidoc | 140 +++++++++++++++++++++--- docs/static/include/pluginbody.asciidoc | 73 ++++++------ 2 files changed, 160 insertions(+), 53 deletions(-) diff --git a/docs/static/doc-for-plugin.asciidoc b/docs/static/doc-for-plugin.asciidoc index f72dae1b7..b9475a642 100644 --- a/docs/static/doc-for-plugin.asciidoc +++ b/docs/static/doc-for-plugin.asciidoc @@ -3,27 +3,27 @@ Quality documentation with good examples contributes to the adoption of your plugin. -The documentation for your plugin will be generated and published in the -{logstash-ref}/index.html[Logstash Reference] and the -{lsplugindocs}[Versioned plugin docs]. +The documentation that you write for your plugin will be generated and published +in the {logstash-ref}/index.html[Logstash Reference] and the +{lsplugindocs}[Logstash Versioned Plugin Reference]. [[plugin-doc-file]] ==== Documentation file -Documentation should be included in your plugin structure as a single file called 'docs/index.asciidoc'. +Include documentation in your plugin structure as a single file called 'docs/index.asciidoc'. [[heading-ids]] ==== Heading IDs -Heading IDs must be in a format that supports generated IDs. This approach -creates unique IDs when the -{lsplugindocs}[Versioned plugin docs] are generated. +Format heading anchors with variables that can support generated IDs. This approach +creates unique IDs when the {lsplugindocs}[Logstash Versioned Plugin Reference] +is built. Unique heading IDs are required to avoid duplication over multiple versions of a plugin. *Example* Don't hardcode a heading ID like this: `[[config_models]]` -Instead, define it like this: +Instead, use variables to define it: [source,txt] ---------------------------------- @@ -31,9 +31,82 @@ Instead, define it like this: ==== Configuration models ---------------------------------- -If you hardcode an ID, the versioned plugin docs will build correctly the -first time. The second time the doc build runs, the ID will be flagged as -a duplicate, and the build will fail. +If you hardcode an ID, the {lsplugindocs}[Logstash Versioned Plugin Reference] +builds correctly the first time. The second time the doc build runs, the ID +is flagged as a duplicate, and the build fails. + + +[[link-format]] +==== Link formats + +Correct link formatting is essential for directing users to the content you +want them to see. Incorrect link formatting or duplicate links can break the +documentation build. Let's not do that. + +===== Link to content in the same file + +Use angle brackets to format links to content in the same asciidoc file. + +*Example* + +This link: +[source,txt] +----- +<> +----- + +Points to this heading in the same file: + +[source,txt] +---------------------------------- +[id="plugins-{type}s-{plugin}-config_models"] +==== Configuration models +---------------------------------- + + +===== Link to content in the Logstash Reference Guide + +Use external link syntax for links that point to documentation for other plugins or content in the Logstash Reference Guide. + +*Examples* +[source,txt] +----- +{logstash-ref}/plugins-codecs-multiline.html[Multiline codec plugin] +----- + +[source,txt] +----- +{logstash-ref}/getting-started-with-logstash.html +----- + +===== Links specifying link text + +If you don't specify link text, the URL is used as the link text. + + +*Examples* + +If you want your link to display as {logstash-ref}/getting-started-with-logstash.html, use this format: +[source,txt] +----- +{logstash-ref}/getting-started-with-logstash.html +----- + + +If you want your link to display as {logstash-ref}/getting-started-with-logstash.html[Getting Started with Logstash], use this format: +[source,txt] +----- +{logstash-ref}/getting-started-with-logstash.html[Getting Started with Logstash] +----- + + +===== Link to data type descriptions + +We make an exception for links that point to data type descriptions, +such as `<>`, because they are used so frequently. +We have a cleanup step in the conversion script that converts the links to the +correct syntax. + [[format-code]] ==== Code samples @@ -41,23 +114,23 @@ a duplicate, and the build will fail. We all love code samples. Asciidoc supports code blocks and config examples. To include Ruby code, use the asciidoc `[source,ruby]` directive. -Note that the hash marks (#) are present to make the example render correctly. -Don't include the hash marks in your asciidoc file. +Note that the hashmarks (#) are present to make the example render correctly. +Don't include the hashmarks in your asciidoc file. [source,txt] [subs="attributes"] ---------------------------------- # [source,ruby] -# ---------------------------------- +# ----- # match => { # "field1" => "value1" # "field2" => "value2" # ... # } -# ---------------------------------- +# ----- ---------------------------------- -This sample renders in the documentation like this: +The sample above (with hashmarks removed) renders in the documentation like this: [source,ruby] ---------------------------------- match => { @@ -67,10 +140,43 @@ match => { } ---------------------------------- +==== Where's my doc? + +Plugin documentation goes through several steps before it gets published in the +{lsplugindocs}[Logstash Versioned Plugin Reference] and the {logstash-ref}/index.html[Logstash Reference]. + +Here's an overview of the workflow: + +* Be sure that you have signed the CLI and have all necessary approvals and sign offs. +* Merge the pull request for your plugin (including the `index.asciidoc` file, the `changelog.md` file, and the gemspec). +* Wait for the continuous integration build to complete successfully. +* Publish the plugin to https://rubygems.org. +* A script detects the new or changed version, and picks up the `index.asciidoc` file for inclusion in the doc build. +* The documentation for your new plugin is published in the {lsplugindocs}[Logstash Versioned Plugin Reference]. + +We're not done yet. + +* For each release, we package the new and changed documentation files into a pull request to add or update content. +(We sometimes package plugin docs between releases if we make significant changes to plugin documentation or add a new plugin.) +* The script detects the new or changed version, and picks up the `index.asciidoc` file for inclusion in the doc build. +* We create a pull request, and merge the new and changed content into the appropriate version branches. +* For a new plugin, we add a link to the list of plugins in the {logstash-ref}/index.html[Logstash Reference]. +* The documentation for your new (or changed) plugin is published in the {logstash-ref}/index.html[Logstash Reference]. + +===== Documentation or plugin updates + +When you make updates to your plugin or the documentation, consider +bumping the version number in the changelog and gemspec (or version file). The +version change triggers the doc build to pick up your changes for publishing. ==== Resources For more asciidoc formatting tips, see the excellent reference at -https://github.com/elastic/docs#asciidoc-guide +https://github.com/elastic/docs#asciidoc-guide. +For tips on contributing and changelog guidelines, see +https://github.com/elastic/logstash/blob/master/CONTRIBUTING.md#logstash-plugin-changelog-guidelines[CONTRIBUTING.md]. + +For general information about contributing, see +{logstash-ref}/contributing-to-logstash.html[Contributing to Logtash]. diff --git a/docs/static/include/pluginbody.asciidoc b/docs/static/include/pluginbody.asciidoc index 3a0a3ddeb..8e6c81029 100644 --- a/docs/static/include/pluginbody.asciidoc +++ b/docs/static/include/pluginbody.asciidoc @@ -13,7 +13,7 @@ https://www.ruby-lang.org/en/documentation/quickstart/[].) {getstarted} -==== Create a GitHub repo for your new plugin +===== Create a GitHub repo for your new plugin Each Logstash plugin lives in its own GitHub repository. To create a new repository for your plugin: . Log in to GitHub. @@ -25,7 +25,7 @@ Each Logstash plugin lives in its own GitHub repository. To create a new reposit ** **Initialize this repository with a README** -- enables you to immediately clone the repository to your computer. . Click **Create Repository**. -==== Use the plugin generator tool +===== Use the plugin generator tool You can now create your own Logstash plugin in seconds! The `generate` subcommand of `bin/logstash-plugin` creates the foundation for a new Logstash plugin with templatized files. It creates the correct directory structure, gemspec files, and dependencies so you @@ -33,7 +33,7 @@ can start adding custom code to process data with Logstash. For more information, see <> -==== Copy the {plugintype} code +===== Copy the {plugintype} code Alternatively, you can use the examples repo we host on github.com @@ -92,7 +92,7 @@ For more information about the Ruby gem file structure and an excellent walkthrough of the Ruby gem creation process, see http://timelessrepo.com/making-ruby-gems -==== See what your plugin looks like +===== See what your plugin looks like Before we dive into the details, open up the plugin file in your favorite text editor and take a look. @@ -312,7 +312,7 @@ endif::multi_receive_method[] Now let's take a line-by-line look at the example plugin. -==== `encoding` +===== `encoding` It seems like a small thing, but remember to specify the encoding at the beginning of your plugin code: @@ -325,7 +325,7 @@ beginning of your plugin code: Logstash depends on things being in UTF-8, so we put this here to tell the Ruby interpreter that we’re going to be using the UTF-8 encoding. -==== `require` Statements +===== `require` Statements Logstash {plugintype} plugins require parent classes defined in +logstash/pass:attributes[{plugintype}]s/base+ and logstash/namespace: @@ -344,16 +344,7 @@ them here along with these Logstash dependencies. Let's go through the various elements of the plugin itself. -==== Documentation for your plugin -Documentation is an important part of your plugin. All plugin documentation is -rendered and placed in the -http://www.elasticsearch.org/guide/en/logstash/current/index.html[Logstash -Reference] and the {lsplugindocs}[Versioned plugin docs]. - -See <> for tips and guidelines. - - -==== `class` Declaration +===== `class` Declaration The {plugintype} plugin class should be a subclass of +LogStash::pass:attributes[{pluginclass}]::Base+: @@ -370,7 +361,7 @@ The class name should closely mirror the plugin name, for example: LogStash::{pluginclass}::{pluginnamecap} ---- -==== `config_name` +===== `config_name` [source,ruby] [subs="attributes"] ---------------------------------- @@ -455,7 +446,7 @@ will become a valid boolean in the config. This coercion works for the // ///////////////////////////////////////////////////////////////////////////// ifdef::register_method[] -==== `register` Method +===== `register` Method [source,ruby] [subs="attributes"] ---------------------------------- @@ -484,7 +475,7 @@ endif::register_method[] ifdef::filter_method[] ifndef::blockfilter[] -==== `filter` Method +===== `filter` Method [source,ruby] [subs="attributes"] @@ -539,7 +530,7 @@ endif::filter_method[] ifdef::decode_method[] ifndef::blockcodec[] -==== `decode` Method +===== `decode` Method [source,ruby] [subs="attributes"] @@ -569,7 +560,7 @@ endif::decode_method[] ifdef::encode_method[] ifndef::blockcodec[] -==== `encode` Method +===== `encode` Method [source,ruby] [subs="attributes"] @@ -596,7 +587,7 @@ endif::encode_method[] ifdef::run_method[] ifndef::blockinput[] -==== `run` Method +===== `run` Method The {pluginname} input plugin has the following `run` Method: @@ -684,7 +675,7 @@ endif::run_method[] // ///////////////////////////////////////////////////////////////////////////// ifdef::receive_method[] -==== `receive` Method +===== `receive` Method [source,ruby] [subs="attributes"] @@ -747,9 +738,9 @@ endif::receive_method[] ==== Building the Plugin At this point in the process you have coded your plugin and are ready to build -a Ruby Gem from it. The following steps will help you complete the process. +a Ruby Gem from it. The following information will help you complete the process. -==== External dependencies +===== External dependencies A `require` statement in Ruby is used to include necessary code. In some cases your plugin may require additional files. For example, the collectd plugin @@ -788,7 +779,7 @@ will be discussed further in the testing section of this document. Another kind of external dependency is on jar files. This will be described in the "Add a `gemspec` file" section. -==== Add a Gemfile +===== Add a Gemfile Gemfiles allow Ruby's Bundler to maintain the dependencies for your plugin. Currently, all we'll need is the Logstash gem, for testing, but if you require @@ -854,7 +845,7 @@ please make sure to have this line in your gemspec: The gem version, designated by `s.version`, helps track changes to plugins over time. You should use http://semver.org/[semver versioning] strategy for version numbers. -==== Runtime & Development Dependencies +===== Runtime and Development Dependencies At the bottom of the `gemspec` file is a section with a comment: `Gem dependencies`. This is where any other needed gems must be mentioned. If @@ -881,7 +872,7 @@ it have a version number greater than or equal to version 1.60 and less than or IMPORTANT: All plugins have a runtime dependency on the `logstash-core-plugin-api` gem, and a development dependency on `logstash-devutils`. -==== Jar dependencies +===== Jar dependencies In some cases, such as the https://github.com/logstash-plugins/logstash-output-elasticsearch/blob/master/logstash-output-elasticsearch.gemspec#L22-L23[Elasticsearch output plugin], @@ -899,6 +890,16 @@ added in the gemspec file in this manner: With these both defined, the install process will search for the required jar file at http://mvnrepository.com and download the specified version. + +==== Document your plugin +Documentation is an important part of your plugin. All plugin documentation is +rendered and placed in the +http://www.elasticsearch.org/guide/en/logstash/current/index.html[Logstash +Reference] and the {lsplugindocs}[Versioned plugin docs]. + +See <> for tips and guidelines. + + ==== Add Tests Logstash loves tests. Lots of tests. If you're using your new {plugintype} @@ -960,7 +961,7 @@ Hooray! You're almost there! (Unless you saw failures... you should fix those Now you're ready to build your (well-tested) plugin into a Ruby gem. -==== Build +===== Build You already have all the necessary ingredients, so let's go ahead and run the build command: @@ -979,7 +980,7 @@ logstash-{plugintype}-mypluginname-0.1.0.gem The `s.version` number from your gemspec file will provide the gem version, in this case, `0.1.0`. -==== Test installation +===== Test installation You should test install your plugin into a clean installation of Logstash. Download the latest version from the @@ -1166,7 +1167,7 @@ Logstash uses http://rubygems.org[RubyGems.org] as its repository for all plugin artifacts. Once you have developed your new plugin, you can make it available to Logstash users by simply publishing it to RubyGems.org. -==== Licensing +===== Licensing Logstash and all its plugins are licensed under https://github.com/elasticsearch/logstash/blob/master/LICENSE[Apache License, version 2 ("ALv2")]. If you make your plugin publicly available via http://rubygems.org[RubyGems.org], @@ -1174,7 +1175,7 @@ please make sure to have this line in your gemspec: * `s.licenses = ['Apache License (2.0)']` -==== Publishing to http://rubygems.org[RubyGems.org] +===== Publishing to http://rubygems.org[RubyGems.org] To begin, you’ll need an account on RubyGems.org @@ -1235,7 +1236,7 @@ It is not required to contribute your source code to https://github.com/logstash-plugins[logstash-plugins] github organization, but we always welcome new plugins! -==== Benefits +===== Benefits Some of the many benefits of having your plugin in the logstash-plugins repository are: @@ -1249,11 +1250,11 @@ tested against current and future releases of Logstash. As a result, users will have the assurance that if incompatibilities arise, they will be quickly discovered and corrected. -==== Acceptance Guidelines +===== Acceptance Guidelines -* **Code Review** Your plugin must be reviewed by members of the community for +* **Code Review.** Your plugin must be reviewed by members of the community for coherence, quality, readability, stability and security. -* **Tests** Your plugin must contain tests to be accepted. These tests are also +* **Tests.** Your plugin must contain tests to be accepted. These tests are also subject to code review for scope and completeness. It's ok if you don't know how to write tests -- we will guide you. We are working on publishing a guide to creating tests for Logstash which will make it easier. In the meantime, you can From e173ceb04e92c94289cc3b061d8eb8efd6340ad4 Mon Sep 17 00:00:00 2001 From: Karen Metts Date: Fri, 28 Sep 2018 11:25:22 -0400 Subject: [PATCH 0094/1126] Note doc file created with plugin generation Fixes #9861 --- docs/static/doc-for-plugin.asciidoc | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/docs/static/doc-for-plugin.asciidoc b/docs/static/doc-for-plugin.asciidoc index b9475a642..9a10f5442 100644 --- a/docs/static/doc-for-plugin.asciidoc +++ b/docs/static/doc-for-plugin.asciidoc @@ -10,7 +10,9 @@ in the {logstash-ref}/index.html[Logstash Reference] and the [[plugin-doc-file]] ==== Documentation file -Include documentation in your plugin structure as a single file called 'docs/index.asciidoc'. +Documentation is a required component of your plugin. +It belongs in a single file called 'docs/index.asciidoc'. +The <> creates a starter file for you. [[heading-ids]] ==== Heading IDs @@ -79,7 +81,7 @@ Use external link syntax for links that point to documentation for other plugins {logstash-ref}/getting-started-with-logstash.html ----- -===== Links specifying link text +===== Link text If you don't specify link text, the URL is used as the link text. From 67aa145287f1d6cd346bc03b9a0ec6faa668e1e5 Mon Sep 17 00:00:00 2001 From: Karen Metts Date: Mon, 29 Apr 2019 14:39:39 -0400 Subject: [PATCH 0095/1126] Correct links to LS Ref Guide Fixes #10727 --- docs/static/include/pluginbody.asciidoc | 8 +++----- docs/static/submitting-a-plugin.asciidoc | 6 +++--- 2 files changed, 6 insertions(+), 8 deletions(-) diff --git a/docs/static/include/pluginbody.asciidoc b/docs/static/include/pluginbody.asciidoc index 8e6c81029..ae0d88a15 100644 --- a/docs/static/include/pluginbody.asciidoc +++ b/docs/static/include/pluginbody.asciidoc @@ -894,12 +894,10 @@ file at http://mvnrepository.com and download the specified version. ==== Document your plugin Documentation is an important part of your plugin. All plugin documentation is rendered and placed in the -http://www.elasticsearch.org/guide/en/logstash/current/index.html[Logstash -Reference] and the {lsplugindocs}[Versioned plugin docs]. +{logstash-ref}[Logstash Reference] and the {lsplugindocs}[Versioned plugin docs]. See <> for tips and guidelines. - ==== Add Tests Logstash loves tests. Lots of tests. If you're using your new {plugintype} @@ -1241,10 +1239,10 @@ we always welcome new plugins! Some of the many benefits of having your plugin in the logstash-plugins repository are: -* **Discovery.** Your plugin will appear in the http://www.elasticsearch.org/guide/en/logstash/current/index.html[Logstash Reference], +* **Discovery.** Your plugin will appear in the {logstash-ref}[Logstash Reference], where Logstash users look first for plugins and documentation. * **Documentation.** Your plugin documentation will automatically be added to the - http://www.elasticsearch.org/guide/en/logstash/current/index.html[Logstash Reference]. +{logstash-ref}[Logstash Reference]. * **Testing.** With our testing infrastructure, your plugin will be continuously tested against current and future releases of Logstash. As a result, users will have the assurance that if incompatibilities arise, they will be quickly diff --git a/docs/static/submitting-a-plugin.asciidoc b/docs/static/submitting-a-plugin.asciidoc index 8de77da37..1a9030aab 100644 --- a/docs/static/submitting-a-plugin.asciidoc +++ b/docs/static/submitting-a-plugin.asciidoc @@ -79,10 +79,10 @@ we always welcome new plugins! Some of the many benefits of having your plugin in the logstash-plugins repository are: -* **Discovery** Your plugin will appear in the http://www.elasticsearch.org/guide/en/logstash/current/index.html[Logstash Reference], +* **Discovery** Your plugin will appear in the {logstash-ref}[Logstash Reference], where Logstash users look first for plugins and documentation. -* **Documentation** Your plugin documentation will automatically be added to the - http://www.elasticsearch.org/guide/en/logstash/current/index.html[Logstash Reference]. +* **Documentation** Your plugin documentation will automatically be added to the +{logstash-ref}[Logstash Reference]. * **Testing** With our testing infrastructure, your plugin will be continuously tested against current and future releases of Logstash. As a result, users will have the assurance that if incompatibilities arise, they will be quickly From fbd1908e3a77928cec3bd60580ccd5321fcfaeea Mon Sep 17 00:00:00 2001 From: Mike Place Date: Thu, 21 Feb 2019 15:34:18 -0700 Subject: [PATCH 0096/1126] Add ephemeral id and hash to pipeline stats Refs #10119 Fixes #10561 --- logstash-core/lib/logstash/api/commands/node.rb | 2 +- logstash-core/lib/logstash/java_pipeline.rb | 3 ++- 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/logstash-core/lib/logstash/api/commands/node.rb b/logstash-core/lib/logstash/api/commands/node.rb index 17721bba9..38ab82d06 100644 --- a/logstash-core/lib/logstash/api/commands/node.rb +++ b/logstash-core/lib/logstash/api/commands/node.rb @@ -27,7 +27,7 @@ module LogStash def pipeline(pipeline_id) extract_metrics( [:stats, :pipelines, pipeline_id.to_sym, :config], - :workers, :batch_size, :batch_delay, :config_reload_automatic, :config_reload_interval, :dead_letter_queue_enabled, :dead_letter_queue_path + :ephemeral_id, :hash, :workers, :batch_size, :batch_delay, :config_reload_automatic, :config_reload_interval, :dead_letter_queue_enabled, :dead_letter_queue_path ).reject{|_, v|v.nil?} rescue {} diff --git a/logstash-core/lib/logstash/java_pipeline.rb b/logstash-core/lib/logstash/java_pipeline.rb index 8305f6c08..bda0e2a0b 100644 --- a/logstash-core/lib/logstash/java_pipeline.rb +++ b/logstash-core/lib/logstash/java_pipeline.rb @@ -216,7 +216,8 @@ module LogStash; class JavaPipeline < JavaBasePipeline config_metric.gauge(:config_reload_interval, settings.get("config.reload.interval")) config_metric.gauge(:dead_letter_queue_enabled, dlq_enabled?) config_metric.gauge(:dead_letter_queue_path, dlq_writer.get_path.to_absolute_path.to_s) if dlq_enabled? - + config_metric.gauge(:ephemeral_id, ephemeral_id) + config_metric.gauge(:hash, hash) @logger.info("Starting pipeline", default_logging_keys( "pipeline.workers" => pipeline_workers, From 3428383b1e5a4ab0e489644cec69c8fbc36fc82f Mon Sep 17 00:00:00 2001 From: Mike Place Date: Mon, 11 Mar 2019 10:10:49 -0600 Subject: [PATCH 0097/1126] Fix incorrect hash id Fixes #10561 --- logstash-core/lib/logstash/java_pipeline.rb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/logstash-core/lib/logstash/java_pipeline.rb b/logstash-core/lib/logstash/java_pipeline.rb index bda0e2a0b..4fbe8ed2d 100644 --- a/logstash-core/lib/logstash/java_pipeline.rb +++ b/logstash-core/lib/logstash/java_pipeline.rb @@ -217,7 +217,7 @@ module LogStash; class JavaPipeline < JavaBasePipeline config_metric.gauge(:dead_letter_queue_enabled, dlq_enabled?) config_metric.gauge(:dead_letter_queue_path, dlq_writer.get_path.to_absolute_path.to_s) if dlq_enabled? config_metric.gauge(:ephemeral_id, ephemeral_id) - config_metric.gauge(:hash, hash) + config_metric.gauge(:hash, lir.unique_hash) @logger.info("Starting pipeline", default_logging_keys( "pipeline.workers" => pipeline_workers, From 9d5bec9ef629928d88e8ba19296d263490bf2335 Mon Sep 17 00:00:00 2001 From: Mike Place Date: Mon, 11 Mar 2019 10:47:13 -0600 Subject: [PATCH 0098/1126] Add graph metrics Fixes #10561 --- logstash-core/lib/logstash/java_pipeline.rb | 2 ++ 1 file changed, 2 insertions(+) diff --git a/logstash-core/lib/logstash/java_pipeline.rb b/logstash-core/lib/logstash/java_pipeline.rb index 4fbe8ed2d..cbec94697 100644 --- a/logstash-core/lib/logstash/java_pipeline.rb +++ b/logstash-core/lib/logstash/java_pipeline.rb @@ -6,6 +6,7 @@ require "logstash/inputs/base" require "logstash/outputs/base" require "logstash/instrument/collector" require "logstash/compiler" +require "monitoring/inputs/metrics/state_event/lir_serializer" module LogStash; class JavaPipeline < JavaBasePipeline include LogStash::Util::Loggable @@ -218,6 +219,7 @@ module LogStash; class JavaPipeline < JavaBasePipeline config_metric.gauge(:dead_letter_queue_path, dlq_writer.get_path.to_absolute_path.to_s) if dlq_enabled? config_metric.gauge(:ephemeral_id, ephemeral_id) config_metric.gauge(:hash, lir.unique_hash) + config_metric.gauge(:graph, ::LogStash::Inputs::Metrics::StateEvent::LIRSerializer.serialize(lir)) @logger.info("Starting pipeline", default_logging_keys( "pipeline.workers" => pipeline_workers, From 2dbe5c1bc9bf8ace80184526f868c24bdfda0815 Mon Sep 17 00:00:00 2001 From: Mike Place Date: Mon, 11 Mar 2019 10:49:51 -0600 Subject: [PATCH 0099/1126] Include node update Fixes #10561 --- logstash-core/lib/logstash/api/commands/node.rb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/logstash-core/lib/logstash/api/commands/node.rb b/logstash-core/lib/logstash/api/commands/node.rb index 38ab82d06..1c53ba039 100644 --- a/logstash-core/lib/logstash/api/commands/node.rb +++ b/logstash-core/lib/logstash/api/commands/node.rb @@ -27,7 +27,7 @@ module LogStash def pipeline(pipeline_id) extract_metrics( [:stats, :pipelines, pipeline_id.to_sym, :config], - :ephemeral_id, :hash, :workers, :batch_size, :batch_delay, :config_reload_automatic, :config_reload_interval, :dead_letter_queue_enabled, :dead_letter_queue_path + :graph, :ephemeral_id, :hash, :workers, :batch_size, :batch_delay, :config_reload_automatic, :config_reload_interval, :dead_letter_queue_enabled, :dead_letter_queue_path ).reject{|_, v|v.nil?} rescue {} From 30adb7a56549560d0b5d67e4ef0b08ae8ceaab60 Mon Sep 17 00:00:00 2001 From: Mike Place Date: Thu, 14 Mar 2019 13:14:52 -0600 Subject: [PATCH 0100/1126] LIR serializer refactor Fixes #10561 --- logstash-core/lib/logstash/java_pipeline.rb | 4 +- logstash-core/lib/logstash/lir_serializer.rb | 138 ++++++++++++++++++ .../metrics/state_event/lir_serializer.rb | 120 +-------------- .../inputs/metrics/state_event_factory.rb | 2 +- 4 files changed, 144 insertions(+), 120 deletions(-) create mode 100644 logstash-core/lib/logstash/lir_serializer.rb diff --git a/logstash-core/lib/logstash/java_pipeline.rb b/logstash-core/lib/logstash/java_pipeline.rb index cbec94697..ab669e0bd 100644 --- a/logstash-core/lib/logstash/java_pipeline.rb +++ b/logstash-core/lib/logstash/java_pipeline.rb @@ -6,7 +6,7 @@ require "logstash/inputs/base" require "logstash/outputs/base" require "logstash/instrument/collector" require "logstash/compiler" -require "monitoring/inputs/metrics/state_event/lir_serializer" +require "logstash/lir_serializer" module LogStash; class JavaPipeline < JavaBasePipeline include LogStash::Util::Loggable @@ -219,7 +219,7 @@ module LogStash; class JavaPipeline < JavaBasePipeline config_metric.gauge(:dead_letter_queue_path, dlq_writer.get_path.to_absolute_path.to_s) if dlq_enabled? config_metric.gauge(:ephemeral_id, ephemeral_id) config_metric.gauge(:hash, lir.unique_hash) - config_metric.gauge(:graph, ::LogStash::Inputs::Metrics::StateEvent::LIRSerializer.serialize(lir)) + config_metric.gauge(:graph, ::LogStash::LIRSerializer.serialize(lir)) @logger.info("Starting pipeline", default_logging_keys( "pipeline.workers" => pipeline_workers, diff --git a/logstash-core/lib/logstash/lir_serializer.rb b/logstash-core/lib/logstash/lir_serializer.rb new file mode 100644 index 000000000..cb9353f80 --- /dev/null +++ b/logstash-core/lib/logstash/lir_serializer.rb @@ -0,0 +1,138 @@ +# 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. +# + +#FIXME +#require 'monitoring/inputs/metrics' +require 'logstash-core' +require 'logstash/compiler' + +#FIXME +#module LogStash; module Inputs; class Metrics; class StateEvent; +module LogStash; + class LIRSerializer + attr_reader :lir_pipeline + + def self.serialize(lir_pipeline) + self.new(lir_pipeline).serialize + end + + def initialize(lir_pipeline) + @lir_pipeline = lir_pipeline + end + + def serialize + { + "hash" => lir_pipeline.unique_hash, + "type" => "lir", + "version" => "0.0.0", + "graph" => { + "vertices" => vertices, + "edges" => edges + } + } + end + + def vertices + graph.getVertices.map {|v| vertex(v) } + end + + def edges + graph.getEdges.map {|e| edge(e) } + end + + def graph + lir_pipeline.graph + end + + def vertex(v) + hashified_vertex = case vertex_type(v) + when :plugin + plugin_vertex(v) + when :if + if_vertex(v) + when :queue + queue_vertex(v) + end + + decorate_vertex(v, hashified_vertex) + end + + def vertex_type(v) + if v.java_kind_of?(org.logstash.config.ir.graph.PluginVertex) + :plugin + elsif v.java_kind_of?(org.logstash.config.ir.graph.IfVertex) + :if + elsif v.java_kind_of?(org.logstash.config.ir.graph.QueueVertex) + :queue + else + raise "Unexpected vertex type! #{v}" + end + end + + def decorate_vertex(v, v_json) + v_json["meta"] = format_swm(v.source_with_metadata) + v_json["id"] = v.id + v_json["explicit_id"] = !!v.explicit_id + v_json["type"] = vertex_type(v).to_s + v_json + end + + def plugin_vertex(v) + pd = v.plugin_definition + { + "config_name" => pd.name, + "plugin_type" => pd.getType.to_s.downcase + } + end + + def if_vertex(v) + { + "condition" => v.humanReadableExpression + } + end + + def queue_vertex(v) + {} + end + + def edge(e) + e_json = { + "from" => e.from.id, + "to" => e.to.id, + "id" => e.id + } + + if e.java_kind_of?(org.logstash.config.ir.graph.BooleanEdge) + e_json["when"] = e.edge_type + e_json["type"] = "boolean" + else + e_json["type"] = "plain" + end + + e_json + end + + def format_swm(source_with_metadata) + return nil unless source_with_metadata + { + "source" => { + "protocol" => source_with_metadata.protocol, + "id" => source_with_metadata.id, + "line" => source_with_metadata.line, + "column" => source_with_metadata.column + # We omit the text of the source code for security reasons + # raw text may contain passwords + } + } + end + +# def plugins +# ::Gem::Specification. +# find_all. +# select {|spec| spec.metadata && spec.metadata["logstash_plugin"] == "true"}. +# map {|spec| { :name => spec.name, :version => spec.version.to_s } } +# end + end +end diff --git a/x-pack/lib/monitoring/inputs/metrics/state_event/lir_serializer.rb b/x-pack/lib/monitoring/inputs/metrics/state_event/lir_serializer.rb index 54ec8bf1b..94ba30492 100644 --- a/x-pack/lib/monitoring/inputs/metrics/state_event/lir_serializer.rb +++ b/x-pack/lib/monitoring/inputs/metrics/state_event/lir_serializer.rb @@ -5,9 +5,10 @@ require 'monitoring/inputs/metrics' require 'logstash-core' require 'logstash/compiler' +require 'logstash/lir_serializer' module LogStash; module Inputs; class Metrics; class StateEvent; - class LIRSerializer + class XPackLIRSerializer < LIRSerializer attr_reader :lir_pipeline def self.serialize(lir_pipeline) @@ -17,119 +18,4 @@ module LogStash; module Inputs; class Metrics; class StateEvent; def initialize(lir_pipeline) @lir_pipeline = lir_pipeline end - - def serialize - { - "hash" => lir_pipeline.unique_hash, - "type" => "lir", - "version" => "0.0.0", - "plugins" => plugins, - "graph" => { - "vertices" => vertices, - "edges" => edges - } - } - end - - def vertices - graph.getVertices.map {|v| vertex(v) } - end - - def edges - graph.getEdges.map {|e| edge(e) } - end - - def graph - lir_pipeline.graph - end - - def vertex(v) - hashified_vertex = case vertex_type(v) - when :plugin - plugin_vertex(v) - when :if - if_vertex(v) - when :queue - queue_vertex(v) - end - - decorate_vertex(v, hashified_vertex) - end - - def vertex_type(v) - if v.java_kind_of?(org.logstash.config.ir.graph.PluginVertex) - :plugin - elsif v.java_kind_of?(org.logstash.config.ir.graph.IfVertex) - :if - elsif v.java_kind_of?(org.logstash.config.ir.graph.QueueVertex) - :queue - else - raise "Unexpected vertex type! #{v}" - end - end - - def decorate_vertex(v, v_json) - v_json["meta"] = format_swm(v.source_with_metadata) - v_json["id"] = v.id - v_json["explicit_id"] = !!v.explicit_id - v_json["type"] = vertex_type(v).to_s - v_json - end - - def plugin_vertex(v) - pd = v.plugin_definition - { - "config_name" => pd.name, - "plugin_type" => pd.getType.to_s.downcase - } - end - - def if_vertex(v) - { - "condition" => v.humanReadableExpression - } - end - - def queue_vertex(v) - {} - end - - def edge(e) - e_json = { - "from" => e.from.id, - "to" => e.to.id, - "id" => e.id - } - - if e.java_kind_of?(org.logstash.config.ir.graph.BooleanEdge) - e_json["when"] = e.edge_type - e_json["type"] = "boolean" - else - e_json["type"] = "plain" - end - - e_json - end - - def format_swm(source_with_metadata) - return nil unless source_with_metadata - { - "source" => { - "protocol" => source_with_metadata.protocol, - "id" => source_with_metadata.id, - "line" => source_with_metadata.line, - "column" => source_with_metadata.column - # We omit the text of the source code for security reasons - # raw text may contain passwords - } - } - end - - def plugins - ::Gem::Specification. - find_all. - select {|spec| spec.metadata && spec.metadata["logstash_plugin"] == "true"}. - map {|spec| { :name => spec.name, :version => spec.version.to_s } } - end - end -end; end; end; end +end; end; end; end; end; diff --git a/x-pack/lib/monitoring/inputs/metrics/state_event_factory.rb b/x-pack/lib/monitoring/inputs/metrics/state_event_factory.rb index c0ef49d0a..d9f70fa94 100644 --- a/x-pack/lib/monitoring/inputs/metrics/state_event_factory.rb +++ b/x-pack/lib/monitoring/inputs/metrics/state_event_factory.rb @@ -29,7 +29,7 @@ module LogStash; module Inputs; class Metrics; "ephemeral_id" => pipeline.ephemeral_id, "workers" => pipeline.settings.get("pipeline.workers"), "batch_size" => pipeline.settings.get("pipeline.batch.size"), - "representation" => ::LogStash::Inputs::Metrics::StateEvent::LIRSerializer.serialize(pipeline.lir) + "representation" => ::LogStash::Inputs::Metrics::StateEvent::XPackLIRSerializer.serialize(pipeline.lir) } end From 0da3d0fb12f0f148a5388fffac9fc1e43b165895 Mon Sep 17 00:00:00 2001 From: Mike Place Date: Thu, 14 Mar 2019 13:21:42 -0600 Subject: [PATCH 0101/1126] Remove commented code Fixes #10561 --- logstash-core/lib/logstash/lir_serializer.rb | 6 ------ 1 file changed, 6 deletions(-) diff --git a/logstash-core/lib/logstash/lir_serializer.rb b/logstash-core/lib/logstash/lir_serializer.rb index cb9353f80..19978da4a 100644 --- a/logstash-core/lib/logstash/lir_serializer.rb +++ b/logstash-core/lib/logstash/lir_serializer.rb @@ -128,11 +128,5 @@ module LogStash; } end -# def plugins -# ::Gem::Specification. -# find_all. -# select {|spec| spec.metadata && spec.metadata["logstash_plugin"] == "true"}. -# map {|spec| { :name => spec.name, :version => spec.version.to_s } } -# end end end From 9c0dc0fb6995faed463b829f478a0ab8e09c11ad Mon Sep 17 00:00:00 2001 From: Mike Place Date: Thu, 14 Mar 2019 13:22:22 -0600 Subject: [PATCH 0102/1126] Remove more commented code Fixes #10561 --- logstash-core/lib/logstash/lir_serializer.rb | 4 ---- 1 file changed, 4 deletions(-) diff --git a/logstash-core/lib/logstash/lir_serializer.rb b/logstash-core/lib/logstash/lir_serializer.rb index 19978da4a..7bae770dd 100644 --- a/logstash-core/lib/logstash/lir_serializer.rb +++ b/logstash-core/lib/logstash/lir_serializer.rb @@ -3,13 +3,9 @@ # you may not use this file except in compliance with the Elastic License. # -#FIXME -#require 'monitoring/inputs/metrics' require 'logstash-core' require 'logstash/compiler' -#FIXME -#module LogStash; module Inputs; class Metrics; class StateEvent; module LogStash; class LIRSerializer attr_reader :lir_pipeline From 06d50daf36c3214a4d7006a40fc0f9a9d7648249 Mon Sep 17 00:00:00 2001 From: Mike Place Date: Thu, 14 Mar 2019 15:05:10 -0600 Subject: [PATCH 0103/1126] Update spec Fixes #10561 --- .../inputs/metrics/state_event/lir_serializer_spec.rb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/x-pack/spec/monitoring/inputs/metrics/state_event/lir_serializer_spec.rb b/x-pack/spec/monitoring/inputs/metrics/state_event/lir_serializer_spec.rb index 9d5096707..36e7ad41c 100644 --- a/x-pack/spec/monitoring/inputs/metrics/state_event/lir_serializer_spec.rb +++ b/x-pack/spec/monitoring/inputs/metrics/state_event/lir_serializer_spec.rb @@ -5,7 +5,7 @@ require "spec_helper" require "logstash/environment" -describe ::LogStash::Inputs::Metrics::StateEvent::LIRSerializer do +describe ::LogStash::Inputs::Metrics::StateEvent::XPackLIRSerializer do let(:config) do <<-EOC input { fake_input {} } From 6bc3ba480421a6cbe3987a26f0e104ce57f1eff3 Mon Sep 17 00:00:00 2001 From: Mike Place Date: Fri, 15 Mar 2019 09:24:17 -0600 Subject: [PATCH 0104/1126] Remove license and add encoding Fixes #10561 --- logstash-core/lib/logstash/lir_serializer.rb | 6 +----- 1 file changed, 1 insertion(+), 5 deletions(-) diff --git a/logstash-core/lib/logstash/lir_serializer.rb b/logstash-core/lib/logstash/lir_serializer.rb index 7bae770dd..afd84c706 100644 --- a/logstash-core/lib/logstash/lir_serializer.rb +++ b/logstash-core/lib/logstash/lir_serializer.rb @@ -1,8 +1,4 @@ -# 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. -# - +# encoding: utf-8 require 'logstash-core' require 'logstash/compiler' From d4a915be2bcd6598866fec4c1471124c9fc5f1bd Mon Sep 17 00:00:00 2001 From: Mike Place Date: Fri, 15 Mar 2019 09:38:03 -0600 Subject: [PATCH 0105/1126] Style change to make code more vertical. Fixes #10561 --- logstash-core/lib/logstash/api/commands/node.rb | 11 ++++++++++- 1 file changed, 10 insertions(+), 1 deletion(-) diff --git a/logstash-core/lib/logstash/api/commands/node.rb b/logstash-core/lib/logstash/api/commands/node.rb index 1c53ba039..6f943ff89 100644 --- a/logstash-core/lib/logstash/api/commands/node.rb +++ b/logstash-core/lib/logstash/api/commands/node.rb @@ -27,7 +27,16 @@ module LogStash def pipeline(pipeline_id) extract_metrics( [:stats, :pipelines, pipeline_id.to_sym, :config], - :graph, :ephemeral_id, :hash, :workers, :batch_size, :batch_delay, :config_reload_automatic, :config_reload_interval, :dead_letter_queue_enabled, :dead_letter_queue_path + :graph, + :ephemeral_id, + :hash, + :workers, + :batch_size, + :batch_delay, + :config_reload_automatic, + :config_reload_interval, + :dead_letter_queue_enabled, + :dead_letter_queue_path ).reject{|_, v|v.nil?} rescue {} From 4e5321a79a7a8a3ae80583e9bd16d4116e0b28c7 Mon Sep 17 00:00:00 2001 From: Mike Place Date: Mon, 18 Mar 2019 14:31:48 -0600 Subject: [PATCH 0106/1126] Implement review suggestions Fixes #10561 --- .../logstash/{ => config}/lir_serializer.rb | 2 ++ logstash-core/lib/logstash/java_pipeline.rb | 4 ++-- .../metrics/state_event/lir_serializer.rb | 21 ------------------- .../inputs/metrics/state_event_factory.rb | 5 +++-- 4 files changed, 7 insertions(+), 25 deletions(-) rename logstash-core/lib/logstash/{ => config}/lir_serializer.rb (99%) delete mode 100644 x-pack/lib/monitoring/inputs/metrics/state_event/lir_serializer.rb diff --git a/logstash-core/lib/logstash/lir_serializer.rb b/logstash-core/lib/logstash/config/lir_serializer.rb similarity index 99% rename from logstash-core/lib/logstash/lir_serializer.rb rename to logstash-core/lib/logstash/config/lir_serializer.rb index afd84c706..82b1ce2ff 100644 --- a/logstash-core/lib/logstash/lir_serializer.rb +++ b/logstash-core/lib/logstash/config/lir_serializer.rb @@ -3,6 +3,7 @@ require 'logstash-core' require 'logstash/compiler' module LogStash; + module Config; class LIRSerializer attr_reader :lir_pipeline @@ -121,4 +122,5 @@ module LogStash; end end + end end diff --git a/logstash-core/lib/logstash/java_pipeline.rb b/logstash-core/lib/logstash/java_pipeline.rb index ab669e0bd..981454ff4 100644 --- a/logstash-core/lib/logstash/java_pipeline.rb +++ b/logstash-core/lib/logstash/java_pipeline.rb @@ -6,7 +6,7 @@ require "logstash/inputs/base" require "logstash/outputs/base" require "logstash/instrument/collector" require "logstash/compiler" -require "logstash/lir_serializer" +require "logstash/config/lir_serializer" module LogStash; class JavaPipeline < JavaBasePipeline include LogStash::Util::Loggable @@ -219,7 +219,7 @@ module LogStash; class JavaPipeline < JavaBasePipeline config_metric.gauge(:dead_letter_queue_path, dlq_writer.get_path.to_absolute_path.to_s) if dlq_enabled? config_metric.gauge(:ephemeral_id, ephemeral_id) config_metric.gauge(:hash, lir.unique_hash) - config_metric.gauge(:graph, ::LogStash::LIRSerializer.serialize(lir)) + config_metric.gauge(:graph, ::LogStash::Config::LIRSerializer.serialize(lir)) @logger.info("Starting pipeline", default_logging_keys( "pipeline.workers" => pipeline_workers, diff --git a/x-pack/lib/monitoring/inputs/metrics/state_event/lir_serializer.rb b/x-pack/lib/monitoring/inputs/metrics/state_event/lir_serializer.rb deleted file mode 100644 index 94ba30492..000000000 --- a/x-pack/lib/monitoring/inputs/metrics/state_event/lir_serializer.rb +++ /dev/null @@ -1,21 +0,0 @@ -# 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 'monitoring/inputs/metrics' -require 'logstash-core' -require 'logstash/compiler' -require 'logstash/lir_serializer' - -module LogStash; module Inputs; class Metrics; class StateEvent; - class XPackLIRSerializer < LIRSerializer - attr_reader :lir_pipeline - - def self.serialize(lir_pipeline) - self.new(lir_pipeline).serialize - end - - def initialize(lir_pipeline) - @lir_pipeline = lir_pipeline - end -end; end; end; end; end; diff --git a/x-pack/lib/monitoring/inputs/metrics/state_event_factory.rb b/x-pack/lib/monitoring/inputs/metrics/state_event_factory.rb index d9f70fa94..64db96662 100644 --- a/x-pack/lib/monitoring/inputs/metrics/state_event_factory.rb +++ b/x-pack/lib/monitoring/inputs/metrics/state_event_factory.rb @@ -4,7 +4,8 @@ # module LogStash; module Inputs; class Metrics; class StateEventFactory - require "monitoring/inputs/metrics/state_event/lir_serializer" +# require "monitoring/inputs/metrics/state_event/lir_serializer" + require "logstash/config/lir_serializer" def initialize(pipeline) raise ArgumentError, "No pipeline passed in!" unless pipeline.is_a?(LogStash::Pipeline) || pipeline.is_a?(LogStash::JavaPipeline) @event = LogStash::Event.new @@ -29,7 +30,7 @@ module LogStash; module Inputs; class Metrics; "ephemeral_id" => pipeline.ephemeral_id, "workers" => pipeline.settings.get("pipeline.workers"), "batch_size" => pipeline.settings.get("pipeline.batch.size"), - "representation" => ::LogStash::Inputs::Metrics::StateEvent::XPackLIRSerializer.serialize(pipeline.lir) + "representation" => ::LogStash::Config::LIRSerializer.serialize(pipeline.lir) } end From a875d9e52902afe2ccffd1b98083dbec74c8b356 Mon Sep 17 00:00:00 2001 From: Mike Place Date: Mon, 18 Mar 2019 14:34:09 -0600 Subject: [PATCH 0107/1126] Remove commented code Fixes #10561 --- x-pack/lib/monitoring/inputs/metrics/state_event_factory.rb | 1 - 1 file changed, 1 deletion(-) diff --git a/x-pack/lib/monitoring/inputs/metrics/state_event_factory.rb b/x-pack/lib/monitoring/inputs/metrics/state_event_factory.rb index 64db96662..5d31d1c6c 100644 --- a/x-pack/lib/monitoring/inputs/metrics/state_event_factory.rb +++ b/x-pack/lib/monitoring/inputs/metrics/state_event_factory.rb @@ -4,7 +4,6 @@ # module LogStash; module Inputs; class Metrics; class StateEventFactory -# require "monitoring/inputs/metrics/state_event/lir_serializer" require "logstash/config/lir_serializer" def initialize(pipeline) raise ArgumentError, "No pipeline passed in!" unless pipeline.is_a?(LogStash::Pipeline) || pipeline.is_a?(LogStash::JavaPipeline) From a8806b1d49708ada069e590a00538b391ff23590 Mon Sep 17 00:00:00 2001 From: Mike Place Date: Mon, 18 Mar 2019 14:35:10 -0600 Subject: [PATCH 0108/1126] Fix spec path Fixes #10561 --- .../inputs/metrics/state_event/lir_serializer_spec.rb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/x-pack/spec/monitoring/inputs/metrics/state_event/lir_serializer_spec.rb b/x-pack/spec/monitoring/inputs/metrics/state_event/lir_serializer_spec.rb index 36e7ad41c..b4c2c64dd 100644 --- a/x-pack/spec/monitoring/inputs/metrics/state_event/lir_serializer_spec.rb +++ b/x-pack/spec/monitoring/inputs/metrics/state_event/lir_serializer_spec.rb @@ -5,7 +5,7 @@ require "spec_helper" require "logstash/environment" -describe ::LogStash::Inputs::Metrics::StateEvent::XPackLIRSerializer do +describe ::LogStash::Config::LIRSerializer do let(:config) do <<-EOC input { fake_input {} } From 8fd6e58e789042ca902893bd889c89faa2a9d769 Mon Sep 17 00:00:00 2001 From: Mike Place Date: Tue, 2 Apr 2019 12:08:13 -0600 Subject: [PATCH 0109/1126] Add cluster UUID Fixes #10561 --- logstash-core/lib/logstash/api/commands/node.rb | 3 ++- logstash-core/lib/logstash/java_pipeline.rb | 14 ++++++++++++++ 2 files changed, 16 insertions(+), 1 deletion(-) diff --git a/logstash-core/lib/logstash/api/commands/node.rb b/logstash-core/lib/logstash/api/commands/node.rb index 6f943ff89..ede9745ff 100644 --- a/logstash-core/lib/logstash/api/commands/node.rb +++ b/logstash-core/lib/logstash/api/commands/node.rb @@ -36,7 +36,8 @@ module LogStash :config_reload_automatic, :config_reload_interval, :dead_letter_queue_enabled, - :dead_letter_queue_path + :dead_letter_queue_path, + :cluster_uuids ).reject{|_, v|v.nil?} rescue {} diff --git a/logstash-core/lib/logstash/java_pipeline.rb b/logstash-core/lib/logstash/java_pipeline.rb index 981454ff4..faa1dd77c 100644 --- a/logstash-core/lib/logstash/java_pipeline.rb +++ b/logstash-core/lib/logstash/java_pipeline.rb @@ -220,6 +220,7 @@ module LogStash; class JavaPipeline < JavaBasePipeline config_metric.gauge(:ephemeral_id, ephemeral_id) config_metric.gauge(:hash, lir.unique_hash) config_metric.gauge(:graph, ::LogStash::Config::LIRSerializer.serialize(lir)) + config_metric.gauge(:cluster_uuids, resolve_cluster_uuids) @logger.info("Starting pipeline", default_logging_keys( "pipeline.workers" => pipeline_workers, @@ -258,6 +259,19 @@ module LogStash; class JavaPipeline < JavaBasePipeline end end + def resolve_cluster_uuids + cluster_uuids = [] + outputs.each do |output| + if LogStash::SETTINGS.registered?(output.id + ".cluster_uuid") + cluster_uuid = LogStash::SETTINGS.get(output.id + ".cluster_uuid") + unless cluster_uuids.include? cluster_uuid + cluster_uuids.push(cluster_uuid) + end + end + end + cluster_uuids + end + def wait_inputs @input_threads.each do |thread| if thread.class == Java::JavaObject From 592591bae9ee0290c05d05878a11d2618d3fb387 Mon Sep 17 00:00:00 2001 From: Mike Place Date: Wed, 3 Apr 2019 15:25:39 -0600 Subject: [PATCH 0110/1126] Add graph?=true parameter Fixes #10561 --- logstash-core/lib/logstash/api/commands/node.rb | 9 ++++++--- logstash-core/lib/logstash/api/modules/node.rb | 3 ++- 2 files changed, 8 insertions(+), 4 deletions(-) diff --git a/logstash-core/lib/logstash/api/commands/node.rb b/logstash-core/lib/logstash/api/commands/node.rb index ede9745ff..53eab8a87 100644 --- a/logstash-core/lib/logstash/api/commands/node.rb +++ b/logstash-core/lib/logstash/api/commands/node.rb @@ -24,10 +24,9 @@ module LogStash end end - def pipeline(pipeline_id) - extract_metrics( + def pipeline(pipeline_id, options={}) + metrics = extract_metrics( [:stats, :pipelines, pipeline_id.to_sym, :config], - :graph, :ephemeral_id, :hash, :workers, @@ -39,6 +38,10 @@ module LogStash :dead_letter_queue_path, :cluster_uuids ).reject{|_, v|v.nil?} + if options.fetch(:graph, false) + metrics.merge!(extract_metrics([:stats, :pipelines, pipeline_id.to_sym, :config], :graph)) + end + metrics rescue {} end diff --git a/logstash-core/lib/logstash/api/modules/node.rb b/logstash-core/lib/logstash/api/modules/node.rb index 985a8a6a4..2b132aec2 100644 --- a/logstash-core/lib/logstash/api/modules/node.rb +++ b/logstash-core/lib/logstash/api/modules/node.rb @@ -28,7 +28,8 @@ module LogStash get "/pipelines/:id" do pipeline_id = params["id"] - payload = node.pipeline(pipeline_id) + opts = {:graph => as_boolean(params.fetch("graph", false))} + payload = node.pipeline(pipeline_id, opts) halt(404) if payload.empty? respond_with(:pipelines => { pipeline_id => payload } ) end From dbea95111abb97806624f004d897b0a4ce186369 Mon Sep 17 00:00:00 2001 From: Mike Place Date: Mon, 8 Apr 2019 12:59:06 +0200 Subject: [PATCH 0111/1126] Add options to pipelines/ Fixes #10561 --- logstash-core/lib/logstash/api/commands/node.rb | 4 ++-- logstash-core/lib/logstash/api/modules/node.rb | 7 +++++++ 2 files changed, 9 insertions(+), 2 deletions(-) diff --git a/logstash-core/lib/logstash/api/commands/node.rb b/logstash-core/lib/logstash/api/commands/node.rb index 53eab8a87..e5b278f6f 100644 --- a/logstash-core/lib/logstash/api/commands/node.rb +++ b/logstash-core/lib/logstash/api/commands/node.rb @@ -17,10 +17,10 @@ module LogStash payload end - def pipelines + def pipelines(options={}) pipeline_ids = service.get_shallow(:stats, :pipelines).keys pipeline_ids.each_with_object({}) do |pipeline_id, result| - result[pipeline_id] = pipeline(pipeline_id) + result[pipeline_id] = pipeline(pipeline_id, options) end end diff --git a/logstash-core/lib/logstash/api/modules/node.rb b/logstash-core/lib/logstash/api/modules/node.rb index 2b132aec2..66a087809 100644 --- a/logstash-core/lib/logstash/api/modules/node.rb +++ b/logstash-core/lib/logstash/api/modules/node.rb @@ -34,6 +34,13 @@ module LogStash respond_with(:pipelines => { pipeline_id => payload } ) end + get "/pipelines" do + opts = {:graph => as_boolean(params.fetch("graph", false))} + payload = node.pipelines(opts) + halt(404) if payload.empty? + respond_with(:pipelines => payload ) + end + get "/?:filter?" do selected_fields = extract_fields(params["filter"].to_s.strip) values = node.all(selected_fields) From 42bbdd78c92a1e5651d343f35159fd80dc91ca08 Mon Sep 17 00:00:00 2001 From: Mike Place Date: Fri, 26 Apr 2019 17:38:03 +0200 Subject: [PATCH 0112/1126] Use pluginmetadata Fixes #10561 --- logstash-core/lib/logstash/java_pipeline.rb | 13 ++++--------- 1 file changed, 4 insertions(+), 9 deletions(-) diff --git a/logstash-core/lib/logstash/java_pipeline.rb b/logstash-core/lib/logstash/java_pipeline.rb index faa1dd77c..1360dd5e0 100644 --- a/logstash-core/lib/logstash/java_pipeline.rb +++ b/logstash-core/lib/logstash/java_pipeline.rb @@ -260,16 +260,11 @@ module LogStash; class JavaPipeline < JavaBasePipeline end def resolve_cluster_uuids - cluster_uuids = [] - outputs.each do |output| - if LogStash::SETTINGS.registered?(output.id + ".cluster_uuid") - cluster_uuid = LogStash::SETTINGS.get(output.id + ".cluster_uuid") - unless cluster_uuids.include? cluster_uuid - cluster_uuids.push(cluster_uuid) - end + outputs.each_with_object(Set.new) do |output, cluster_uuids| + if LogStash::PluginMetadata.exists?(output.id) + cluster_uuids << LogStash::PluginMetadata.for_plugin(output.id).get(:cluster_uuid) end - end - cluster_uuids + end.to_a.compact end def wait_inputs From 98f06702238ca99356a9d4081dd3185f892019a5 Mon Sep 17 00:00:00 2001 From: Mike Place Date: Tue, 30 Apr 2019 11:59:03 +0200 Subject: [PATCH 0113/1126] Replicate change from java_pipeline to ruby pipeline Fixes #10561 --- logstash-core/lib/logstash/pipeline.rb | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/logstash-core/lib/logstash/pipeline.rb b/logstash-core/lib/logstash/pipeline.rb index 2ce46b1fc..82add7120 100644 --- a/logstash-core/lib/logstash/pipeline.rb +++ b/logstash-core/lib/logstash/pipeline.rb @@ -394,6 +394,14 @@ module LogStash; class Pipeline < BasePipeline filter_queue_client.add_output_metrics(batch.filtered_size) end + def resolve_cluster_uuids + outputs.each_with_object(Set.new) do |output, cluster_uuids| + if LogStash::PluginMetadata.exists?(output.id) + cluster_uuids << LogStash::PluginMetadata.for_plugin(output.id).get(:cluster_uuid) + end + end.to_a.compact + end + def wait_inputs @input_threads.each(&:join) end From d1c51f7d6244a3e12eb7ecbe3fe16f741755056f Mon Sep 17 00:00:00 2001 From: Mike Place Date: Fri, 22 Mar 2019 09:52:36 -0600 Subject: [PATCH 0114/1126] ephemeral id Fixes #10589 --- .../lib/logstash/api/commands/default_metadata.rb | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/logstash-core/lib/logstash/api/commands/default_metadata.rb b/logstash-core/lib/logstash/api/commands/default_metadata.rb index 5bb177f42..b9ce83f1a 100644 --- a/logstash-core/lib/logstash/api/commands/default_metadata.rb +++ b/logstash-core/lib/logstash/api/commands/default_metadata.rb @@ -7,8 +7,12 @@ module LogStash module Commands class DefaultMetadata < Commands::Base def all - {:host => host, :version => version, :http_address => http_address, - :id => service.agent.id, :name => service.agent.name} + {:host => host, + :version => version, + :http_address => http_address, + :id => service.agent.id, + :name => service.agent.name, + :ephemeral_id => service.agent.ephemeral_id} end def host From 27d0ecab969e6cd0f26cf2c9b1786b35dc96f475 Mon Sep 17 00:00:00 2001 From: Mike Place Date: Fri, 22 Mar 2019 09:57:50 -0600 Subject: [PATCH 0115/1126] hard-code status Fixes #10589 --- logstash-core/lib/logstash/api/commands/default_metadata.rb | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/logstash-core/lib/logstash/api/commands/default_metadata.rb b/logstash-core/lib/logstash/api/commands/default_metadata.rb index b9ce83f1a..001074cf9 100644 --- a/logstash-core/lib/logstash/api/commands/default_metadata.rb +++ b/logstash-core/lib/logstash/api/commands/default_metadata.rb @@ -12,7 +12,8 @@ module LogStash :http_address => http_address, :id => service.agent.id, :name => service.agent.name, - :ephemeral_id => service.agent.ephemeral_id} + :ephemeral_id => service.agent.ephemeral_id, + :status_green => "green"} # This is hard-coded to mirror x-pack behavior end def host From 5d64a61c21295da468bf69737df4d43715da9d44 Mon Sep 17 00:00:00 2001 From: Mike Place Date: Tue, 26 Mar 2019 13:54:46 -0600 Subject: [PATCH 0116/1126] Add snapshot field Fixes #10589 --- logstash-core/lib/logstash/api/commands/default_metadata.rb | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/logstash-core/lib/logstash/api/commands/default_metadata.rb b/logstash-core/lib/logstash/api/commands/default_metadata.rb index 001074cf9..25a83ffc8 100644 --- a/logstash-core/lib/logstash/api/commands/default_metadata.rb +++ b/logstash-core/lib/logstash/api/commands/default_metadata.rb @@ -13,7 +13,9 @@ module LogStash :id => service.agent.id, :name => service.agent.name, :ephemeral_id => service.agent.ephemeral_id, - :status_green => "green"} # This is hard-coded to mirror x-pack behavior + :status => "green", # This is hard-coded to mirror x-pack behavior + :snapshot => ::BUILD_INFO["build_snapshot"], + } end def host From 0793bf1f5aaffc4b8a6d016a6a810f7427106b5d Mon Sep 17 00:00:00 2001 From: Nik Everett Date: Wed, 1 May 2019 13:54:43 -0400 Subject: [PATCH 0117/1126] [Docs] Asciidoctor support (#10730) Ports elastic/logstash-docs#688 to this repo. Asciidoctor doesn't quite work on this repo, but it comes closer with these changes. --- docs/include/input.asciidoc | 4 +++- docs/include/plugin_header.asciidoc | 6 +++++- docs/include/version-list-intro.asciidoc | 1 + 3 files changed, 9 insertions(+), 2 deletions(-) diff --git a/docs/include/input.asciidoc b/docs/include/input.asciidoc index 9c6a7b802..83d7734dd 100644 --- a/docs/include/input.asciidoc +++ b/docs/include/input.asciidoc @@ -152,7 +152,8 @@ a new input will not override the existing type. A type set at the shipper stays with that event for its life even when sent to another Logstash server. -ifeval::["{type}"=="input" and "{plugin}"=="beats"] +ifeval::["{type}"=="input"] +ifeval::["{plugin}"=="beats"] ifeval::["{versioned_docs}"!="true"] NOTE: The Beats shipper automatically sets the `type` field on the event. @@ -168,4 +169,5 @@ Logstash, it is ignored. endif::[] endif::[] +endif::[] diff --git a/docs/include/plugin_header.asciidoc b/docs/include/plugin_header.asciidoc index 9640b1c59..d77f7195b 100644 --- a/docs/include/plugin_header.asciidoc +++ b/docs/include/plugin_header.asciidoc @@ -1,9 +1,11 @@ ifeval::["{versioned_docs}"!="true"] +[subs="attributes"] ++++ {plugin} ++++ endif::[] ifeval::["{versioned_docs}"=="true"] +[subs="attributes"] ++++ {version} ++++ @@ -28,12 +30,14 @@ To learn more about Logstash, see the {logstash-ref}/index.html[Logstash Referen endif::[] -ifeval::[("{default_plugin}"=="0") and ("{versioned_docs}"!="true")] +ifeval::["{default_plugin}"=="0"] +ifeval::["{versioned_docs}"!="true"] ==== Installation For plugins not bundled by default, it is easy to install by running +bin/logstash-plugin install logstash-{type}-{plugin}+. See {logstash-ref}/working-with-plugins.html[Working with plugins] for more details. +endif::[] endif::[] ==== Getting Help diff --git a/docs/include/version-list-intro.asciidoc b/docs/include/version-list-intro.asciidoc index 5ba89ed4b..c396d201c 100644 --- a/docs/include/version-list-intro.asciidoc +++ b/docs/include/version-list-intro.asciidoc @@ -1,6 +1,7 @@ [id="{type}-{plugin}-index"] == Versioned {plugin} {type} plugin docs +[subs="attributes"] ++++ {plugin} ++++ From 735359c4c9bbee789c8119b2915c3bfdad5d4b6a Mon Sep 17 00:00:00 2001 From: Joao Duarte Date: Wed, 1 May 2019 19:16:10 +0100 Subject: [PATCH 0118/1126] bump to 7.2.0 --- README.md | 16 ++++++++-------- versions.yml | 4 ++-- 2 files changed, 10 insertions(+), 10 deletions(-) diff --git a/README.md b/README.md index 2198bed2e..bb4b6d0b0 100644 --- a/README.md +++ b/README.md @@ -28,14 +28,14 @@ These builds are created nightly and have undergone no formal QA, so they should | [deb-complete][] | [deb-oss][] | | [rpm-complete][] | [rpm-oss][] | -[tar-complete]: https://snapshots.elastic.co/downloads/logstash/logstash-7.1.0-SNAPSHOT.tar.gz -[zip-complete]: https://snapshots.elastic.co/downloads/logstash/logstash-7.1.0-SNAPSHOT.zip -[deb-complete]: https://snapshots.elastic.co/downloads/logstash/logstash-7.1.0-SNAPSHOT.deb -[rpm-complete]: https://snapshots.elastic.co/downloads/logstash/logstash-7.1.0-SNAPSHOT.rpm -[tar-oss]: https://snapshots.elastic.co/downloads/logstash/logstash-oss-7.1.0-SNAPSHOT.tar.gz -[zip-oss]: https://snapshots.elastic.co/downloads/logstash/logstash-oss-7.1.0-SNAPSHOT.zip -[deb-oss]: https://snapshots.elastic.co/downloads/logstash/logstash-oss-7.1.0-SNAPSHOT.deb -[rpm-oss]: https://snapshots.elastic.co/downloads/logstash/logstash-oss-7.1.0-SNAPSHOT.rpm +[tar-complete]: https://snapshots.elastic.co/downloads/logstash/logstash-7.2.0-SNAPSHOT.tar.gz +[zip-complete]: https://snapshots.elastic.co/downloads/logstash/logstash-7.2.0-SNAPSHOT.zip +[deb-complete]: https://snapshots.elastic.co/downloads/logstash/logstash-7.2.0-SNAPSHOT.deb +[rpm-complete]: https://snapshots.elastic.co/downloads/logstash/logstash-7.2.0-SNAPSHOT.rpm +[tar-oss]: https://snapshots.elastic.co/downloads/logstash/logstash-oss-7.2.0-SNAPSHOT.tar.gz +[zip-oss]: https://snapshots.elastic.co/downloads/logstash/logstash-oss-7.2.0-SNAPSHOT.zip +[deb-oss]: https://snapshots.elastic.co/downloads/logstash/logstash-oss-7.2.0-SNAPSHOT.deb +[rpm-oss]: https://snapshots.elastic.co/downloads/logstash/logstash-oss-7.2.0-SNAPSHOT.rpm ## Need Help? diff --git a/versions.yml b/versions.yml index 7d730b9c4..0cf0238b4 100644 --- a/versions.yml +++ b/versions.yml @@ -1,7 +1,7 @@ --- # alpha and beta qualifiers are now added via VERSION_QUALIFIER environment var -logstash: 7.1.0 -logstash-core: 7.1.0 +logstash: 7.2.0 +logstash-core: 7.2.0 logstash-core-plugin-api: 2.1.16 # jruby must reference a *released* version of jruby which can be downloaded from the official download url From 3fba3af9f9f084ff711bbc98c2491ae6744b81b5 Mon Sep 17 00:00:00 2001 From: Dan Hermann Date: Thu, 14 Mar 2019 12:06:58 -0500 Subject: [PATCH 0119/1126] * Adds a java_generator input with jdots codec to facilitate testing, adds float config type * Breaking change to codec.encode method * Sink output for discarding events * URI and password config types * Utility methods for packaging Java plugins * Plugin API validation, fix gemspec generation * Plugin Jar validation * Update developer documentation * Update codec metrics for new encode method * Beta: Isolated classloaders for Java plugins * Address code review comments Fixes #10620 --- docker/data/logstash/env2yaml/env2yaml.go | 1 + docs/static/contributing-java-plugin.asciidoc | 3 +- docs/static/include/javapluginpkg.asciidoc | 161 +++++--------- docs/static/include/javapluginsetup.asciidoc | 4 +- docs/static/java-codec.asciidoc | 98 ++------- docs/static/java-filter.asciidoc | 10 +- docs/static/java-input.asciidoc | 10 +- docs/static/java-output.asciidoc | 10 +- .../running-logstash-command-line.asciidoc | 3 + docs/static/settings-file.asciidoc | 4 + logstash-core/lib/logstash/environment.rb | 1 + .../lib/logstash/pipeline_settings.rb | 1 + .../lib/logstash/plugins/registry.rb | 30 ++- logstash-core/lib/logstash/runner.rb | 5 + logstash-core/locales/en.yml | 2 + .../java/co/elastic/logstash/api/Codec.java | 37 +--- .../co/elastic/logstash/api/Password.java | 22 ++ .../logstash/api/PluginConfigSpec.java | 45 ++++ .../ir/compiler/JavaCodecDelegator.java | 8 +- .../ir/compiler/JavaInputDelegatorExt.java | 5 + .../logstash/plugins/ConfigurationImpl.java | 30 ++- .../logstash/plugins/PluginClassLoader.java | 69 ++++++ .../logstash/plugins/PluginFactoryExt.java | 18 +- .../org/logstash/plugins/PluginLookup.java | 14 +- .../org/logstash/plugins/PluginValidator.java | 57 +++++ .../org/logstash/plugins/codecs/Dots.java | 61 ++++++ .../org/logstash/plugins/codecs/Line.java | 41 +--- .../logstash/plugins/inputs/Generator.java | 197 ++++++++++++++++++ .../org/logstash/plugins/outputs/Sink.java | 47 +++++ .../org/logstash/plugins/outputs/Stdout.java | 17 +- .../ir/compiler/JavaCodecDelegatorTest.java | 25 ++- .../plugins/ConfigurationImplTest.java | 84 +++++++- .../logstash/plugins/PluginValidatorTest.java | 69 ++++++ .../org/logstash/plugins/codecs/LineTest.java | 164 +++++---------- ...ogstash-input-java_input_example-0.0.1.jar | Bin 0 -> 2962804 bytes rubyUtils.gradle | 132 ++++++++++++ 36 files changed, 1062 insertions(+), 423 deletions(-) create mode 100644 logstash-core/src/main/java/co/elastic/logstash/api/Password.java create mode 100644 logstash-core/src/main/java/org/logstash/plugins/PluginClassLoader.java create mode 100644 logstash-core/src/main/java/org/logstash/plugins/PluginValidator.java create mode 100644 logstash-core/src/main/java/org/logstash/plugins/codecs/Dots.java create mode 100644 logstash-core/src/main/java/org/logstash/plugins/inputs/Generator.java create mode 100644 logstash-core/src/main/java/org/logstash/plugins/outputs/Sink.java create mode 100644 logstash-core/src/test/java/org/logstash/plugins/PluginValidatorTest.java create mode 100644 logstash-core/src/test/resources/org/logstash/plugins/logstash-input-java_input_example-0.0.1.jar diff --git a/docker/data/logstash/env2yaml/env2yaml.go b/docker/data/logstash/env2yaml/env2yaml.go index 507f73f0a..e63390e8c 100644 --- a/docker/data/logstash/env2yaml/env2yaml.go +++ b/docker/data/logstash/env2yaml/env2yaml.go @@ -57,6 +57,7 @@ func normalizeSetting(setting string) (string, error) { "pipeline.batch.delay", "pipeline.unsafe_shutdown", "pipeline.java_execution", + "pipeline.plugin_classloaders", "path.config", "config.string", "config.test_and_exit", diff --git a/docs/static/contributing-java-plugin.asciidoc b/docs/static/contributing-java-plugin.asciidoc index 04e994fed..e509eaaf6 100644 --- a/docs/static/contributing-java-plugin.asciidoc +++ b/docs/static/contributing-java-plugin.asciidoc @@ -17,8 +17,7 @@ The APIs are in the `co.elastic.logstash.api` package. A Java plugin might break if it references classes or specific concrete implementations of API interfaces outside that package. The implementation of classes outside of the API package may change at any time. -* Coming in a future release: Tooling to automate the packaging and deployment of -Java plugins in Logstash. (Currently, this process is manual.) +* Tooling to automate the packaging and deployment of Java plugins in Logstash. [float] === Process overview diff --git a/docs/static/include/javapluginpkg.asciidoc b/docs/static/include/javapluginpkg.asciidoc index b3f16c198..7f23d2f0a 100644 --- a/docs/static/include/javapluginpkg.asciidoc +++ b/docs/static/include/javapluginpkg.asciidoc @@ -2,123 +2,73 @@ === Package and deploy Java plugins are packaged as Ruby gems for dependency management and -interoperability with Ruby plugins. - -NOTE: One of the goals for Java plugin support is to eliminate the need for any -knowledge of Ruby or its toolchain for Java plugin development. Future phases of -the Java plugin project will automate the packaging of Java plugins as Ruby gems -so no direct knowledge of or interaction with Ruby will be required. In the -current phase, Java plugins must still be manually packaged as Ruby gems -and installed with the `logstash-plugin` utility. +interoperability with Ruby plugins. Once they are packaged as gems, they may +be installed with the `logstash-plugin` utility just as Ruby plugins are. +Because no knowledge of Ruby or its toolchain should be required for Java +plugin development, the procedure for packaging Java plugins as Ruby gems +has been automated through a custom task in the Gradle build file provided +with the example Java plugins. The following sections describe how to +configure and execute that packaging task as well as how to install the +packaged Java plugin in Logstash. [float] -==== Compile to JAR file +==== Configuring the Gradle packaging task -The Java plugin should be compiled and assembled into a fat jar with the -`vendor` task in the Gradle build file. This will package all Java dependencies -into a single jar and write it to the correct folder for later packaging into a -Ruby gem. +The following section appears near the top of the `build.gradle` file supplied +with the example Java plugins: + +[source,java] +[subs="attributes"] +----- +// =========================================================================== +// plugin info +// =========================================================================== +group 'org.logstashplugins' // must match the package of the main plugin class +version "${file("VERSION").text.trim()}" // read from required VERSION file +description = "Example Java filter implementation" +pluginInfo.licenses = ['Apache-2.0'] // list of SPDX license IDs +pluginInfo.longDescription = "This gem is a Logstash plugin required to be installed on top of the Logstash core pipeline using \$LS_HOME/bin/logstash-plugin install gemname. This gem is not a stand-alone program" +pluginInfo.authors = ['Elasticsearch'] +pluginInfo.email = ['info@elastic.co'] +pluginInfo.homepage = "http://www.elastic.co/guide/en/logstash/current/index.html" +pluginInfo.pluginType = "filter" +pluginInfo.pluginClass = "JavaFilterExample" +pluginInfo.pluginName = "java_filter_example" +// =========================================================================== +----- + +You should configure the values above for your plugin. + +* The `version` value will be automatically read from the `VERSION` file in the +root of your plugin's codebase. +* `pluginInfo.pluginType` should be set to one of `input`, `filter`, `codec`, +or `output`. +* `pluginInfo.pluginName` must match the name specified on the `@LogstashPlugin` +annotation on the main plugin class. The Gradle packaging task will validate +that and return an error if they do not match. [float] -==== Manually package as Ruby gem +==== Running the Gradle packaging task -Several Ruby source files are required to package the jar file as a -Ruby gem. These Ruby files are used only at Logstash startup time to identify -the Java plugin and are not used during runtime event processing. +Several Ruby source files along with a `gemspec` file and a `Gemfile` are +required to package the plugin as a Ruby gem. These Ruby files are used only +for defining the Ruby gem structure or at Logstash startup time to register +the Java plugin. They are not used during runtime event processing. The +Gradle packaging task automatically generates all of these files based on +the values configured in the section above. -NOTE: These Ruby source files will be automatically generated in a future release. - -**+logstash-{plugintype}-<{plugintype}-name>.gemspec+** - -[source,txt] -[subs="attributes"] ------ -Gem::Specification.new do |s| - s.name = 'logstash-{plugintype}-java_{plugintype}_example' - s.version = PLUGIN_VERSION - s.licenses = ['Apache-2.0'] - s.summary = "Example {plugintype} using Java plugin API" - s.description = "" - s.authors = ['Elasticsearch'] - s.email = 'info@elastic.co' - s.homepage = "http://www.elastic.co/guide/en/logstash/current/index.html" - s.require_paths = ['lib', 'vendor/jar-dependencies'] - - # Files - s.files = Dir["lib/**/*","spec/**/*","*.gemspec","*.md","CONTRIBUTORS","Gemfile","LICENSE","NOTICE.TXT", "vendor/jar-dependencies/**/*.jar", "vendor/jar-dependencies/**/*.rb", "VERSION", "docs/**/*"] - - # Special flag to let us know this is actually a logstash plugin - s.metadata = { 'logstash_plugin' => 'true', 'logstash_group' => '{plugintype}'} - - # Gem dependencies - s.add_runtime_dependency "logstash-core-plugin-api", ">= 1.60", "<= 2.99" - s.add_runtime_dependency 'jar-dependencies' - - s.add_development_dependency 'logstash-devutils' -end ------ - -You can use this file with the following modifications: - -* `s.name` must follow the +logstash-pass:attributes[{plugintype}]-<{plugintype}-name>+ pattern -* `s.version` must match the `project.version` specified in the `build.gradle` file. -Both versions should be set to be read from the `VERSION` file in this example. - -**+lib/logstash/{plugintype}s/<{plugintype}-name>.rb+** - -[source,ruby] -[subs="attributes"] ------ -# encoding: utf-8 -require "logstash/{plugintype}s/base" -require "logstash/namespace" -require "logstash-{plugintype}-java_{plugintype}_example_jars" -require "java" - -class LogStash::{plugintype}s::Java{plugintypecap}Example < LogStash::{pluginclass}::Base - config_name "java_{plugintype}_example" - - def self.javaClass() org.logstash.javaapi.Java{plugintypecap}Example.java_class; end -end ------ - -Modify these items in the file above: - -* Change the name to correspond with the {plugintype} name. -* Change +require "logstash-{plugintype}-java_{plugintype}_example_jars"+ to reference the appropriate "jars" file -as described below. -* Change +class LogStash::{pluginclass}::Java{plugintypecap}Example < LogStash::{pluginclass}::Base+ to provide a unique and -descriptive Ruby class name. -* Change +config_name "java_{plugintype}_example"+ to match the name of the plugin as specified in the `name` property of -the `@LogstashPlugin` annotation. -* Change +def self.javaClass() org.logstash.javaapi.Java{plugintypecap}Example.java_class; end+ to return the -class of the Java {plugintype}. - -**+lib/logstash-{plugintype}-<{plugintype}-name>_jars.rb+** - -[source,txt] -[subs="attributes"] ------ -require 'jar_dependencies' -require_jar('org.logstash.javaapi', 'logstash-{plugintype}-java_{plugintype}_example', {sversion}) ------ - -In the file above: - -* Rename the file to correspond to the {plugintype} name. -* Change the `require_jar` directive to correspond to the `group` specified in the -Gradle build file, the name of the {plugintype} JAR file, and the version as -specified in both the gemspec and Gradle build file. - -After you have created the previous files and the plugin JAR file, build the gem using the -following command: +You run the Gradle packaging task with the following command: [source,shell] -[subs="attributes"] ----- -gem build logstash-{plugintype}-<{plugintype}-name>.gemspec +./gradlew gem ----- +For Windows platforms: Substitute `gradlew.bat` for `./gradlew` as appropriate in the command. + +That task will produce a gem file in the root directory of your +plugin's codebase with the name `logstash-{plugintype}--.gem` + [float] ==== Installing the Java plugin in Logstash @@ -131,4 +81,3 @@ bin/logstash-plugin install --no-verify --local /path/to/javaPlugin.gem ----- For Windows platforms: Substitute backslashes for forward slashes as appropriate in the command. - diff --git a/docs/static/include/javapluginsetup.asciidoc b/docs/static/include/javapluginsetup.asciidoc index 02e5d6011..8a753138f 100644 --- a/docs/static/include/javapluginsetup.asciidoc +++ b/docs/static/include/javapluginsetup.asciidoc @@ -20,8 +20,8 @@ git clone --branch --single-branch https://github.com/elastic/logs The `branch_name` should correspond to the version of Logstash containing the preferred revision of the Java plugin API. -NOTE: The beta version of the Java plugin API is available in the `6.7` -branch of the Logstash codebase. +NOTE: The GA version of the Java plugin API is available in the `7.1` +and later branches of the Logstash codebase. Specify the `target_folder` for your local copy of the Logstash codebase. If you do not specify `target_folder`, it defaults to a new folder called `logstash` diff --git a/docs/static/java-codec.asciidoc b/docs/static/java-codec.asciidoc index a68fde22e..a1b4ad144 100644 --- a/docs/static/java-codec.asciidoc +++ b/docs/static/java-codec.asciidoc @@ -20,8 +20,6 @@ === How to write a Java codec plugin -beta[] - NOTE: Java codecs are currently supported only for Java input and output plugins. They will not work with Ruby input or output plugins. @@ -51,9 +49,6 @@ public class JavaCodecExample implements Codec { private final String id; private final String delimiter; - private final CharsetEncoder encoder; - private Event currentEncodedEvent; - private CharBuffer currentEncoding; public JavaCodecExample(final Configuration config, final Context context) { this(config.get(DELIMITER_CONFIG)); @@ -62,7 +57,6 @@ public class JavaCodecExample implements Codec { private JavaCodecExample(String delimiter) { this.id = UUID.randomUUID().toString(); this.delimiter = delimiter; - this.encoder = Charset.defaultCharset().newEncoder(); } @Override @@ -91,30 +85,8 @@ public class JavaCodecExample implements Codec { } @Override - public boolean encode(Event event, ByteBuffer buffer) throws EncodeException { - try { - if (currentEncodedEvent != null && event != currentEncodedEvent) { - throw new EncodeException("New event supplied before encoding of previous event was completed"); - } else if (currentEncodedEvent == null) { - currentEncoding = CharBuffer.wrap(event.toString() + delimiter); - } - - CoderResult result = encoder.encode(currentEncoding, buffer, true); - buffer.flip(); - if (result.isError()) { - result.throwException(); - } - - if (result.isOverflow()) { - currentEncodedEvent = event; - return false; - } else { - currentEncodedEvent = null; - return true; - } - } catch (IOException e) { - throw new IllegalStateException(e); - } + public void encode(Event event, OutputStream outputStream) throws IOException { + outputStream.write((event.toString() + delimiter).getBytes(Charset.defaultCharset())); } @Override @@ -132,6 +104,7 @@ public class JavaCodecExample implements Codec { public String getId() { return this.id; } + } ----- @@ -154,6 +127,8 @@ Notes about the class declaration: an appropriate input or output in the Logstash pipeline defintion as `codec => java_codec_example { }` ** The value of the `name` property must match the name of the class excluding casing and underscores. * The class must implement the `co.elastic.logstash.api.Codec` interface. +* Java plugins may not be created in the `org.logstash` or `co.elastic.logstash` packages to prevent potential +clashes with classes in Logstash itself. [float] ===== Plugin settings @@ -188,7 +163,6 @@ settings are present and that no unsupported settings are present. ----- private final String id; private final String delimiter; -private final CharsetEncoder encoder; public JavaCodecExample(final Configuration config, final Context context) { this(config.get(DELIMITER_CONFIG)); @@ -197,7 +171,6 @@ public JavaCodecExample(final Configuration config, final Context context) { private JavaCodecExample(String delimiter) { this.id = UUID.randomUUID().toString(); this.delimiter = delimiter; - this.encoder = Charset.defaultCharset().newEncoder(); } ----- @@ -239,36 +212,17 @@ public void decode(ByteBuffer byteBuffer, Consumer> consumer @Override public void flush(ByteBuffer byteBuffer, Consumer> consumer) { + // if the codec maintains any internal state such as partially-decoded input, this + // method should flush that state along with any additional input supplied in + // the ByteBuffer + decode(byteBuffer, consumer); // this is a simplistic implementation } @Override -public boolean encode(Event event, ByteBuffer buffer) throws EncodeException { - try { - if (currentEncodedEvent != null && event != currentEncodedEvent) { - throw new EncodeException("New event supplied before encoding of previous event was completed"); - } else if (currentEncodedEvent == null) { - currentEncoding = CharBuffer.wrap(event.toString() + delimiter); - } - - CoderResult result = encoder.encode(currentEncoding, buffer, true); - buffer.flip(); - if (result.isError()) { - result.throwException(); - } - - if (result.isOverflow()) { - currentEncodedEvent = event; - return false; - } else { - currentEncodedEvent = null; - return true; - } - } catch (IOException e) { - throw new IllegalStateException(e); - } +public void encode(Event event, OutputStream outputStream) throws IOException { + outputStream.write((event.toString() + delimiter).getBytes(Charset.defaultCharset())); } - ----- The `decode`, `flush`, and `encode` methods provide the core functionality of @@ -285,7 +239,7 @@ responsible for returning the buffer to write mode via either `byteBuffer.clear()` or `byteBuffer.compact()` before resuming writes. In the example above, the `decode` method simply splits the incoming byte stream on the specified delimiter. A production-grade codec such as -https://github.com/elastic/logstash/blob/6.7/logstash-core/src/main/java/org/logstash/plugins/codecs/Line.java[`java-line`] +https://github.com/elastic/logstash/blob/master/logstash-core/src/main/java/org/logstash/plugins/codecs/Line.java[`java-line`] would not make the simplifying assumption that the end of the supplied byte stream corresponded with the end of an event. @@ -307,25 +261,9 @@ above is a simplistic implementation that does not maintain any state about partially-supplied byte streams across calls to `decode`. The `encode` method encodes an event into a sequence of bytes and writes it into -the specified `ByteBuffer`. Under ideal circumstances, the entirety of the -event's encoding will fit into the supplied buffer. In cases where the buffer -has insufficient space to hold the event's encoding, the codec must fill the -buffer with as much of the event's encoding as possible, the `encode` must -return `false`, and the output must call the `encode` method with the same event -and a buffer that has more `buffer.remaining()` bytes. The output typically does -that by draining the partial encoding from the supplied buffer. This process -must be repeated until the event's entire encoding is written to the buffer at -which point the `encode` method will return `true`. Attempting to call this -method with a new event before the entirety of the previous event's encoding has -been written to a buffer must result in an `EncodeException`. As the coneptual -inverse of the `decode` method, the `encode` method must return the buffer in a -state from which it can be read, typically by calling `buffer.flip()` before -returning. In the example above, the `encode` method attempts to write the -event's encoding to the supplied buffer. If the buffer contains sufficient free -space, the entirety of the event is written and `true` is returned. Otherwise, -the method writes as much of the event's encoding to the buffer as possible, -returns `false`, and stores the remainder to be written to the buffer in the -next call to the `encode` method. +the specified `OutputStream`. Because a single codec instance is shared across +all pipeline workers in the output stage of the Logstash pipeline, codecs should +_not_ retain state across calls to their `encode` methods. [float] ==== cloneCodec method @@ -376,11 +314,11 @@ To test the plugin, start Logstash with: [source,java] ----- -echo "foo,bar" | bin/logstash --java-execution -e 'input { java_stdin { codec => java_codec_example } } }' +echo "foo,bar" | bin/logstash -e 'input { java_stdin { codec => java_codec_example } } }' ----- -NOTE: The `--java-execution` flag to enable the Java execution engine is required as Java plugins are not supported -in the Ruby execution engine. +NOTE: The Java execution engine, the default execution engine since Logstash 7.0, is required +as Java plugins are not supported in the Ruby execution engine. The expected Logstash output (excluding initialization) with the configuration above is: diff --git a/docs/static/java-filter.asciidoc b/docs/static/java-filter.asciidoc index e2d2a05b0..e526c93ef 100644 --- a/docs/static/java-filter.asciidoc +++ b/docs/static/java-filter.asciidoc @@ -14,8 +14,6 @@ [[java-filter-plugin]] === How to write a Java filter plugin -beta[] - // Pulls in shared section: Setting Up Environment include::include/javapluginsetup.asciidoc[] @@ -86,6 +84,8 @@ Notes about the class declaration: Logstash pipeline defintion as `filter { java_filter_example => { .... } }` ** The value of the `name` property must match the name of the class excluding casing and underscores. * The class must implement the `co.elastic.logstash.api.Filter` interface. +* Java plugins may not be created in the `org.logstash` or `co.elastic.logstash` packages to prevent potential +clashes with classes in Logstash itself. [float] ==== Plugin settings @@ -248,11 +248,11 @@ Start Logstash with: [source,shell] ----- -bin/logstash --java-execution -f /path/to/java_filter.conf +bin/logstash -f /path/to/java_filter.conf ----- -NOTE: The `--java-execution` flag to enable the Java execution engine is -required as Java plugins are not supported in the Ruby execution engine. +NOTE: The Java execution engine, the default execution engine since Logstash 7.0, is required +as Java plugins are not supported in the Ruby execution engine. The expected Logstash output (excluding initialization) with the configuration above is: diff --git a/docs/static/java-input.asciidoc b/docs/static/java-input.asciidoc index 06815c540..0f99b7ed3 100644 --- a/docs/static/java-input.asciidoc +++ b/docs/static/java-input.asciidoc @@ -13,8 +13,6 @@ [[java-input-plugin]] === How to write a Java input plugin -beta[] - // Pulls in shared section: Setting Up Environment include::include/javapluginsetup.asciidoc[] @@ -104,6 +102,8 @@ Notes about the class declaration: Logstash pipeline defintion as `input { java_input_example => { .... } }` ** The value of the `name` property must match the name of the class excluding casing and underscores. * The class must implement the `co.elastic.logstash.api.Input` interface. +* Java plugins may not be created in the `org.logstash` or `co.elastic.logstash` packages to prevent potential +clashes with classes in Logstash itself. [float] ==== Plugin settings @@ -274,11 +274,11 @@ Start {ls} with: [source,shell] ----- -bin/logstash --java-execution -f /path/to/java_input.conf +bin/logstash -f /path/to/java_input.conf ----- -NOTE: The `--java-execution` flag to enable the Java execution engine is -required as Java plugins are not supported in the Ruby execution engine. +NOTE: The Java execution engine, the default execution engine since Logstash 7.0, is required +as Java plugins are not supported in the Ruby execution engine. The expected Logstash output (excluding initialization) with the configuration above is: diff --git a/docs/static/java-output.asciidoc b/docs/static/java-output.asciidoc index 15e57816d..67de9344a 100644 --- a/docs/static/java-output.asciidoc +++ b/docs/static/java-output.asciidoc @@ -15,8 +15,6 @@ [[java-output-plugin]] === How to write a Java output plugin -beta[] - // Pulls in shared section: Setting Up Environment include::include/javapluginsetup.asciidoc[] @@ -101,6 +99,8 @@ Notes about the class declaration: Logstash pipeline definition as `output { java_output_example => { .... } }` ** The value of the `name` property must match the name of the class excluding casing and underscores. * The class must implement the `co.elastic.logstash.api.Output` interface. +* Java plugins may not be created in the `org.logstash` or `co.elastic.logstash` packages to prevent potential +clashes with classes in Logstash itself. [float] ==== Plugin settings @@ -258,11 +258,11 @@ Logstash should then be started with: [source,txt] ----- -bin/logstash --java-execution -f /path/to/java_output.conf +bin/logstash -f /path/to/java_output.conf ----- -NOTE: The `--java-execution` flag to enable the Java execution engine is -required as Java plugins are not supported in the Ruby execution engine. +NOTE: The Java execution engine, the default execution engine since Logstash 7.0, is required +as Java plugins are not supported in the Ruby execution engine. The expected Logstash output (excluding initialization) with the configuration above is: diff --git a/docs/static/running-logstash-command-line.asciidoc b/docs/static/running-logstash-command-line.asciidoc index 876a82d5f..b5cd5219a 100644 --- a/docs/static/running-logstash-command-line.asciidoc +++ b/docs/static/running-logstash-command-line.asciidoc @@ -72,6 +72,9 @@ With this command, Logstash concatenates three config files, `/tmp/one`, `/tmp/t Specify `false` for this option to revert to the legacy Ruby execution engine instead of the default Java execution engine. +*`--plugin-classloaders`*:: + (Beta) Load Java plugins in independent classloaders to isolate their dependencies. + *`--modules`*:: Launch the named module. Works in conjunction with the `-M` option to assign values to default variables for the specified module. If `--modules` is used on the command line, diff --git a/docs/static/settings-file.asciidoc b/docs/static/settings-file.asciidoc index 837741b6d..df14f9d96 100644 --- a/docs/static/settings-file.asciidoc +++ b/docs/static/settings-file.asciidoc @@ -110,6 +110,10 @@ The `logstash.yml` file includes the following settings. If you are using X-Pack have been pushed to the outputs. Enabling this option can lead to data loss during shutdown. | `false` +| `pipeline.plugin_classloaders` +| (Beta) Load Java plugins in independent classloaders to isolate their dependencies. +| `false` + | `path.config` | The path to the Logstash config for the main pipeline. If you specify a directory or wildcard, config files are read from the directory in alphabetical order. diff --git a/logstash-core/lib/logstash/environment.rb b/logstash-core/lib/logstash/environment.rb index bf70f7762..31df098fa 100644 --- a/logstash-core/lib/logstash/environment.rb +++ b/logstash-core/lib/logstash/environment.rb @@ -43,6 +43,7 @@ module LogStash Setting::Boolean.new("pipeline.unsafe_shutdown", false), Setting::Boolean.new("pipeline.java_execution", true), Setting::Boolean.new("pipeline.reloadable", true), + Setting::Boolean.new("pipeline.plugin_classloaders", false), Setting.new("path.plugins", Array, []), Setting::NullableString.new("interactive", nil, false), Setting::Boolean.new("config.debug", false), diff --git a/logstash-core/lib/logstash/pipeline_settings.rb b/logstash-core/lib/logstash/pipeline_settings.rb index 95ec76ad1..9fabab3a7 100644 --- a/logstash-core/lib/logstash/pipeline_settings.rb +++ b/logstash-core/lib/logstash/pipeline_settings.rb @@ -15,6 +15,7 @@ module LogStash "dead_letter_queue.max_bytes", "metric.collect", "pipeline.java_execution", + "pipeline.plugin_classloaders", "path.config", "path.dead_letter_queue", "path.queue", diff --git a/logstash-core/lib/logstash/plugins/registry.rb b/logstash-core/lib/logstash/plugins/registry.rb index 161354799..8c7435632 100644 --- a/logstash-core/lib/logstash/plugins/registry.rb +++ b/logstash-core/lib/logstash/plugins/registry.rb @@ -105,6 +105,7 @@ module LogStash module Plugins # but it is the case that we can call lookups from multiple threads, # when multiple pipelines are in play, and that a lookup may modify the registry. @registry = java.util.concurrent.ConcurrentHashMap.new + @java_plugins = java.util.concurrent.ConcurrentHashMap.new @hooks = HooksRegistry.new end @@ -133,6 +134,15 @@ module LogStash module Plugins require "logstash/plugins/builtin" GemRegistry.logstash_plugins.each do |plugin_context| + if plugin_context.spec.metadata.key?('java_plugin') + jar_files = plugin_context.spec.files.select {|f| f =~ /.*\.jar/} + expected_jar_name = plugin_context.spec.name + "-" + plugin_context.spec.version.to_s + ".jar" + if (jar_files.length != 1 || !jar_files[0].end_with?(expected_jar_name)) + raise LoadError, "Java plugin '#{plugin_context.spec.name}' does not contain a single jar file with the plugin's name and version" + end + @java_plugins[plugin_context.spec.name] = [plugin_context.spec.loaded_from, jar_files[0]] + end + # When a plugin has a HOOK_FILE defined, its the responsibility of the plugin # to register itself to the registry of available plugins. # @@ -262,13 +272,31 @@ module LogStash module Plugins # @param name [String] plugin name # @return [Boolean] true if klass is a valid plugin for name def is_a_plugin?(klass, name) + (klass.class == Java::JavaLang::Class && klass.simple_name.downcase == name.gsub('_','')) || (klass.class == Java::JavaClass && klass.simple_name.downcase == name.gsub('_','')) || (klass.ancestors.include?(LogStash::Plugin) && klass.respond_to?(:config_name) && klass.config_name == name) end def add_plugin(type, name, klass) if klass.respond_to?("javaClass", true) - @registry[key_for(type, name)] = PluginSpecification.new(type, name, klass.javaClass) + if LogStash::SETTINGS.get_value('pipeline.plugin_classloaders') + full_name = 'logstash-' + key_for(type, name) + if @java_plugins.key?(full_name) + plugin_paths = @java_plugins[full_name] + else + raise LoadError, "Could not find metadata for Java plugin: #{full_name}" + end + + java_import org.logstash.plugins.PluginClassLoader + java_import org.logstash.Logstash + + classloader = PluginClassLoader.create(plugin_paths[0], plugin_paths[1], Logstash.java_class.class_loader) + klazz = classloader.load_class(klass.javaClass.name) + + @registry[key_for(type, name)] = PluginSpecification.new(type, name, klazz.ruby_class.java_class) + else + @registry[key_for(type, name)] = PluginSpecification.new(type, name, klass.javaClass) + end elsif !exists?(type, name) specification_klass = type == :universal ? UniversalPluginSpecification : PluginSpecification @registry[key_for(type, name)] = specification_klass.new(type, name, klass) diff --git a/logstash-core/lib/logstash/runner.rb b/logstash-core/lib/logstash/runner.rb index f03ac07c4..45e7fb231 100644 --- a/logstash-core/lib/logstash/runner.rb +++ b/logstash-core/lib/logstash/runner.rb @@ -113,6 +113,11 @@ class LogStash::Runner < Clamp::StrictCommand :attribute_name => "pipeline.java_execution", :default => LogStash::SETTINGS.get_default("pipeline.java_execution") + option ["--plugin-classloaders"], :flag, + I18n.t("logstash.runner.flag.plugin-classloaders"), + :attribute_name => "pipeline.plugin_classloaders", + :default => LogStash::SETTINGS.get_default("pipeline.plugin_classloaders") + option ["-b", "--pipeline.batch.size"], "SIZE", I18n.t("logstash.runner.flag.pipeline-batch-size"), :attribute_name => "pipeline.batch.size", diff --git a/logstash-core/locales/en.yml b/logstash-core/locales/en.yml index 7ff23e787..b162808df 100644 --- a/logstash-core/locales/en.yml +++ b/logstash-core/locales/en.yml @@ -290,6 +290,8 @@ en: Sets the number of pipeline workers to run. java-execution: |+ Use Java execution engine. + plugin-classloaders: |+ + (Beta) Load Java plugins in independent classloaders to isolate their dependencies. pipeline-batch-size: |+ Size of batches the pipeline is to work in. pipeline-batch-delay: |+ diff --git a/logstash-core/src/main/java/co/elastic/logstash/api/Codec.java b/logstash-core/src/main/java/co/elastic/logstash/api/Codec.java index dba0d201d..aa5e18dbb 100644 --- a/logstash-core/src/main/java/co/elastic/logstash/api/Codec.java +++ b/logstash-core/src/main/java/co/elastic/logstash/api/Codec.java @@ -1,6 +1,7 @@ package co.elastic.logstash.api; -import java.nio.Buffer; +import java.io.IOException; +import java.io.OutputStream; import java.nio.ByteBuffer; import java.util.Map; import java.util.function.Consumer; @@ -43,28 +44,11 @@ public interface Codec extends Plugin { void flush(ByteBuffer buffer, Consumer> eventConsumer); /** - * Encodes an {@link Event} and writes it into the specified {@link ByteBuffer}. Under ideal - * circumstances, the entirety of the event's encoding will fit into the supplied buffer. In cases - * where the buffer has insufficient space to hold the event's encoding, the buffer will be filled - * with as much of the event's encoding as possible, {@code false} will be returned, and the caller - * must call this method with the same event and a buffer that has more {@link Buffer#remaining()} - * bytes. That is typically done by draining the partial encoding from the supplied buffer. This - * process must be repeated until the event's entire encoding is written to the buffer at which - * point the method will return {@code true}. Attempting to call this method with a new event - * before the entirety of the previous event's encoding has been written to a buffer will result - * in an {@link EncodeException}. - * - * @param event The event to encode. - * @param buffer The buffer into which the encoding of the event should be written. Codec - * implementations are responsible for returning the buffer in a state from which it - * can be read, typically by calling {@link Buffer#flip()} before returning. - * @return {@code true} if the entirety or final segment of the event's encoding was written to - * the buffer. {@code false} if the buffer was incapable of holding the entirety or remainder of the - * event's encoding. - * @throws EncodeException if called with a new event before the entirety of the previous event's - * encoding was written to a buffer. + * Encodes an {@link Event} and writes it to the specified {@link OutputStream}. + * @param event The event to encode. + * @param output The stream to which the encoded event should be written. */ - boolean encode(Event event, ByteBuffer buffer) throws EncodeException; + void encode(Event event, OutputStream output) throws IOException; /** * Clones this {@link Codec}. All codecs should be capable of cloning themselves @@ -74,13 +58,4 @@ public interface Codec extends Plugin { */ Codec cloneCodec(); - class EncodeException extends Exception { - - private static final long serialVersionUID = 1L; - - public EncodeException(String message) { - super(message); - } - - } } diff --git a/logstash-core/src/main/java/co/elastic/logstash/api/Password.java b/logstash-core/src/main/java/co/elastic/logstash/api/Password.java new file mode 100644 index 000000000..9cf0e231c --- /dev/null +++ b/logstash-core/src/main/java/co/elastic/logstash/api/Password.java @@ -0,0 +1,22 @@ +package co.elastic.logstash.api; + +/** + * Wraps a password string so that it is not inadvertently printed or logged. + */ +public class Password { + + private String password; + + public Password(String password) { + this.password = password; + } + + public String getPassword() { + return password; + } + + @Override + public String toString() { + return ""; + } +} diff --git a/logstash-core/src/main/java/co/elastic/logstash/api/PluginConfigSpec.java b/logstash-core/src/main/java/co/elastic/logstash/api/PluginConfigSpec.java index 8d3abaf7a..dad40b273 100644 --- a/logstash-core/src/main/java/co/elastic/logstash/api/PluginConfigSpec.java +++ b/logstash-core/src/main/java/co/elastic/logstash/api/PluginConfigSpec.java @@ -1,5 +1,6 @@ package co.elastic.logstash.api; +import java.net.URI; import java.util.Collection; import java.util.Collections; import java.util.List; @@ -83,6 +84,28 @@ public final class PluginConfigSpec { return new PluginConfigSpec<>(name, Codec.class, defaultValue, deprecated, required); } + public static PluginConfigSpec uriSetting(final String name) { + return new PluginConfigSpec<>( + name, URI.class, null, false, false + ); + } + + public static PluginConfigSpec uriSetting(final String name, final String defaultUri) { + PluginConfigSpec pcs = new PluginConfigSpec<>( + name, URI.class, null, false, false + ); + pcs.rawDefaultValue = defaultUri; + return pcs; + } + + public static PluginConfigSpec uriSetting(final String name, final String defaultUri, boolean deprecated, boolean required) { + PluginConfigSpec pcs = new PluginConfigSpec<>( + name, URI.class, null, deprecated, required + ); + pcs.rawDefaultValue = defaultUri; + return pcs; + } + public static PluginConfigSpec numSetting(final String name) { return new PluginConfigSpec<>( name, Long.class, null, false, false @@ -95,6 +118,14 @@ public final class PluginConfigSpec { ); } + public static PluginConfigSpec floatSetting(final String name, final double defaultValue) { + return new PluginConfigSpec<>(name, Double.class, defaultValue, false, false); + } + + public static PluginConfigSpec floatSetting(final String name, final double defaultValue, boolean deprecated, boolean required) { + return new PluginConfigSpec<>(name, Double.class, defaultValue, deprecated, required); + } + public static PluginConfigSpec numSetting(final String name, final long defaultValue, boolean deprecated, boolean required) { return new PluginConfigSpec<>(name, Long.class, defaultValue, deprecated, required); } @@ -135,6 +166,20 @@ public final class PluginConfigSpec { return new PluginConfigSpec(name, List.class, defaultValue, deprecated, required); } + public static PluginConfigSpec passwordSetting(final String name) { + return new PluginConfigSpec<>( + name, Password.class, null, false, false + ); + } + + public static PluginConfigSpec passwordSetting(final String name, final String defaultValue, boolean deprecated, boolean required) { + PluginConfigSpec pcs = new PluginConfigSpec<>( + name, Password.class, null, false, false + ); + pcs.rawDefaultValue = defaultValue; + return pcs; + } + public Collection> children() { return children; } diff --git a/logstash-core/src/main/java/org/logstash/config/ir/compiler/JavaCodecDelegator.java b/logstash-core/src/main/java/org/logstash/config/ir/compiler/JavaCodecDelegator.java index e65ce23ef..aff529b89 100644 --- a/logstash-core/src/main/java/org/logstash/config/ir/compiler/JavaCodecDelegator.java +++ b/logstash-core/src/main/java/org/logstash/config/ir/compiler/JavaCodecDelegator.java @@ -10,6 +10,8 @@ import org.logstash.instrument.metrics.AbstractNamespacedMetricExt; import org.logstash.instrument.metrics.MetricKeys; import org.logstash.instrument.metrics.counter.LongCounter; +import java.io.IOException; +import java.io.OutputStream; import java.nio.ByteBuffer; import java.util.Collection; import java.util.Map; @@ -89,16 +91,14 @@ public class JavaCodecDelegator implements Codec { } @Override - public boolean encode(final Event event, final ByteBuffer buffer) throws EncodeException { + public void encode(final Event event, final OutputStream out) throws IOException { encodeMetricIn.increment(); final long start = System.nanoTime(); - final boolean ret = codec.encode(event, buffer); + codec.encode(event, out); decodeMetricTime.increment(TimeUnit.MILLISECONDS.convert(System.nanoTime() - start, TimeUnit.NANOSECONDS)); - - return ret; } @Override diff --git a/logstash-core/src/main/java/org/logstash/config/ir/compiler/JavaInputDelegatorExt.java b/logstash-core/src/main/java/org/logstash/config/ir/compiler/JavaInputDelegatorExt.java index 6bdcece18..4ceb3f564 100644 --- a/logstash-core/src/main/java/org/logstash/config/ir/compiler/JavaInputDelegatorExt.java +++ b/logstash-core/src/main/java/org/logstash/config/ir/compiler/JavaInputDelegatorExt.java @@ -118,6 +118,11 @@ public class JavaInputDelegatorExt extends RubyObject { return this; } + @JRubyMethod(name = "reloadable?") + public IRubyObject isReloadable(final ThreadContext context) { + return context.tru; + } + @SuppressWarnings("unchecked") private void initializeQueueWriter(Map pluginArgs) { List, Map>> inputActions = new ArrayList<>(); diff --git a/logstash-core/src/main/java/org/logstash/plugins/ConfigurationImpl.java b/logstash-core/src/main/java/org/logstash/plugins/ConfigurationImpl.java index 6b802dba1..7215a4a24 100644 --- a/logstash-core/src/main/java/org/logstash/plugins/ConfigurationImpl.java +++ b/logstash-core/src/main/java/org/logstash/plugins/ConfigurationImpl.java @@ -1,10 +1,13 @@ package org.logstash.plugins; import co.elastic.logstash.api.Configuration; +import co.elastic.logstash.api.Password; import co.elastic.logstash.api.PluginConfigSpec; import co.elastic.logstash.api.Codec; import org.logstash.config.ir.compiler.RubyIntegration; +import java.net.URI; +import java.net.URISyntaxException; import java.util.Collection; import java.util.Map; @@ -39,9 +42,22 @@ public final class ConfigurationImpl implements Configuration { Object o = rawSettings.get(configSpec.name()); if (configSpec.type().isAssignableFrom(o.getClass())) { return (T) o; + } else if (configSpec.type() == Double.class && o.getClass() == Long.class) { + return configSpec.type().cast(((Long)o).doubleValue()); } else if (configSpec.type() == Codec.class && o instanceof String && pluginFactory != null) { - Codec codec = pluginFactory.buildDefaultCodec((String)o); + Codec codec = pluginFactory.buildDefaultCodec((String) o); return configSpec.type().cast(codec); + } else if (configSpec.type() == URI.class && o instanceof String) { + try { + URI uri = new URI((String) o); + return configSpec.type().cast(uri); + } catch (URISyntaxException ex) { + throw new IllegalStateException( + String.format("Invalid URI specified for '%s'", configSpec.name())); + } + } else if (configSpec.type() == Password.class && o instanceof String) { + Password p = new Password((String) o); + return configSpec.type().cast(p); } else { throw new IllegalStateException( String.format("Setting value for '%s' of type '%s' incompatible with defined type of '%s'", @@ -50,6 +66,17 @@ public final class ConfigurationImpl implements Configuration { } else if (configSpec.type() == Codec.class && configSpec.getRawDefaultValue() != null && pluginFactory != null) { Codec codec = pluginFactory.buildDefaultCodec(configSpec.getRawDefaultValue()); return configSpec.type().cast(codec); + } else if (configSpec.type() == URI.class && configSpec.getRawDefaultValue() != null) { + try { + URI uri = new URI(configSpec.getRawDefaultValue()); + return configSpec.type().cast(uri); + } catch (URISyntaxException ex) { + throw new IllegalStateException( + String.format("Invalid default URI specified for '%s'", configSpec.name())); + } + } else if (configSpec.type() == Password.class && configSpec.getRawDefaultValue() != null) { + Password p = new Password(configSpec.getRawDefaultValue()); + return configSpec.type().cast(p); } else { return configSpec.defaultValue(); } @@ -69,5 +96,4 @@ public final class ConfigurationImpl implements Configuration { public Collection allKeys() { return rawSettings.keySet(); } - } diff --git a/logstash-core/src/main/java/org/logstash/plugins/PluginClassLoader.java b/logstash-core/src/main/java/org/logstash/plugins/PluginClassLoader.java new file mode 100644 index 000000000..f728f0876 --- /dev/null +++ b/logstash-core/src/main/java/org/logstash/plugins/PluginClassLoader.java @@ -0,0 +1,69 @@ +package org.logstash.plugins; + +import java.io.File; +import java.net.MalformedURLException; +import java.net.URL; +import java.net.URLClassLoader; +import java.nio.file.Files; +import java.nio.file.Path; +import java.nio.file.Paths; + +/** + * Classloader for Java plugins to isolate their dependencies. Will not load any classes in the + * co.elastic.logstash or org.logstash packages to avoid the possibility + * of clashes with classes in Logstash core. + */ +public class PluginClassLoader extends URLClassLoader { + + private ClassLoader appClassLoader; + + private PluginClassLoader(URL[] urls, ClassLoader appClassLoader) { + super(urls, null); + this.appClassLoader = appClassLoader; + } + + /** + * Creates an instance of the plugin classloader. + * @param gemPath Path to the Ruby gem containing the Java plugin as reported by + * Gem::BasicSpecification#loaded_from. + * @param jarPath Path to the Java plugin's JAR file relative to {@code gemPath}. + * @param appClassLoader Application classloader to be used for classes not found + * in the plugin's JAR file. + * @return New instance of the plugin classloader. + */ + public static PluginClassLoader create(String gemPath, String jarPath, ClassLoader appClassLoader) { + String pluginPath = gemPath.substring(0, gemPath.lastIndexOf(File.separator)) + File.separator + jarPath; + Path pluginJar = Paths.get(pluginPath); + if (!Files.exists(pluginJar)) { + throw new IllegalStateException("PluginClassLoader unable to locate jar file: " + pluginPath); + } + try { + URL[] pluginJarUrl = new URL[]{pluginJar.toUri().toURL()}; + return new PluginClassLoader(pluginJarUrl, appClassLoader); + } catch (MalformedURLException e) { + throw new IllegalStateException(e); + } + } + + @Override + protected Class loadClass(String name, boolean resolve) throws ClassNotFoundException { + synchronized (getClassLoadingLock(name)) { + Class c = findLoadedClass(name); + if (!name.startsWith("co.elastic.logstash.") && !name.startsWith("org.logstash.")) { + if (c == null) { + try { + c = findClass(name); + } catch (ClassNotFoundException e) { + c = super.loadClass(name, resolve); + } + } + } else { + c = appClassLoader.loadClass(name); + } + if (resolve) { + resolveClass(c); + } + return c; + } + } +} diff --git a/logstash-core/src/main/java/org/logstash/plugins/PluginFactoryExt.java b/logstash-core/src/main/java/org/logstash/plugins/PluginFactoryExt.java index 15453c5de..db71fde14 100644 --- a/logstash-core/src/main/java/org/logstash/plugins/PluginFactoryExt.java +++ b/logstash-core/src/main/java/org/logstash/plugins/PluginFactoryExt.java @@ -1,8 +1,8 @@ package org.logstash.plugins; +import co.elastic.logstash.api.Codec; import co.elastic.logstash.api.Configuration; import co.elastic.logstash.api.Context; -import co.elastic.logstash.api.Codec; import co.elastic.logstash.api.Filter; import co.elastic.logstash.api.Input; import co.elastic.logstash.api.Output; @@ -261,6 +261,12 @@ public final class PluginFactoryExt { return pluginInstance; } } else { + if (pluginArgs == null) { + String err = String.format("Cannot start the Java plugin '%s' in the Ruby execution engine." + + " The Java execution engine is required to run Java plugins.", name); + throw new IllegalStateException(err); + } + if (type == PluginLookup.PluginType.OUTPUT) { final Class cls = (Class) pluginClass.klass(); Output output = null; @@ -271,6 +277,9 @@ public final class PluginFactoryExt { output = ctor.newInstance(id, config, executionContext.toContext(type)); PluginUtil.validateConfig(output, config); } catch (NoSuchMethodException | IllegalAccessException | InstantiationException | InvocationTargetException ex) { + if (ex instanceof InvocationTargetException && ex.getCause() != null) { + throw new IllegalStateException((ex).getCause()); + } throw new IllegalStateException(ex); } } @@ -290,6 +299,9 @@ public final class PluginFactoryExt { filter = ctor.newInstance(id, config, executionContext.toContext(type)); PluginUtil.validateConfig(filter, config); } catch (NoSuchMethodException | IllegalAccessException | InstantiationException | InvocationTargetException ex) { + if (ex instanceof InvocationTargetException && ex.getCause() != null) { + throw new IllegalStateException((ex).getCause()); + } throw new IllegalStateException(ex); } } @@ -309,7 +321,7 @@ public final class PluginFactoryExt { input = ctor.newInstance(id, config, executionContext.toContext(type)); PluginUtil.validateConfig(input, config); } catch (NoSuchMethodException | IllegalAccessException | InstantiationException | InvocationTargetException ex) { - if (ex instanceof InvocationTargetException) { + if (ex instanceof InvocationTargetException && ex.getCause() != null) { throw new IllegalStateException((ex).getCause()); } throw new IllegalStateException(ex); @@ -331,7 +343,7 @@ public final class PluginFactoryExt { codec = ctor.newInstance(config, executionContext.toContext(type)); PluginUtil.validateConfig(codec, config); } catch (NoSuchMethodException | IllegalAccessException | InstantiationException | InvocationTargetException ex) { - if (ex instanceof InvocationTargetException) { + if (ex instanceof InvocationTargetException && ex.getCause() != null) { throw new IllegalStateException((ex).getCause()); } throw new IllegalStateException(ex); diff --git a/logstash-core/src/main/java/org/logstash/plugins/PluginLookup.java b/logstash-core/src/main/java/org/logstash/plugins/PluginLookup.java index ef946c065..73137bbc2 100644 --- a/logstash-core/src/main/java/org/logstash/plugins/PluginLookup.java +++ b/logstash-core/src/main/java/org/logstash/plugins/PluginLookup.java @@ -2,6 +2,7 @@ package org.logstash.plugins; import org.jruby.RubyClass; import org.jruby.RubyString; +import org.jruby.java.proxies.JavaProxy; import org.jruby.javasupport.JavaClass; import org.jruby.runtime.builtin.IRubyObject; import org.logstash.RubyUtil; @@ -24,8 +25,13 @@ public final class PluginLookup { @SuppressWarnings("rawtypes") public static PluginLookup.PluginClass lookup(final PluginLookup.PluginType type, final String name) { - Class javaClass = PluginRegistry.getPluginClass(type, name); + Class javaClass = PluginRegistry.getPluginClass(type, name); if (javaClass != null) { + + if (!PluginValidator.validatePlugin(type, javaClass)) { + throw new IllegalStateException("Java plugin '" + name + "' is incompatible with the current Logstash plugin API"); + } + return new PluginLookup.PluginClass() { @Override @@ -48,10 +54,16 @@ public final class PluginLookup { ? PluginLanguage.RUBY : PluginLanguage.JAVA; + klass = (klass instanceof JavaProxy) ? ((JavaProxy) klass).getObject() : klass; + Object resolvedClass = klass instanceof JavaClass ? ((JavaClass) klass).javaClass() : klass; + if (language == PluginLanguage.JAVA && !PluginValidator.validatePlugin(type, (Class) resolvedClass)) { + throw new IllegalStateException("Java plugin '" + name + "' is incompatible with the current Logstash plugin API"); + } + return new PluginLookup.PluginClass() { @Override public PluginLookup.PluginLanguage language() { diff --git a/logstash-core/src/main/java/org/logstash/plugins/PluginValidator.java b/logstash-core/src/main/java/org/logstash/plugins/PluginValidator.java new file mode 100644 index 000000000..5011169a3 --- /dev/null +++ b/logstash-core/src/main/java/org/logstash/plugins/PluginValidator.java @@ -0,0 +1,57 @@ +package org.logstash.plugins; + +import co.elastic.logstash.api.Codec; +import co.elastic.logstash.api.Filter; +import co.elastic.logstash.api.Input; +import co.elastic.logstash.api.Output; + +import java.lang.reflect.Method; +import java.util.Arrays; + +/** + * Validates that Java plugins support the Java plugin API in this release of Logstash. + */ +public class PluginValidator { + + private static final Method[] inputMethods; + private static final Method[] filterMethods; + private static final Method[] codecMethods; + private static final Method[] outputMethods; + + static { + inputMethods = Input.class.getMethods(); + filterMethods = Filter.class.getMethods(); + codecMethods = Codec.class.getMethods(); + outputMethods = Output.class.getMethods(); + } + + public static boolean validatePlugin(PluginLookup.PluginType type, Class pluginClass) { + switch (type) { + case INPUT: + return containsAllMethods(inputMethods, pluginClass.getMethods()); + case FILTER: + return containsAllMethods(filterMethods, pluginClass.getMethods()); + case CODEC: + return containsAllMethods(codecMethods, pluginClass.getMethods()); + case OUTPUT: + return containsAllMethods(outputMethods, pluginClass.getMethods()); + default: + throw new IllegalStateException("Unknown plugin type for validation: " + type); + } + } + + private static boolean containsAllMethods(Method[] apiMethods, Method[] pluginMethods) { + boolean matches = true; + for (int k = 0; matches && k < apiMethods.length; k++) { + int finalK = k; + matches = Arrays.stream(pluginMethods).anyMatch(m -> methodsMatch(apiMethods[finalK], m)); + } + return matches; + } + + private static boolean methodsMatch(Method apiMethod, Method pluginMethod) { + return apiMethod.getName().equals(pluginMethod.getName()) && + apiMethod.getReturnType() == pluginMethod.getReturnType() && + Arrays.equals(apiMethod.getParameterTypes(), pluginMethod.getParameterTypes()); + } +} diff --git a/logstash-core/src/main/java/org/logstash/plugins/codecs/Dots.java b/logstash-core/src/main/java/org/logstash/plugins/codecs/Dots.java new file mode 100644 index 000000000..8430d9496 --- /dev/null +++ b/logstash-core/src/main/java/org/logstash/plugins/codecs/Dots.java @@ -0,0 +1,61 @@ +package org.logstash.plugins.codecs; + +import co.elastic.logstash.api.Codec; +import co.elastic.logstash.api.Configuration; +import co.elastic.logstash.api.Context; +import co.elastic.logstash.api.Event; +import co.elastic.logstash.api.LogstashPlugin; +import co.elastic.logstash.api.PluginConfigSpec; + +import java.io.IOException; +import java.io.OutputStream; +import java.nio.ByteBuffer; +import java.util.Collection; +import java.util.Collections; +import java.util.Map; +import java.util.UUID; +import java.util.function.Consumer; + +@LogstashPlugin(name = "jdots") +public class Dots implements Codec { + + private final String id; + + public Dots(final Configuration configuration, final Context context) { + this(); + } + + private Dots() { + this.id = UUID.randomUUID().toString(); + } + + @Override + public void decode(ByteBuffer buffer, Consumer> eventConsumer) { + throw new UnsupportedOperationException("Cannot decode with the jdots codec"); + } + + @Override + public void flush(ByteBuffer buffer, Consumer> eventConsumer) { + } + + @Override + public void encode(Event event, OutputStream out) throws IOException { + out.write('.'); + out.flush(); + } + + @Override + public Codec cloneCodec() { + return new Dots(); + } + + @Override + public Collection> configSchema() { + return Collections.emptyList(); + } + + @Override + public String getId() { + return id; + } +} diff --git a/logstash-core/src/main/java/org/logstash/plugins/codecs/Line.java b/logstash-core/src/main/java/org/logstash/plugins/codecs/Line.java index 30555c1ab..5d52b2f09 100644 --- a/logstash-core/src/main/java/org/logstash/plugins/codecs/Line.java +++ b/logstash-core/src/main/java/org/logstash/plugins/codecs/Line.java @@ -9,12 +9,12 @@ import co.elastic.logstash.api.PluginConfigSpec; import org.logstash.StringInterpolation; import java.io.IOException; +import java.io.OutputStream; import java.nio.ByteBuffer; import java.nio.CharBuffer; import java.nio.charset.CharacterCodingException; import java.nio.charset.Charset; import java.nio.charset.CharsetDecoder; -import java.nio.charset.CharsetEncoder; import java.nio.charset.CoderResult; import java.nio.charset.CodingErrorAction; import java.util.Arrays; @@ -52,12 +52,8 @@ public class Line implements Codec { private final CharBuffer charBuffer = ByteBuffer.allocateDirect(64 * 1024).asCharBuffer(); private final CharsetDecoder decoder; - private final CharsetEncoder encoder; private String remainder = ""; - private Event currentEncodedEvent; - private CharBuffer currentEncoding; - /** * Required constructor. * @@ -76,7 +72,6 @@ public class Line implements Codec { this.format = format; decoder = charset.newDecoder(); decoder.onMalformedInput(CodingErrorAction.IGNORE); - encoder = charset.newEncoder(); } @Override @@ -125,34 +120,12 @@ public class Line implements Codec { } @Override - public boolean encode(Event event, ByteBuffer buffer) throws EncodeException { - try { - if (currentEncodedEvent != null && event != currentEncodedEvent) { - throw new EncodeException("New event supplied before encoding of previous event was completed"); - } else if (currentEncodedEvent == null) { - String eventEncoding = (format == null - ? JSON_MAPPER.writeValueAsString(event.getData()) - : StringInterpolation.evaluate(event, format)) - + delimiter; - currentEncoding = CharBuffer.wrap(eventEncoding); - } - - CoderResult result = encoder.encode(currentEncoding, buffer, true); - buffer.flip(); - if (result.isError()) { - result.throwException(); - } - - if (result.isOverflow()) { - currentEncodedEvent = event; - return false; - } else { - currentEncodedEvent = null; - return true; - } - } catch (IOException e) { - throw new IllegalStateException(e); - } + public void encode(Event event, OutputStream output) throws IOException { + String outputString = (format == null + ? JSON_MAPPER.writeValueAsString(event.getData()) + : StringInterpolation.evaluate(event, format)) + + delimiter; + output.write(outputString.getBytes(charset)); } private Map simpleMap(String message) { diff --git a/logstash-core/src/main/java/org/logstash/plugins/inputs/Generator.java b/logstash-core/src/main/java/org/logstash/plugins/inputs/Generator.java new file mode 100644 index 000000000..25cd596d7 --- /dev/null +++ b/logstash-core/src/main/java/org/logstash/plugins/inputs/Generator.java @@ -0,0 +1,197 @@ +package org.logstash.plugins.inputs; + +import co.elastic.logstash.api.Configuration; +import co.elastic.logstash.api.Context; +import co.elastic.logstash.api.Input; +import co.elastic.logstash.api.LogstashPlugin; +import co.elastic.logstash.api.PluginConfigSpec; +import co.elastic.logstash.api.PluginHelper; + +import java.net.InetAddress; +import java.net.UnknownHostException; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.Collection; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import java.util.concurrent.CountDownLatch; +import java.util.concurrent.Executors; +import java.util.concurrent.ScheduledExecutorService; +import java.util.concurrent.ScheduledFuture; +import java.util.concurrent.TimeUnit; +import java.util.function.Consumer; + +@LogstashPlugin(name = "java_generator") +public class Generator implements Input { + + public static final PluginConfigSpec COUNT_CONFIG = + PluginConfigSpec.numSetting("count", 0); + public static final PluginConfigSpec> LINES_CONFIG = + PluginConfigSpec.arraySetting("lines"); + public static final PluginConfigSpec MESSAGE_CONFIG = + PluginConfigSpec.stringSetting("message", "Hello world!"); + public static final PluginConfigSpec THREADS_CONFIG = + PluginConfigSpec.numSetting("threads", 1); + public static final PluginConfigSpec EPS_CONFIG = + PluginConfigSpec.floatSetting("eps", 0); + + private final String hostname; + private final long count; + private final double eps; + private String id; + private long threads; + private volatile boolean stopRequested = false; + private final CountDownLatch countDownLatch; + private String[] lines; + private int[] linesIndex; + private long[] sequence; + private ScheduledFuture[] futures; + private List> events; + + /** + * Required constructor. + * + * @param id Plugin id + * @param configuration Logstash Configuration + * @param context Logstash Context + */ + public Generator(final String id, final Configuration configuration, final Context context) { + this.id = id; + this.count = configuration.get(COUNT_CONFIG); + this.eps = configuration.get(EPS_CONFIG); + this.threads = configuration.get(THREADS_CONFIG); + if (this.threads < 1) { + throw new IllegalStateException("May not specify fewer than one generator thread"); + } + this.countDownLatch = new CountDownLatch((int) threads); + + String host; + try { + host = InetAddress.getLocalHost().getHostName(); + } catch (UnknownHostException e) { + host = "[unknownHost]"; + } + this.hostname = host; + + // specifying "lines" will override "message" + List linesConfig = configuration.get(LINES_CONFIG); + if (linesConfig != null) { + lines = new String[linesConfig.size()]; + for (int k = 0; k < linesConfig.size(); k++) { + lines[k] = (String) linesConfig.get(k); + } + + } else { + lines = new String[]{configuration.get(MESSAGE_CONFIG)}; + } + } + + @Override + public void start(Consumer> writer) { + if (eps > 0) { + startThrottledGenerator(writer); + } else { + startUnthrottledGenerator(writer); + } + } + + private void startUnthrottledGenerator(Consumer> writer) { + sequence = new long[(int) threads]; + events = new ArrayList<>(); + linesIndex = new int[(int) threads]; + + for (int k = 0; k < threads; k++) { + Map event = new HashMap<>(); + event.put("hostname", hostname); + event.put("thread_number", k); + events.add(event); + if (k > 0) { + final int finalK = k; + Thread t = new Thread(() -> { + while (runGenerator(writer, finalK, () -> countDownLatch.countDown())) { + } + }); + t.setName("generator_" + getId() + "_" + k); + t.start(); + } + } + + // run first generator on this thread + while (runGenerator(writer, 0, () -> countDownLatch.countDown())) {} + } + + private void startThrottledGenerator(Consumer> writer) { + ScheduledExecutorService ses = Executors.newScheduledThreadPool((int) threads); + int delayMilli = (int) (1000.0 / eps); + sequence = new long[(int) threads]; + futures = new ScheduledFuture[(int) threads]; + events = new ArrayList<>(); + linesIndex = new int[(int) threads]; + for (int k = 0; k < threads; k++) { + Map event = new HashMap<>(); + event.put("hostname", hostname); + event.put("thread_number", k); + events.add(event); + final int finalk = k; + futures[k] = ses.scheduleAtFixedRate(() -> runGenerator(writer, finalk, () -> { + countDownLatch.countDown(); + futures[finalk].cancel(false); + }),0, delayMilli, TimeUnit.MILLISECONDS); + } + + boolean finished = false; + while (!stopRequested && !finished) { + try { + Thread.sleep(1000); + boolean allCancelled = true; + for (int k = 0; k < threads; k++) { + allCancelled = allCancelled && futures[k].isCancelled(); + } + if (allCancelled) { + finished = true; + ses.shutdownNow(); + } + } catch (InterruptedException ex) { + // do nothing + } + } + } + + private boolean runGenerator(Consumer> writer, int thread, Runnable finishAction) { + if (stopRequested || ((count > 0) && (sequence[thread] >= count))) { + finishAction.run(); + return false; + } else { + events.get(thread).put("sequence", sequence[thread]); + events.get(thread).put("message", lines[linesIndex[thread]++]); + writer.accept(events.get(thread)); + if (linesIndex[thread] == lines.length) { + linesIndex[thread] = 0; + sequence[thread]++; + } + return true; + } + } + + @Override + public void stop() { + stopRequested = true; + } + + @Override + public void awaitStop() throws InterruptedException { + countDownLatch.await(); + } + + @Override + public Collection> configSchema() { + return PluginHelper.commonInputSettings(Arrays.asList(COUNT_CONFIG, LINES_CONFIG, MESSAGE_CONFIG, + THREADS_CONFIG, EPS_CONFIG)); + } + + @Override + public String getId() { + return id; + } +} diff --git a/logstash-core/src/main/java/org/logstash/plugins/outputs/Sink.java b/logstash-core/src/main/java/org/logstash/plugins/outputs/Sink.java new file mode 100644 index 000000000..86fc67981 --- /dev/null +++ b/logstash-core/src/main/java/org/logstash/plugins/outputs/Sink.java @@ -0,0 +1,47 @@ +package org.logstash.plugins.outputs; + +import co.elastic.logstash.api.Configuration; +import co.elastic.logstash.api.Context; +import co.elastic.logstash.api.Event; +import co.elastic.logstash.api.LogstashPlugin; +import co.elastic.logstash.api.Output; +import co.elastic.logstash.api.PluginConfigSpec; +import co.elastic.logstash.api.PluginHelper; + +import java.util.Collection; + +@LogstashPlugin(name = "sink") +public class Sink implements Output { + + + private final String id; + + public Sink(final String id, final Configuration configuration, final Context context) { + this.id = id; + } + + @Override + public void output(Collection events) { + + } + + @Override + public void stop() { + + } + + @Override + public void awaitStop() throws InterruptedException { + + } + + @Override + public Collection> configSchema() { + return PluginHelper.commonOutputSettings(); + } + + @Override + public String getId() { + return id; + } +} diff --git a/logstash-core/src/main/java/org/logstash/plugins/outputs/Stdout.java b/logstash-core/src/main/java/org/logstash/plugins/outputs/Stdout.java index c124fbf4c..07e70ad99 100644 --- a/logstash-core/src/main/java/org/logstash/plugins/outputs/Stdout.java +++ b/logstash-core/src/main/java/org/logstash/plugins/outputs/Stdout.java @@ -1,17 +1,16 @@ package org.logstash.plugins.outputs; +import co.elastic.logstash.api.Codec; import co.elastic.logstash.api.Configuration; import co.elastic.logstash.api.Context; import co.elastic.logstash.api.Event; import co.elastic.logstash.api.LogstashPlugin; +import co.elastic.logstash.api.Output; import co.elastic.logstash.api.PluginConfigSpec; import co.elastic.logstash.api.PluginHelper; -import co.elastic.logstash.api.Codec; -import co.elastic.logstash.api.Output; import java.io.IOException; import java.io.OutputStream; -import java.nio.ByteBuffer; import java.util.Collection; import java.util.Collections; import java.util.concurrent.CountDownLatch; @@ -26,7 +25,6 @@ public class Stdout implements Output { private OutputStream outputStream; private final CountDownLatch done = new CountDownLatch(1); private String id; - private ByteBuffer encodeBuffer = ByteBuffer.wrap(new byte[16 * 1024]); /** * Required constructor. @@ -51,17 +49,10 @@ public class Stdout implements Output { @Override public void output(final Collection events) { try { - boolean encodeCompleted; for (Event e : events) { - encodeBuffer.clear(); - do { - encodeCompleted = codec.encode(e, encodeBuffer); - outputStream.write(encodeBuffer.array(), encodeBuffer.position(), encodeBuffer.limit()); - encodeBuffer.clear(); - } - while (!encodeCompleted); + codec.encode(e, outputStream); } - } catch (Codec.EncodeException | IOException ex) { + } catch (IOException ex) { throw new IllegalStateException(ex); } } diff --git a/logstash-core/src/test/java/org/logstash/config/ir/compiler/JavaCodecDelegatorTest.java b/logstash-core/src/test/java/org/logstash/config/ir/compiler/JavaCodecDelegatorTest.java index aef26ccd3..57ff1c7aa 100644 --- a/logstash-core/src/test/java/org/logstash/config/ir/compiler/JavaCodecDelegatorTest.java +++ b/logstash-core/src/test/java/org/logstash/config/ir/compiler/JavaCodecDelegatorTest.java @@ -9,6 +9,9 @@ import org.junit.Before; import org.junit.Test; import org.mockito.Mockito; +import java.io.ByteArrayOutputStream; +import java.io.IOException; +import java.io.OutputStream; import java.nio.ByteBuffer; import java.util.Collection; import java.util.Map; @@ -158,36 +161,32 @@ public class JavaCodecDelegatorTest extends PluginDelegatorTestCase { } @Test - public void encodeDelegatesCall() throws Codec.EncodeException { + public void encodeDelegatesCall() throws IOException { codec = Mockito.spy(new AbstractCodec() { @Override - public boolean encode(final Event event, final ByteBuffer buffer) { - return true; - } + public void encode(final Event event, final OutputStream out) {} }); final JavaCodecDelegator codecDelegator = constructCodecDelegator(); final Event e = new org.logstash.Event(); - final ByteBuffer b = ByteBuffer.wrap(new byte[] {}); + final OutputStream out = new ByteArrayOutputStream(); - codecDelegator.encode(e, b); + codecDelegator.encode(e, out); - Mockito.verify(codec, Mockito.times(1)).encode(e, b); + Mockito.verify(codec, Mockito.times(1)).encode(e, out); } @Test - public void encodeIncrementsEventCount() throws Codec.EncodeException { + public void encodeIncrementsEventCount() throws IOException { codec = new AbstractCodec() { @Override - public boolean encode(final Event event, final ByteBuffer buffer) { - return true; - } + public void encode(final Event event, final OutputStream out) {} }; final JavaCodecDelegator codecDelegator = constructCodecDelegator(); - codecDelegator.encode(new org.logstash.Event(), ByteBuffer.wrap(new byte[] {})); + codecDelegator.encode(new org.logstash.Event(), new ByteArrayOutputStream()); assertEquals(1, getMetricLongValue("encode", "writes_in")); } @@ -216,7 +215,7 @@ public class JavaCodecDelegatorTest extends PluginDelegatorTestCase { } @Override - public boolean encode(final Event event, final ByteBuffer buffer) throws EncodeException { + public void encode(final Event event, final OutputStream out) throws IOException { throw new UnsupportedOperationException(); } diff --git a/logstash-core/src/test/java/org/logstash/plugins/ConfigurationImplTest.java b/logstash-core/src/test/java/org/logstash/plugins/ConfigurationImplTest.java index 2a171e2f2..6d30bdda2 100644 --- a/logstash-core/src/test/java/org/logstash/plugins/ConfigurationImplTest.java +++ b/logstash-core/src/test/java/org/logstash/plugins/ConfigurationImplTest.java @@ -1,12 +1,14 @@ package org.logstash.plugins; import co.elastic.logstash.api.Configuration; +import co.elastic.logstash.api.Password; import co.elastic.logstash.api.PluginConfigSpec; import co.elastic.logstash.api.Codec; import org.junit.Assert; import org.junit.Test; import org.logstash.plugins.codecs.Line; +import java.net.URI; import java.util.Collections; import java.util.HashMap; import java.util.Map; @@ -105,5 +107,85 @@ public class ConfigurationImplTest { Assert.assertTrue(codec instanceof Line); } -} + @Test + public void testDowncastFromLongToDouble() { + long defaultValue = 1L; + PluginConfigSpec doubleConfig = PluginConfigSpec.floatSetting(numberKey, defaultValue, false, false); + Configuration config = new ConfigurationImpl(Collections.singletonMap(numberKey, defaultValue)); + double x = config.get(doubleConfig); + Assert.assertEquals(defaultValue, x, 0.001); + } + @Test + public void testUriValue() { + String defaultUri = "https://user:password@www.site.com:99"; + String uri = "https://user:password@www.site2.com:99"; + PluginConfigSpec uriConfig = PluginConfigSpec.uriSetting("test", defaultUri); + Configuration config = new ConfigurationImpl(Collections.singletonMap("test", uri)); + URI u = config.get(uriConfig); + Assert.assertEquals(uri, u.toString()); + } + + @Test + public void testUriDefaultValue() { + String defaultUri = "https://user:password@www.site.com:99"; + PluginConfigSpec uriConfig = PluginConfigSpec.uriSetting("test", defaultUri); + Configuration config = new ConfigurationImpl(Collections.emptyMap()); + URI u = config.get(uriConfig); + Assert.assertEquals(defaultUri, u.toString()); + } + + @Test + public void testBadUriThrows() { + String uri = "http://www.si%%te.com"; + PluginConfigSpec uriConfig = PluginConfigSpec.uriSetting("test", uri); + Configuration config = new ConfigurationImpl(Collections.singletonMap("test", uri)); + try { + config.get(uriConfig); + Assert.fail("Did not catch invalid URI"); + } catch (IllegalStateException e1) { + Assert.assertTrue(e1.getMessage().contains("Invalid URI specified for")); + } catch (Exception e2) { + Assert.fail("Did not throw correct exception for invalid URI"); + } + } + + @Test + public void testBadDefaultUriThrows() { + String uri = "http://www.si%%te.com"; + PluginConfigSpec uriConfig = PluginConfigSpec.uriSetting("test", uri); + Configuration config = new ConfigurationImpl(Collections.emptyMap()); + try { + config.get(uriConfig); + Assert.fail("Did not catch invalid URI"); + } catch (IllegalStateException e1) { + Assert.assertTrue(e1.getMessage().contains("Invalid default URI specified for")); + } catch (Exception e2) { + Assert.fail("Did not throw correct exception for invalid URI"); + } + } + + @Test + public void testPassword() { + String myPassword = "mysecret"; + PluginConfigSpec passwordConfig = PluginConfigSpec.passwordSetting("passwordTest"); + Configuration config = new ConfigurationImpl(Collections.singletonMap("passwordTest", myPassword)); + Password p = config.get(passwordConfig); + Assert.assertEquals(Password.class, p.getClass()); + Assert.assertEquals(myPassword, p.getPassword()); + Assert.assertEquals("", p.toString()); + } + + @Test + public void testPasswordDefaultValue() { + // default values for passwords are a bad idea, but they should still work + String myPassword = "mysecret"; + PluginConfigSpec passwordConfig = PluginConfigSpec.passwordSetting("passwordTest", myPassword, false, false); + Configuration config = new ConfigurationImpl(Collections.emptyMap()); + Password p = config.get(passwordConfig); + Assert.assertEquals(Password.class, p.getClass()); + Assert.assertEquals(myPassword, p.getPassword()); + Assert.assertEquals("", p.toString()); + } + +} diff --git a/logstash-core/src/test/java/org/logstash/plugins/PluginValidatorTest.java b/logstash-core/src/test/java/org/logstash/plugins/PluginValidatorTest.java new file mode 100644 index 000000000..68e22563e --- /dev/null +++ b/logstash-core/src/test/java/org/logstash/plugins/PluginValidatorTest.java @@ -0,0 +1,69 @@ +package org.logstash.plugins; + +import org.junit.Assert; +import org.junit.Test; +import org.logstash.plugins.codecs.Line; +import org.logstash.plugins.filters.Uuid; +import org.logstash.plugins.inputs.Generator; +import org.logstash.plugins.inputs.Stdin; +import org.logstash.plugins.outputs.Stdout; + +import java.io.IOException; +import java.io.InputStream; +import java.net.URL; +import java.net.URLClassLoader; +import java.nio.file.Files; +import java.nio.file.Path; +import java.util.Enumeration; +import java.util.jar.JarEntry; +import java.util.jar.JarFile; + +import static java.nio.file.StandardCopyOption.REPLACE_EXISTING; + +public class PluginValidatorTest { + + @Test + public void testValidInputPlugin() { + Assert.assertTrue(PluginValidator.validatePlugin(PluginLookup.PluginType.INPUT, Stdin.class)); + Assert.assertTrue(PluginValidator.validatePlugin(PluginLookup.PluginType.INPUT, Generator.class)); + } + + @Test + public void testValidFilterPlugin() { + Assert.assertTrue(PluginValidator.validatePlugin(PluginLookup.PluginType.FILTER, Uuid.class)); + } + + @Test + public void testValidCodecPlugin() { + Assert.assertTrue(PluginValidator.validatePlugin(PluginLookup.PluginType.CODEC, Line.class)); + } + + @Test + public void testValidOutputPlugin() { + Assert.assertTrue(PluginValidator.validatePlugin(PluginLookup.PluginType.OUTPUT, Stdout.class)); + } + + @Test + public void testInvalidInputPlugin() throws IOException { + Path tempJar = null; + try { + tempJar = Files.createTempFile("pluginValidationTest", "inputPlugin.jar"); + final InputStream resourceJar = + getClass().getResourceAsStream("logstash-input-java_input_example-0.0.1.jar"); + Files.copy(resourceJar, tempJar, REPLACE_EXISTING); + + URL[] jarUrl = {tempJar.toUri().toURL()}; + URLClassLoader cl = URLClassLoader.newInstance(jarUrl); + Class oldInputClass = cl.loadClass("org.logstash.javaapi.JavaInputExample"); + + Assert.assertNotNull(oldInputClass); + Assert.assertFalse(PluginValidator.validatePlugin(PluginLookup.PluginType.INPUT, oldInputClass)); + } catch (Exception ex) { + Assert.fail("Failed with exception: " + ex); + } finally { + if (tempJar != null) { + Files.deleteIfExists(tempJar); + } + } + } +} diff --git a/logstash-core/src/test/java/org/logstash/plugins/codecs/LineTest.java b/logstash-core/src/test/java/org/logstash/plugins/codecs/LineTest.java index 68bcb9df1..abf3afdc1 100644 --- a/logstash-core/src/test/java/org/logstash/plugins/codecs/LineTest.java +++ b/logstash-core/src/test/java/org/logstash/plugins/codecs/LineTest.java @@ -7,6 +7,8 @@ import org.logstash.Event; import org.logstash.plugins.ConfigurationImpl; import org.logstash.plugins.TestContext; +import java.io.ByteArrayOutputStream; +import java.io.IOException; import java.io.UnsupportedEncodingException; import java.nio.ByteBuffer; import java.nio.charset.Charset; @@ -239,71 +241,28 @@ public class LineTest { } @Test - public void testEncode() throws Codec.EncodeException { - String delimiter = "z"; - String message = "Hello world"; - String expectedResult = message + delimiter; - Map config = new HashMap<>(); - config.put("delimiter", delimiter); - config.put("format", "%{message}"); - Line line = new Line(new ConfigurationImpl(config), new TestContext()); - Event e = new Event(Collections.singletonMap("message", message)); - byte[] b = new byte[100]; - ByteBuffer buffer = ByteBuffer.wrap(b); - boolean result = line.encode(e, buffer); - Assert.assertTrue(result); - String resultString = new String(buffer.array(), buffer.position(), buffer.limit()); - Assert.assertEquals(expectedResult, resultString); + public void testEncode() throws IOException { + ByteArrayOutputStream outputStream = new ByteArrayOutputStream(); + Line line = new Line(new ConfigurationImpl(Collections.emptyMap()), null); + Event e = new Event(); + e.setField("myfield1", "myvalue1"); + e.setField("myfield2", 42L); + line.encode(e, outputStream); + e.setField("myfield1", "myvalue2"); + e.setField("myfield2", 43L); + line.encode(e, outputStream); + + String delimiter = Line.DEFAULT_DELIMITER; + String resultingString = outputStream.toString(); + // first delimiter should occur at the halfway point of the string + assertEquals(resultingString.indexOf(delimiter), (resultingString.length() / 2) - delimiter.length()); + // second delimiter should occur at end of string + assertEquals(resultingString.lastIndexOf(delimiter), resultingString.length() - delimiter.length()); } @Test - public void testMultipleEncodesForEvent() throws Codec.EncodeException { - String delimiter = "z"; - String message = "Hello world"; - String expectedResult = message + delimiter; - Map config = new HashMap<>(); - config.put("delimiter", delimiter); - config.put("format", "%{message}"); - Line line = new Line(new ConfigurationImpl(config), new TestContext()); - Event e = new Event(Collections.singletonMap("message", message)); - byte[] b = new byte[10]; - ByteBuffer buffer = ByteBuffer.wrap(b); - - boolean result = line.encode(e, buffer); - Assert.assertFalse(result); - String resultString = new String(buffer.array(), buffer.position(), buffer.limit()); - - buffer.clear(); - result = line.encode(e, buffer); - Assert.assertTrue(result); - resultString += new String(buffer.array(), buffer.position(), buffer.limit()); - - Assert.assertEquals(expectedResult, resultString); - } - - @Test - public void testEncodeNewEventBeforeFinishingPreviousThrows() { - String delimiter = "z"; - String message = "Hello world"; - Map config = new HashMap<>(); - config.put("delimiter", delimiter); - config.put("format", "%{message}"); - Line line = new Line(new ConfigurationImpl(config), new TestContext()); - Event e1 = new Event(Collections.singletonMap("message", message)); - Event e2 = new Event(Collections.singletonMap("message", message)); - byte[] b = new byte[10]; - ByteBuffer buffer = ByteBuffer.wrap(b); - try { - line.encode(e1, buffer); - line.encode(e2, buffer); - Assert.fail("EncodeException should be thrown because previous event was not fully encoded"); - } catch (Codec.EncodeException ex) { - // this exception should be thrown - } - } - - @Test - public void testEncodeWithUtf8() throws Codec.EncodeException { + public void testEncodeWithUtf8() throws IOException { + ByteArrayOutputStream outputStream = new ByteArrayOutputStream(); String delimiter = "z"; String message = new String("München 安装中文输入法".getBytes(), Charset.forName("UTF-8")); Map config = new HashMap<>(); @@ -311,47 +270,14 @@ public class LineTest { config.put("format", "%{message}"); Line line = new Line(new ConfigurationImpl(config), new TestContext()); Event e1 = new Event(Collections.singletonMap("message", message)); - byte[] b = new byte[100]; - ByteBuffer buffer = ByteBuffer.wrap(b); - boolean result = line.encode(e1, buffer); - Assert.assertTrue(result); + line.encode(e1, outputStream); String expectedResult = message + delimiter; - Assert.assertEquals(expectedResult, new String(buffer.array(), buffer.position(), buffer.limit(), Charset.forName("UTF-8"))); + Assert.assertEquals(expectedResult, new String(outputStream.toByteArray(), Charset.forName("UTF-8"))); } @Test - public void testEncodeAcrossMultibyteCharBoundary() throws Codec.EncodeException { - String message = new String("安安安安安安安安安".getBytes(), Charset.forName("UTF-8")); - String delimiter = ""; - Map config = new HashMap<>(); - config.put("delimiter", delimiter); - config.put("format", "%{message}"); - Line line = new Line(new ConfigurationImpl(config), new TestContext()); - Event e1 = new Event(Collections.singletonMap("message", message)); - byte[] b = new byte[10]; - ByteBuffer buffer = ByteBuffer.wrap(b); - - boolean result = line.encode(e1, buffer); - String intermediateResult = new String(buffer.array(), buffer.position(), buffer.limit()); - Assert.assertFalse(result); - Assert.assertEquals("安安安", intermediateResult); - - buffer.clear(); - result = line.encode(e1, buffer); - intermediateResult = new String(buffer.array(), buffer.position(), buffer.limit()); - Assert.assertFalse(result); - Assert.assertEquals("安安安", intermediateResult); - - buffer.clear(); - result = line.encode(e1, buffer); - intermediateResult = new String(buffer.array(), buffer.position(), buffer.limit()); - Assert.assertTrue(result); - Assert.assertEquals("安安安", intermediateResult); - } - - - @Test - public void testEncodeWithCharset() throws Exception { + public void testEncodeWithCharset() throws IOException { + ByteArrayOutputStream outputStream = new ByteArrayOutputStream(); byte[] rightSingleQuoteInUtf8 = {(byte) 0xE2, (byte) 0x80, (byte) 0x99}; String rightSingleQuote = new String(rightSingleQuoteInUtf8, Charset.forName("UTF-8")); @@ -361,20 +287,34 @@ public class LineTest { config.put("format", "%{message}"); config.put("delimiter", ""); Event e1 = new Event(Collections.singletonMap("message", rightSingleQuote)); - Line cp1252decoder = new Line(new ConfigurationImpl(config), new TestContext()); + Line cp1252encoder = new Line(new ConfigurationImpl(config), new TestContext()); byte[] rightSingleQuoteInCp1252 = {(byte) 0x92}; - byte[] b = new byte[100]; - ByteBuffer buffer = ByteBuffer.wrap(b); - boolean result = cp1252decoder.encode(e1, buffer); - Assert.assertTrue(result); - byte[] resultBytes = new byte[buffer.limit() - buffer.position()]; - System.arraycopy(buffer.array(), buffer.position(), resultBytes, 0, buffer.limit() - buffer.position()); + cp1252encoder.encode(e1, outputStream); + byte[] resultBytes = outputStream.toByteArray(); Assert.assertArrayEquals(rightSingleQuoteInCp1252, resultBytes); } @Test - public void testClone() throws Codec.EncodeException { + public void testEncodeWithFormat() throws IOException { + ByteArrayOutputStream outputStream = new ByteArrayOutputStream(); + Line line = new Line(new ConfigurationImpl(Collections.singletonMap("format", "%{host}-%{message}")), null); + String message = "Hello world"; + String host = "test"; + String expectedOutput = host + "-" + message + Line.DEFAULT_DELIMITER; + Event e = new Event(); + e.setField("message", message); + e.setField("host", host); + + line.encode(e, outputStream); + + String resultingString = outputStream.toString(); + assertEquals(expectedOutput, resultingString); + } + + @Test + public void testClone() throws IOException { + ByteArrayOutputStream outputStream = new ByteArrayOutputStream(); String delimiter = "x"; String charset = "cp1252"; byte[] rightSingleQuoteInUtf8 = {(byte) 0xE2, (byte) 0x80, (byte) 0x99}; @@ -395,14 +335,8 @@ public class LineTest { // verify charset and delimiter byte[] rightSingleQuoteAndXInCp1252 = {(byte) 0x92, (byte) 0x78}; - byte[] b = new byte[100]; - ByteBuffer buffer = ByteBuffer.wrap(b); - - boolean result = line2.encode(e1, buffer); - Assert.assertTrue(result); - byte[] resultBytes = new byte[buffer.limit() - buffer.position()]; - System.arraycopy(buffer.array(), buffer.position(), resultBytes, 0, buffer.limit() - buffer.position()); - Assert.assertArrayEquals(rightSingleQuoteAndXInCp1252, resultBytes); + line2.encode(e1, outputStream); + Assert.assertArrayEquals(rightSingleQuoteAndXInCp1252, outputStream.toByteArray()); } } diff --git a/logstash-core/src/test/resources/org/logstash/plugins/logstash-input-java_input_example-0.0.1.jar b/logstash-core/src/test/resources/org/logstash/plugins/logstash-input-java_input_example-0.0.1.jar new file mode 100644 index 0000000000000000000000000000000000000000..e8d0147b9392f4b18cc2b66fcd60cdc4becc2752 GIT binary patch literal 2962804 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

3y)74DrWVLT?ud8=YjJdRadB!9UlB~^ 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%0Av_Cr2 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%0Au-OrMWGr*grG*&#u)iW~H1Zh&_J1&L&A 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 z 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�vjObc> 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.u}btiwo|G|aPQKaj!s(mXEe&fx>6!; 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

8nXX};eDB&M7r3YszoTvRrr)hoN%1b)*m4mib)o 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%0DT(0Wy1X@MDy=Qo&S?- z|DP%6KPOzpKMjd-$ukON=3$CrgMeudl7r@aa*>d#s8sv`g6oR2R6^JL)|pX(%hesS z%6t*zB%jWNe4lg|8#Q(3mWupG<@=5!Ef3_2kd; z>C919E!oczM?xo@RbGNZ)IF>F!KCzcBPWmu;D8Ted@S5Y(s_1|@8kg{r8|K9+vuZ; znTweb1|Q7uICd_g)+@$pE3v3Kb(gcY70N|*6nZ@+7c(W^#nS+bJ2(?&5UOW$zCChW zvxGzY;wDBOYb8)+v>xll#^^-M- z65dK`)tnJCZi2f01X7FkJ`U%myd#G7Bo7=fK|9QNf{}|%`)48rv*7*})0|{PJWjG*=@_U^U-kW|wGQHH96Zw z!e>%>-HCgl0i>>paR@|H`ozc>n=9Y8#~$uejllz4ILp$LB1yc_q$wc?aX0IT%$zyE zb7D9-&ao`dwZFSme_46>OC|qN03ne%73Wa&oLJK5P4@K+N3E`RI zfp@4_B!9$9JM$`c+8JwvAN~Z%jjYHns_;=2 zVX3`SpSM$Nwnn*=Tt~kR4#dm$)hm&foUx>A@L!zVb_zMg%NTRg*0`b$^w#JW7Sn&h zH|0!j`C$%Yw#J}_G-0%vTbL%UUtAJX2*o*}-0sFTZ)9_;T91lJk7zXxE}fMv`T@$ z?NtA9Q9(neKVs4O6Ri7VNF)8{PyN-XUZ`ogA*-Og%f_3=GthQ|S%^|d5Ejx33IKz~ z#uqonDq81Bh&rUp&Qm6&ait|juy<_HKZelr)!h#UG`MR>iKg&9ZfB$vjdv4WI+`x7vM_dp%%7H<|U?9dAR_dsI)Q)3s3W^Vcf-=J> z1R<5dSEU7SU1w0HuA&~y*ECjNiaW99Pv-Tcn$IvPos6bL1_-G|dgpI7u@L7NmP%)c z&8otB3Cv1S*+~9=z_E~P*Lp24OHg$(m!4c5rky+#TdU)&kHt_3XW`PCK{f(hI?u8o z^@mr%S`69eH(PV2#hO30#Mfi45D16GI4_cE{YsCUm+C*=iLZ7mZBwgWWdBGN>LI!9h&wKRQZ(mR{u+V@4B$V`)pbto)Zu25914n>POY9W7y zi;jtfISyN;GT)MXPBsS%2Pbp5tvZug$~E7o)Lcts*}*|oy1HA2*u|~E8cQFtaMHkW z@3zu379K{p+(j94P6f|`x#SoGx~jOA8?#27b?iHDM7`gPLkh^Z08D4^i5efu+U?Qp z$AmlwTRo-ZQsi<2GxrCTm~v=RHw~iPyUWK|=a|%DpOQ<7P%hgt&Oy~sOsr=>NEPY= zP*rIh@;Y390~oU7et6xUvzJ_WZTZLi!aUQ+T|?a#85{3d%ZP|V%akMs{f-6K9#XbJ zY2Bn&MyBy5a}IpHDPO-5Nuxzm`H+O@!jk~s>E&eRWZ9lAxN6vfp?VD%;F;O>WSw(5 zJHG0K4!W7F9Vp?NM#YEfF7Y?YJJe#G7odqF%QX3Fnj`lat=FsfS_ww=v~?nQvOta3 zDSj&KXgWXWh=gal#;^8M0rr6KNb_YfK1qq2HTz3cJzDOhcSWSk%6JA0)8()y=Hv>2 z5iuLXw_Y{OxZ1B)#siNN(M4d96@G$Z;66;c15&Uq^&|V@+EgtVdN1NfuRB4M}oJQsshTriSYe2`1$w%)t#(cZn^eOTx1Su1V2_T|X3@ zVpr6_C9g1Pf7e`lV?Ii{)oYV;7rY&I$IhqjhZFL#UXmh6y|_3XyJxJ-T4w{Jpa-m_ zdn8|b_18(C7Su8s$zDRLCvi#@p$o)l=6=h#7YLtJ%NG?zSnRG;7a!2s>l(^1Vve{v zZ>qS|7S#_<#?;rD4l6OL%y8QYFw8vC^3=N)OhBd;7Jfm8@i)nA(f3^5H%pX{d$T<#z&GZDC{z+%L1X6E z!a$nx$KYWV|19)g2&WxSC_ZD)m{j)#X)&i-9@O|Cz7Ruc1=ip1RKGF3gyhv zy`|f%rBm;cER=r*x1{jCu~T4QxiYK0%Z{CZ5;6 z0$Up+WE=j`yR~-9d0MQn1qhsB$zKSjCtNtq847=7xopkCi-zzer0zzV-=bjkCAamH zpZP#p%D^eYyE08-Px+d+b#MV;)u(_YM1t4sLs)v(h zIcXNQEyUYhxq+MlB{%j7QXNDUtPdq#tO2zD}HBz(@s;|7N9uG+P5O&EbcyGMPYs>?HF(N!zmGw>U_4zxWdES?c zqmt<_)jPVdWR(_$vC)Kql`NbVrbZ)sb&=H)PM>VSgxO60Gw?%9BGR4k+zEsxMLEod z@?}SihsEGC9-Lnp(cOI+yh2}>cr$)yJL-*mWaOeb560#x{(hCshHu$)x#j&ak7z6Y z+}hZ2@dSF~Vu!L%ede!(*|;9vy$=hrb1UF}=~KdP|4JnMnnVw5Ht4ncby=tV%&Xe{ zq5(s-@)^r-^sf54NrmFla6BKSZTJq1cDJ+bIO3cC;xSFg&yi+HHSgVI*!ij|D%he; zd;PF6!&|U84;=d!(LnfxR;-p@`NnJ&%f`*}g^SA(AHgWgn{UiP*(wr6%eL^i@i-@( zw&cf(Gs+Q|hB1pkG%%|h^B>2{l|1;!UNy@-0pBwy5G;^I6QwueizDOx*U8Wv#EDRm zRcO*$sAW*cVI$gcF+<+UC3$73@mZH~GDvXKXV^pfKCVPNPdIuX48^M!zRoiqaQnzM zk6x6ni+~jU9_mNMbr)u&Yj%rp4jk`?{|(mLrcyDA8d|mXaO(#Mg&?L%$nr*Y-7RSL zrn8zZRY=barcN!k3w;enjE4i;^!=rf$1SKU*A3w%E(rNDIy3?zY0lvff|9mJf-^vP ztHcrcXzEX&SPjpPbE}S|CqdQdA_KvV8|1X5FJciG-jdlN0Me_JXKH z$nx|3nJZ+AGCp23-Th07eouau5(hv+)pu)zjzCd`2QdE%J`SwePjO5^@yD<@Q&}O$yV&Za}hN`d{V42JymvTs!4AuIh zA@O@3W9ERxT)q?&hwzj9EN5S8_>>ZgV%!3H@u{dbfzMiU7sW}t^a;9(6a5?bA2F%- zTG3DNIiHpJmumIj3rn8=wy+d-a{V9B_@9f)NwpWhKQ_p9R>E z?cSz;?}<6(bTh3_Fs_&ErzgwV;Qamb?ls$Ky3^yGUrrCG2K_@>pDmw11h`Vn*sw++ zQgE9FUKX~B@8EWOP@&Hl_V+H%oy^TW54_#ZP8Cl_RA}?CJ^rQHDXv2Y@|EG~CQnCb zD1^H^Jv{vFH3IyVkLh9U0-04(xm@B_W+U#WMAd~lWY4jNJCFXcJGZS97<0j_pkhG?PkCq8>NxT8JM!S3sEqjs+xzfqb ztnNCcx$Y5b%WP(CeL813C%6{8c37lTC$LsZ6RikWYtU1rO%(Q%vZgN}`Vg~eF^#iI z#&RFC_N&)d$sn~k+XuhEBlU*PtpQBLY)gOa+!)kR(l|E}@)t`HFs z??ljtDo`2OePBD#e9lc4Xz*U*nl36!V|BNB&A7Us_Q`QXdG#g(mM8*XD*mY|Ofp+! zs0{@P8LbAL5@b9Xu+%{Dz!~V`DX*zBjX2zZMKh_G0^?Hl(t&~6_ybHZp9Ook@>#s` zI$q2+>X}BKfpF9Bt{V%nuMdi^P0XSp%~LA8BEIO(j{4D2!ql~l{NkI`3Uhmibw;Ey zaki-o6G%lSE>l+`CNoL7%!tD`aX%kGKn+t2Fm;=I3YP7;D)0hHx%=wAj#0P>*!2+@ z!&kmeXdkWibGgvXb6l}kR~H4)R^%pV9<)IEJfzC+`vi(lnfx-0Z3oXf08O^>cVtk- z!aov{rD1R_HBRO9cvXe>(tMEaR!!_osg?rEDW;a}H9Iax;&^lK|j$Ce#{#n=<= z8^Fflt}^T7@??kf&rnlEf#$2&b#jl~R=V-<799KnuHucTr+8!HEjp-n!wRfExO~$R zV8<|xOx5+>uI!NwPwfWRTWt`mID0^esw?!0`Vq+K(?TN*6D&oUXOcU`c;_xS_~QnJ7r#6)F<`6I9kE;Gnj5uy7$204PLTwsA7ABj zFIx2m{WWRK`Ezwd$pN;1T(sP5;#bQ7vmwwace0u~uvRkHEpP_f8TvxTF(V^^m9bmh zT9n2fK;F0=8>fVzBAo7xgR;AL%vZNM|L9|Pv$j%y>CnYa)&g=PR(oZXYLXNHd@$2Y zo?=2QO9YZ`5`&Rh*S0@ZuwX`w#>BS8eikp@Z|V`JRmd|0Y-14nri2^aQlh?4m1!+Y z{)DG4gSM*KZIJFw$TG(xyt!0Z(Ygeqbqk6YBQ2l)slG3ek@+O*=7ai8qSPYUW`xmt z_`2A*#-~AP=d!-kk8un;-p7Epm+QBx;{1>H>f}%LeXO5o-qp%IGIgT|w@5$hJ?`%} z&Z$BHC5b#IycvysPW;YOzTJnJJCIF_x07bOFpJ`YUCUUG=T4xb@1!4tjL@RYq$V5% ziZm2FA8Uv$4!YpSZP)}zc53yfnMxhAqtP(^16 z3zcQ1ajGaCB5(v9Li2p%b6E{#t<|!Pu2QtZzCNJ0>;0ZB?4yS4P!A$?o(@hn>~k=r z?gfpsmcvDArlTgt$9v>6;x*D&Wd|mx7PhE&as=J_IH6m6RgGTT)^sLcoXN!Ah7yWH z1W%~Y7lt@BvhLu6$rusLf6PHxx>P(2UWHPVq2t4-!sxB7y^32BS$1M}ejHszgbX$f(4UGwf4^z9*pjewrQlfV^#@myBYQI{O$umP&PP91;;91sp+88H)#> zSH|j~*0l@$)SPvXWqnX<`l>R*0wzX3NFYhpIwV+D1=NB*`?$}85u=FEEQ!(XqYJy^ z3ROS_gc@&1p(+{PU!8yws7Oxe<;tS_yw)2RVx^d|!-^1v#4`d=E$XjB3(m zgY~1ZTTSOUx4zb7nMD%`rFUt3#dVjcsabAsaeigid!8k}qbraTDwskySNtw22-S!; z{1?ktBr4$sC)fB7 zYaEt2E;0B^8eJjTLmPa;H=_8$iuq1T(;>b6Njr9WlApx;)JwGg7r(`fCPt~x(&K+0 zfA6>WkKRDk*635H_#fO0?q7DxeBj{VM&Nj^;B>CwwqoE-3myBfiOOOj0&qE%19c*A znFAfpJ|BgZ3;Re`Ij{N7Zvz1X`;p3TnXmWv(zz(HY@>5>Q}n>lq^gH0$;aF($%R}= z#YIJEt%YbQ#)qWI#)n55Rw0Z`_TXm4Agx8B0(V&~LP8X5^8I83(DP}osX~#k+PzOj zqN8QDX`BM%9@@QKG;<)7#>O**W0>;1k+8tWL-mYI3``7+-@XvT5Q8v-z{E~N?=yay z0x$**PW1p4a{~QQv3Z|jJdS<-BQF0@7mW4u8+MLn^al2Sn2gg~+nJeJ*qZ(E%3?`x zWas$#(O>wYxQVstKbLBYT2S7~i;MhbP3&nMu?!3X0wjf{vC@#-SO|oK0t8S}z>uXJ z(z@}zqtdA!{l%`eD@#7jV2w?x*jnr&Pz1F4=w+_;Rhx@zor{+l?cN_wTjRz^WH2jR zS1)|8lbctqN10y#hq8ByuC&{>hO1(G#i-b}ZQHKcb}F`Q+cqk;ZB}e26?}Pd+CKaJ zTRVII7wc)Ot&4Rr=Xk~#ea_zdSp2=~aLMfy5K_b$^i1}XpM2Ebl_B}JDXHxBwNh4+ zf9)~mRE&F3G*cFFxv_<3Rr1uWJdNt`I5zo#gk2ZPZ9&Vo;Hv#+9i1Gz!a-#o%pT~% zl80*oor-HDyvTzsW`>-`1H>gyRHozp&g zv=>*L>LpkIXg|+bN1CKvB=s8kJxMR@U1@~?Q1|#`SX$QKErFVy*w;4)S`5z&UvUzj zS!jp86VVW!Gt>#ULDG^IvUFy|rB=3fL^gZ41=koAC(}M&13U{Wo^qx?a<$&+eh9Ux zx;^LD=_l){9{wsfx-!K4p|vMF{KVYakXD_z=+x@Ty|w)d%gYmai%QP=dd9g+*;b9R za;?CrJ(*{pT6(y>e;7Tp4Cxk=8G6YdEVgyrG5jEJPJ$+lE{KVUA@uj zu;xb6i0=$Y(aaa7tSKR(T6GSE6;#Id6(BG_&JU&+<=mK1EXZx>kYm-xuv671ln~6#!&2B7QM6I$ z^Q6U#%&^S&LX&RfJjm9~6GZo@snuxjBPM?Bxb~9CrpB5+GZ+R7mW=TmNBRfY!pf(v^dQapY$AkxsP!c2N+00ZaHI2cbdH!VhmEzOJpYfR>unhFv4 zHERhN%|q)7g4x%rsCMHFw@OwxA3D;sfZAYG8Dz1l%&cOwrNVtmcxvOLDYQq+kk5; zJ?WBxBlgzxvI50Z6$lzz>zd2$NXYSZn#@<3wYsCGNhE zDwYzd2Cf^Lfigv{#lR&T<_#G1{478CZG1;87}5kwOU!C<6lz?(CZI}^xwVk{-e77u z6R%z8AqM)p>67{+tjsK!Om@j{tp$=(4K=u$>vkQRr>rUhax+-%kj#t9=60fC&E&}} z2a!3y6y^-jB|e6whVOYLO5Urq9*bj9;4=m_q=I!y!qnL>2YR&;@oj(ve4CAel{+EE z^nzdP4GBzKvB9{L_iwk#?POS3w9 ztQ-ayM;sk5*d{iad}4U9x8N_ERdR4CGV5}s7mKxCm_Q|2Uxhu>GpO%~q?eaiiXbs| zTN!8JK9;ZpH>9a#Q_soe-74ZVw@|`>pV%y%h;*`&T6LgT#PGtDna9eTgCm^>gbElj zc_UE3j-mS3B3RM4#hL2n42ITwB&}JPul~@?rJ%v<{CwFxdWn}kLcPG>))F*F4(OBW zL8Y6(KEmC*9#c36A~j5B7mBm6L!eWiiP!=_(2_;f<%lG38(YKXqz=4DuP!CaD$0exmExUYG)U}i1Hp`? z-DRM0psrk*E975G463Pj*D`>M9D^^mTGCY%tK2KjOqss640wVHll<*_g#4(97W!%4 zv|mW4o6}euUBkWvqyxQ%ZuG*(dsC1!o~i^KkJhMy2HVhr^+;p&ogzC$S@L%->CoBc zxtO(NaE%;$cuFIrcn(plHGt}*FB+I%))<+K3nlF)u+iI5T!Sr%$N#ef6XyocU( z=U8RQ0!Q~~nIlJdC)3xINsnhc$0zZ~$J2H3sS`&=ZD4MWfz!ofjy9b`V4!VjcW7Vt zW{3r$d=W{qwr?|WNb9rK5v4R4YY0%R^cg?!kXu<-^d-Y=Z{6&#EY>^lVzHxD>*hu2F}Tz5HBZ9Yit%J)E{WQ znGiR%l1ER1_2kq&%=eT!EPke(eJPvN?Q6VRI>yO-7y9uz#*(LMF8nS|hISg>=^c!> z{MzB@%C@NXO@!EQm(}SV^#|5<@Z{FcwNzgnx>jcQ*wpDO_j}hQ?-%(y?C$BtIuojV zdb%gX54FSWD_PKu?4DjQb zTaH8gMsk^^L1g3T&>z>`J1%wYWJT(4y!H1n(3HLm3pmqjEq3ql-Bq_(uN(sCnV&j5 z9AuiMC;ZH<-Dam%X%9#5;H`yc?wt?Fcan}5luYIok9qz!e;l}t9mf{Ow)6*6xaNy1 zHl~doC$<s6$1+nkoSR{;*s%rhV zJ57*4HF6c?38rOrFA#u@ax65ffGHepk68nc8SIHz+V{DrFrgS7cf1|RCSBiX!kBb3E-_dm*otf<=@`Wu^Rsh#8{7rMQM#^^LsrURBu}YsPkMtDR z`5QgIu3`*)yE^4*W$e>*F;{EGL=*?#G8H$S;j%b~@(o(a`ZH9Z2q6I&wQuR)D-eCl zPGtGOS`Y`i3PYML3&+>u!Uz>4oFNw?c;@bSrcerQ&Zycb>qQuR*WF)o?BC;sw4O|e zX9nJCt0^OSfCU!d*#gr(`JST(`-Rm*Cu^6@safWWK4H^C#Sytl*7vqT_27$TJez@B zK0#E0;*#j+^7lIp?{`}bb=^sYc*)J_(1ONd7ZrGpiFXx1l*vPRoK)zGr_NhuA`jF# zrR-THgD>w}xH2z6>Dr|B6`WBveZL~lu7whx=Z{al7vmnUy^qe`;y!gSTjsk2HgDxX zBCD8tPPyl>wh195c4atAn9|34oiX1SQ4o_Ei)^UX;ib(HX=iUowu-RhM+f$ag!K)m zjmy6^H*BG`m2|>EY53D1&>?-HcQ%mjRw*p_Q5r5j4&oGm6WDSPhFak97FzLU$>Jkr zA^=X4hNS)+Kv%J*yiBWpB3SHBBZmjTs^n!wU+AQ{U6EXQKQNV$>J*b(`h9v-5uL#h zJcstqnnyaZW0H2uLy+Q|ziZiUMgeL{iuh~J^o8!-@CCvht_|ufdbY~(!~BjniT=ax zj+cL_;P+wP4=a%$^v}OQL9Mzwv`bz-)8YcFVdng2S}g0DsIpPLHyz>rdKeEiSv)N& zk$kZg_`bpYLO9bE%p)z+hDK;NiXT0#*jw0B=R>*e%nl#3XV>_|Naj@%`pz$Slzpe( zaG*YR%=41*lAq@ph+Ce7uq{W;zfr0o5FyzJ;>EgA?ab|y4c^XEJ=q$}F%8D?idHe) zx11F>>$U%#hp#Gbo3Q|tbJ!tf{r8BXLXfpOxY;Cad{cHu;ZSMbzW9yGKFR@h>Mw`M zQP_Pj&&L_{Kz84CGk|;UrZ_wJCyDSFX)6f!R*x#M{;KJizd30g?k z2StAIFW-WbKstVp;9Xr5@#R|J!Fv4MJ))7*0Eh#%4i51`^c?pM z0XfDWe=&vAD zq~#8B=5&*trW>6xtrm&4Xpqe(WpalD~@4~M{> zpY@gEQIWI;MIOdqp~wD6AF5(6ZgzXwM-p;xvw<#b7$I84GF_j#sZmfvfTKJq=0c7d z|BtO`qYQt-`Ds&&mFfS4BLRdvr>JsUgXtu8EApZc*R{UU?He`EH!}C8d35B?0p^}n zRJ~m0)Fj|*I;@Xbd+{amtU!LqGytIwqd%e^a9eIx&{d@3nVHp7@-vm{$3f7lQw)?x zy@8)Wp!LLBoPG~yRISZ)eUi=$P{eRrY_J)VEyf;ie*9pP<7{dsQ&oJJyMJcFSLXuQ zq+|A%BG?N!Y?3_Y!h*YRkwZ9ur9_ag#qm6H@J85q3C6A~hz+-w#p`i(z)ZRRT1Fmo zql`kiL%z zcmB^$`p3|Bf>;BcUr2xy(gugXV>$RtxT|cPzaF~NZJ$A@=9W{rhD_Sc?uCW=ZKUR5 zav?8Io*GMR9hUIVz z%_Cp238TrguH-CTV|D6kTq1gf;7D+}rI42((V#nKfSF2VLcZopp0xHVJ7R-f+lney{bL}~L2-*@NfjOkCG#*}>R&GX4o9Eup ztY=Mn;^79lF~xlMg|;x*Ew!yexyF{!wv={`_SG$YDtRxuY{9ci8}R0p2Q@H$>%D4dhk{%lj*7gQL5xD zC@V6pYi=%PDQk;#!JhavKRKffnYG|P*wt*^NGH^=?xq43_?RUrLI|`Nz~N`laz3;y zcDa-agG&U)cQa(tG!YseGHDmVkZ;is9{gm|Y^3$Rf9;!$gnXd{^;wwm3Gt=y=;^)i z9t66673Gm$%Nbb+HbqnnlmrDv*d?sznpD@|gLb{hZw$QfVX5rJx}#0fCg_)>B4gI} zq7*^bIHFMQl+jq_*I7sy&LhojX9|Fa-_6NwAA!$EqCd~qK#%1h&DEqOn}T^sUPDJc zE7D)Q;@7~}<0$!g;xapm`>JV#yz(sor7f#ya3ewYh(jcDu_>*#-K;61dQZQqWZ(%C?hI|LHOICLh|Bup_>%6nKqdF{X9i+Hwx}y1=6yC3i2PdlKv1ttZA?LjE08b5BpB1DwqcP}CI!iyKuj z+whtziOpeahkv;%DeD!$ll(`F<`W_IUb!pf50p-APiox>mzyDaQ0|*F0Ug z%eq6N&tUIRTfZsUf03lhyIPo9Sss}-m9SUt0+i?+ z^EqO>^BrM$gsq?8a0JHQUj4mj7N{ha(4;Hq+XkgBoRus2T7wLm1DjRboAu38`U5Ue zK21nSshbtTLHWR(5?yP&hOm*lf&+R?R{&wuPi>sQG;IHJcMTjKfz~+4Gh@n7sO4S# zp)aj^{z(UBy$8oDzsY7N=5~7L{B}?!3BBs?*z~-Bsl1Xzt{twDw|Z;0CiRXnI@LL3 z)J|e#3m%>w{8fT4%tBaB?vX2V&*!Y2-jQ_V@}cv(s}b6J}1Jks*DS6x7sB$#oe}k zF@Xi|6kL&w@&mo2fUlR$&RfTYP`X1rJEhAh67+vQ+5WZ7U3I*X@{iJmB_`ZT#;0C2o-^ei`&l_EH%f%br@cGC? zrJTCGCF7jBb;!*;e2yhhcgxBiTK;@Y$+=}U4Bn(BC~ga1%oOtcYIp?JD)&X4xMc2YXFQ4G?79yx8qde$W99%s|c0+irD_J7BdCEc(AAm8?Yz( z!S{2iA*s_VcuaNHcYFW%fYd{riVw+8>E+5oR}&)$6K1BuP%{pxUag{DLYGJlJJb~3 z+&{=7Wj_Q(fh#G7BoJpZtb`0 z!EIx&=&VB`rthc*jy8$^YVR^#i`r5TfW0uB((r3>v2|TT>yF^Lf`NY zLhKAMjf<}gZG0kVra;YtIewejfbsAwrYL`mew=k;@q|O*NEz~XzPmj{gJ6z{?sr-{ zS&vQ9vB?!8I)x%4+@SSa$8x&e)>l=SjDzfxo#^1#83YHY=(|@nL)n-KCV(+X&WSNF zg*8u3zcH`=#h)rKy(Rdj<4-cb?Z4Sq{4>9Z{27x=W`R6x`T12wBOdW(?(awCKF zUX*V;*a;XWj626eyheJ@eV*(7RkKz^A+k_@EMC<7g$y?00Lt#r43m>i7b5(6)v3`Y z%L4C%An%60tI`zk^s))rLq70G&F*uqCl5E~=o0`B3`PB(pvT_}_xETvcz76{pb;xd z&mG^xkOKB-O3x~+AjTtb7E#>fZ}#PRRQh9QNr6-t3n!c2ExR&;gia=sn)5-6px#_A z6|N69rfGvOeeyKQH@27GHOw#9%#Z1~#=(2_E`;aQhJCXe^>#cZH|7K|k^+rVM%zrb zy8@}%z*bQ?ju^O}ZGK^#ZH0BA%M^%VINSep_m0alNJ8UcjpmxaZi{REeK|lxg(g5E zUb$3+3wy(zyiy>o$ZI=qRid3Z03j$Yq(Ayb$IjTqh+}3cUr5`NvqR;((qvBLg$8O` zR*k|f`e}_J(!OHp6|~63zeDJTNzrhU09+Xjs8i-K>KOzrvFi?LWbd707btv&Tt!3C z)U7Sp>BC6i531uC%g86Qz)23l3Yi(izQp*2qNH8#1oYs-vYoXpOKb437O7H(PSXKUS<5BT{ z?6SW99g=ePX3qMKMt}Ji$T~UN{-NBmH`2HIOB_W=nwZl@u@Hg zVMBmJpbg@wfS`6a?KE-;_o6t?$LVgBu@R8Kd3>S;l+u+UXb{1d9!9HAoF3o$&T)LU zQZ9wz_CQ-wuIPU0r{UX78hPj^>JuupAzqF7ceD06-r3U0W@yZ z-jVO=C@ql&lB5b&jM->hMi5!tg25F)6XzQg6qz-y!Y2k8!CXWaKn3X&LfIr}%>}Y= zG^7%9<%GF-_WFgM9cCI0&`F{i&uj@P8jC{4J!HT>=)?myL*3e`OYRHWBhk7t_zri- z2yoxDkOlQ0ZHP2P$_mc)gY>VWlSH_B!2Om2jfWE}9|V*OIgmVNC9s}bdTGZl^TFNl zaE-ag>6N?Ygp{M1XogDUR(#Gc^odyub@ zW)p5TH+aG}HP{0mQdm&L;0%8gvI_s(OlpXslyUmy?xW5=RqbEnZK|(SEe~9=8KR~W;L?q{v8xZu#>ik!T{Idh# z{jWpB(f*S-@b|>9f1_12s+xT&h0wi=)Qd9VtjJNwG|0nQq&56BP}<3~6-omLq|M05 zj6Rh@zD$b6$RLQU>yKVrZ`-QZV#hQ2!8Y!%`0r5BLx-CM;u54G?oalYnU7tk4xdA$ zT)aO{hjhQJhuW0cf*@mR*edmjU@Kn7fbm8t$KKSSM}_OxAvIgDeH9!?c#?tgH3Jld zeNI7#t*=qaK$%zEC8Ty7FI_Gt$j`-e1{_?61Yxons7=d3s|w=O`CT{Ua8sC?fJFAG zbE$+n7F#XA2U;DPSSs;;!Gv86DT zFa{MBAZDwSbIGK+1K48Fp=pH=8LVJnxN47>k!bZ5Hag)J$APDJ{Q{P&X{`7?fZn(Z zNp4C8b%!?WSL$j`nGz-wU)sy1xSS9*FiAAwh5_cQQByAySH+q%5bDOM4WrHf`0+K0 z)nAQR7KiS@NaU&ssVU(&stTz7Q-1(?2(~)9!(^Ui2i-%K0__Io)`#@-a<= z(^qs>WW2y@6-A9@itRzGp0uj94aJ<@rK_-U#Swe$*pkOZXGrxa4JUUz_xR{5!<=tG4?Vg49S)Gtp(%a)JrFIajXU7N9q6Vqr&&mAfvBm?$riY0^ecq1B7 z?3N}$^=2&n+&XB-=3;Fco#wsTOMt8jv{r=2)MGcq5@S?~P(Pc|$HZT~XX+u`(3h~3 zocF@X;E|4P(F;nx4v|T&eO%Xt{ep&G!?$7$5znUh*-f;!TJ?ukniB@HbEPRQq@5#L ziK?Oo@Pi(|Q#ClblyoL!E1jGVd}6a|Gua*7$r!T>#~wX$8zt`CwXACxgBcwLUpq{V z4VJ{(2(~4%U?}sC4ATV!D~(5_q=(5TsdpRz(GG5%;ZPruOqHPD*%fPk+{c%nrlGY{6*|FaJ|Aoj7dt?FwG^T3 z)e?OglJjMm53lOGEP34=uz5hKIu$02a|q7x-(QJrXWN{p{@Qg%$#%Lk{3y4`vd2I{ zBLVBdW^P~Y{{hu*2d|1{-*F^__D!`nh=AGokXgqkn!`8g%IK+=w};mb!&ed_$fgT~ zdEF5*aYxK+0jYtqqzk0e)bjJ*R{04-gqr-+tS+|5I-g#jD??F}ZZnRRMungssuhX< zMa(FAnDY+2M}hruI+wZcyo<9cr)X~L;!tZ1!xY}O>J*0M1q(Q`M{Esg(L4OUZ|6a5 z&8PzU=qdDM^QQP z&GVLM1|ErZp;n%tc^{_)>}?%nyC``Iu@w%93qrgN8jy8CX?QVS_ZmDqFi#%~0H9b2 zX6ZWqGT3vxTR!t=pTUJCGlPgOJ%F=7{NCqI(1^W7kFf0oh7UkgTL6 zKw8Q)x#Wmwv$4YKH`GlcMAqTU47jnw)Ol`P1hty|i`T<0Oi6u4SbHFy zvzPQlbWy?2n(4hWaawgZGs=4{LL#yB%DKC;Fr~}WLL@v2H}W|8N(A6{#Fph-o2a=K zoK-T5;$@HfMF-Rnl$vc-(mO~f2dFpNwO%`cbH>$#c z0OZ9Glhe@erxq*qSZk7VHkd1tdc$K0k5SrB&t?!va-MlMzd-zZde2r(v6!0mgv_#~ ztGkC51ni+XO)_r@^O7<#j}+Sjk#x3*v?5$eNYn;e9fsBd{~pTrh-NAmBOKEzCRQ|+ z!iQ`yN27TB4U@`UKm5>7xyW%QVy(4l5`$$W<-we)KSU-u2VLpI&9C zukKDr$)tU>ehKwAF#JH!$j%!*6two^3Q?i=&|+6Bnx>AAQ1Pf;{o^uA-pJ{i!a}d zfAZ_{_IFe9aMOM955d@nQy-*@P{R&vN4=%fw?itT+LSyuYq7ch%GK}$fvcI}s~#?^ zu&H&D9Sj;St3R{LNTx>B8#i!BPSXb+PD$Qo$F=x8``+zm*Z;M`8D;Ks?{}&plzy4I%+S$zB#`=#*6;glx^7l)m zpl$K#Cd(Z^#S+O9*_gJtDpF8Da3QE15P~4!sUct{xk-B3lKS0+WPB3rruwdQ;14@l ziH>?mf~J^huax@7b&rds@#-yJZy>h5a44wd>g_L6qij@r?1IPnO0(Vu!_6|_Fo9L? z1n5m(r9!-s!M$47`a)70OJAeG*2PR{NBnR`0(ShXrH`)3;YE7G9nmEK9G;vHKvvj= zq{s88rJojp0|M&2hO0{6JBCNiDn!>#%jvNV=h4p*9*Crmh0G`mJe|_?D1qU|YMiu{ zdISg7vz&FxG*0F~*XnJxkJi#RgW~9zXr*-wsKBXW8gioKR;`H|GjW@hM}*TSzfOrn;5#lxo!;J?Lzs)YlJFba2PG)(&nmv29x zpC3f}MoM77Fd;sI4$|@$r2R^U6_|8!7RJ*_Dp|LZ1m*WH)YtjCPnhLONYv!7K*}$Y zui#0-p~W5~BgXZ^5&$XLtuC(%?&hiUmDl&Fspv0vyY*x$JB}cfb|hi-Y^ve6Ejc>| zDEgiV1Hn%vsL44N=<$Xkf~pB!dpG*?y9{-hB>T9EJS6$1KNEs7g3Mr(_-r+%pqUCt z?LL$=CC0)Wn1#@hUPkdM>j#XHgPf(>O*Sgmk#3ItZ&M|E8gN3?e zp+cND55Z!LHAEN=9Mk99O5lyn%w{w(x?eQt(EVCx4O)ksLtKt)f?i3;T4F>Np)fJ2 z2T9&*8c`ag5sT+m9v^F%J&Dv$-!roOew9>6Uv+r6cNWr(#2H#D?oL?e-FXd7yV{g8 zP=^^zwUDm7Oi381cykFqobJ2X~kJ-@)H=&20CysQ-T zGc(yljrvwq+22S@8M3KASdt#@bTU9S8cbbQaq2vI$f|7#6pW%x1*dL?UJZH9U?*%Y z=obfrYaj=i(@9y|46sO--gn0(bTm^=^#(16RW>UQ5)1b4>P_YCMONZDNGSu{FqqC( z!VX@gHM2!~Dsp^=tVf{OQw zo^Hg}#;g|l+|dGm);>vECp2Voy9OGRewkMg` zZ5Dvyus};Oj10!=!>owR1+BzndqxM{q@ic~c3EVkP0<;SS=E09*JROx*@vr@zdz>I zZ;QifaKvu|gLR!0luqyIrwOE~oATbEN{y#i>q);pn2CO|tN6@DGyV3#gDY9b$-`py zechZsWt2-~11WGaSwtUBld4o+&rW+yQb+H;7e}?I+;c|zl`FAezI%PPb-mw#h>o@? zi^4)rgV?D=*S)+%mW@|2%>o_(#X*dyJ9~R;rc@(8x!?ryi%RoH7h>D;2`#|qa^hQ~ zQoSVHr2L9fIi*r%d?w&~K;65$9cXP9Z?1~3>FXAi(bP5bI|+0StbA8J){|wikq=7` zeVQvoECMgVRp-s=c0DdX4=17k5F*j%EbNrS$favA(a?shO{8P0p`Snsv!YN*-|msj zuwq|O6v7YB2}f9Ir(lWYHBv4;4{Qtq&lq@DxB8*RUj5tGkfXZ*?e^UA#xbtrDLhyD4<5paERQU=PX~Cff~B0p zO@b+Rt)bHfv9ahgt}xMOx0Ffy@IbBtm8FS0lCuE2wns!Zh_P&(aNogvz0UaDLUZPV zfax00uU&SYGRedbIVOkQ-EyZ(hLrWc7WS6%li5eeVs#OCnh)^JjZvd&MX1jx*}EV{ zEDw&p-tS1d%^>~+Mj9o}NC|8z2`t$yj=xlcluKDB-pUNSrQucM9RlpPtWBLKRY$;v z7DI%m_G7DDfh!oCSBH$_WBxRpugVm*M0E-$ogGJ{d+LxHhn(-BlAiz@#MxI94ZOrp zoaGp6?8I(Qd=ZMAvKK3Cn36p%q5UnwTiBmJ03t!mIRQdN5<`o>aTHGjU6Wk}ZaWPh zqd~R@50Q`^*j^Bz1MK=O*wh0p`0d~|9+mv2b|1MyYBE=6o0Vxj7&R}+-yi9PoB(Hw z0xE;6$C%x5BA4Fhx7wa;+V@bxb^)tg(h@W13CDHO_}~Y0SZ&^1Hxa5EnX8f>cui>Q znnoLigXWURwed5!a%Z%mD|VS(+z-9q2D#L5wM~6x7%8U$g3&t=E)e%g2j)I0W)TSZ zCFZK(S7n{M7$-t`;xjxKb6rQLg$sm7@sg9s0)c(PmoB*f4PX9wnERjYXaBAg#_^b0wM09SktFhg{XOtVp``0qr0h z+kubk9TcEMhW>0lM%mi6@+$4(H&Wdge;-I6+@8Jx|3qxEuc^7v>+2!Gcc2o)$VRG= zxDV1}&1?6OGasdENn39QcA{Pt6d9cuM(e}MEr>#%j`FaV8rG$B`$2BdjYcNW1Kr2R z9Av-+$L2O0p|k`b>``|?cWP%iGuJ$A_by;Ufh8eq29yWrKcZ=7ZV%T&LadBh_1$)q z4VA6M%ZRc{Zm_7mknM`}yLtyT8{``Fu2XTqUqakQJo`)1OB5Vx%m_XA1kUpx7ysth z@xp73DUR7L3b!oVYg;8%?4G*!^pjxpBBIb$vh~tQmn%iN3;l492`a*3D2fTOl%5@F1NC# z_O;4is*Mh+d3bTmLl;)YD=5!8l*j;Qlt>*r!+s#Ty;=-Jj>S;KhD~i*tQ8qaw6jt+ zqw|fse#QVcXA-Xm3E#NVlY^Hw71?PaHhZ50vZf@P43)q|%!?W|(+s|8=WI)xz~%74 z^D;A5l{=c$1<%uhml|@Ir13b)*^Ocz3>ob2$hcm@ehE2cGn!=w0#6sd=$t7b_Ghi> z2#ICK7G{-a`#(4`G!}5pYV$;d8Y!|kLc}g_nTS-(tf6TKkoE-URl>D%q~GI8wAdqr4fZgE6X)mkiYN~f0`PWg!$_aR28N!5dVjs$ zuxg7)eUye_6qF!=0ZWK+|13(s;Ga5*2?+mPXuFYA>s6IFJx5k0<-IU%)y7uRdDL{g zUG$CjraMEqUCvRWjv&m&z0;C6)^=U{xslLKjaj0N9?&{hpr$FAsLmuY_7K)`*do_j zxw|VJ7Ym|GPEy}bE$Pu4k7(W8cfM-TBlnr=C@YH&XxvG0|RXB{f47uQ2E${_D9HH3vZHDCVS2ZnIV36A(7>H@tmmVv!9FIP z9KUu1wp^*k+CqdmcD!0Ly`a1wZ7#*AGqxT6M%5n2xR+r#r4a~M!qJwx1l)<1Ao;)& ztQGtyrhXB9fh?{$kHZ>ZmWuDDDI3JPdVu(a6=lC7j~o3SaZ!!EVRaW{FDvba6@0R~ zc4S5PLHYevq}#ST{uK|sUorWWZDh-F-|GtGw>Y=D>J(e(sY~f)UNq~3Y0VNsb^QRh~BSMU=T7etYJ*DINhIfscic{Q)`jmytWo_|E3Xr+wuD^#9JV z|2!5T_>YLq+UWl_-1}$F{?B^kKmL*byR(tKquJ+dqQ4ThRgCl>oT5P86WKRm)~uh> zp!Coi${?(MIW1%@(aik`aS~Eo8PM?Cx&2Crg&gUrtQ|JSDQj=`pmZW@qI06*Ig<}2 zRgqkFe%>__%c=4f-zApL(BX7Aj3lNfXm)BLaS+9GQ)*Wc$AIYHfC%ynk#=lM9)4KQ zl~rrH_f(tI5St36F3{@^&!=+SvgU}krt77c@vp=VfXmEDK{V4&#Rm+g9w^xf^1|>p zx8zIkZR5jNOUVhW97|NmIjxFLEL?z3$?W~9MppNab{YO$SJ}_{_OIIZ|Nrddk988# zchonr*SGrr-aBWiSZHDm0lb5?%>vcd&^`IJB4*nfJC;fGhQuTG(09@`^pOO`$oeM< zsN?ud6Bj5_)-%fENz9O&-{9ZRn$Vjk_q++cUZP*{t+rAD0?Pzew_K)^si_WbQ&!7A zUQer|zhv~|<%Jkl0p47-X_kK36Na(sNm_664f3&sK^zd+5^2Xs%IF-d$^FdpEhKx$ zG1X%a>+~&+`^xHPpKz9Le~D2dGy|$Dq4euoGfp#fmqaDs73&h+b?K)E(9T`|uQ9Z0 zNUlWZ&h;GaCPp`tnxg~zKn0mu#c+SK3v3&qpD7)2ZA?yvVtfT4&XKK!VK&LHX6_*6kq9CRSUMZVxvF>FV~LzH06>-eb5_?C;xwR;qW4D%;nlET`;= zVLyGTN9GsV2kz=lXX0q2p&Q0YFqAfH>!U=Cdz`!mGN==v-r0RGg!GC{89T(c3=;@T zSN1J$j+m?>TGd7MWYe;$Rgw>JY(}$aZwd&{jn8%)&H?*f&Lz~U_BSVx9zr|oC`VfY zuM%dZ`&9{5Er5^Ri3r69XzNge4NWBe`N-t9Y+AaDL+2{V!TSuW()5y-UuCi=QJqxO z`^V8vX?N%2vn|>xEy_DvtaJq&699-xSJ3Po^w5>>6vT4~X}b3~ZE)?-&;a#9+Zpm- zuN{01a5VbPD zJ1qKco`=6UN!?T0aaaXH*jBxgjz68|@VbAZ?2$^K5)Zy}Bx57ZMwa&TInRBu@!JMkke85F5 zRb}n=Y(Y<}89yyW*OB2}tZXFq)4ySeZza#Wu{VZjB|>A-JpM;o>F*y6qHHm5uP)F+ zGnB#cTCCn-eF#q& %zX@S~gFK32J)r);X1u|;gN|7`0^a+&WiP#!HlGg1OyK;P{ z*Ua0GE1D5P@s{m8OE|9yMjl(Lp|l;t7)Py7$lVVI zNDMJdbYw7^EBFF5*$Au_M?V=_fERonEJGwz7#=>I;~&1I#3b3SXOn zS~+qcfUy;P2w)h$py<~GLy}4B9B#DSI5i%eg89cQh*IsX4M!}_ZQfsGmSS`kcWTed z$$ALQ+D>JXPnZJzQg;4j0X6FTQwnDkQL1Ef{o7DilIy3AbRo@RFsw%Mb33s>DtWVc9-z`7Mu>|Yo-IyIdS3ErJkwF$|=L|;`^?*7pyIj$p9ds%sA89 zm?CSu9Ge_g)Ya<8*m?ucC^&0;u7b^~$B;9xyv_kzUcGeB{?fM;R~~t?DNvo$%7lt& z$vPgIk<}K*s|nA@3>gbZ13ZEQc|hr+Grwna3$_8OL6A6X-id0`m%XoWZ;H%-3r<~zyG8rmsf{YstCOfyu~0--Mfa8w z(?Uwp{9>~J6$0^9s&bx!U*p06xCzWGw#iw1u_ncGc0%MDoZb5ve9dg8lrhuW+~g%a zLngbvJ%Cs}IARW-ed*C_^RP2>g7@S79o)yl6;qH_1yC`7(7QqAeq|KVr)uvZ3x@%E z3Ux8o2iy9g0k&hQUx~Ivn!bf4A5!C!fHUTf6Q?yt2Z`y^ypz;H znFxNdCQ*Ts)*MhLe*pGZj}Zz0=tWCHJZR)H##&zJ{L$}K*kcbMFP@(RofSGw+UYx@ zQ9Z8t+&44!?BS+B$v}IZyVS!c2&g;o+?Y=jJPKHn)8Rc0tO@7a4 zRb{r)u|Ws;v!^pp#8tAlBC#Dq_vXSO60FU#4>ne)1H2w`q^!Y`tQw%(t8b2KP({htt!v8_{Vh<+oF?Rjn}Z892QxOH97kFcy|2E+oS|2V|I6 zL{lOO4VaxlXt9CGg=NayAr&i)8-6;D!LZ9UlIC=NN)ZM$ctZQHhO+qP|6Uq5^A z^TydveD68?{ZW4^D(;G^xH7NIl`GfEb(CBwgpq2OrG|2t8_*<}^5_H~XJ`4=XZ}v* zLNw{EWep7g7wHS}r+1+xzQ(q_J+YP3x!%7WoNp=5Pj>maUc|ErHpC)1bQ*2}m6BJH z#5p!R*5d9Yy8He--GdEcJOkIAj_~8+w&ncsG(|(c;v#Cf$D1?r0)#6{>*Wtu>;Ymy z9Js>Q2l!;GEf)g>^)uer1c8y)J|OjFg;=P$6U0ExY8lb!2jX|+Fvijkhuq0KVtMUumf_qp&d`N8)pmwYxT!dy0 zoDLe_j&5gXB<2LGC7L3UqdU}CqX+3tHpB+_xI8UZv!DJvn=)zMpoa0|%*b$v;?g4W z>tCW7xlq87r8R>P1$jEOmB#HsAK3H=sAzwMe`1DwvzIlBuZfhcR=oK>dOq zlL0^Rv=Uu7L+34oNI!WGF(q9u^N@8wHz|ZK$6jK!Sfuw|pwKZ%MD@lo>hU$-)QJd-+j5N5tcR|K64SeS-JDBW{0nC5qOc>}&@CLqogIU5I}nZpx;L$e(Cx z%$F1c&d}BE-gVeb*YzH^m6oPI?5A6}4mZ`Pr`(_79kbD*bM3}qy%}dS zHW^iC)1}0-uzjd&k1I%PrW~n%#q=LXMe{4YmW;980 zwS*rq*Q$Jzxc{>god(2A9+eZpu#$s*S7-ENFpnl&UXaCsz5z7zhVtnikq%pYS})(Q zW^nC0a!oZ~Om_`Z>fJm5DalJzbJ)KiD-V=ppJ_sR^jySS`B=#1!g~;BIJ}{JxUedEH|UjLz6^blyf&}gyHYwoeHZn+n$K&H)ATU z$)QYTS3GcfMx#$#)*xF_(d2fm-+l<8eFhzqs6FM z`4zLoBx6bJg{=|^=Adi0L~MbdE?40qy0*{O0@P=PQ6a^Nr6@|+BUfH8w+U5eYRt$@Xs)ehNN!TN@{K3_G-!@-<*8+4< zn)q;B4=x6!32f`WbVw2f`O8fUDmkJ2c@TGL-c?Xh=#tCK6-;&>*+rEE`VMAe#Nik) z?V(*`6|_Oa!(V-lvB@^{gEfR%1i->TmQiwaPoTdK3A0fkKuD%n6y>*cYt5UZ=_^VqLg#>N~7KhI63O7K($@4nXY7# zP^03c+5m$o&|5huvC~Dp5ihsux2F%cC(uffD8i9Q>4xkJ1sbH<7xA{z^U6)4Ex8{>r=%}~@9p3GDa}cP$F86Tv z0>y1%iU9Iq(*^eOIR@glnh=j30ulVD#C@Qh6Pcd(}cd)W+<8u@1Nv4FYOE zt3lZR5lQ*qS55wrv;O|yeEwOYpMDS4cCLScEdR`6eJb+S*dhq;Y_=Z83lcqu?9jQJ zf|N4b_u`tFn=E;bP#CEYHc%{iv3I~Ti^kQY7G{OwcRZ5y@7d*G3i!{15rU(uO&~3V zjv-+5+#92(qvK;Y>}kLFP2nt)8ENKZd_SKE zu}jGK^!E&qS>sR0%4=4C9*~pq0r!}Z9ph8T_>7x?+pzcEraxCYRY79(4plrViZs){ zi!MKa(apVP0!Qi{oZ`-&%i`}fXz0(E!tp6q6r-f&ojeJuX(Dyz)5BH3ylD8$qnFcP zb(YI>&+aHP3+?JO*1QDklX)(=<(s&Avm7^`R79{X`Dkb+tf6zM-oueNbY{|<*O#md ze=4$RRjaXXM4iV2SWb8isFvrlI>Aue$^cDfahtI4l1=Dxw$M6!va_Uyk7N z0v1NcqkjTh8|Bo)TgTiuIyzaiNzGQSOvhlcXImd#quzAqOBCj!UJ4-EcDC;fPKGC5 z%N=W5azNJYH8+*`nPJ%>b;CwDJwS(k2z64R zCN>zR3<#DoDNASz2Q_dw=oHyt7@JP0$Lc@mt&%=)I?2Yvc;b+?gt2qnebaU-ii}Ju z{lOu-ON08pO@&E+t8i-@e~NxZ2G>)Dvo5mqrS9yw15XcB`ga_8!IH!Bo9T0Uyn*Mk zbKl2%5Dx8ia{O8Sbzz?|Jmr=x+C7C5-eSkpVvZ)S-G^3{Tdn&G#lurUM}5{G2>KvV zgK)36IibHZ1(v2dRKU&USt~-I(d$N zNNljtNb;vTO{bG3Xmo@S0}(R_^@Z(4j2W_{f(?vaYzn`LvJhj0AWDNzGiFQtLL|=S zAH_i2D(Y^4I&gDMxMVwPM)4lvHq4R8jO*A7cwG6_(xG?T@0nX#MK=xG@iP~;hY2~A zP!EXgQ5urUn!X9$KY+|L^waNc7Y9Y4#i#SB^}mqrGS#EM%w#@zxspt0On<;w z!qIYV3pPWDpsWP@S4$@AYie}n$&k%B9I_~qA;YMw+H9b*uYTUeaq!@~II_G0pm-f8 z&JpjZc(*PaQcw~p5G8B{N$d}6FD)Y%Z7(`r&nGJvUrGlk`K`WtgF`SJ4&VVKFzyZD z?j;vhp%Gu6M&7)5enGyuKoRe`EW)GOLTiu~M;2z9wjt$+OJdvz{UY4@g-^|JF7{=| zqklJtkPdr02f93N+ew9!?2Q8|<;S!a$6)LZLV}b82hA3g&!S~6z!+Ibz0fsK;IImb zOGtWF{HSVFSgQeYu2CX-xiGJ2Khg~Qm6sYNm63RC60`2qP%TZVj*-_wV<?o&e`Ri1VL zH84>l(f2o_HCS;wmTb4+N7pElCmuRE!9dGWMK|h~lZa!d1cdh?B*M#LjYx%MwMS+X z$0V3)aBgI`0Fg13;W&!f)=OlX&1z{#c?1<=AhQnySF!EPckMXLN|2vpff2?_r_a_n z;>$pC{nb7L6Pm5i;S3@~TjP_QRPF`WenzQ3vcMnMD!As|lii39Qxy@%By)|7#AYf7 z%74Ch_cU{*S0Go83QzEG2^d{Nwx|@2QC|Z$qjje3NSPhHZ}VhdB!S@u7UTYs~Y;v95!h;-5aR!sj` zsb%?r(51W{bw#%xV+(RI^7sXR_z?=9xfFL2H^3~%<%bruG`^)uD{V&A8fiX9Jd>wV zH#rkup9E&cmi@L^Kl)>|o@$qq(yC0PTt2{9DvP#YmEZHWi|vmS%3EcW(;Etk4yNJ^ zrwFF*7D-RP_evQiQJ(aSdf#h(!a!KW}kJ#EvD{@z^7ajxLpTE_Ey zHyg2!`N8<8^!CNg`8FRvOIMrG`8nSedeewG)U-@KAu(jf2|4?8pziCJy(r#>`okQv zev&jBlcKhYKcno%DeK3jclwqU2J$A(Ut26!&s5{v0>EOq`4w*_LQ{fMOU6XT5%a_` zR_G#lPQxcbTBfHU%Pm+dTu@}|%J4@q>hWq6szN0Sv4vpGwYYY15LshSJEMXcfmj-& zy!bGfBe;`sOL+{_*h^zJ23Pg#G1${x;-co|<$X5xQHLS@%~`i^`2<(1MUo5E&HCTO zbvTo3ox(-8O@nufMQBjf;*6xFitF(tNFg4xbzdej51)}P&#l45_OD04w3>PXr`pd} z8t!MF)je`@ap#6|pWN~T8uSLMEh(P??Y?*ua*$2-(0S>)^WWX{WPVQyY6xre6({NV z;!}k)O@`1C3sF?L;aEW2o=Ccq2rqYn)-*HVmuPPE9_Jy7!u|8FQ?f|P-;p)h}A!2tD?|W znNQr6QGCu@GN<3s-*%6jY7WIXk5r?SA@>9sjc>Mc80MQe`=J94dc{tlD@JiGJI{74 ziB0Vd@d@V&YuDsw;IfaEW zuDk{uk7u<5dY+7GOcHy7)wP8BQcWM$x%@IWC0zFCvw7iFEZ|}2vc&^ypuRPr6M%Wv zsO?2n7vF&#%jQ(o7nM1pmH6;Ix8I}0X1aV0V_BHQLNT^odnw$P41RIqrS-@0VSJ8) zDi(kvQYsmfn-ub}>SB8iMKCs4gvNf*hiN$+M(eY^-6nayWOdrXUJbbE-GlG#rpM^5 zz;Igf{DSIRm5#tYIKrrP5-zNxc|Eyv{n|1@!fO61wLXtHA^nJ`Ib@Fc)bKt1 z>=f%Md2v+&4R7L(^UdAl4Tg|F*KU|Y`(<$e76sHoHwe$@B_OA9ULx;%#p5oPOySR+lIv62uTeiBn)-L?hVMrNb0X%SX?G#wo z6r&jF((M%)x!t^53c)N+84t`!cDn7u4{IcRs713oYQH02+_INcUaFIh!48Y6nh_@o z50*2Cac?2J6ViSJS@hw^R|}wwp5?sP1mW((7D&c zfH%}K!JfDxdwwK9kw{Ulx_%-}-BwgoyJB1xCBAev64QmnMLp>>&C5L z+zj2r2~Q;3IStuZJwReF?9#JsAW~OZ5)3sXAS?53uJ{{I0DDslEsm}`UeTvu*-j%D zf=moHF~}Z`wLjTrc~Me4{k)5i9C`~;W?K*&vt#_qv;c8G^3~*)5ymtjDKdZ0;6_}1 z^2;0_e{7vg_x1dW6R_jgHPR8#d|Gi;_$y)uw@0J#&vU+bKGJ)YouTI3hb#v`N6B3L zZK|Y2_Al%rW!D_oJI-$ub7(*{4ryDK?`ySq($0-P@*KXJalvR+5uH&CylYRjjsYp! zgJYxMUM7-OwenArl5CoK;{j2rukt-2AqQ$`vd~Ga^YC4Sr$-fuy8A1@FR>@b!t8 zq*Mb=tH~O^rQd<66^2=&ON5dZ^ z2>vJZB%XHQ>ibE+O!>^@|97H_%zu3RKXDY`-*YXAvX!ZesI{HtKXUNDMszV_3ZGc< zz(-7lv{M576N?gpQY;A!_H0P75;Tfm(NA^oZC7zJy}~h>RSOD9T}gWV&y_+Cq>S!r zVYyNf*@J~A;3$;d5;xJ8#MEdu&eoLCA&tHsojRpfKa>N`o z@gYp7$6+F=SCVE3RW>BhaY_~=;@K4AJCjmUihBv*iCsRoB+E8fGQx1h9jw7cWphOd zitO@41S49#{?tJ@bZ*M-_8-t}b)(_YWyNALF?l-d{q&o4p+!b>S>ZvdXnu}|kr5GJ zp0++LP_kab0L(nuW!ZJhHXYb+pNSFb4RwVZDxOMgEW}kY^_Z}4f46ixcGOv3YfU*!Lb?J4NZ%~VDsOZTzXI@FAc^mN{PYU ztuKb(Ap+H;=Y)OGF8w*(T?`9P3TqB%`6$r_tO#Y&=`khT-sznO=5J-EprW#1Oh+Bp z$LZY%%goGPsr&$A^>_sXQh3o^0h`7a0iA@e?2)XahLK-soncjFq)bP&Y zMT3E+qV_!d&ZdNzS%A8TUAKLuOD>hcKfL|@t(-XIu~8=aBnv-g_G)OGb8(Z{iCXIZ zx5VgL`#;J0pQp4=<%d187{a@#1}_ag1mGJK5#APX2;_?4 zTNi;3+&74?;UWZGkqq$z*U5L~)h%|YoClD*!>s7zMZsw>0ZKBQm#_*=yWY9ck=CNs zjPT^)F-j6Oyfe&eZ;sx)Efeo9&%D1BZI~DRqrN%pMB~w&=&^)7FgO0G0+eqj>l7J& zE|_rHBJa3868HrHER>jM*QT4{>l`$HI4e9-_(gy-F?%u4=ZJ%6b;b{;YDMN5?Kb8G zBa8Zg;3^lK4;5lk{4S{|oKSwv)QN^uPf;das93|&3^Ez>&eBJ?H}m`MJW@n$+JXh{(AAS9?k8_f7RhtqBBO-%Sp9IIkK&upeH8rxb@4K1}+kcIPu^OUOHC6MHZf*c>9=f_u1smZS{d7n> zr}LhVwc?-=V$H%TFD-K26CrMI$OK6PF5m3(jFEL8MzLjBBzA(ySVO^^-`h<_V2%8? zE*7o6zihThY}%S%Lm^XaB)_yER(?XCebzlmvZxE`%vqtk zn(J}8t%L{=_rT8BR8-jL2NlQWo{H&?4a3S`LSjS7w;cV2zR=l!Y`KFW$+q63j$LD8 z0XROw!HbUj=<6et)5%BzqSb+F0e_B^fFT^ZHFbf@SY|?khnJqPO_jx!Kk1O*YTvJw zz=w?vXG-2vp}ES& z48M*QaVj%kEXaw(-7|)`-{KNW^TXh1b7!*O#@A)gKUltMRX&nncfBOnU^v;d-^6iJ z{%F#?SxBuEKfrNx{}LsPLs_0qaf{mFM`2hd(hIZHOSJ8m6H-axL>?dM5h}f87_V>) zO;Z(kyU;(Y6W$WJtG4Zuicdg(cu2CAzHjm6rLbw*?$?_OB*XOAbVN}uaY`c+I3g<& z+vAC-drpqzd_V2Qh7L1;sAS zj}7Ym#Z8#Qg4IHMKH)D%__jnk z$B1n-)J0Y7L(+qU=+m#jd_c8VGtaE35hJmykJOBw3HZ_^Of_LD^Pq-H>Bgi0M_Uz3 z!gvZ(d=vQL_CD;ZZmKU7|LWevO^r<~K3{*& zpk->X9*PUDAKvpjIwR=VC;;1E1V{v4zkR+2Ec$K-0KRq0@e_Q5zSY-VVXDp*S0!T^ zt1cU>pKhxzGmoh=AE~c)G!-*pwO@s%IbE9twW=etJFMr;;{w`MT?_QmW{hw6y8T#dJq(uV}@voYL9Hrj;g zqrw+u7o7oEv)AhIio&-Fs%%}@P2DSNnAba|)<`4wACLaw33HFq;P3ID&l>Qi z>iw9$+W6`LxdFH7{)mtJQL^ZzI{**j0?t2sne!#7y_oN#V5ja2#AP$m4%}Un;GC}p zYjB|~^ifcORO>c1a)-%rj=2I>rwnvq87Qg{UGgP_@fesv{bI9?z*0he zX|*aebY3H*Rr7+zm1-Z95#kr8y1M#{Ax2t9GO>GKNU*LYW3Z5AsuP#b>tuUNS%8ws^_F?tX+g7%%)}P9cm?7t zmN%1W;F+9_@MH=qLh)uj?;ywFVDB#3tm)w}yH>v$4dGIf63?JW8m$=j+T2a=;ZGty99&ZqXMez%Y)u0Ss+C?< zJ2w{-)=q|WFtUoI2zT4A9il}OnyCw)Y5uf|WYf;TaO2xJBN7zg0O+(N$5Ph1ov$mx zlU1xjWaMa!tbiZ(jWZ>AwRA{BdS3p|*_6xdI$>i|b0r-L$>tg>WTMZ#No;DeH&PC- z!r&1(1v|grpxy0tixY~&D7tD?uei$}KRvdxdMOq*;UW}X`MZjcdr7g4b0s84;mV)e zx20(&(qv_ia=LBm@T_tRRN(Dm9S9~jXqkOoU%NVKu&CQ}A;Ajir8{R&6YH@##+~m++vrE zH|2|%b9LBEs;43$n&QxX2vaU?g|L9k6|F?*@r0U&HDsD_rqL^aC9($WX_^!`)2K5D znpJ~A-0nj)mYq^U>!`HQ2=*Zu$v@;S0uKWbeaHhlgau!rIN8nY2P0KXiMztG-fK}M zd!N{)ezsUJBN78uGkrAI9|SkCozUTh2bhr(d;jbrp8_BjGDRbJ}T%e7mM5M^Z>dm;@4-**Nv zker<$yQ2o%ef&vghZ{=Ban9LDiqO{Yf2)jN*t0DY$wW+4m89e}&`#qU1thp5m^2x8 zhWnW^Xus7Y@1mxT!4hZkBsx=Zw1A_oay+mSn7m$bCxOFq-+&cT{WhUjQE(5>oh-DV~!0XIC8Iq3cKiBi#Tg`ri@f6d0_b58{7ggnz0jq?l1 zjf4*GZyrviR>Y5epYRq9O+KfhHI{j!545Mx-!rgfA%Y^ThJCS;)8;*R0HNs8D~~`a-GGQW z$r;z!abvLdj6BI|z0=mxbUg?_RC-gxYs)m7wmV@gU&^$_Q(D6k3uCHk+0luHqI{Ht z5qCW!-JmovCNwr{3+sx`G)7v_oWLYa^rqTCXbkWkP?5cA7IT5JVg8`Ji0wgjB^6V; zVU+kd8+X?lojhI98+9#jL}kzeTOpf15)~EGS1{G99%98t`72%8#$N~mF>1_yDUvo= zK8hkoo4_a`L9lW~vYH(t{|<)ooHy&Zv@FN+oxj%iFjW_SCGj*2ahp zJes|Sg{=YN+7)X(()9?9<3`koDfAAZ7q8F7R|2p2vt#!wLP7pe`t65HocAyEn>j8~ zv%3BG+i)IIl2^8jm(aQ5wu!UrA>VS3xYN{5eiHXAVVFuy%6fTuBM)%S3?4wQMnE1G zvGIgBZwd^HMr;{hB2bp~J`8G$h|?au;vB`vH6NrFUTz))$^Y<3SkSYxDQb(E)p~W_ zyM#yn(A!3)wgGSGD%kqvuRD1eGX9|pQogAwukmH>(#p7qptEFBQl|$Cj=VyyX9-1z zl%1Vvqo?r&_zJUUgd>@FZQ{$X-N&3D}Ek7ppo1Vbk{C=Y^{%81hC81H}%kZ<_YT z(=6v|M}+8*okm2rMSe#yw+(`L0n{@vrCh4lZkpEa*dO*EBppx41&xFoIJcNh%5^|+ zFz=BOdO`LaB2uk~pFP6m7X}!!PYp5J;dHt|sD_G)Xa5-wj;gRr>x!X!SDWXg-qLK@ zh3UI7f3zHEy_mW5LhS4zcMNi?X(|ePxB>$OFERJg^wFHiDXKrmu_`I!53poeI6Iis zYB|QyNGAv$kbi<;0#7#%ZT%(k$VA<*D(6?RE$T5QUp7xVQ26mHXZhG7Pre3`{CrkQ z8Jqn)9!Qvj;)Qi$GyZ{35-QtT`tfiT%Jk{u^-VUW;a<_i6>xG)Ugasqi@tJrz^#7$dc*d9dsh*o@MY0>L^n0c}NWx)N? z^Y|Tfe~Egu5}%1$x3A@@*`Nha!x8yd?Nh%VYXz~Jay+(8cK_5h+HvOr_eYxH-6O?Q z90O1Wd7_6Iz9!hi7cX!M-+R|L7$#tEQfELkYC+v?PfX47G`mEmX}ZIn zzHIG^!ef0vR@Zgv#$`Ntgo3j-KzVyWW2!RUu}T!=+YN%PN)??4h_@gkNGOK#S**x$ zH3;u1iQfS$n3{}Ap;`70fI1mlWP$_DFSLmJn5R3#ch@MbNuAWXqGoZ=p1y9a4Rrk{ zx^+GG+Vh3Qd6GGEblbNFw9b~AOHc62H}ywN*iBw_7i+%OnCK^MmkfOwXb)!6!_*(G z<0adu-35Io^uI0=3T%Fo6&8F^!c;=i)m{^!an7q2#_3oea{GEaZT{BEd;yG2rg0N< z-2hCp3xyhnO!1F~xS{CkuepF5DEv0CgVmo7wOtDF#Sv7<&fV`*C+FY~lI0|=06TbO zPwIEo60ZU9NTd(I3!rRfBj^8So|?e<`+k_E zly>Lb-CQ^gH)@4s`lNbY^rJB9MnQMm7%Z}Gg1P*?52*hv|9;5u+tQZlFt#m%LX%pU zyK?b>mPU%PxxzwNyNXhogmKJ4Lb2HqX9-c|O98AZ5>>3myzdg!15a~5gs$_Rl^ z5@6cIII&}tl;t}vG|$8)xDj(=4^NMU`7e>=hb6`dqlxyIns|G>Ya8>0SUef^LpLFj zmb>&*@f!BjeND~Zg%Zm=JucLv@9lU}lN&T5-n{;rMw7WBQ%3zF@zf3))y4#AC;Hl! zIRk+>Q$=uT{YJbwvHboexp(u#wqx5EWw2|$F@o^r?3eQhgkk#j{E?$+9>Uwm*#R4f z?g`wYuaP{6A)bCD4AM=^y}Iq?xz;HA~35om|FD;aYP_FFJm&mua>hjFX$ z>ouBfC7$~*hYw#eXpIKHm7)WZvrWVAw@%TRiAkXF19P^RlM@8D)r~)eQRh5%FK;wx zF5Hwef9`Dnq5oCjc6EvgEF%(;*beg;(o}PjpUW%uU(-!-J_x7%PtZK*-^M$CkE;J1 zG?xZCm{=Q1SsUm%m|9!?|3_DulBVpZqT9PaorPww$ydavkZd_Rpol=PN-c_bU>>0$ zgMWb@cWmF8Oihd5WrZ+uVDjUkPsb3(gbZx9)-WjiSt@73g~tKY%gw{W#g}w_zR)X% zXnA2hVTAr2BdJY^Seh7lsjZ~&BZ{JolSDlz`aRVJrl(Vo9(|c+5ub#nCR%_dT1dPi zV0;L-C$^knc=f^W1Y@LoBi=8SrO8^tIInn2(pa^TBo8BbI^N)^29VWz$>kFt2i`TA zT!Rx;5zFS+($8)=-3tnEPis-Jsi0)_Ub)6d#;t1Db>VZCQm`Unv*Y$iz-A+tDQW*P ztI)I1r<$Hj307R#xwwTK#?!3D~!T6GEngvFYs0KxaC&S4bx zOrlKiQ&fuqXrpH<(srYf`mNtYptJLrHm#z-Dl@y*Q|vL(m-L^w2#iFsoh=_`msD>j z>rcTLG1<7n4)_QQpIG)?l|`#H@Pr^RhZB41n4c=8DM%k#sEg!Ss19ypQXi8Q>=OV4^ld|)ecbGAzh1}y2sYrCajq1=`HAN%kgo1m+J#@LQ9luQ)uAIuUAlQU?^XfVt8% zBh!;7$XcN}NU;iw%SJQms5edH6wlS%!70>BfLMs{3ACzemoWKTRtM~$FN&HL=h%0# z;A3&cV|8#I1-SAkm|VKzSjr;o2Pmxq4fn|(9GtoxV5%}3g+CR7T)tlE#irENUbv~+yDJwpHbu^3Dol!W&w_ROMn)@^~KH(GSl>JQ&y z`wjNkhBo{}Ep*3UquhY<8yq_;jky}3gZB}14IOTW1O_GaMnZaxT9J$00#f@)8IC%% zTbFHagJFn~Vzu>?)zsZ+t4W}l^uFZ+3+;f?%U+tt+?`>&ZD5=(vf~rT=He3LK2(+K zNYyL2pm%*Ev6D#qo~Bc~3F}+a6|JD*5Gx6xdM!@Ve6eb710@xk`E#(9@}g#U&Fqsn z=9M`b^BFg0lue7lX_BKgw`%w1i0?UjxCEwU`%N1C4#Vsl$ti|tB9F+Iz!L*T{^fjv13yGFdFIDMlu8b7#T!il<+#A5LZ zIRO-}zs0k~1MLDKAR|Zuid_pY#729S*f$yV9RH?*`tV?;edUL4_T_X`InEoa9z=WNfCd zYUG{;@*U$uO?Nw&3tF$K=PrtvOAgs1O&#*0yQYJ8*l3{4FBP?+S$JwLttD-*1Cv zjwfD_2A-hrg&@Ogb3-!l!I>QIk6i=;kw-u;J(Tw{x@+K}HF9YPqL<%2bF&>Xf7S_N zv(Vyu)P*oZ?+KJXpu-=kj97paFh$mX`0cvZPj!jUB``v-6#`6wUdQ;GX}se)Jgar3 zL;4=c;V(TQEGDdV!#>BpBsHr1 zK)xUhcMg2D2ZmghqQzSqmbQrA?gmCTo6CS{TvwTi{^_DYyyuw>Von@xyU)J2K#~QA zgzGoQKsk{l1UVJscQQMr9_96lC?93BpDFF4amfPP*oWKh>a9Mo#lj5fah*TUTq2vh z3OUE=gC`h=y!1#a!$N388YM`js#t@S`-kk4^aX-M5#>pz{~)y$=p~EOb}DK;!a~C( zDB06PI<|CMLh=)qt0Gm{K$zi(B78vpl}nt>)bA!gY3-&^|5F|OzpJkP*I?#fx#Ms2 zi_Z%9ugu|P#dcxg3Z3VtMv*-i36>3xnD>(uCB#304Qf6dKfY2TKEEXi*mWiL2%36T z^R^9{7BxAA`6+@{d}ePQ?<-gY@K|)8;Cx8E;dw}{dFVj*{($`n60vjGBLz^k6{D-M z9o>SZTnpRzF*-oGw{zI}ho_O;G6d0sl$M$4x;-{N`%&Y3Ls&lYrCRG;tP-iK_$Ntb7@}hSUph! zrTWq3`p#KSMOvXC2ABu*J>cMD}8+wQ+FaYyP~Ie%v;B;>g=TIFDabhXx4 z!Z@JPtY|H{Hv^kb`c=Z>g}W#*>)?9oa?i1Sbmo>(6Zy!~CuRba_gWQhL#JbaIps{n z>1869zvd{Y>3{oul=RD^8o_Y)w?~y=^3b`_we3HYF0<+F_6g?SB62vheYG^Npkc5v z()c}2HY7b#!uEo(aR*q?v^SKPvJ=^giwMsu3__3kvV3)#Hf! zhVj$K5rr{}ILLX?1{a?w&p?Xq%v*WRpg_r2= zwDMUtZoEWF+v2-=D%<<reGrVt@+gdGWl0nhT8qeD1eQL-4Mrn`cn|1EBG5(G=-?6918!O4KxSZr*ksLSV zA9t|P-vZ@AvtD@x{clFk2t;X|-wD!qf5ngUiCwY_|CvCT{f6+YnAbXVhb5>LfRKyU z!@vd2>5C}2S)ee*1VSO9fFK!70^$;JO#wnbBoeau24y93`4y}$0V&H8Ms8P^E?~jf z>_sZ(r~}~{TzeHH$pUoCI53ZSNl18^1UVOS_0Q<+2mn+ZpE%J1Q7T$W15t{|r&N|9 z@Vj;3wHjq@WZLWH_O*dM;zUQR>13<*oyByWi@D;Q2$8kRg|h zb=dr;@j*nYkDLx6^s^W&S!rm4vRT{FW&v8QOe>)pHzv!#X z&)k9kZ!0l>AL@$#$33(H(BiYscLFMX>MZ=l09m4t$7VHv~u7Qwelvd!lGj}`NVp5%WCpU%zAn~ zKHl^GqE4LXnb=YID)Oq*3Dlz0M^Sy*+;WEZMrqWc-sZAGVen7Evx2_OQz3IwXOI1r zh23*zIPn0D=PirmOe=q zM<#I=bj7^GX^4yL$=|#Bk;n3xN=B+WtF)(*xy~7Ak{*thod|Hpfec-Mb(3?agR*TjrSFh?+i@c^Y+L=wb?X7t~Z4gM8w! z3;noFoE^CpcwOKYA6;8On-foM3Yq4R2rlFBn!|J7gW=b|w9kYFHqXd(du2ox3w zDU?XbeN-z6XiO3ZvtCsRt(m#DnYpHqB(>7cA7x<(hG1^GvU-)3=E-HVI{k-vy6nXF zgSH_GDp8M$y4B1T=xXr} zTdnbq(`r;0w`~Gog>|)z7@Hqu-koK&gczOM_ka(V+qT1Bn=jX+QQ_eI+~TxLCyAFp zC;$K-{1{+ZKM@e%$n!_c(`7VZz|*BWfZTJjVuzCFtcRH^y)VM>u?jE&eR5O%fQ;!y zRg3PRv}w%LTDU{{s%6v>xs|}B(@%}1GslR^&C;50!1ZmgNjK=I^T>QNW9dDCouAK&iKox4&&6_-DPI`Fw@QC4II)d!Z0JJ3jIC-e_TQ)J;~vW;$P{ZBf5yjs^jDVb&<#gU|9R-;=@es!qsl zR;G(0O)_SJ8=<9c!@~x!DeM05d1#ffpd96nSDvfte>y2OsrEJ+wS*Hprj#aHF@TQf z&di(gohyTbL&C@+mNc4_GpZc$+LuAadhfo3B{$PlU100m9x9*SqM|U&+~a&WX;D{Z z$Sf6z{jHNA-7hWRpk-}?fiMCz@ai>lDnI9v;WiFuR5XP;4DuZYnnglGHGHhJZK$P(vQpODHk2ZRCPtMup+}FcQsKq+;E0JP~p&D$rUNkU~D?U zVO%k&(U!xkY3G8oS zn$R2g1G%2)l#*|ch?#v2dq+P)tS=A}DiuG3i^p?2%e(rH@)Ldrius=)9B{MkwY19x z7J?67_2GARPf}vl9N~c`gtXExrv0(AZtTq4JK4pc)W$Ea=B`pUs_~TA!kgEBNP$6x z_)<{wfrzHf2I}s`x6|WUJ%radv>KDZGWULazY@1#UcnJNXyo_UHsRJa)$8~EZO#m= zomp{^5IGLl;7!?H!cL!q92SD^Hlde0cWT@`f07C?J3e!c5%j>4k8=_vqKB@5l@ht>}m@EYi1&SE#VKz+Fb^IZ`E3uiZfc zuQ!?pvZv5|P%wUPgFIKAVjSQ0U17A-q7*w`YVLqF^-3HhKCj%(&>h`*f}>p;urn}5 zIwYJo*j3V=BYu9tJP*H$RTVuKlJt%J5n?~vMbPF9$z~Zk5l`B|*`yzqfm*E%5Pyj? zM_BzsCPvul=FWw{!YCUMT9E&}*-dWpHQelwwo*g6)nk+avPC_7W#1rpDHNq$>a1)% zOHhK?BVbpBZCi#)+ny~=nf#pW7fsnQq&7ui5pN4ew(0n; zU~T;MIkXskXu#BNsD*qs1u&}vr>w*PvCgSisSaO2{NB=6OK~@?4fZ_mWk>gdOL*#=f$zA0c|dOYQOeFGeKfx?i{et-voCvA|CuA%$kxDY`$wGi#9 zzi!6aw&A+!*cE@owkiTGFeW@zBQw-CCGzV89|f?rY}W#hCa)j+xQ^LDnK2W+xSdBr z#WF9wX;#j8R<8Y0>`yPlpME>8F#9Ve9wC^K`2L%f_0qs>V=|i$jW!pY9i+6Vayg6n z*L~{d+$*`4MpfU$%b6ev3R4iv41Zc3^eKHDK{^{A9{A;YSd+*)V@$gw!|AD9>16H~ zILS>X=EJ9TdnT#^2$6ICvC6$oGXv-A6Fm4kY^oP){~^wNRH4gcx5 zM0>1$(QP*rl}x6#?hGp0i)IXDvJ$#vx52q}1TbarAjs>ma3>;{YTOvVh@~#M&a+;R z;Q21-KdI|cxU~&(rmoGGQC42#VGo4bxj}Qn4Z5mwVsf@HM1ba8rwHAVC>gZ|kBme#2$>m^9lqqKf)zPSTVmQn$()4g*(rE`kSXgPL2o z=^;oWOEV@@$R=``nLUcTUJ;u$4G>Iy8H@d)a1`qvi$(87#Bkg=bbOjjanEsxjnQiv0bb@M9`o6OoK?@6DlPlg?oX zXYAKt)0QAw{2{Sd)!tZFS6}IjFWH$1l}_?rLRcxi7?(W$S}+0}2z7O)QNLb5aZ|?f zI4jpR*L{!6`Oi1lr~?_+cCvDYomz^!`!m5fJK^)s`{9gjg<%c^CwjMUa7%KQQx7(g zV!7faDJFnR0gMG_61q+8T@z##hF&VEc)$F+EK>m2K@B-PO0uxeYe-P8xP}DPkp(uE zhKjC?&(fN$Vk&2u(a8ZF6ce$IoOa?Ck)64`(Ffoy!J%#b^)D%xoT)tzjF}1nuB_ox zcuA?9V8i$yz3IVp2Dw~)%P(kjB|K>DCcMJM}ByJhwsFvoy#i^ zS;pe=L1B?b$^hTeO)zaykGvQ#FnAEuD!DJ_^Xkysy%e}~s1tX2VGz5MzwSmo&SPGw zYK=g8xaVfbIrL=7M`Ho58d2N+;vg0g_{W4gkCI~d91)`6w>-(QqVo?Xwy3?~t zXkF{|sW*-afo<(tOmzZUt}WSV=hdp|jJ1WJyXTJ(W_dH+IbbYR+K~)UG=@`uodN*H zQ=&`e_|k@W5}g>%2j5SLz+5d0H-}YGx(&7W-HO;!1l0t&U@?hP&RB_;?JSCXaHfMP zebZ4|7<|(|VE-Z?>g)RjygrS^p0WQUart*W@PC~_Wv_2%YV&{QH!b#G-lG0(P=$Yt z{qN35Qo5#A|NKYZ(aP%IHNlh0KUMz94Uk4*po43M!f?wq#aWB_0ZNS?*n}Yuv+#qK z5A7m;6e|dU(bkAxq21%2^^w+w+E;JMZUwSj`3?MeJA8cHKN&LF`h!lszr(wfaE!0a6ftQF1fa&1e z_0*l8ZV86JL+Z4cW|QTD(HDUkCvdE(0!hl`n47w~5>f}o-=@#81j_Yj4w*G4izI>&3X}HHTU!caD%eQDM>$iNM*PQYa^$%>&td}nr}B(M zAOJxR5Yr0TvGDB0>KY#vMkZ6PLC*PiSS7xdRStKPj9_s_NxN1Ov56~vcEXLn_ame^ za}!EOo;xf|U)vi1+t4~G6`-E`JI@L{*v(~wGjUD^2SX7V&fKlZ!Wc2gIWvVs9_$NZ zDvBqv4b?`KV2vd}@L=M-S@B-z$q^JC_X)y8NDS2l~89vYhbD9so1#&KbVXt8-fx)ErJAFm_As= z*yKZ;1dKJI2ufDz<(YF|8m@Aa7&!_?F0^W#4Je1wD>51v!vFydEFE#mh(i5>i4?T% zx7bSzVJw72pfH7Wb(rZep#dtm)N~ofgD}-Rv#DAUdJ`0AW*|4EE;P%C7)V+G`g(%w z{*F=0@K3l=5hR*^MOnjN<8 z3Nl*G((8|F>)BHXQ`B1ZG?p&NwwL5A=4$m-m^<63`ez#oIm1YAgkkh# z@p3zxADXeD4zF_OjO2$mWqd;rWd@$c1QL_e?5p&h)WD1}b{_)eb{qTfB-eP<92^UY z)b_()gjWx(8wn4O(+nEZmSos}a*eT(euUU_R`O?HZ={;wnOGnGxe%w*>p*1^K0c)c zoBeU4NYw>_5nd1fs0V6(IsCkYq?7Oa?r!3O7|RJ26yWQ~WR*7>-HwE*clGWI&$Q)x zORp{rTAS5_t-eL3;B`Ce@=c1#%g<ek&15&69B*0oUO5jp z(P-x~#CMEhZ+@n)VI;50(ngRA&lFrz_eJBBVTBnwxcON5qOJ_-JH?nUDq9ADHH9FDl;ksI=}L1(X7CpOe3$4) z>F*Jr#PpcFlss3I+}ecGUer{1gj= z(+vr53LhbKZYS}$g4$C&5^TEG*bfLg(8%a{QVKFy`H2d*5p)(-_$;jSNZD~RBPmnR zJ?8l{Dm`8d00%)wHFzZI7US#Y}{q zU5}2ml)@3V>evN@o+_;7ccm$te?9i6=S{!nx`K^%KPcC)Pw_2yG}FX(tsfb-5&f`i zRIi+v@*-UTti$yl7Y3ZCHymw$_@fEds$Crlb|BA`teGxiLh0y7bKb4pJQ`mNbtLLl zxpJ91(EA$jey}c+mAC(dbfLY!)nio7cVy3Ku^cBch%tf1L5+;<@a<%O{tBitfX5f< zc4Ui?UrB&1vb6OHx4#A9buZIOS!bUDQaFqx_~!2OrN{g>oTJbWk=K1`5iyP#pqvf}=po8q0<= z0t$C`(X$*+$gnGP-0Jkt8*!p$K{JAhqUjVCgc@PqiFFTiDTJ8T0Lf|(SFDy*+zD}^ zKxrSsuSx|jX@Y3f3$IY7`I6@ zeYSB>{HLeazatp3|GH}a&Ft%6TAKWw3I6flA6DGT!1RCVD^{rT^x0R9{!wLV>R184 ztV388lK*R&&2OMUkcBPGvIC>5a3G+*)kNF8q-uvV#~bXeo17;V59O1v=Xve*RA zh-y0S?0iCj{nU=?Uz9bv8uWEfGo@kQA&#Tg!PtV|EDL>NQe%Ft)%CV&78A~J$fX+}kb@Ea?!r5Lx=r5kTAzAEGR zUIi8#3acUIyt2->xF`j1SnJv}Kj6c}wQ3?L41}>SD;aB~q`^hj*<`(tHj7)cA2@iI zdyvH`GCS1hFWn%gVyhGXy5JGGD)7E29EjcZeOns)jA&s=PeHi0j3Rv|s{#h-aR)-3 zRM1d9G4NPf*$$Ftu_1ttvlu4l+l(s-Dy>(_)A>F^>p*KRnWBfx;Dgeu4;BB{TrK$y zoTu-n&4`y(0{s*DzaKDHuU(81j&(VH9LgFk7iCQdlw@_`*{%+SINm}`IXc#>E7GI~ zj~d|Xuf>`-o)w9~ivfr-dCh~lu$q;kk_Omn#d}}_{Zz`vL*{JJ*+8i9HIsF0F(J4c zlg*x4vxJ0SmyD9+Dem?L%#wQferYHXIXhpA(5PBBJQr&~9_Bo%DKK^-(52NEcPxM& z8HsPq@R(Qj@W>VOHeV1aO~L{-WpzQ&r3?C-Y>CrrBHuGA*H>%sXjThdTs8aM)+=}6 z;gfCDb{}Bjy9cU?O{~oxnX5`#%63>EsTD-~e?DdgZRu+a;#XZ%vMDilMB2i8qiK7` zZDwB?#TrdC-RZ|6V88oykNJ5kTsgyk^zgd!tww@yr%!}DI)axQmrSqS-Xf_iev-jI z`EEOxTJvtkV?+FYJ0HtnHF&4>gOiNInHI#rJ{_ehQEzLeOH&y%uW^b+6vQE8>P$o+ zhKeaoH*w?E-upi-E%oiL8XmnN2r*-x73lbNNCLkvXm%eCf>Ckp;2Gh)Jh!DT8@V0d z{GQ8dm5u8VulN&6R@soi)Y;w5nJ&Hp0o|TmAg5Bt0lQG0Iax0W^tY6NyGR$hqD&Zx zgB7<7zD8%{6?@8xX|E!ixb+{ZP1n%W_KVJjzbIru<)=%Ww7?I+6}M*x$B}TMt<@@x zSJi}3r4Y(iFl#5t{EeOnA6Afp30;ykV(euZ>!w?ZJ2$T>U3xJ80kDyirZ8^{jPCrKIXM!hX5X=*Y@y@muXP zD(Do^54PAtZD)H5YPp|pPlQyo>1!Hg^4jRCQx_e=m*!vxs>I9z_=({KFtSdFFNP+& zDF?xx_=Z%auier4P(K4Ji@i|B*hQGfysL@+2r+&%W_(qz39amtUq8X-75tQpdVBV- z7LI|9O>OS~aQ^n|FhK)yt{tD=crzMuMi}Ka;6BZ%w- z+O?_&=Q=|vZxi-XSc&8WwsheH%p-Xx+D+gD{SW+8m5y#mT@O~1&>MmF2rq~w9CcMi zC=~87O7S{bvm=Ct!k$mNdu8FdP zU}e*G^HN}&U!Pp6hOL^<_Aub!^aJ)bT$TY#yTn=iB&<}uZOPm^Ave$yg+}m>=DM>S zLN7!ObtaAhET-zXy%fu@4$~aHQnO}^iWY+`5VLmfd{jeUn)D%ui?IeEXGie_Qh5Vv zUkM@(5OpWG!H&-aG5hfc%9jTnu92oqcSCHW5pCazfm?i$VcbiyklkTc=-j}2AkdA% z0pdmR4)yu^;*S9cp!TcmyFg)2=6+liscfgc!TzbeM^h|$K;|>sb zkYPqjr_Ih81rD!JLfucP>Vcfq71S6RuZmTPx)qdqmu=*yhDVUqmr0kOc8 zW74WxLEhh0Yi^xwuN=amM#|?JbbCoPy3L;Tc*Av!d7W&>em+3(+lc+4+4qUz=)2|g zMSdoGYZMeJ4eb7H@P?)dxi_Q|5TW{m_RN4)%$b!wYEZ$DriJplmwG>F9wA~iL(gke zoYeuQ+GmvAws~|1Jm)u|@;y7q?!z)Mj}1te{{mdyV2; z-m`yv31_q`W^Iu*%H3h@_E+qw{F4j;=iQDmxh+K3v?UZ>0BtT?LwMmuRgfj!VJo8NDANZ?Ok)hk8Qur^w`4L2rS_sWoR4l=fU(&?^ z`Qm;$9oQ8>Xq?f}=0NSr>rBTJN-IuF6fo%YPCqtuF@2R05V++}fAJ&b9&{k3as5@k zcBE)Ao^`#|d?GAPv$-(NUylv3sMkyEc! zFX)YCziYs5`^;`Tm%%3GH1>HfF4)TRdzO?s;IJ z;bS|HX*}H09FpQjfZg!m*(Vt6$S|`MCOoUStkvhwmvW|s2JYdu9Mc`BF%n}Ci$a4^BwaE*V*ZI2lTZUt$?Xyky&eX_vQK09ss5B-&xHPXvglr-~U{gi) z7&MyqMFe*+DZIiUeFmVXn7%;DKN3rKMyG^bF?l)GNMyyJ{Mr!%X_B}^b8;VTYrXzqo zRUj|%o53qIH+N}XGImW?hmK)F!#<7B9m%wh?|i)ib!pe?q-YS>f(1so$$+BxcTs(tcjP5q;t{@_`<+A;M zE>Gn{_F!}bT2d@XwZLB#eY@zj!|x7~k3JZ)?~dTZN941|oOz(l(auwfR`dRGp3WLW ztIZz#w3TCnVB`w2U?<0_Qp+AZ$L4AtvflRnLx*2uX()F~I^tB|`%z)8G=7@4-|61+ zITFj(uvfzKx=>ZLf+aZUTt3H!^`1BD0)9`XCMqjPH!f?`J9RJ9Pr z3goZP-W=N(_=*t2_i4vbNM?8 zZ=$?Nt-06|@|()nP^{3P>38zIR!b7X@Xw36y6;QLhGdx zAaJEz*rnox{ODX1N#o=vsKS963MThhDxPYl-R;qqYoeiHj3SF2xjMXK+)sJ3mt+4M`D@mvnErBX{IB&+( z`NMTE&$gY^M-6^#!A{yV7y@mLtBit7^G&zjyuEW%T~)1$L!-)%SiezJcm|BTe;Y2e zCL*`Z=s8dZVM4l!eW|mx(iiBE+CMIEMiOwS-zZohS9>2BhVtZl{MKiD`O`XO2w|F4 ziHR5Ha`#FE!>!sb+S#^IqI!o7f~H9k8nc=^|$2(4sQw?0EnsbFscU5*X=-Ii{8xmSgP0Yu zfQhc%XDEcB-QUdMDwTdJ%*!IZBfxW8!efprUCD#z9$+A$p@Zf6VU)8a=>`o8V6W+< z{bD*h`nZDJmasJt79J+^PT0$mt@$Bh6ccPPz4FJa{pE~3UAw#63zRO<0nAcVkS+o_ ziXMUbD|jdpX+Z|uPE~>eG8i3oomQL58A6&J)ImDS2 zy)#KHmU~LAHHIyxdgFvrpI_};MXI8BU@qJ}m_!-=2C5BAPfD%>{7SIIv6@3EjFThm zHqdI}e-J%bM(-~K?{{0ZwNE35;kGtOiXTsPk{&y@lycS(xcN2=G!;^Cb{PK^C!PEK zPlcpu4u;V-6L6vL&L3WYFl!S7Jy*@ohcQdyu|AYzA(qpXStUT}o|5aJZzk?4;QhRi zd=ZGp1?pmHzBa>c7eVDc6Pahs!Ge67LXbgk-*h=fCP5_6t4DDXovC3nx-$&so#+aT4*$8edQ_F~!xt$%`@2sMTr1D01+Hg}7<>|@OvLZCflJNQwR z1DSsm_?mmW4dfSGCqD=4-=`0=4fv;+%_S~id+)P|Oa5i!s`CGXLKFLpM)=fd|Gmr< zf13X#AC;zQCoQsEb*XGFtDOYb;NvSO%rXr)`rkPCpZ0enIV0M`pRkH;+Q}5V zr)5mE$&lg+T7RgDnU~gtL1nEuz zN3!ewvVCBAD@SN|&?#z%FZz(BD ziko{Fby${Oo(Ndk$oUZ6x)th${1ilqchsvfk^0HL)MU6{WVoMq+B^S)V&mUV(^(TitA*@wQ6VK=sSy`e1W|sDZ0E~9=an`3A+B4(}GBmXl?A~~NtHhge z9coUc(r8Gy_i_yqH4(-D+{!{rGA=1Yaq-RxAZ~Lco5>0<^8MJhu*_hZaVyC|;M8n;Y(|>KG-bvU&HJy- zOl#+9$0f#AbUW=RXsMg!%W%M6*W&TgJs@qSAf>5aX;L6H_mIL zV9=rQuR(0?3hblqykX_S=<}owSOcMeh?=fD@IR;kbS9Xu;BOC5BM4+*8iMgLt(gg< z(@>N&#xHx4zk>-sQ^M7aILrYmJ!!OJdq7v|J^EaI*Pmn$Kdwez<@AIS%>VaQ8F?dv%?>(drGy*s)<*!q`6wuWhXq4z@QG7hiR zV5p^lyKNJaZemBli;9g*cbUH^7luM+>VoJv*xw}1mk0f3BG1Yse@PXg>mscl$fpgv z8vQD$eOxA*uto7tSv-oY-~djN?H~)-dzgPDRMxTlu87b)95xi z*z?(Dp~}Ss8EqB-rHHPte1>^vp?Mw z2sVvbDMj^|z(fe{^XLvj&2+CB4MzOqY$b0pe#aauO8?pmck&3$$7Wr=GK@m;5R&v# zlGR4V>82^Mh9ccU`(uUnizUi>XYCv74yWHU&9Kw0cuT52Rn<-lcr%Pya84Il$=aXC zt|RBwE6~|3nw?<3>1ej+OMS?%kD&o20ogEv-lSmf8gw7v!?ahFd}nog2++>rkBtEv za8I_D0y1n>f!GU=Zq!rTrmDqOisM9P4f!4H07MbaGOPlfigJm_pdeb-#>#m=G4-ZN z7?J)_O29-{oFQCNo2sb34Rb*LYF}0r3-xARlMs_F8-^m$_%9dLi2C>>17kJ<0-;}A z)N_;HA@k&@wJ_ySp{aYfJH^da+zCgE&JEZwH1mW6)HTRg=a9mk6UsNtY7{7=2RJxH zm1bqMRq!GP8?OzhFvJp^gZ*oDh&8m5>3@_k@r9)7j3_OmESW;T2^uSt6aZjA!+*7` zF61cy&dq&6JQ5wA-b{SrpiJyCC%6dN-0JghVpc3VJ-9&WscYVGi_ zQVkC%6F&R`>MlHL8$whju3U+Y%eXTD-4}?4DtvAL0-=x>$;VE{cX%5>M8NGrYRO14 z5d(jh?yo)+o{(|1Od4h?iO={ef`tZd(Fr+t2MCXdeBklGZe^qz_c9Y}2)%I!cVmzF zX%1cH6v{xQVF(6yE@(`ZMV;5CD#IjpM`sXrc~J4>#;v1uKIbQ*Hyg#r_d7s%Io8_= zNOTU@1%HluVmXGvYq%iZmo976AQ^cZ^RP}pjT{jioVKqz*Wh8PIX@Rj-OyfDs%yH} z*PGkeWh*C9j(`K5x%a9;>ZN7>>55>j*zQ=7P$S%@)#rrU{X+5@6cb7(I((geO!z&S zY1nO-&(ccud$~K*MJb^RgVAojfkUmN%9;b9+%`G@1n{uSqer#p^%@1jfY-wVc)7}n z2)?9KQlh|h0qZV~FJ!~8BadWJr z)}&#-N5YeJ6UZ6l{Z2Dd)$);hYz~f)l62*&bmK0`RF+3%IZr0AF%~2V;L0O)lc6^( zx=;krvUq_)Y2aGsq5JDLT(M{=j2;$ZGcmn~j7XLhQPg=toN<}Y_AyqL;blM7FDL=r zbSMvg6W~?DP3)~CgfwK%!jV}9Z1S5((ojcKV;y_9mg@51r=~qI*KgTb3T;kA3nRXR z{wlr-@DPoHdi+9z4W@8P!n06daD)bEIgA}Nm>n1yAFz%ANrbBiZNa05qgV^-vD300 zM6>frBcv~1wZ8{T@75Bie3)g&a@vuO7dbhb@5Ubutv}H^udYCDal4_h02}q*Ds*U+RSdEJVj(|?#ICf@8Qd(}CpiZoeVTd;p`w4Ta){jKI|)W@ zylQD1L?WrDL_nE~5&B*oOFlNo(7*2Tffzmt;qf(yBl!(;PuQ+0Fdtg#%OAxpNZ?jI z+1cpwcH+*rYokKeixtMmvZ#JdpeLr9r>{><=BdnLBlR8S(VH2Wv7u)>A*Ac4rFCB& zfe)i5aqx~33S9uqgW8XUdByJJ6b(rMYo_-I8?tbtL+^ z7HpGBW7Mi|I|HQ$v;2lHh&NyWP5v?~@b*FRk_NM05rrhQ0<YXcZ(zN9tr_8tljIW%m#K^wL;e zH&e)%tem?nj1aZQF4U8#FRUB+nV_Ukc9OtvEvFnJa#=hC#7;MXV|NV)Itc#^A6fL$ z9e@c`#H|ScqRC(z4$NA@D~Y0;N}@x|s8`IHsps!N#@%YT>m(7xxm-zP8&v_mL)_i|F93xx9)t4mbmaw;onsEV*jVI0I}fTVC35;Ji1Q2!id zJ#;FYG{0LwCxmhYBlXa5XgIuKk$MFQd5o-nT3C5*U({fctw}yR#ZpW{mG4=y^gz-Q1C-42SkgD|L(I{Jug% zLyJLkqp*lC3q~xb_8UW`ty1~YXi^oPGqs+2a~bC)4Ux&Zd{MN`M-#&OaCE9??kdDt7v1Vd8F^O4oJhIHW%T7FCbevL)=B^|6%TPa;@aEY zlD4(DrKC{+U+RPhpaLOLT}!b*J*cR{K)S^c4{IZ2VOsqT>~zv0q#EJ zzI+tCJ=G8qLoR|CnK2jfzIl|a*h?w_w)|pd5qryEf;q1r?K0u%X^COZ?NPdgX;}Qw z{S50yLDyyF&E@V`ew9wyQ#P9Iy2qI-xmp`5Wp`<9I>uzo^&<9gwNpg?=RUEqmt1@} z4vdpIO=?N!4QcA6`Nmjz=67Dy=56U>rMXU(Dy;1eJkV?w)4`3 zqTuw^Tu3sjQFzXlYZC*X%}>&4!W|2E*mD&;xypq|O0H5<1_v2sC;UUxwp=I|A?GJi z&XRqw1)kxF^d_ri_;vuhy^EpQ7b))Jp(Q}u$`TWIW?%wow(}zMgiCv@ZF*VpbiMqM z6a+(^ZzDZeP=f$m;Tyl9T_1BLK{)gDwsVHBg+t`>3TmWHIR_?OSvTR2?ysR1hL}m(j@VpnPs7q`?lOya4 zz)6OIR}PHYV^eCfU^K!?MFPReK59yJ^aIc@#9R~dB+Ejv z!)dCg>ULI6p~{kA#d%76=NNQ(R$=?~6s$H(y@Pni5WRYrc{O|DhY-9TN)!W=%mNLs zEqRZ}k3M?z>OFXL>s@Me>pkiq$H7)c^kG{+kiHUU#g1?z^oyN>Fx=(RT~CkiN%-== zl}l8qS!8yI(DC&9B%W(C1imvk`v}*#ws=>{LtF@-RZ}uf^UWztB(PZJ$i%H5WV-o88mIoZb=o=(C z9k9+bln0AAG%KF@$goVRW= zfj{D86t$sFno|`imj;vNw=XaPt02XoU=QyR0_zqyZVsU4%NR-(1l^4Ke$ivG8EP1i zewy89Spvx=YE$eS{X2;3qNN!^+=Et=Z9?k;UNPTWuFqquzPMm&034h7C zDuAC|^se`M+m^hxJ|>u87R`!^8_`hYEb7~1QwWFOr+H(vpeT;8si0*-UZFAF4RI3q z$${O<&y2o26LR2zji#lP1z3I3Z#vFkQGIgxMRIPE`kiiXbO(E`-RLWc&$r(LGCJdL z#w2+#_l7(#t-}Q1!Spv{rCo09viLNJ$>YUzlqn3wuM={j)zD)Otwi_HC$?AIJe?Jnfd7bqc zx-2I)~p^c^Wb>xc4!Zt^fBMX zvv^}sy{Y?U3?I|^CkD30E*UZ3rvke%fxOB7A3EEZR_7o2m(RuguP7f>_1dka^W7uG zAHe?Z)~kz0#MHN9k0))0*JfYsaf&*#-sX)*{MTxWY{#7p*pI^@^$sHK%;X(S0L^8i zA6!_1qVLa@1kEG_Kt_TvfWaP6CX3J_CV)QLl%yLcf!?kZ3QTlf!Wz>r8HEwnrefg2 zlENA**U{D$4nlJfVKN(9BkC3GlO$(bt0aOMcUKwQ1&!>@)!AaHr$@oTf)at;XLokj z*QT;!A=R%H&9fz6$2<)Wz**Dx_wO|^QDQTD4y@soG9~~Nq*}oV2L% za|z}-gsv1JQz5AVtJPV6R<@sgvo>{!pWzXpooSJ1)!Z0)h2r}QX*<1@Mjezb%ze1i zWvbeAb@W(>;~e#-GFGq()%O zp4IM+}&93j+QT-k(bD#G`gO(4PGRVj)0N+eyr+;FA zMEln3!qxIKcMmAVR2A;)4!_>tLCrFTqeKZDxL>(NSx>akz=RbE+@m#V$lWP0gbU<6 zO6$1F9Ekv=hcdAz2`m`--ZtrQ&Eg`G#gjINp^WNqxo@XImC{6}_u}G;G2%%M?ZOev z<6|2(6ox&00;g2g0-ZtZeo7psWbUNe#6+eQ2%uzXS3+5Um9YierZEkoL?qRuToE5a zJ^qM*M~#`OQdQLgR5?r~kX=D(5yg45Cb-n4*pCtVnkCx^~+{X1@K2s=_l!ysf3Bw%Fx{10RB98G%{^>KI#Q(H9MP2uDTESZPx zjX?iS3jn3E2HcI#mpntxk`!~ zIFiXii4oAn^VsfCKVd!L_AWTS%jOputueABz!L>~n6B(f?$7L_0K*XePIP0M)Q}m% zb7^>unDVXu3v;f({D}nMKkXe>SIk{sDJK zQ?Cl*dh2#723$moA|^)jAK{a+-oXq8bG5UqcNKM3ny2=qbubvRoOYb>7!yjBkDq8P zH3dbV!&{!Bsc%ufv1qXrHn0zqLJ*lv)-c(y9xnPdxMOM+xpv+n?Y+z~=s|0GT#>|~ zJN^hOOy=%C7+FT$X%At*L{wYSE7}i-32LO6T&8I)B41C7mI!eKudB7p&Jh+a!*+^0 zH!NRryz{6rUn!yqlzP%}3zYC(4=y|?=~(`OdTRD|F!A@R&?vBrFu-AEmmx9Z)<6ixF_NV={J9}Y^P{r^aN%b-kxXiXD$ zcc*c8|8QvBKHS~ip>cP2cX!vu-QAtWt#KM>nL9HvyEkI*-H82>RZ%}OGxAhcL}liA z-v?Kc&9`i?sN%R+0?`4yvjNtha8)vDY#rlF1Q$wp1|H>4G$PFj(HYqb{k}ZTCePo! zbI^7VxKpI1&K}TZW8UF@L*CFp)HQ(DB{mabW3zdhyk@F=6LHYC7XFGS(khZ>T;EGJ z#n0fPVe#2MaosrK+Q|hQ)L|5Z>7RVVv5e8kB_YZw)Wt?Z_688*dl)+WWYm11?tPA6 zVgXulM8n0{KyNULfX>C_PY7w-8dcXa5;a zrY;(=4SG=Xc-#k_wMUcWQ&!pedxs!95uw>p8y~jL=dJ22hJA31DkQ}4#YRq4<|=V} zal{OY_~OLDZ1(}*0OB>oOZNInkb64DKKJ?1MSqD7=DaUj*8t+<9(E^vyfvTLfyk1- z6YaM!!zjX9e$X-=wGCKAT2+4^1Y`jr8jlvRi0Il!_DVJzznha7@C8CLyOiq-0|NQ(gn)maUFDYL-u8DwmcDyU|s$d z5>3yJaHc-iNGFZ-C#>G-vA~r}WNx~>?6g3HFf(h!WVo=T^il(s2!aeDuM#osvRN|= zc%pwMr-lJ%q?NFiMbdPzmLR*FAv(?ATX&EHU0l~M{;}lY&8=F zH0wo?cE=v;M0I$Ia{hp0-W*5{XJ#S`#A!f*yv`TO8Kj@MXOT`!J!SBe`cqVrdYaei ziSXvC+M?Q|kJ_$ID84TC=XMyTcG5r)m^Scu5U4Bjk^g&tDGONb#hf%txg8bq8cTnw z%adk)g7>L>0?H z&lb4_s*={4&b$n`Xv5S-ERlZ>(kyF5M=T1fupt`968OBm1GaIR;&=~{K9Dch?kaeE z%6xorrBUr}&=G6U9cvgyBogg42r$gBW-QT*#e>h}tTvbQfy*m}#h%l#j8`hFhIL;E z{-<3}~VTNN7pdwp(Ul5R}EF*DN`RX;q2B9Ig$C_P){$VLTdP z=kDtABgnPD*}bMI7<=Xe zeo6n1`Z&V}o|$YbBz#C~1-Wm9cw88HZ`D4_vt#Obezs}f_&WAYy^#8g)ETOXds1cM z?oSx;0827yb2(bRI7;xiO4f0OVVNafYIQmu&t=W6Uq~e|9N3Fi%=eekU~e)#%81-)jiRp>WjbO!};831~I8h0=wPTn+g z=W3d>__xJ;@WlDtQubI7yD+kkRODpo7aUZ zy)#eeh?EJ}4O_l>J3i>(uh7+0_WO1pqLhhk4f7UcHiLk0oqCH=2f z?K1yAR_*^IY0t^Q$@KgBzhyEtDz^5E%qYHFZqpl~Et_-xw@9WBrt}D$C>v{Om7*zd zZ*!JtB9g@wQpzQ6Deai=bn)pz-h0qDMJOjOfeVt}>1Z@PO+Me|^F2*|pRb?bea3v_ zhM=bWTa#o_F?@fEjPkAW%?y$Z9gW^hA03BqQ#ZlAjI?_gbgK3@4ckZKRehM~?eTy0 z0WDyMgB1HLO_;SsZhkZ#kcc)hfUh=6v@V{cGU=|8VI=Z`PbPr2B`5n@#PCS~ddxWv z9W0{sHqpEIf-1rPdJQN;Bh=AF{1|bn%w;ygYm|V+Zh5S_t)C1s{(Z4HA*~H)^)rIb z&CO#ld%$J(-xotmp4d$O78kSZ2N{eS$cWRsED26e~ipa+(WppK^Vi}t+q z?~@%#q2jF>jk)rvuUQeq4=P=xpKqo^EtQ}5aVST6NG=6j}qRcVl@gY(t%E){yZxbcKYhV?H5(Fvh>~bIDpdl+&|D2>h z<>0w~qMx+vl5XwsKzGHEHh)2-667MLkA14ySom%H2KV`R(LaRWw>Mwc)`&uV3bRtE zZKqO`3pwoZv?(rWAmkOMr|UBF`adJw(xkk^@0;~1mKFM~vdScvdq_WcSak{%2m5|S zsV>OXB;AWu3+ungw9BgD9rH*bW>@(LSAHU9C^&;$llr$*%;Wm6)EeYG)g|VVc*Klc zB%H`i2v2UdqhDb68*p4IXIP|%=okZ_SmOwa~Q`}|?Z^Y=p?VDu2ig~Ssx zxRV^htIDZqFIsZ*qr#!93c=_|(lNUnyW>>V-Cg-LUAwQrr~c`=DkxB~36o!b_U6f} zFJAz5KPoE+m3#T>@j*fXU5uRaJh?>1r!1*N2d9dcp()Z4z>(j=KtMktV@dE%won{; zh|+l|0yt{|QBwAVNr5ct1Ur`r9R-nTsS;(frbxzB=*-ffPC@ozXl-&1Q*zSwTu@^f z+z~t1a|79F1wD#1kQ#n_E^Wf6T!$n%9^a{aD{mqyMCmM)j~2SzI~17OZitcsU#`QD z9F8BV=s}%g9qd$!FAntJPB{>%a2=$kjVr!WDxm*{3S~~f6=WZU8cpOfB=2?@f|<@@ zPSA2CD?ND^=u{#X$OqsAIDD2Xu)>}kgy7A4FpPUMG_Cu4Xy;6Xmd!b1* zUNOL0*Fj6^h@@#Zx>Y(Zl+@J@!{3d1)Lfm09Zu-{pQizErr-hgrCZ`{PEn2HgReAg zO1GS4PP`@V?FC7Vn$&(yLC9Vze~TX&t^C@Q*F{3Swtz)jbjfcp?aMVb%B}E6v&lOO zIoJ6T-9R@$3RGER6s_QoWbuOc;R?P}6*pyUudRA55C4sCdS%$QL&aUWwuh`ocBX)^ z@`g@3$33ktpeR8(Ei%wpdw!Ckrx=I+3uSgW3opGdyLtIjtNjMfamvq zI6XhyF4uLZx)z3c>qGQ;R)jb^Gwj$>NV=r>Wna0uIv(dXSk^_{BOLgnSdibzA|G_g zoe>kH(JAack{^jL%PUb#Y4LI@L6(}a7PBaTE<=zL>|L40hj0%>9bD1 z0-ASj))DGGJo9wkX( zIqwKm`XW_zPIp%QWC(mE2^+xg1DpXW@NRZA*x|^kz}sKcGaxwJlSRwR{gRNW8wvts z?d%#rb^Kb|bhK*R@jg{7Jp$O3m0=MCdCO0?WW{PYaV+fQ<&lAeVKOQS<0$w*j{ds| zps=dTtx>Qd;4(V!&VpVAh##Xi3~x1XG=Ep=Al$%mdFVjS?!=C?T)>B?i5Iy~Zyt&j zcF@v*iLj9}qos&WE8k@RTzn-s%oIP06}Z%Vuob{@6}z8^UReq)N~q{RpNogx2dY8_ zDfY%jkdtF+sbJF9F~r-N#^wCcD4|u+!Ht$n@}YX=|NK!kIMMHvz0&{N4jVp46FWA9 zmK;VZ)AGWJ)d=$fLd##Auz9qWWBykR~7IPl8r5T5Zh2^kj?N1k4# z{jQFU1CpA%nIPa4&Dp~G+C>YMm2-a#meke9$8wR&;J41$HwczNup6X4y|06%`!$^g_z1D?2+bEFe5$+x=rqqRs7{yWT5EMI438v8y*np z9DNWjagv=)%L}elk`qEvh+QZ(N<2rIjNcOV_4+2vr>zo;b@ZGGj4^A zMy!{hM^nf>wm(o*(@I<1keRQH;#i3}!49b$v5~&UVjMkaJZw6@qC3Gdno$cQ@>?86 z{jVeeP6>`+JoHu1NmQ)Cbbt+QDLF~pi#R64(WQdrriIOr7&ssAivV3UV6HfB_c|#u z#N9DX0^NjmI9cCvI7nT`++I$>xG9n;`lmxpGD#CXDmCoSZG#k);L+-t4LF8Gl||0a zV60P1)1Ptsbdsc`5vjp*VYi7&6-3(FGLv=bm^o&5lDv}$nHX2ez9vvXi#^=!>u%cb zK~=sde)0*sd!5d~ zNmGiB%}^ntV#-=kmTy>kl;HYRYpndS^&{DT@8>NSIB^-At@TX__;c zYJl(*Y!U2nontU`wbuB8#5x3iKB1NkY`Zgc!>X=0MDfsSxG~G}GUYW=5(pCP=}82R z$s9k!Ly7hZZ=53aqZ8)mjU2AN!YmTSDKwOoTS)u4(~g<}(vkSv;!<+U@C?j?Am7@8 zxnp84#f@{3idK11dtXOeiXi?lfj7>OyBhkvRh#8Hl!TQ{Q6*!f8fUd;S*W{4py9|( zuizNmW^1O}H$vK-*5l!>Qv=~DDw`}6q?Pl)p$iyKfWVKI6UY|t3jDiNB5tbg;dF2` zMAlp-axU0;gWwEEirv$T0R|$tea+VUp{QB)5B5fM1E|*N1n2;qSn##XxEFU{IeTA# zvUwGrg#-~N^57VChtiojrw0~CSqKS{N%~f}1*__-=;k+tV@~)G3@Wzg#V-|Y0?rUv z-0iG+21|a~KM_FH@GZWjw4;^Z$1G}|QN|pCOIpG+QqU}%C>cBHq5fF(>5 z8f9O|xPQhh>zlh=sRsf-^TzQPNwK_`e?9tHM1E>d%_U+>OReFY6WUf3sHGo#X&imI zpZQTArg1ACaHtxRzous|X|_h@gIc;nENfV>*h+E_-Ufr8$Sq#@zm!i~8PiR1Fl(#= zD5SsO5fVGw&0dRM6oZRMF_=b6#H{JYb2?sn1(&ffY)xA^aqR{6kw(;%VC8wSI4f?l zEVKbX7;LKo;YC#g^CGAVnsED3@nahjerY(cQ^#r+9JScqK9$e*Ea~c>N4T{e`Ll_Z z_Zj0@I9~GqRvCFtx?;kave`_xd?lcfnA9Ptq!=(zL4#+it`ak+sB=9>mNcY-g6u8m zY$(aYjE#$_ws3qJc9t}1ys)z1Egb&+7aBLvjdjwP#74!&nGou*dE~hQKm005Agp>l zFlhlVOW$2WwrfM)TtS|zj0}qlLObI=0bLzR0Dv90EFU8eJ9?J9(i6sgV*nuAjs=ek zvjYAhT?6mvJsOF{sEaK!zU1VziQZ;%ukUJQ)KJ9|fX`S|B&yLQN$x-x`3MEo-sX2O zD99AnEL_cjP!=lvYwHZGZ>8zHE}0AUI4WSypKHv zPPbSY<&y;26d`>u#aQjL^UR?@$;3_xg-Obrz8Dbn(raPUAwoj0P-;nBT8? z=g65*o!W3_6*a*o^Je4}HYs}$h8DYFlQ)v9I2tkQMGT4Jr+6C=xNwHxDHv1bm&){{ zIMTl`0kZnd&TX)=BJ{Q#%c)IsB)PTfVZKGd{2JOc&q`3rNZ4Wr=L4!OB?&!CNpftk z=&?`b>-ha?XWl##xKlO}d{B!U0N5h3P4W11}7LSCPOOxPce2$inp>kbH zzXonbnIuo+)Mcyu@J^1ckUiavTdQ0pW^v@k6w*?Rt$(zcX-?j7CHj`lE}k)S_cS;@ z|N6*`ETk!yL|4~I5Yl`?U+3i{r-~ZDzzZLJ0f{fD!q!aSd{llR6$HOks)m75Bdfvo z$z;@xc5Fm9sfhf<_L%W}WJZ@^g7ZPXJQ6An!qZgniK7K#ZAnwAS$;>+vI)QjXk?;? zESxk{%)xIholY;YyG*xL~GF1vz8YWRon1ugGoTAXT41d6`a>O%fKD_ie{dr{e=5QMR)Xy@N(CQ70~{%gor- zPOd^!i=@UvZQaD$3TUF+ZJs+;u4i9LNEfLTpOA;YGI|j|N^zMiQ^SLnjq@*L_iChz zRsl*x?aSPgHdD-_dgPCsyG; zy>j$Nm{wmf-=%Z(hrj$iEmT~Y32xJrz4^6H)RjN1pIZ<-Hxb9F1;J!6(21rB!bKN*7$Vq##5TFNzmh;ru!SxesjBdA}61p21Y01 zCl?L?oRn&NGnFGf{~7y3F4#|r9Q!>kt|mY6o3i_ucdQ)yKW*ploW8t4x#M`2_LHpK zl^XKn#IZxxK?xhom6CpZ9Rk%r@>NpDqq^^pETMeYZ9C1(Q-bY!X2oL`!^Ma|AHQ)K z2S`v;Re95v9q?0COzb{`S`2MF%k`70rxLN&xHC(%{GPnX&Gv($=7F*QdgTSnH*V(o z=--)l)dJ?p(X1h}BZy+&3hG0aGUHvCH9C$Avrw*Ibi?*#+{n9eqUah9c#FdCAxMc{ zkLI;(R(!I51DX%i=Y9oqxX&cL7WQ4@uKczGH z&x{DpajP%jU5e`7(&{;1A%bi4r`D}Cg9Z=#NcP*!>1MIrS=aOHA2wlUV59L?pFn!7 z7}PSpA!6~3!;_0kz0hJ$h}%H6%^8Dd!`Qlei5FvlU$$VuefPUmPWOnr;@>*J=49?q z^23XFnvkuele&h~Zrm^YeFx>beKjSTp9@ z>8_ynD|sxJC)T&DnJ=*=k0i=FPNa|ycb88_KZTR)dt{d$_+oGZ|`z^ldei%UdZ8X(ko%mASHzz;*5Ycx>Rk=|QG!z0hH@_yC= zEw3#?YjJLXAu43PPaJ`=MY-xRt&RijOOX++tq&(PqPG1`XN%grXp%U|%8d<6; zpRPN3r?Ze+=S2U8$@LS{D9C592lL%J$8WHgg7GVszW<-fKD6#xvCB#d(S#!4E#RY^ zPKe&q|058Yl^yyy4)7K6Rek?qGNkfFx+GgZmlV0)^|*H(XaDwQT|})7je!0bHIqf~ z;F01OdvIMx_wk~Y3{ib9o^+fhu~FPYDCGuSJc*{|BQvVt!@ocN`R3`Cl zD+!YI)s`Aj%8aGxR?^m`z1v3c$I8-vu*6|85n_qRf<9R~hyCj_XS=2G(Jg7GWkj^l zFkee;<+-|f%5nT?W{NY*$kj-{otu0o`sEPlk^|r@Gs9DQ^Db2`O1X0-s*!V^HcP$> zUEB;HUE39~#4;Ul<4q1fv-+vIU9UFVNI`Dd4VPGR%I2RPl-nAUKP(S;uM=F{5=Aff zIXDhUe{eTv)h6&Hk!m*BV$PoyT(_Pvds1XaxE?{1dDiLxQQ&?cKM;Jml59HD&{tFf zi6JcHL|iC~-C^ew&#~;!%tZ0I$?%gL9Xg&zC4r#fQH|ZNj-i~HUeLo5Avz0Ak(sh* zh`Q1rMw*t&>GD~6(4TnXwtzfr{n18x8L z`5dqFb-%nKO1-r`*O8gA8OIccWx_FRmioQ~P3nQtp3-577g`bEl0nW`SDx>|*up_1 zj^-HQ134b2u8dp6el^-9@!+M|lU|5qFMrmr_zPj$OUinZ|B|NVoPBZ1s*r;LQQgT1 zM{WgbFroe3b28J6M9x`N`*JPeMN4n2&v~Oz4a1w}!!)cj#BmYEWr9Y|54-_VGtmrR z)v20OfJ=54wt_^IuQTMJB2T)|HkvUhkC_Tc{()z{=2XXfv^HINg)SU0f2VTR0w86z zG!G#=R&T#Yc3ZEj(HGc=%`JmC0>H|+c(r8mw1^6Vs0zn+ddt*teTX+|9~|BDB8zGBZMgv~vtz5hTH?5s%-$ zPG*eVyNnEKHuEWPycl@D8H?%>0#Le8{scDaO_Zu6KDP6PUHDlf3=tf(l4~LrI}PcG zWa=6?OEFgSt-l*F)=a8p`kp?#*6LTf=k$DIpcxmL%KQL`@hc=)M-dnMy>5^!XO{bS zW%(EoG~TJlf;zg&n5^$p`nMd36RD-^i|t&z6a)na+b#*m)!BpQf7PxD7kzfvr5Vo_ zZ!FO%nW^pG7_4942$fXvP{q~cGaU+zWoITEC7fyz&cEPy<;YJ`{yY+N;2&{f!?+%n zbK;B~6QNuMs83vB#^E00W-*N4hGMslAJLY8>befCGI$b6^Lq_AS~_4u(lF1@iA67| z5;sIuRDfblj5dT_i3jDy1f_uNh0=F2!$s$WQ-q`#c@)<0;Z7>s993xKn$anY-XU-< z(xw@Ds72k`a7rAXG$xq<;-;a;riythHJ-rhmDerT{Y61ss*b`vMtj9CTSK)7!~>LEEJ zYLtneM%OdCrPrZ$l2&ICu5_b%{chQDn+0;4R| z2nEg!&*U{)M^BEC2ktyI6pP1zB7E$XPiDvBlcQH+$Ssjc{P-qFvR(lY@(X;kd ztQyNC+mM?k1g1Pjm<4>OvY9SwTF-SY>fBK=A3QaT)p~x-T48T)EwS_xF=lkWq-i_* z#8UO0Iom)5pc{scnR5=5+^@-NY=ZQ1-T2^A{N8hdx-cM5Fv8XmegUiN%>6l?Ns(wL zx01q5Js*FkPI23S$laTLeWV~9BbyiIZ2HQt1A^2FqN-&t1X+IUFT)Q9sN^pwI}g)o z!6qnr3T3e(PA`56!aWCpspzN|LF_ZNBHAiE9z=5e@vh3?&$TRkQvyh@I7c~F4r}yw z#lf#48Z@g4p|3_V?^TwluUax*zp_HzEQvLltt?vOJ$Jm+c5VKn6sPW4Zk*hIu3_2* zkk2T?qFc6#aLNVfb*Sa!Z&l>x^OdL4dM!sxu$_}1dAK&-B?81eRC6l5tL2q@6wBy# ztJt{J&F|!`aA#G`@0DDU@``4T%*&~6Czq9<0go!aO`dqY68t&4b&Pvn%hI38o$-Qo zsrT2*C|`=Yho@CDZikgJ1fok;5)pWg$rXyD-jA}QtQ^N{`6~@SD!=67$5;D>TH{lK zX08KjtHGv4p!}e?;TyzYyii{a?O2X|gF%jIS-7BcjSX8N__{DY`ztj#+FyXrxndd^ z5X7MR4R~&p+%J;P*~82yf3hFV9c>B{91UBlkw!}iaH+&RLc6C@jhJ*ia=ZId3j&;| znHtR3o!B*LwMnKixK2EF3AMU7zSK|y~)GxNniLaRuWPu7Z$^q5H-v=te-#Nii+>gA8dd$zm%wc2U! zIFng4lAoTQg})5GxNAcT4bLdx;!enz1ue*hzgkwE6XQpIPk&No@((z-GC7B*UwYY979pJ!LQI2&$1mSpzXkN zVe#PYQ|jCjM*-V59)JFrJ-MlP;WZpI!-@6O*ijmY!67D@(d330pC3&3kq`v2QW^9)W2-|zIX)hw;tOHM*od@yT z2-2D~Trj2D>cDlHy1lfzVO;RetaxEx@ZOBCJun0$_fNC(!#>WqU4AIiE5DkEAop9& z;YzvFl%H!^lzkEbs?tR5AK|Ehb-}3Ts?2)bc%?*p;FiJpX0>UCjGk5Jq) zy3p23`1??glxu~bsI67_`y{UDe3d(33P!I5p1;X?r6HzL?>rgM3JG2tFXBNV2H4gf zsb%ETkzbUYIDTza{=*$)-+ONx!lnm2j*E1n*AusUo9$?DVf+rohW13`s7tdEVJegFg7tQ zv9o&DWkkhp6WY)I<@v~YdcN4`wmb-aF_*(>bs0P|T`pWc(BeFOWNQ~_o4OD#?0(oq zSk8Vjgp5=EWv251bTUR<_``Tp z&l`WgH5Np+ZZ_5N1HC7HtGpj8KcLub*f9^V%*)euN`=t&IvR|lRfN)cR5?PoB6Ek(OiK-k!?h7 zbP3vrJzJ33s|CT_I9t#9f5A_GLP2TFI*OeJt=Hl$0`QXT|zTy z<1gnovNH<-b{^`^PJSc1AE&5ze>?@ycH|C$aD<_3&oG^{mB@ScJC6-uQi_!}0W3_m35CEYfaQhN!_zUE9lWg)AhF?q5DJL|5Gyp0-< z$n>nUb@CJc@y`~>_=OCbdD88NW2($=BB+B)PESHjrXr6!00I0MU-uS>ADxOv!SQle zdF$rUBq|5N?Iiigi9a^WC%D6-#A($h1n8qVPA!qY(Id8tTGk%>(jtj$ngxLsJG4$o zg+owj|5c_xF9+4-g3e9&almK`!Y?sv=se3S+*N?&gl_CZHe^nT{$3zAtuGn2|Ai+1 zX2=6|sPj6wq#V^2NJllQA>%1L{+j+;5Ow{P0ad5t?}Vye_HKAY0nyy8AfA?x)6A{t zjxgX5rc5}GQr`SDP^a!}E~7}#FtT_2qVyE6XO!TEz~9XRlgLs;^dc4OKvBF0CJ@3) zwtln%Ijl5X=lL zWxU-Cmn|r3k(j$tvU)t-ypZ`@@Zq$10@uaiM|vRwVcAVkG8Mh2PKglVk9MSMqZVpFu&V-ZcAUme{=1GKoBYh{ zAB&|@&S7fS;Cw=goEu}FziL3gp%Lwy+8}aU0B`|wu(n2)m4Z)6Up*?09|2%RGSIk2 zRQtOr^`jP8UKDqaPG|yYqLKAd7}y!ImefA-q_LB9-#p>YZaa3^P4C#?+4_!(pGd7l z1uw~7#)SF9kCCo(%PufJm1ihQ+|s<@W~)feU@JnPv^!bFAGmXvmb=K=T7JcTNG6sY zzk7L z!m8Hzt;hczu2-kHA~^vWGlLC#efJJ?ITbFxw27*_aSgu6PAb5TD+YdC8uLRw#yH z?TdW=5vmt~l<2|UR+GU^2;VZ?=WT|y)J6>YuC`&LfBE5Wuq9^W?zi-h*q` zr_c)0kxbe^*{AIgJpNUZA{+5If!+AFoEzVSF;PBjfKRN=sWb2EK zvxgD*!`N#d)w$uW=h)b5+ms>13AKxn|0%kH0l8$owP}7t=FwnSKJrADb)5=MhQI^3 zfR;UN9Mm%oW?LvrfWqbQvrCkM4_Ks+l>zp9*hA78t4||QtX;4II*Wnb$^~c-xdCUF&^@i0iiQg~+3oCv9 zHin}u(=-eX2wjZ748F)qEzMHoO8W^KBDZOkW7GQ$J632D-?5)4SrbFCtcktgk96|6 zZa9DIbeg7`@bM%f&VpQY;WE%>!qvlWqD@P?ty0RleKhRBc)-~~L4c_2uvWyQbW17VFx;dyM`a(_0 zvkxTOsBtVxg`4TUhYq~GH<7lE6Q#rbkWTe~om|4$#86Ip-JrhATYr`Tua;kw2S4>H z|1QcgxiTNk$&_rbhV9!rLGblNhwa%KtN&s%0rKo?3C1v%m}9?7zKsZCoq3gWf#W4rCB)PQ5L{_3k+1e^TzRG! zZ-d;k=;qgiHMQUywz#3=B_q}gZ-(2rz;Bh=iiF*&{ZjgkxPGSgOXjy|;~ds02*sRk z=Py7uV)uG)LKiNIIHC|zK9Zj>PWSYWYHcmcypohB&Hr_ipAZV;qwE@^=%6)tP>IG@tKb@j1*lO>0|g1IG!v= z8P=)AtVx2Z`5T$Fxn@pr6KcEV3T5sSA*lH+VcxBeJGo_X4plE${#L05Rm~E40CK}l z20JIT`i=r^0z66f$#GGMp;XhFW%@f$U`0!|X~ihBg>uoPkLQx^L5bbu(=^cs!X>QS zgqUiC6`uUry-EGi?tToIHudoad5}1(oOg}?n4jpvG^?qo=Bl+?1-)bzqGct>dngfEA|UM%#^9UnM!yyH(8HWxpSj+AgE6QYx2V+2vER9oQkccCRQsKbKmRv(ml(Npgt8Jp8 zlz$*%-r@z3h{#)urP`Kce_MS|(LlKuyvfO=^qo+jTozUpJ7BX|9Dk3&7N-<>{8$9 z4bPBJFs%s|3+{p=@Pb5=XS}?V%yvz<}xoqs!&tzrr9tU;_x~SPhEDnr*!q8&|p{L(>qp`;0oE ztJCL0&Mn)B-|5W}M%*7*Dro}PruZ{B%A4F+3i{Ll#T`8R`9+8(IN`(2O&N4^+c!(& zQs#CZ>Bii*t?na^tsdpdo$qVNc2^|CRu20 zDgj+7?qF=k1z5)gT&O5UW|e1y)>A7n7b1^R=`!Xf!|*@xNKe4@lJaAZDLi-?YkE*! zvSGOd9yA$7=OHenj3h9tO+G!c;h3yzwM=s+JD@b==1++n1~HlW8!C*le&uS^msFHb z4{&S!!!gfp$rh7KT69&=h$2})Q5&o-G?aI^carIkYRM}{vUi%eRvUI=0I~wNT~N`b z7tK07ejfk1riA9^r}PfU4bNRGn?3kNbCjza$O3(qtCUMOZmCwHPNGECu-5(gPn}I0 zAJ|TO{;1>bm!)EdIB{O6LaOqCxS>nP^+GO;C;^ASQ+VZ}d1i@+AT}{18x-(8tOR)X zC=eTTkDL0jFomB1VwW_`qUUOet^JZ6yOsTeC_o+Q(g!7hw(yURE#2?j?q&ZeA1VcB z)n|>f{QTGpv=}`KkteRX%ZMc;FWjIX*(#eVw&jvgbaD{hC~9}K@DUL2 z#!ja)*-qNsIX;Hc$V_9BX*wtDVBK-gyncdju{Frc@W-g|xHSsd{F%!BAYxwOO1P>Ic_ukEaJHwKAwO==1gYi+uX5NBFTEs<<;g zyJ@ozbd*#!dn$bYc%7g(h<>u2)am zJ}H2hvqt;dqYn;8d!*VxdIvrKc)l6BCMa5*^B2*GoXyyZI466>L>NgMR5ZM7qGjB= zF~jWKB9$;N3v%O-_bIh}fZZPzZY`CyOVx;$WV8xH+~yz=7p)yTH=sHxhs~eu-=z%B z0gZW#^4_VIj8({=ue1{QlYh$gUs(o>xLnKFiZ<6=w*Z@@V&vT~M0ygnTPZ)|lD4L| z;o%7NB>rh#6;d_gc{3Fp!_ZvvS}6v}eW z(W)4xS%kzUp2F=4=8l9zwicBkZyL_Jlr8!#YEy-K)TS4^GHeQ}WQ_(4kBm}>SmND_ zTJ!N;jZGAA5ET$)m9p?QkBCi3Hr-0z8wHIaPVLTXIfJJRSTH&l$$}A4X&SN9376&| zgK{FZHW^(S)>lJUgG?r|W2+c=iVNOdwKZ9v5{Hg9gX+M2c-;}nx(?TvMBma}F|QJ( zCx#r^OqYDyU@R)0Hl|ceAdqXD%bpl)U@m&3KlMFe$bO{f##-vjPFjwlFN&of8{&<) zpp>enBMq`gp25f(r^gO7BQ3I|GmbXnET*K(_dO8E%CPVwFOH|zj=12JS~KTFoRy@{ zj3gtyC=5JE%PNdKSjj33J^*ByhF=5&?|Z=)xg0;dm_MMF$KmU9cpKhnN_|j>MOk$H zElEm`!s9Mj`0+dMcnx_`FaIa1sH&k&8HN=Eq#*GBuAutQ3fmY2e+hqG@~$rs4Pq(+mC{kL+`}s}oixi@c7ykZ<$sinwfLHks z|2BRSd(PZFKSsrINa26141M{wKq`$JAROGIC=5$3rxc(`G-_I z+Cot;)ZpdG}l19;($=CmI(xJY7Hn0B<3G}zQ@&5_Sf1XkQJr(0W!ea8xsB*EiHT^HA)_-wZhz)0|tiyOp}@WOqy zH>MxY9apz(QGFvnK?TRK(dR8lGcA^$v!Wf{WK^TQSw0+^*qWMV`PiD;c740H!5tv) zVTT+AkkGM{B`M}YT(DWwfkq2M&00;AjI1u9tb0mpo0NvCjEKFB_B- zRH0JMPc@u%N25A`oE- zH{A}UzVlZG1f|%nYA>&c3DGyVw2B!m=_Yo)mycZlntEhz6OFxeIKfDjc&oSE*c7*A zlHbLFSd+0MRO!6o;=#Mv z`f4HrJPO$We94AjxYYm-t{VpfUfm_3DqNUuQG6}7xr>-t&Ie}|idx}*9O zfWJvS4g7eCJtPACHkU@`7SByMWP3^03x<%Y>1n6 z^k<-V@ofm$FLOASXzEjEIquU#E&QVpeYqwg`X^6EbhO7LRTbrhsv-k`=|6YXWU3+I z4&SOy=87`^bF45Bt7Lw41_@Gnc}L8TKV}*H6L8{)$hvBuLFJ$N1g`y58;rAL@2YBm zE|DFJE^>?Y*UrEDlT6Q+v9v9&1U~0IUct!iP=E4N4UGrtkrQ$R1yq*_$E)$mr@;K)q-{Cm$tT?}D3~Aqz%~ z6EI2bG1$XZUcnnm*-8%X6sGsP-!cRT;KnK@lC}TQeXR+>J0R+kU&@xGd7D|O5{z#Q zFT~kC)!TdQ zWb-=Ei_lR`oWP-0AOmHikKszK%|G5xC5~09@eKS^Q(bVlU&IJ@f#zI)ihrP=_Y(7Y zyq|}e27AX6Bn0(x9}Do=q`{0k6Vc%7M2(F(jYWqR2Fu0t)%IGu$C{Y(XeztoI=3Xv~y&H7q_l5b{0~QeqQI7s;o!v#yZ`qU zAJYJH^U21br#Kajq*x-$$V;07{_}nEc-F8LK6SR*x*!=&ivx> zzv;^g)?2gaKSBONfFun8(txjsJ@9{t0{eFako-SI09yxZeJ7#6SPZeuSBitVoxX#U zl(G9i7>S~c9FhVuk1a2!Jd8-KSrsIqnO3X-b1Wo5YC7p)J`60(#OJBcs6|_BfA%a0CW9`WfJjd;};|*8751*bNJK)tL`udev zoWnHQQA81$(6^L4`ud8!D^4!yz#u=QoL_|3vaOUa-VWQ9ppL=XE$TI>p0T3+)KNoe zTH)BVk*?zkW{lM-(Y0vH=5F&GG!R|PL z&|;)6-K$HeMMiSOZ7CERRBi@&aR%C?TSocyJ#e;x<7}A?g--~)4?XIb*^F5YM?fUk zlqE4~3Z)IFY`>Mp31(33Lsi~Byc%)CHDD{zB7q-x8SzB0C78mW>r<#4jLRRn7%6l= zk#pYay`@+j5zp!pj|*2o6s#qXzno;;Su;X5qdpqJCT|F3akgeb4EJ>Y%xygHoSPD^wCeD zjOTAzM>vt2hCApm{yAjd5=Q(aGKbnAV*{;0d`x5_UBdj194AjF*2`J4ao04cc;dU>qZffIYM@;);gBE|Fa-K+iX&=L?LuPi!t~&er!aM~8rw zj?kgjHc&J2>3tuf!lbLn(;nt$ma>7Xz8>21{hJTRhmVR_$QSj{|CgAVe-Eb>_|Hy% z5jQ8}uRIxB8)MFl6A(&HM)u0J#p0}>!fEb>)S&?s+*ExjG*LenB=y*_j&G@{Uut<3OGb8TD zNbfI34BoOR`^=g6)5ry&PboXp(@^)&nP_f)Pk2UCA)v3Iw6)K*ek9kSy&}3il(Tep zVMB6I#Gt%1*BH9qs(OAmj=&QBGcaEMYCn<18GI!4F&;`fLZs|zyP4QXwR56 z-L$bL?*M+$9VpZu3VP~m8q^*dJM|qdY9BRxs%swqtGhD@U=DvW4KGQ2x@#d+Ut)Rq zXNCwq1ayRFiU>X=cEW2%{}T5H7=MM~pU{y|@8Lr~VX#r2;Uaoa*h#OsP<`p_w0C|0 z`yMRj1Uxr@%Xumf9Ep==l(L0PJ^QKHnj(f7arU*cs^HBSRlN%GnlFcl-Klb>OcoNE za4OIvsfKWHONYx~hOZ0pm?p^5Y+KH7~sNibz6OV;Y^&*v&1)yNq=uS*6$W`08|Zb=sMelsFZmeQ!~t1xCj> zB|Eb&?V*85g9>PK66x#-u6sQ3Wa!b3Y(6WL9HpWr7!zoyLNi! z5BQ-uX#%X4X0kS|q)#bll#oSxs?XLonUU>lS2&qpkX8HN--Sk~Zsc(2`lOsU`g2lt z4;OyoeD*V8j#o1?B~GOqZYVUjro7hdZ&&U~96sxlbeVByV5_dz%+E!z&sk+Vp7NS> zhQ%@XI5nhAj;4N(XyfnKd7z5=Qcq1O))*H%f+So27RRqP^n2o_V3mzJgkUtskvLKs zFXppVYW!1a441YlKviKF%VurN%qSefZm^o>#we!%a3ialoFoe5WRz@FC@-iZh){sTY+f**S|`gX0uUOt7N6FoEeZatbnx ziLO9FjsmSuc(Ppb3}UTuCe`X z@p@x3U!#k#(cQ|tW^O1MET-(N1qHz;g-dQ$;4xxniCNLE z%PaVTF4*a|KbOvj^EG*MA#C>=#7++=9+q1*Lu*9$Yb&O1Ui|g7_Y-O`e zpF609TDC}SbH6L<-hB|6#0W4oSDsD_Tv~ZNkJ2Y-oA~b{!&{{I%o39LpxZkx0nu!Ag_A4 zHWS?A>G@ZjfJo}@W{DD=N5UhfwjR12ejZ9FSCK!lFuzj0FNEC;KD0xB2Bz-z{XycD z{4C>?-7cBWsnKTn<-Hydydo(PbizlYRg18$3^mo*1AkZ!%GYF9MA;`KvRIDT=~OtO z0_BC0K5Wb2t`+FIyQzHUxiK8WbVU+2kpXe#Xms*pFB^ZWWV}#oAUOJGWJ2Mm&jyzd zcea>H^!0{2P}dyIxDK8nIoLW54eHiF~3Lv?0JD747rk5Mdb1Ajuwz%Rd; z!qA~`b;1L}6!r4ZV+i^0%_)ue9_ zdkqLi)C+c^n4u2@%A9&{Uw|3)iJm<(DK>S~Fl>G@0=$|G{{eIWAw&h_iHsFKxqWRi zziX|(9w1OOKoKGX%7haV0sVV3!lXlOAU~%W8M))E0R4KOZh!-XLIB5i56C0VP=rZG zyU^VJzNtB;Sy?&mt_d?*_n@U6@YkCLKUz1E>|Q}@FjVs{^-7*dlC}N&d5;at45z*Y?)T7~}8+X3-={I6liAK64Zffw8@2s?KU!ifKbD_mv$fM}1 zanvg%l^^&k9}=XLEC1pD!%wN=ZjZqA^C?oapbI^Y+e+@~)bV5b^jDX!*HzXw@H3>% zl0H^FWhQ6kfE5mJRA#FE=m1KCAWg`ff_CYM$mHTK;!(kKWcY-FHbS9k!E@y^FIjUo z+Q9MPwL62CfZ0oas<#B}&*(j>fLj&)BTIwlcJyw9A-3Qm+r{1W=jiY&%2Ev8uhFzT z1+aBMmNu#WB<3jvlRj5kWYSdV)#d3Ry_!k&PXS_DV=9E90rS{>j!fDUAJQibM|c0bczB>bl1; z1lRF#s+00_rM0oNumH=|`{~r!Efy1LHgl|(PBDeqr8$gS=0=et7sirehhheS9-X^A zi?Kh^27P}J1&udZ%Y{p)*P0wCQHqJS%4m!q$q62SDN5A z|1`3gWSKvX#%zd}8G1rqh}KA}+(mUr#H0?>2~8?c5zWm$iB5MfiIq~?--@0OD8oOi zm`u0Xdp@COQ9*HFRnn5KmJ7L2)CR*6!c0>?4uFi#oYUSB8wlbsN48o<+V4}G#dL6@ zm)n*$6z%KtbXjpg6k1&k_-&rM>YVSxrn;hB<>fG5PlkM-?050I%IFfA%4}&gO#`q& zESqY)vP7bEOOD=ZI-<5{QYGv>n2K<`{Mc8;<-}k;-Hsa55`IO+e(k$*4PC2Rnrw-} zr-yF9!J6Vag~1mYGM-9)Y&)X){GLCPjs`Fal*||*Md9{Bn={=1WwLgmb|Zwsr+8zC zLU+xtAmK1Box?=d-~Lz$6z4FGqKtGcl`@Dx`(-J0hGs(sq3B%{@V2Zs`)hVgq0eI} zBNr~4jrwbv32S1=SF)bh+~`g237p`(GRZ>Pl>m}!FVN%wt+{{nj0<_zJ#7E2$T1(ZZ za+RE(je`uLZLiUZFTgz-iMuo$u^L6h;tz=qtPJ3y??R26SG zA(#>|*?SK~Gw6=5t$JgervXZ%PiAfyHRLB1=dvf)kilDd>ZfW6n$3js(I@LM}@`=bj z!U)efay=5z$~l4vbwv=sYJC#@QIFI5=#C(dKH`bB4z>=-V70xUaW4{OUP(;GbsS3T zQge4SErAszul}yne#m8fltG5zGCI5nul#jCbN*guOY8i*&9wT!$0=K|Vz`^DbzfQOht zJC7rlqjIPfMq^SSkv&cOy#Yyp5K4t2J6^_lhIzPe zqxGE|68TBI)dl(h);PRQ=#W2*CclZQajvWD>S?L3jJYoD*!xZGZ8q{_B|LD@F!m^c zabYuCs6wfGR%kqHK>X@#mBg(<#+4@npzR;1m-aq@CE;(KK!ogpbtuzri$35V~Rx2myYbS6Eiu0g=h@N zHV|z*FwRGwam|LkJi5;PNew4EgL;L})}}hCa)s!60O7aQfjPlif_{y-f1nib4a@yW zBukTIxE> zFSc9(k>m;#O&wEmZ7&HU_x6G^Z$UlZ6eJVzl||{X%2!BHLr{wT5GNnjN*^0PCEjQM z*_xAkRsym(B97n?1)8gyIPMKAuK^2uPyNnhl*dpzd!lucvb1Clq2iTa*_J?!J(D@W zlUK+y3~=uWHC9K~&-htU**_IAZ;)s(p|VUkGwdtw9s}itmoZvGOkOpX4&L7?l_6qdNzZwveO|t*_il+Zn^XTq#~r#(AbTbf$iJAsnI%0sR0&YdpAWham z^Pg@JzCuflRvP_F85LLJMKK!eXxdv^-n!0EuNk3Rl{^)+$j36qSS(7g`Q?d{T z3#=(7YLfU{Smau0#=5Ws5u|ZW7bZwF*=R59>&6_n+UvADUh+ENZ|YPa>(`#&7KT^oJ^!1M&NfS0K3n5wWWVYn?aa?Wwm9f zWYB;~)WgEcw%Uo;2Z7*)E}((GNUyEbvIN(n&-r+fiowpqJWthL zD`4qf`ZxX!z|te0HMtfvfs4g;zuXz|+%wDw7a67{2`|LcJVag#KY za$P1k3G!N9dK6|=PJK>q*yWz_BGKl^!olRGpn@cNt5k4sR#p~309k*cwgNYAxEzqO zjTdw?xj;|=|B$&9*L#B-eZX);MKzOBxU&KBO4EF+F;wcwoE`;f12u_LCBrs)t`K$F zr{$7vGt_Ex%U|p%y$TC4%m7dVCVNxH8<8knJ+{KG*<;OcX2r7NHE6&XA*{Zo9WY6k zk=6V2Dbvk=yW878Bk^}+Zpmj$Z4deq)X=3EqX3a?D(aCk*|oJ z;|~x%qUVChbo>nBA9|Pqlk$~-U-ziCLpvgwc}X|Zl$|QKFtZ+$BUsx)r4T#Z9J&Od zU{KG3RN_Flm)N?5;s75F0bc?8^Q7e2wrzy555JYZM2I!?XjfhPNduum)98o}^Bp{Ftod2F-5950Gry@0uK za{h;?{8(!Ixq`JX-p5&@{4)NGcQGLrGzG=KEKv$UU|x-GN#usb-CM|YZ=DrLiB}|? z{AiJggAJD)&c{6=7)_hWH&?71rE4vlXZcCNPQKZ96B_f3lK)wiTTu4HA zV0+17%qOG!fcgAe@b%U9&ryc2IIC8(79fG4^-jy8tVF5%=dEp>Ssfz{pKq67@{mz;6R5gv*XG7dIE zs6sQL%A!34+}DR?GhlzOjA&~`bI5P4v#x^}(0Ppu@et?uqRJ{#ZW zNI50Ssi3x&+7DoDHG%}Nx+?0N81OqvEM|m5Amo4F9+3@owxYlP!N zs?<9W|LuvQvyII^g26jC~yx^~N=EC9HnqwpG>KL`f+y#M&a@rQaqR z{qwaE8E}V$TQyhRcF|YfH$}&#@Oa$3Z)9a+A0~*SN62y+dlO#UUU!>EPg7n@Urp+X zns4CO*6<|^x^e>#_-l4Vp->yJyDZWG`rxmTGVwco(f;2A3;W4I>zUIMtw_RRoA~{1R6#8_-;cKr2RsQnf2atG29WB95$sf=zqru}{T#1v2yd^pplXkA zsMi>nbl_|)H%qRf0vj2nfGIDiDpXOLI(wwYh(Ryjjbwx+wP?OfHNB3~lHwFH9H)Os z>(>-*xhhS=mdK}&QgXa2x4w4QIN2{_3<}Oz2m3`Gb|~>{;o>GUedc$gSJRU8p2{CH zHQf%q`BZoeS}bl+Aq$mFd6WS~QrJACz1v2SjuxwQnO0LZi|JnDY42aEnT<`2Rwv5% ztV27?G9z1r9tFa3N%IKN^JgB~p=0xggBY6H5ed;Y6(luPi?KFUc>U=d)2reS0J+8j zg>c+#N97CLHZ%c}>-HpkZAQtrPSrbva%jdy`;=%I431q!>jMW--F`+8^!lcp+4Q?p zq>#0S)rk;ZfPcw#FMMVLbaSy>XyEdJ?&U5^++Q))H`vp5mjOYQktpbhs>T~avi<3> zNT>qThB$bmwF3C;uu~(68lpf>rbe!H##VN#*HGmI`@F2i+QU?g&9zf@X>`LbE{0Ew zURG7wxv9qSrBux}zp(%+?Ao)+Be^KmZ4FfVV#6UTNjC_*$=6|#ayMy_GdIDJbT>&s zHSVdlC-Ye+OH9I`pd3k)CQKFWqJAP&`Qf_va}y$64M&_zHRStZ)HpDlz85je2Bk4-KX#CywKlKf}G2&z>oXVu^& zRi!T&-oFs4QfM1ykQ0)Hyw$ABi9&;bH8#_h%Gj0=m}-uoI|o|V{q49^1ngrA+@do- z$s#Gz!%VC55c!PLG$fq^AySK`=QC3sN=8ybs2ITABI^=ZShMd|M-IgGFplbn=(Frd zn2uKp+26@MEeCF|W)L!j>sZ<6JB`Vweukp`Tlrq5h))r^?T#HKLm*hv5x%$%OFD z)9nwAhd?Fb2{T$B!`tQXtAXSbLI46Nn<5|%;3^xOq5BAVw^xMX9}6-Kj%C99cxm?) z9U$?opIScK7Td@5_zoY&>fG}B1K#=$CpXOufyT!!3M5nWpnvI-F#Bewk8hg~xnmE5 zj6!HO=Z0IEd{hq-bGSCh{A7^kS3*M3Q-3aN52Xu>WE)j$7%1ls$pymgtVs8;9m3{` ze-8I1VHB?*v1Ied{lg)`9;5q^~}#b}4DfPb&b1vg=%-$ez3vUr>~mnJLdElv!waHp(tI2cBiwD^?5;wHEIo+Ng#KqGXRmx~{q z$KtmkzelKpAt)t>?_!SRmOPQnaBor%$HeYvwPk%-YWOhlx-(?quGNL_;)n4$MtQ(G z@DXT%w#U*Tp`~;W8RAl*XwUUHfZhv%-DLe?Mq6{ig}GA#tf|718^<7s5fV+9Q;NXg z<;xS^e$RH<>y0QvGf-vVSL!gevDraTwgr_JW)0pmV~i2KGX9eC8Qkrb>1&DKvB@|6*8STCgb)to-j>eT zo+V?^*&1Q9d`N_mOPci#UW(7IxLgP1@-{Jr*O9L@pv4lHkaK zzdUO6?4=#SGS?;@!blV{jhkr7xDUo8M5PYGfxkBz#xz=SeJW{wQjb8^eLnfLSjXQPlxEs4@BmpRhZRGK68RTIihq zegi+~PIpv$8xbs9>%6}2!_(FIciVJ7I@JN44M1g1wS$($^tYJvZ8cf>Sh;nLu1GPQBD2t0H*r?_z7S7YTCc+t7-qC zum0^Oap`IC z#fdRFxtU2Rh&fUXkFgh#GLN>hp`ozTGLLE$k}`LSG716=k+Lv~Yd zutbo3$Us?Bf(3&t&VmgX;C2zM%c^1(fg=30m2GG=oy7sQP7N70E_DxN&x?3FXqH{~ zbFbWrxSfqLJ|_^LL7&1rOi;V1aEY(_rqh#|jz>IKnM_>1?+?E~zM0xH1(|df=@Uju zNC)o>I6>MPQbxL7+k9hk@KF7J1k8>z%#9l02CZh~sKOdSV6l}TyOmP0d~gi{hiCCD z4q`eB;2xNS3=zOHFH*pXYTI9#nW9_r8w)abYzOH#fWKkNg*a)jdXrCPeV;?b`9Onmy354DyJ|~ z58&uMGj-z$B;k-f)2usIm`9-(OSzSs-FWG$4=OmUIo@SUeFL45afmQ2y5Kd6hzKz( zFwE}bvoZ}mHADiC6nAdK+nKz?m$kP1+Q>YPCKxFidu_C)!P1!7t=89?m-fHb9*~y3 z8FsNmw*i@$kI+GqE6*||eOc<&+Xl@rd1tmvt6cNNw z6yu0i+(Wfz!_*(QT2&9aqI|_Q4t^T zW&#P)KOyfdF(FGzkb)rOTGR;ATN%R;07@MuL+rSf7s@8rGSSZNmc3SyFMmv7E@Uxc zp0!IOU>6d$Uv?xv2#L|M{QQ2PN5QY2BTWb4)61l~9*8U^1 z1S}(7N(`6Hi96)jnLDsF8p%yHBrqVFpp}!m^7I*9IqgG?90RaR#{X-#>wIul_fG=r zF;H1vr73Q{Xzl44YG~FuHNfEc-S^LvYSr~8^$(4!DCMhxp?j>lENn8|jOK8k z5jqCMZ6*@y->x!qz7a0y%rdWHR$NIOGOp&jxU<2}e?rFpq(w{Cr0Knk5!GaMsZ(kM z!36X--MJ?Tve-klcAW(`k=s_*nqI6_7Xe$GeoYDZk3O%T=&wl2O=Aih<;5e%HI;jm z>o)BbwA&Va&0pK_3x%4fA!X@o(m2y-F7yDQ!g2Sn%v|eStO>&nfWLe9nbDv1#H`6I zyuibWGHXK9TM?=Uf?xchJv#pJnG}T;(#JXz6v+G;5;-oMg#E7*!b2;c|fw( z=;UM8gD$1gI|6OIf+L zWEH2T#qXWuq8BCdlZnt2(cWIEDgHQJq@)N-Q79=?6Q55c#(;t6jjifwTwcA^?JDZp zV^>?tgQZWa)K{Ptu%$< zDfr4|#T%8%%Gi{aKI98hEHQPM5EFV->$M(SGNmWk4Lvl7bSBE_zK`WwRfi zWS6BjM{lkf>4j`qjyLjaAw;|_n3ePL$DhAxTyt-_13$hlIJ9v8jJ5yXJ7@nw;{SR0 z=D)G_ANZA(e3abuTFO^&pgKIr)3JnchxM-d$cze!OjO ze}22B_JK9T(4`@9ml^o2|7=ejdB{%4VJmKsmpbWSDT*4>|~r25*^S(hp{6LBH+l5jUYQbmx1!24Ep83U9ejTaKxO3 z;pgABSubACW}Y`^qRF)$Qy0Wy^Ir8 z%rh`iSfFEZau9#Y3NsnX<&u*$+6pk`Xzp$Qgb3xT#+b5>X^!C)L7#H*n935B%k#G+o0GzRyOcFmbfATF`69sX(rH>^u)88xmp?^CQ} z03OH6G9^t~-8Ivfi?e}Y_-J9)~NLxQ_}%;#x~7Irreps z@o5**BXktQnRUZ2R;;vvKKdeeJ~0>|#gXUiRT@yzMUion7mzEG8>>tGQj+`p(qF{@z`3mtY@s%hm^gP7=@>1MsbnL!Opx<3N zFxYHtnv9^;BG72cSYrs@xtJ9sdhj9I045{=F7}dMClO^zOGR3PAgrUWVWPc7C_Jp6b0&JbUBB(gK z6O7QeVJh>TiL^o@oeJ$l<`;NJR79mRoZtO$fGtaKVM$j&nj9HSrLtv7nWS*bsZAUO z_iC^=&m0g}R)*_9&q@^k0FxB|=EP>>X-_)ZjX3F*%n*QE=gvMIbGya(Dx{cfWc1~X z&xS{dRHhc{U{s-1PiM=LP0^sv3VB`2)Zk zkKw3F(NTuED*qyByR#9p2ze`kCqi^=IT~h{*fXp1{9{XW2VixpE`@mj346Uy#P+jf zx?%lT4tJmYD|%{eoxH57BUsP+gT{<43DGiX=bL%>J-bMIY8Z3265%3))gUQJyEX;o zLS+ED3Z@-3&tn3TwZMGN{1qwVwC^qq@$3@NT*(LtL08ipD<{!bAnQIlmZ;J+U zBsR?YSt`?o?LKL~@7Hqfs3=Jd^`)KRmmTChD|T278Nh>(s$hdSlQ#vFu|pet3|Ev# z6{kFtmXu|bZGkUd_9+|q&pOn(4ds+*CO60gX!fH9_NY>WCyPZ!%Tbz`H?7xTDOv`%WBlW8kvTNQnf_PYUP zDD*3>&xu-{KKv%y>WX%$hGhA@GbvWKT$}Xvz9M=_{d{E@21vOyWIN?k*G3?mjm}Ic zOP8kyTKnp`sm_N#xN-D2q5&0|RW(=tVI7n~sZ+>E8g6Q%AzCv(nH2-CCB=z3tR)acMd})u}@J4Rpi?YEM-$%jb4iaLg9%G_p@pel` z0a-gcZbdBm`;aonW`v$6z&`4&T02NXcNUuH%a@ER1VWn z(hq1sz0WpsY+5;;S(h;S)rutI`XsOh=899EiytNnf~$q!!Nyx>!RilB#bC=55d6~| z=yHkGSM;WErv2&*ts{8ppdz0&B?@>+w06eW0#1`sbssX^ELLTjFq?%;+EGWWej<@F zcp6qiu&%$x&|hmRNJ^}0xxD4y%jB~`d7H4^*DqM16x`EdEq<(&Vt{XpN98B^!(kLv zI@yy*G}WLAt7vQoln)Ff1NTp2IlO5W0T6R&T zjB(kPl5Fd}RE434T1V#*lj&n5x>2?jp15%nYyCw0=jgD;F}cX? z8szRZ3#^%`{Xi?$vV8x5WIv-HhO#arVwZe|nlG}RW^jm3nBF0~ zmDP){aNdFDP&F;RMQ!V0xE?=MuLz9h+pl!C1GF!J%Fg>7`$Vl_Tn0~n^lfi_MOS6* zAlB%(;P2xMS*O5EPGj^V+a>!O<7`-`;OX7-+|E#4(cc4s)dlbUrrT(58mLl0C*uRgC^Y(B4-f{y&+q}E0m|>&)f}_UwxBgzi)@mm2*CO3^x7z@R?vCAb~-5fyiYX zd4&x1xWVcX0N#!@oG26KJ6DcRV7ER&0g8j5cP`w7 z!>_2Z-MYv>&q(9wE>&92M@EnnPkP?x>pRU}W(HOCWL5?aYv*4E0dFUnr6AodYr}*2 z=Nt=}PCBR6)s@{d-nvNq>Ry1}vistzHZo+Pj7QOc?(*mh|Lez?_&o_q(bg$-)P6>8 zNR!mjoUy~bJb#p5RDYF_wX@T6I=%=q#=rF8{+&|)@54X;Z+j*AwPF7SY{dUiZv35N zcd5O3A}?b2kP&lb7y}a!qUO~@OWM?{TU!%A*|6pT0D4fl{I(4Z2~&fcY0f67a7)cA zYntYki(3oLYY~bbbt{4aik3MgeD~&`CAwQoOrG2NARTf!-j5qIZ$8_u-FI2Ge;#t4 zKB0Gfyx<39SGrCBNQS%PrZij`@-XGirDP7Otd^-73VgMRv(#G0(gJKu z?OCIRNK$Ey$>NIw=P9)hW^+zaoj(0`kxsI5>BWcT2Ej!7m0-Lin)LNyg4LrKWH+H| za>w_bHtj)|90f<=$PGQ&s{I>L1W2Q!Zi-F&^N!jECms4wp^vJEap|4EOCBIoz+wynqSy} z`ZBrTLqB&xgEJWQ7a<{M;^yK?Qo<2))x?tvr1@Sa4j$M6tgQc`d3z`*;U|=ZkIu!~ z<{LoW!rs1qaxwFx*;^rm(+IHTPGnhbGxtUJxbRUQihC4(kCj_KT<=Ji97Ms7@5_(c zS2_&HerMIKleOPkf?Y?--{#s%?|9hI^K5BS5-eFu8c?!R(&!t1;B^%mZJNthTEj6D z1D9*aZv2KMZapSk_~5>HAZ7R#O%A~WrNkD025#>tSA?j^d)a#S2aOVOEy zaxK`e1VD#+JpDFhJt(jXwd4Wtp68N9Du}g~frT|EKnRpA8p3l>c9ru&opIX;-cQ8a$p&sT>8{hd_A*oaoVl2IvB+adn@px2(`LtBrr5lcR~h^J zcHNkFmggSX8p=Y5xxb=Qly-h&UX>lmcY-6nB?!2%We_2&L2`b(?mQXfwixVqpc$-ol!8*K7kRD^#wQMA%1Lk zT1V&wHx7t=)5|{0x(R796VF)z+xtI2>12|!C4TJTFnGq@X!haROZ5L?g)Q6Bd6($R zvDe6)DG%C2k%`HWt&^{{65S#K+kE7WEY6v~4=^Ja7gDmrCNt7D&b9pYlLWSAQ_Z~L z^-ho3@>ApBt%MUOB=Sk5`4^=DH9AL&WL2Q98n%tfAi8FtiG&Ye1vbBaSNa&{vOY)) z0&8G$mO__F<<~PpyXDnZ7ov-H;_xCdVixxi}ge`5zS%Y`%3upQG%WAuORjV zm(XMXtLU7*h2g2&<1?4I!H}z`A8TxJ))f=d$OY9ZoOhd(%a~CMnWWA<>F7h$9R7_J zVbM(1z5~n#%_$O}ISq%yu!;xa-90rVYWHdm>wdeFMl#=%gu?c{=X2uiWq^sjRtDcK zLHHJ-hSod=ukLIn0@*NNjo*umiLEj0h$CBy1f*_+NP4qQhGnyNXzz2SI`6Hnz-!aG z1e!yzVGV<#6d;})B5hr33Hv?he$###I2mHCA{q7p-c}Eh@T99vark`#kh~tT$asT! zSyP>BvGZ;FfC0#J<4ad;yJOCi@6H zHXRcC()^w14R*xDzBSDx4!%A`;!zSZ%{Nrv$gy!8fqOnu`a6MVlu^ys8)XqhA2s4} zhP;^S%^+8?h&`EtCS4op>kY9DMGxLGoY;)^fYAVSLfzq8YIR9frORt>D0Ti1R|2O2 zPN$f!vegCyy~8N?O2smj;NZeezNzsGn$_~NeLpv%tVqX_9h!a9#*orZs6fnk&wdqp?o zjG&EDPn(8&4xXK`oaajH;Vo^>FP3XzTDKO>`Rzw+>A#5G7CCq+biGYfvg~+JUkB4y z|0vhS*L3kGXPgB=E1i@{I!0wzo64!$|Eb+j?Q5&GEF#L1V_6+s{Rung3>CB7>dCaE z&0^^rk2(#}V$G-*1shYjGc5%f(;5f-m?Ae_WEX|rE+YZB|9{~!H3jnMkfD|3HQ zE<61%uN)f}V}~!f=NI?-GXHS<%Oyu&z{$zM+`!q%_-pO&ul}PyqO9{}kb}%41XCo1 zAk3>`BoHJR2i8XhDG~UrJS1N_*K+Ej*i74yaY5}5@rl&UpC9&WvKPa+wMr{*#-g`3 zv60qcI?eNB_;_41^Ao6Yr_CRC^2C@m*oy54mY6jNlp&JfvqDbw;1g$$bboSIH;ty=^=q!n*s|AcL)XrQB`<(T+ zeuplL#W)pfHOu4+uz>DoK~-Trm2uUn zL#+hHdsLJbzFA({@sr>qnlfx>uQ+w$c9H%Kz91v#%~;meNoI%@+U20C>O!0j^m&mI z$~Nf#i?nx)vaE};1v8Xk+qP}nwr!gkw&R9v+qP}n8FoYlvg50IRsFhNSG{`OfA$?? zkMrx?v)5j0t~uudQF^LJMevNJ(Fb)ctqE=lS>DKf(x$dg?h@3BELQ=DpA`1sg&msf5sO7LfQTT(xB6~mO? z#Aedd+zW4q@;X^bxX;BHTF(vx4Qf{fC0vM#>*C46BZX`u&D29)GFTExIzYV7mW%E; zLnX}TDs+55#x=7>Yt{EGTMVPMclw*_$f*$l2AN$GB8-mYRfKVdG~4&R(2ec@B(nTp zTG4-iToQ|G<~GF1qi7a)-k9s;o6ZIJt926=hqlWi5PyKQiKm<&45jYIUlD93y$8s- zC31_7LgFGL4&$C7dPI|yMA)$vVA=H13t_}a&7SrYUZ9jGS*sw+mX~0wh%l_>5ELW(M;DSy49 zBlkE6g6|dNL-AnU77!SYJ_g5qnq@y@JHt7(YMM?gzlVAX;gUUxR)_48rs ztaL_`bt?PvOJTi;LtBcvb^5lZdrTl3C}@?Hc)SjUl2-p@F~7-|Q3lddj128uKtpxR zd5#*Y??R%B14|J*@O|8Gj2sI*iZumQ{8l|v3YDH3gsn@EL`PMPa@RR=%^ZF|rRqago_AJ66Mr?jR zuyA+OvcUC#O(7o))cS=#u-aGX7(@~kv}sjpo18<~TjL&Rp0ofDt9XTzMcNAwUFwmD zZlA_ccA$de%WjX&Zsqqb&_9*mW(^wj?swH!`Q1?YzdyJC7_ue)k3Tml2g84Yw2`6n zw{60|QZgC;H9i;1PD+6YB2>*-A7YK|I6dug3eUkK!~_bB5$exzZ^|^lFi%eX9`zgp zKPnv3b9%I3-xgIAT|Pd2huH&)0u~KORKPnhZ@7267t-)`={nA_o@qGjlUwLGrYED( z4|-zE4cwIc6)hW}J>V=e<1qS6F(Q7df_q!f%0{MGoHQrFBx}17JH31R4hs}K>qm_}AOZ&95IC0rnte{Xk&jKOz~%f)E90;r`Tf`3p_FwASgvqRF>4Eo1t1H6{rnuee}J&Zdpg9R5A}4+3PY~?#JR{iI)3o$+8d4H@r?k} zKiNkGtEKXg?Y{sK3e29ElhEs@lKOVTd+zCT_khh+HzIkE)Z45 z>L0?*oHGKGJ6j0-)<8>G6(%@^_kN8J)z!%7HB3rbl=DrqrP;CGC##)6WHpMY_ogn|VUBTXY5BeH)q#x(VkTs-$d$5Y6CRf0xGigcQau8w1g(M2^ zs$k4H#Uz)KazR5*W60}UYAYm#vt3+ZqEkVoOlFErM$Q?iqs5C zSb-ngqc)7rG3tNn*+x)jgcPlmD63HEOK`Zhq-$@@CQrqEt{#$dN1=Sn+Wa2atG`7D zXzlB+oO(>#WdMQK!|dYbum3YYyXyMqO6!D-C3)OQn?H-yrhAjAv#}h|_q#r&&8Ysa zWjO{tu{fSfIE7BbQpvre%MF)KLZQd-ov9)Dl1Af=Tm|LEf+OaIz{4k|2NxlP=PZR^ zOv+`mg+kwpOtDLx7Nc;T+d^C1wA8F|f~f=f^e55g$Uxw9MQ*36fr_MCHVOTi7-gHp z$V7SH{Xh{m_~XnzsA;}R#I|Sx`qHmL3%$07uT3br`Pss-E(|ETBu)4u@%~7MU16{k znOhR74c14_VSLGC9Y4#Gxl~nLA__6yYP3anoWIGtBJ(+jD5ra!AqAC6g#ja!kD#bC zVpvgiD2g}ROzkCKLd1tzf{@+dfeC*`LaBBkq_C(;KYp6J7j+aZ$R}x2bO-dYB2lLF zCEw0_q(pOyw#N#<{br>cZAq5Cj0*OKG;O1~a$;1SrK2kG z*c#*#b)wlF;z+>&(WU*(yye7tF3 zisJdvQ|ivY(1{p_M` zt`0^=T8#$@k_{~`uVYyK*f=UEhI7iZXINa@xzb1do}{hhLulqRvb-&}y-g5sQbdU; z>1n&;uVo|L>QaKXSsw(G9Z7Ww$Vc4r=H>Q+$SfWxoSOQE7YeU^{NVZ{lQ@IJiz_{? zw|KfZ$xsYm9-$BfyYYHtog!hZeT9vaYdcIp557%e5F_fxlPA6Nj8aq0sQz@ZDA#X( zPvn*NvMe!*lVQ$zGNv~~JEZg+;PYfZK^R#iSx@X|_Fw~n1;He#>&53nll1e^5D*jz z$#tUA3zMUu$sg1@90?iPjJS=WJ3dcn_;N=W#1Mi=JrUz)cj1&R=9O*8 z+kY!liqU*2o$X^IGqm9%?BbL(8nQi72)B>fdH)anvvkJ)F7&H&uBaVN8j)Met-WP6RMzPZ$_9$*w5<%!JT6;Tfrn)|Hv>XX-jXE z?Cxp3f<;`wS2Ja5?8o1<1JCQJ=*;n*|-ii|?n3lWv*ao>Wc44(DDm9= zb668A^qm)`%SSSoMiw(U=)!unc`_uF9L>sFwfmer@~|d$1(I8&u(b!Qu(gK`q3jNt{h3%h1E^r?tX(nIFqtV*R8XnB zbe=k^w{Sblw|I6I9{BhSEGFiqq433W-!~5|`&|U!j&kr1jB4c`Gi>f5bZ87Ta~o$l zw%r?OYP=HG!YyeJ5%Yu;>0@)Ky@PbWE$r?AH`uQAD-b`EOO@Un%O$Ak>pA&G3nno1 zL$=|~Un!4J*mN#9VdEB3DP0cX#ROh~W4ln>-R>x!^W-m`pNpbc8UCF_;o3M{IhmGmr!D)*6Ep)G~nB)XlRHtL8Sjoy*M1hGK%wu#B z_|}kfoCRBlA=4+TvzH<+h0A6_l;H#w!#kbcqo?fyz3jCN`YT7L37!9(#YgNkXzU(qrb^jdv^+DnIKdW=k|fq*nEhIj zKaR@+eH!Ow0bEmd3wn6_*Ry@h3XEX(>c=cj_JjJYkh_kMyMa=5PS}wzw52bm_Z%RXNg1aP8;Y{|qNRO!0!Me`b@QI z8J;@C!M4|MiC&)(gI|&DK-DA+RwxQ1v{PL1L0*YgUo5<@g?%2~@_a;tlo9hzID$NJ zNH9Vzo}){Y>Znhm&r1+m7BG`4d*%J1UT+l_{A2jH6jk}Dzd-@ig^?QQ9$Y@Pq#yNT5r z&>lFds9)rkOqtVcvI`3(3TMEGi!4_u?6w;N4U!X~vRH{M3uqKc(UO*fAUrpzeg=1>@GaI7W$+x@C_C- zZro!lj-ZD!ZTJ3g(?e(^$#3b94!?(ZXZLB}n~&#saFNevH_Y7UH2{A0&utbwKguEh z{r)K5he$mC)4n<1hfe%#ly48gAv%*E<)J!KtevGTw0*?W^_g9a&Gn^C%;R;q+jEQC zONcQyS3$i-lXxIXG6R329A-%((>uUKjTZGefq}j_x(vz6cyNM_6riFMp%7PYT`tlX zT)e#wD32-g&B%WuUv{8MW{m3gflL49f}A7f>Qg*Hk{T7jg%84WSGib|)8m1%cVRG$C-0d$PG z%m4s=Swew}oCX75^qRv_3c4Z|<496eULxQ~WSuhT#bRNy(!pL@0)k8qlG>8F=;Wpi zQZajcq>E8*J(Gk~)#P1oW}Yvu4B9B0xWYFpyQ`{6@9eawY)es0Y*`zC^b6i7YsyJH zx`Yyz#mp$bLQ)G8aptzpE-(JsW~l9E%RvEW=<;+MUY}u}taNBpX#2cm;B79wv=bk7 z9|f*5xTKU~N)}L)JIxuAlwnl%vs$x7dJ7eD8QpZbiVL!RL&m)6m1HF%gxg}=`teW4 zdqZf&=8v9eBMkIXS10KfaS{M|^7eTZ<$jxG3u5Dm;(jC^ZNF$E*SuVA!rY(a=k3*n zd_2|D0LxU0uB&P6OmoZbl_IWz!cq^%N=>&~}O2>CP5oMEG z96Z z=CI(E24qkY(1NWLJjwg95b12ka4XqYr*04mJL_Ho(kg2WMrnpX71#$c_w)1Uip&fJ zn|fdVhLRMRm_AS{(m33U4SDcKxlxDvNW6B%vbz0!0Ijl6VeOJ7*#ST8wCk&i z#fgvdEW_5LiyzFk;MkB+7?ZkIi{qEmpMzUmvTun)f1t48mVY^M^Yv(wv?R{6$`Cb< z#xrPDZLv70c{#%H>8|gmcZ*CP+(?=~wM`gML^cJ^FAEj_V1WUji}Uyaq5vXcK;bV7 z0q&4uQBYusKD`bx`Re+kx8I)BWy+EbDo?p;jx>XBz69Q7a!mNOeL=tPZr&m`>|m(uVC85n>mBpfK$%8w!Kuo{?=QcX1axK)z5Y5X_XI?a|Mq4D&mfN~k8d2y)yAfKzIvP&fd^^%oNb!*G11Z|YM%jzWO z=S#vmZ4YllwJxYlJ1x%n_Exv*iLQVw9~4J(QSccyT`6waNxFErL+`6Ek==>hNUp*| zcIMWMN$8le3e^lN^USNV3(C20#Hi|EnSNs^=k40+dwgWQc?3AWDSZo+G^2`T39)b_-im98yN%u;)CD^iDEwH#aXO9a;%$>UJ{e=ovusMT% zFKz&gGsZb?MtA7b=k}_J-$TBtDHt}b+DS8$vK;#U*lqqYE1+PBGyVfWEBYxY(sc#L zKXpB-7GCv)B9F1#xz{&`rt7vuWe+)|u+Z~e_$RPVuf*T@q)EnG&>q&TZ0PfTq8DTg z5Fdfs2o^acyb3BE$zrQ;0r^Rvbc}ctjuyox#}P>_jFtw*<;s)h`n&vi;D#@-x}bVS zyDdLa9xQDE$gXpsx!rc3;i*A_*S!+bL?D*SY)G4J7iu{CkhX^Jg%<}1Yz4=NPGN9hX|yexg$d>7e0f z7IRj?^;MOElo|u*$i5o#HCQ}@Y`8VmYl9x5I(Vc@G59)JxV2@EFzmGiQ3H15OEh?f zO>z>fCtXnk@!My#fNiO|O`blRzlI@)aBeb)YgeG}0PwXu5I5SmG1E*Z#5G*d&P5O! z!);v1n|^Q3mPIHoFauXK4NIUkyuj@%ATr>Xp-RsE_CRMmO72G;`QJZZob^5k>jR*z9AHMgV3+ zhm~ZYlQtRK1{E4WN;E(V)FcVeX>zw<18HQw&|w&oUZVON17APk�PWpYjF!H`LVA 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

h%412Bj*X}lO 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 z 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%0DXAR83N$1Cuu`z_3M+ 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
a*~2e`2L3MO>?fVIZkMbn~iS`$re@HVAPIC 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

<`kfRp%5cZFLO2d&6MJ zqMhyxFN1l^HznDi-Dc4US!(rbvnxfs*yd45>(?A(i2^HEu+y1+L&KJNGdf^b9{g5%L$MP_6aHS z!uQA%X7f4LG-~xCq9$ss5sBA4uB^Pi9|)LyL4+mnkkxnNOLiSTBPZ^3j^fT;oSRa< zP1nR3+IQA{@v<*pGcN6Ge{;Q^^LRV2LH2@i^Y-b(|B%Gx=1TMp-h$MqS&G&lJ^uNH zwLq!ak-MuA7UQin%@-8$vkfSP$8xCLD>4O;#XmO_4MgjvbDC7VWK9R9BOaz?ctJEv&3-(34ULN}Mf? znUUN@4~kV#!1f>oryBA3#mU1RIyj5g)Px)x!CfmVr8nzNDx}gqPB#{4iO}) zCb#&a9@%#ofokkl27&^!!66NcW$W z#4yAeHQ3c$<&O`TRehc3;d1|!luckiw3pM5Kx(>mtak0^+G9mRG4GkDK}7f zI4_tA*~Hk@asIgj{HSqT7?|U^pB8bX+Rxy`XTU1$lq2ESpdC;#ks%of@XC5IH-m9eakPDKxAF!0mR&IzuVU67K3~OgjU!?QOUe45?UGhR}J!eS_OF zz!GP%M9-IV9J7sOCk@WQ?te5qCv@GyeNr8L*Ot-oT#qWYDv83qUjX#E;IH|14Y%U zxy2sm8e^7Tt=GS!3^>FG=9;k8oZs|E>^6-&fuotf`cZn%GH)C4hz4>&kUaP>No`4s zNSTr>EtgMA;6LhWIcjg2W^ak*V2NdK+2=R`Z0W+#NPPBE5K|Ko*N|jr)LcLlW>paj zfLo>Y*Z3{8B~2p|YsDbdA}&ilHdSY?P+I7;66)YQU5!DB1?N+nfmDCYMRJ}1D% zg@(BX+Y{Bb4W3xyCRJr%S{VPCO+%Ve1yAs)M*{=64eAbpSUQsnaD=iC5QSUep|B zrYb@z32NUvNz@7pQ_9Cr*sL=(AtlX+%3KzjSLJE=r1vt@(9t)F)ZNcuhgcQrnuJpBsZ5}-#Si}bj$;*7Hizvs74*MhJ(K?u>3`vYh3$>(oQ$juT>macD_Y3R>LPoM zjI2Zeec$tXZ1rJ4xMC3;Agfhv^6!<*3n9;ojG5727JcLMN{abH@I9UVzN$i>bR`D? zz7BI7c716-^pf6uf4My;^(NmVh`y!^6#b!b!S+rG)qhaoC>Ldij(ifpEc@`h2QP3_pZ&aUC(K ztv2^=SxdwD^5>;dWM~+s_Bidb1jO&FUO}F7|O^P>l0#{?MfP3mT#exIl30SUE)wZ_d zQJ&CSx!Kz|M=kfGU-%50qXj_z??A91Z0K9E-hDukAZ#P(m%GDqL>LHb{nVn(QfD0a zzot3zX-(Pqj~MA8Ttou{D#Ol@M1MRmn!*=J;Y1I1=3av{a5AMkpc7(nvh=ZCKyt$* z5d|d+277rku<+OhUw!;qL&*LGt4946LC3kF9_05wA- zS|Agx`$?_Grw$rI>01vmQwcePKh*G4qgAA<<)i1K`Oe3sShT7);>3huY=AQ!h*6n0 zPnW>406(Q`fBd{V>Ik6*=z^TU%Q++ba-Txo z@6^vYEvj6KHTm!VB9P%8AQIMoNm<-~%zXamKg99hh+QYgzii|3HeZ`z{(a(PD4!~S zjmv$IKn%m@^710gF)XP&^Z{%tbi;~^1^csA&z%_9iTw0Pq)D7>UcPw-K7hWctcF@? zmHj$a_e|>KQ&H)1FwRx-L-X1@b9h*Oe9z#1KHc2>{AP=-jrg_bBn&|_aTKLxj8t~U zjyVLE>ZqCII5+Z?V?>NuyYCKzilDlMU!Ms``=BD4Ex+4ZKVd}?jqF~xVRCtt03ufrTkX|lbl?MPx@ zHX7h5)4!x$j#M?RQu24{D`)Z#A8HsIs6Af3!DcY5~IVGFZqw2_}_6Ek%hyIJd-x8JzCYN5Yuy&Uc|V5hlxXSJxOQMf_n zZJalrrferS9agyCw!tBV2iUmFJx;OcMcZ)TnXn!l44(v6@&$3bNQ+>Rz`Qp^ld&1p z1c&e(G541tOpQ^MrfIR7L`1WKn9na=(px5iA#K_f?yyYsrVpZ9nPyA9vBvG6^=6#uR7raf4)mgzj@zHET2XuNj1qjyo2ZS)gE~ zM=w~mej>*f#t&#S&96p#Wiv8{4q?|*Ej(+J+m==;Iu9wmjyPY0nWg7=VrrMB+f&YJ z%lW>H(@WyhfQ+3o`5bxO;5^EzE~U3jd8)DG&_O+B##WOtNGS1Q4Qvf5wKhw4RSwGc z%5-*eGeTUslPeq4%&{|x^b0ei1CZPQ^3o|y4S2$eIY5B>&_wWgUpxeA@_ zJX2NZJmVmEo_|T!qBa7S8I~_!O8N*z0GHVsN_jwU#DN0tU--N%k`rcsC$t~cN+IK{ z6xmViQCW7gT{QBW5hi7(NoLA{6X$ohAbHjT>y*1hU~R~@2gh(6m*_zh8`IEFyfe@z;0=tBf?Q)#FQ6B7&To|YoG;xaJOVWn8mk%S502B*0ZsBSnu(84} z!|GNC?R+;3PkvSZw7wcdT*iAS@d_Z%x@S!NsbQ7frkf2 zM$uccrcNcpR8y>KCeSXn2o9Rx{)Mdgb8n;Z^i@dU`@&ZIpA*XedA|M^oB{;{dox?d z|1njsU}R}z;Amt2Pe)+Imm?5K>FdCi;xywZU<%L|DuCoCPm1SE1TJjQ%!gUx<&(2x zz?dOFCK{83^!=%Q?d57m{RvuGfZ}nL(C{Wl)5XXrmS)&n-vF1wXp+^@)iLSvuwimD z+4cJ!X6u_*WFB17$~AW3ZgV&#efzqPi>;FA21@LsK0rsb5@Hza>wS+#L6VZRr$54J zj`YB0r0X|eiNqocZfaqZMBXLaHco#@gw_Zo%%jQ?piXdPEYiSOkFmAQHQkRh7n?V} zGt5bz#4^?n2Q!INpPq?B**7$wK1ufPEU7(4cX+AS!&>&uWEjuQ;}D*%Cl2@LH5a;V zjgd)&G^$)0hPq(Wo;q|?;BA^H3#gr7Q;^t|tb&e57oLC-EnkW(z$`Q%ExJoH>YH(J zoIO^Hr&gg%2jA>jlBetquQaZ^|0$=Cu^WkmRCm&zN>%JX#D*Hv%+iSomS>d5dms-h zS8F6fDxFrLCLAJ(3kh_07h6)UE9Jm&q4>?v!@Ciok0~7qQT>OrG~-i^eq@h}6nbGM z&7_gjY3@io{3^M*xt@9hH2q_MoXLQ0ifcSd72*#t=RjR$UO{C*Tb7~}Gi@%^C}dXo*w^#+*9NBKQLxqzbI+}!jLZGz zgI6D$U^rTF_;oqbT&n1t>g+(MoFa~{+T+X+S-PIAD8ci3def?)pd2JHY&P?40m-bq z(YLoIbuLBd>$EBJHO2xds7=PcNr3XVGtb%4e|VG%Cls zA}Y&0qN5z+GfEr z($fO=Ef$s)Kq@lbhkQdVpjul>y$bV_rFV4-fD{*7`YdYu(EH@n6Q;&Wtax>h@a<&@Uhmj5D9mOGn-eLPzu><7d# z>!LGlmQ|%KToTY9g>LxI7~f0F@XQ)VRO&epFPt}=n4%-M@I=8o2zA0}T)DXiWbP<@ zQhohrh!qVkyEPOSqIh+?B1-L~qf(?_J#G+4Z6F)Kt?%^o$6a@4+TDS7xX1J?up*#< zEPycT6zAH?;!AK(Lo=3mUeF}6VR$ZI+*Me^{(#C~$J=l(4*nypjho3MgTJEC4Eq;HR3L7Hal_tEZ$#>Nd zUDh;j*MI?k16&YqAjBLF&x+i^)!KlT z@2^iuo4-tH{}$u>>JR|z`Irxh)D+x^m0BW$v>Ko&K3%n-{Z(Oxfm*87SSN2HEGTGW zE^`TkCgXl=9#P;PUQtmtKZpZq;AAY1<8B~HSW!{%JtD9cqz8T0v@?=6e4^#j3+2gh zu9+H4 zoL+}Lm)Cdn>WHPy2$#Oj~N?pNciQrJC3^7ng!U$TBM~y-?r4fQlAf*&cTfrQz zBh#e!IbHV|1ZWt!$qHt<962)ZEllWJ_C|}A9gTT1goq_cGN>I6_olHa61Fwr669LW zRPkvk)|n;+l$dn7(Ez6S)HhT5>bX<$aMXGGkQrsN4gAcI6|zTM0m>APok7ZS6+!fs zsKp#Tbpw9Zr7EUYJQaEOwb^_$5eywZ1rk!vbCT3IbE#3vt=$4>@@ZTRhYDa;@uMUG zG&j0XR*A>buC2)l0!h_RW?|5@_ftmoN*mfVfOlW}G=89*T#4o>uKJ8t?l}QIe48MC zPLvsx6Jqad7Jq*AeCbD#JoWf3b91ex%FYP7Dst@O%A3dM@7(GMxEB|&fvx+U01+jo zgQ!1wO6LO=Av$I;n7(zDB@Nc!b1WUZdD(K6{uuCeluE;aIWtVnwJsz^zKr8&EY3O4 zSzDQ!l~hI<6HN!bwJ+WA{v?{Tx+*DW5XzI){ zT3>jGY+Q+aamw(&W&C+B@)!uLgu{(6zB#{hIe!Acr!|WbdZVv!uZqTE)Mg3z?$trK z11IG4>ryg#qrR_eRHxt-Lr+8>LSU}}tWAKbC|J0e=)Dw0EoOe8u55R;$pRq}@J>UG zECDZD7weK*j+Ls46fV5u`9o=54ZkwMLV=<@8!8aktz7~M(V)jR*mGCkm~;;=0A@eJ z3?D+M3A)N8z7nNJmaZ}OO400xY#g@4FteDxf!5Vb>U58LgX!F6g%WexV}locM2EpQ z!`S{cDG(8@=CFI#7IO3%^_`B@deNZYX%mcp0)bhd3HdNI;v!XLqPfj_0FQ!U0 z@vWNJB~-Z(h_G8*8&oBFaSxLwaH@o)^`Lk5)m3U)tA>Ngpppz7qD-foCtANMCc0_; z+bq>}%bO;u7$zFNL3XNc1ZT83QE5zOZA_lwkK-Rh(v3sq=lLYe^#LwWF@=|wT?E~M zJ99=NzO+bER886j4!vjLcQu1|uu!_;?ToRi8-yf+3|b1ah|;!Tc~Xq$y#dEEXll9}-V3Bm0$$Jarvj?^{QR+=U)?o4W{ zsF8!Jinnzur5k};96>@#Kc_iU;#hxui~anKc^ce9{uq-@WWk`!kcm zy|I+CRE5~&+^ht`%x2S8ekB&cE!PMf4G%H^;Hd<!8&edVk%^| zTDSKmguu8cGPIH(C=ra=-c;YLj;APpIePh;lz~y;#2Lf!B^h$R+;HD^H-q1kOCgC# zK$U^xdtr{+s6=cJ(RYxYm|#Fu4H@%dngcVU*4a(MmK0HNpsW@}J*Rm>L&~Wj<$I$U zhlY|Y+`t1#LO-Y`e*gQ6Esj8OO7%g6Bf_kknxO%aE@4R8#GhqZ@vKhKWWLhc-5p@< zav^>GR)-`2(<*=TCzk5IPk)Io@v=!Jbm$~nYAwryHKef6WCLL#!}H|O`yZ>ytvdXy z%O|2?s-#TIz`SQ)cOl*;^W!!7lxF%e`x+80cyxrA@t=1*zCaR{+}Ked^$mOwTmfPz z7yk!o?-XSVv?Yn2v~AnAebTmV+qP}nwr$(CeUc~f^4?q3T~(uBclCQ8`)hygIp$t# z&4`#0-1;KJ&O^8?EZ6E`x(C)Mss}=pH3Q3(!W1=gw8<`uxWUgAP9*o4u?LvJyj2UL zXOzJ;D)o4-6>FiE%3DF1%J1abg$Jx#H4D5QDRmd0q!h_Dg_kJrX%cK>H?fC4D1mLc zk7grML@YtTdXrGfUZAe!>`_FNF$WYVvJb($GP!d1P0)Blrpg`hyyXj}XQVP6l-p9R zWloh{o_^|sr+4lsaQpfwv3q$DY(Wv~5aO(79V^$X$3`{Fw-9FDCSw`Aj8xSzU{AE+ zmWr$)E+K934X%Vk(k4^T=fHjz824O=?>E-tL1=OoqG z4Bn=ETKuIilTxpgFOVE^#*rKo$=i!x^1|Jnw-D(hn4hZjPUtOOOt+}2G)G10 zo!nEhQ2ECh)|k>;=-2bSr50l>6>q5gz32|OVluA5km>hBxYt+@GJxE{a%!7SdP+=M~uYx9r zB$Eq|i20yVoE|6nfDtKvaWqBI$DV#uMy-~R>#5At$NSokud*S+H^#b zy@z(P;pqvHSNhBbH8GjM<<-kqopilC)rTwB*9-INFW2rT_N;r#S_?(%;HxR)BpMTk z+ZhqbiWw4?+ZwyfCJv}VY?`COl+0gKOsfi*Z~P_<@D^tsFw+AN6;z??FM3PT`JUMy zOuSYPl0Gyak13_2u4h5;gJ@ioB&iS5m%(!cfZDjYU&;KeR4!J}9k3MP_(F@}=8AWTj34Hos;*@LE$qO>NzVg_<3@gT=zqgf~O;7|0GBld(aWPIfEQ@r<#X&W` zj&M_h*;|%T2!)N4+EiNGBds=8AGoCJz}wq{zMGIt59YhG15I9*6?%u;HnX(tU_UH= zYsm?$(2{7Ms#$I%4(IB6F>!nIt4#}8kBK2h0^*i-7F{zTdubUhc6mayayWg-&fzzs z$JqQ{az>IPjJfQu8=J|^_J&D0#|`@7{xX1t0(0%GtpTn>Zz)r~SEUhjj1Hb28ce8> z1Ccna#v3N$GAy$S1pvzt&f-|uk$9ehr*ogTrul^7`z@;#6GgkoJ~h0QzLTQA6IraH z;%{jNK!(Y&L`0l}t){mD>JFA47k#`gCa>N6@4M{AW~8JN4x3m*YgHQ^gq^!&(BG^C zLZ9pl-yw^Y-H!g}q2W!P#D`z!zRJgp2nZI9AKF7_y?FyxOZjL)@LOpF+j@St3`5a> zX|GssJnK?#haWKfR(;ZP9q$lub%QJ4+?)S=NB`y3vaBM~3cY-LXTaTt0n75z)l$)s z=lDg*6_YgsaD*FJICaSmYO202-xecy9{LykVPfL%K87IgKKhc-hzuJ#bK9#21u`?! z*Q6a~%K^4ljPTvzVZinlP;Ote-~AtPuLz2`(o8!h!}wB7J1U20viz-n-`0JXNEyD~ zc;&{)iO^O$D$@m0n0$P&!66tuhk!BzkzZGSU|bAHoLeS(QZxs=p<%+|%%K*l$%!<5er?RZHqsbBX8Er}qFVSo^rR?E<&@DFL4DUU)aH;BAQz zD8Wg0GBZ9|4!?v8bZQ4LvHO++$;F~da2m|%kDXyAE%B)CJhFxx8@?rwQfX=t-&zdl zbqRI#pf4nj6eIJy5Z`tT^nN^hXs1%=&iQA`9~4)A?gin)b}uwB(>KYquOo1X-L#>$ z#ho?tJk+|;L^b7CxVvPSy(J6P^i|`=ljHthCg`i_5RLT0-gvi8d?oZ$Iwl6FjRagZ zZ1(G1?^Y__td+c(%DK}Ovj)q|J8W=ySt0XNXt!)SC|JBlpQU*Od*?nO`5%fj2*fX}*+z@1X~e z(6cJ+dP3hIVckuRruNzg*$wKua*IhXDCttsS;jB*hPk?H1g7XJ(fa}h)!2iCf$#SS zs7ZI+#Rnj{L+o-zF?v#p-W)R193s)(J^CW#jzeIMFl7yZU=PKu`pmh*VZu&gH#E#! znRV^ZCE*O$iR9EACPgbgSx`6F7$9tk%e(tZitv@M6JMVgPKLMk1ScaQ(ajvt2 zX=@w1@hagk@&(4Y6NNDDG{@-9q3*aypMJDN-+dwvqO28s`-CMV`K8mWP?^?n+g6@u zCYwTRo46h84?h#30r+gaTFhY7{>c=Yo5)aHXx0n8cK;&?HiT|pWC{KmBrHne+Y>-7 zk?TIhk}_8}EEr#vemHy9hn#M;8xF0Hn&vb%3l5AGRU!26ZIykZI0@FM>nqRmp(JnruZa86YPF~mYeczk&o6HO`K-tYVt_K zCQ?dwTst5`>5(7MPy^VVu~+bM`e^#QvCipHkv))3zpAQ~d0GSzz}qmXs~g}t!7h~{^tI4)MV7d;ILR|nt?jTWOY}A z;K3(6Ye#%sz`i;&7-g~n>hvdnL1%>G9gWwfUHR=^XNo!ZL?y^A6RUM*29?eTO$w+c zWvCrO{ZR?Dfn)RF<(|DMY*$RmR&h*uOay_JRM#m9iXx6s8*ylGPw|F21*-iyJnf`D zLno|3dQ>ZJpOj81$wv?4Um7Lzh zl>=OhKBA?tQu9E96Pl`ZUt`0Ny4|;M!_X|s#{tigoxD=TUTWhC z`Rj5gxf|My>pppvap+gGvAkqDe)xu#a1MX#?4+}X?10Bqo_eOzX*sIB%}kT6Ci@K2 z&aWK-;MhD9c&-?|eS8;Ofk*s5L~0&mVr}6Y7C1yYvt^iWUH0ubi;eE|FkAHFqs%?_yNSCnExY<@?SwQmH&HCOvu*8#N70^ zxub)#-9LDgAE=DkLfFOF#!1!TA1PY@hMEm4|C`fU=UfA-8oWHRFoM0Se1{h~96I7} zdQxF{aMCUqXSIJCofU+C_v!9+hSz3^ns6L7@xYZX3wEDb_TapkRzZuTouf4NW`e zPpYOUCOw{o*mUH~wSR9hJc)B)vh>-9fYy^_`4M>j0_ra@CKbTERf|E9q9<-_Hx5}! z`um%{2{VNVH-$|#xOGU?I-&`yX8hXtM*YDTTMFbdWp>U)>>}>IepHfVUtSgtJ2Yv1 z>jk8k8oRdCGvzi}(*N@5nnGY>6!v0qgL?hliX+Z~if58llg$+rLnKy6I3}}YZ^`D- zpl`agu?v~25cI}i4*^U_l-1Pgj;3Zai@cDWU~!8%`1S<_5+no-%-I3j*CBKlINUV2 zB9DOL?ARAx$yZmkyI}F*olcCaN?G*5scc0N@#}LJs@C)zf_Jz;^I3|)a9n#wQTH-$ z>j5((Zp98VBgCYM9vbg6&iqU;G5`Ulu&sEHb?_tCC7wW$C(p4GYXI6M$S2pxIC9gN zp><>~m&Ju>Y%qi~1Wk+*YhxP^6}Z@Cg9MHgCdJzuHKxGI0suk(rk;2E@rQTuQA* zeiv(%TecS&ahoDSC$FpQ#Lg;+GSW-%a8m*;THmWUL_9i;k&^a6A!?OM1ks1h%^@_L zhvAhGVhhS76zJu^0veYLtf*ANN6)xZ=X%VABp|esS6uw}>Rd0KJPyuZgyM5=z}3MI zYR-XLiB4RQERjXJf5^^43)HV?exxyrKM9oolbHOk|0v%7n}3wNv$3|4`EFG$-9yEbdXiY_PPX=d-BD=fLisVf~PL3!6;0o(Q{{>)v(~shC;aX z;4xSRyhyrp@&Pm3cI5a5T1*U1=}cN6OS{EsuobcX6Wse|4*fH*zESI1E|kiXA3ykB zte_xVzU-MRrrsUsKZ=rs17ltO^OHgUlN#o~8oIFkH;eK=P8DS*bE|)$@6GBE{Mg4R zUp{JS+s5pU*#l|72o*~<+{&AxWxL-RUb{;a`(^T$O>|4Qvxd0sQk^6ls6$O1JQp*Z| zB9%^uIXA$?LPR`TE}qGOP1r^ASP1zWX1jWLlnB68liY^bz+~x+Nl5>|3HIE?*6epI zsg(b*au3f&*$J%W)&(1kgV~yVcVJ2s#(bJh+F|xaSn&upqklmjZyCt|(-tsW3JA0| z)04Kw7%_pT&>`TdF@oYX)Nj$PeFW=Xt~8bT?Dl9xhnI^jZ8K63r=S7-@Xk3~3;%8$ zjVZ>^fLq8V)8Tq>i09X)gc+w+x{<@;WuS2SQJ$ma1a#~r7~ivB()H9>s2<@oHZ-Sa zf5j684%YGJ3{A)}<58Jp3|fd0R-Y*LfL z9asLA#hRA4?d9np`kRrs^c`Rv^-wtlW!c&!%CfQ5nnZIs7obm^FZ22n#t*Og&oe2(7 zT14(%DYN>?A14)>T*LQ284*5OH3n?t>gP``ZXNF)${)~ts{0@?YDqE&HG!cmINU{h zXp}zTqbS_@2db~l5xaZ;u$m)FC;s4#E!7-WeB}ZA)QPQ)wvMc=d{QW|K7V}q+u5Bh z#ifotfw%I6o^9eXGb^%=w=mc*EZ-7T=-(Y#C^a}8^(It$s9Yhu<)Qaml~K3m?k6HMr! z6i;OZXo(iD223k4s41qrT1H*j(%}Xo0+XuDE4Bv)XYE{0D7#@Zy#<~|b?I(Wf8__l zt*(?S`V9C>tti_iy2Xa6F^cjbctEKTvXj|${z|F{GSm+8Ppb&hejXJfi}pN#B9yS! zxz;&jb=2hp=%v=CP@zKh?eV34`g;Xh!+dD#fN0A5^mUtizds?#dgt1Hr+>u{@JeUSyQ%_1((J6KJ_P zH8nfut?^MLl*)P{e~;E%EbJ9(YBMAgQ6jz7BH_q(dtNC=IC*tQqj#lD(YG+Mk&mSI8Izyslcnc&(V}EdWRO* zw+<{yVgaGfuB^XoR(S05j+|iMnu)!#4~w5LP*o=%O22ipAPy zSxYdwmRP9;7nexQPyBEVXjqoYZ`nEv4Ljyp*0@kfm?Z9Ju#YIR8!Yza9)z3oawNE8 z=)tPTTMHUx`}sagl)M&@acB!--Dx}}Wpy=_c~-U2!3DhW`zcxZa?sJ^cjlR80k$fF z2OpHFXuNh3SW@e)1j3-zcZsNbjq6n#?aJzbV`E4_sL!N^3`q}cdY6j^*Y%6DjePs7 zl8xDvZ9Mefurl`qxPD=&j18o8qqHIOf;-ja2Fk>AGLD!!Ze=s{K*RE?hd7p~`p6nm zt(`1mhqi4Ko+swct^s0^m!NX3D<=M43r=llo;2VZ*26MCa>XAdcCer%i}T!MPV}-& z+%%}$GC1p-ymPqxn*~(cN7Zg)I{sCGOa-*U#;mlGv`!l53jEygkr}62^2$mb?2R~c zg1Jfz8IwS~iYR9!z7wFZRET}58KAYIW&E>PVb1*gdcp4uO3nxdFhey)VW9%wbaW~H zb^r>fw6;N<#OMqdoINV1q@vY$4=iD|<_2AiM80W3)oMLGSw2fQo7tD3Id%nUo-qo` zy)osoo9MhMTfgjp=jIl4ZQRm%5!<+(Wr~+@c=FKIP>iJJ0({;6^xKtTbh6sMTRMi# z-YbMfCzouLHfFYIWb*O2Ey!>g^OWl8ZSujEbT(#*P1d|~`J*!B;ng)ii7oiy>rlJC({|(GLLsufLC^Kr1yxAQ-;BJ zi3QRZ(oJFzytwNK<0ete6?d?M$Sx^`|9xyd`eBZev_5BaMV>3%F+(N!U;@jYG*|io zz0zVm^Y;_P(pp``Jt=j)OlwOEABJWP>Z=HHWEeicVxhE|IFXsyu6=EJ;oi zl7}Uedumol^Wak>yYUz&W!{2eW?|^RV${<1aH+;>*|Jy0&PaB;8jtvpC3WFsoo{B- z#5xC?^!_w2hg*fb;ZI!|Fl1+@Vv2I_j2=^%RC9l;8tWu?jh$fg;@+tbIjZxHSK-Gs z4D67EImcAuR`|2HR}3hmYUnu@G$5dM%_z-@%SYCr)R;JA4Key(!$AI4OEJhq0Id^b z^8uX$QhMp5ifNV-kWifXH^o+91RN6jgUTMb>zq%&?3teB!;KF35`b37;eQHaw)s z>dt6f)g!4XuGC_~u}gMZSk>rnPGDYGcc@BU-G5Ta(F$kVi$2O2iOX_VgcQO!Ge;Sd zzcUFIEGk4e)GVb7m!OJgvXm*fhD9E?6f`n=eL{X_g?img2P5vperK+VJizY}1>*Ww z?3Yvn$PUAgezFJSe>bYI{x@Ic{~YfBsZRg*h4t)z%fc3t)XZy+h|nz)mVc8=378MX z3}%KGYaxZ)A1>ABvO;TZZ0pqfQ0Gm5-7AFqB0ub2Tt?hfNRc*qzM1Mi-EzF0`FQ{Q z1oKno#u5dUeMp-$)WLt5Sk(E@(6gA~O(I)(D0ZpNX8+TqxtX(zG`130f=IrZqhcGo z`ImAl`7dv^)P_INCl7|lM>e&|VG0@qe_mU4GvsAY6rnH`l?!}F3U`8xq`J>u$M3$| z)6f*8poxTev}-jiGKtaKz(cj^nib%Y@%;P(u@2x*#~Us9OYY64$^nhqqJH=mPWdm4 zzc3g+Mq~c4*D?hv33uiX+bZZ@CxFXs1xO8<1^g_{lob#CWTK8>9)BRB-l>28FgcVg zz1GYSQ_#sYakk&qLj!M?{MZbZrAD7*FaJhf{*T%^eT6Ylb;L9GY*QU+d5jJ5IV%) z#xocsQgvdgP#WC3>+0BPdIY>kJb~Ra9FG9j$mg_}T>uP??w!>KiivlM`*(Q!Z>9EB zOqn2zDx)S%a(x`76o55V?Wc(aPGJ>E1^ltv#Kjw&p;}=~AY2g_*q9kV#a^JzNdPVr zWDacvJ>Xs_0{STj`*@*$W%dUGU*!W#>aG0d9WYeXc+So1zfi+lfmA!|`u?Y%IE%Au zkL=HMz4o6LPyXw4t@Ph)SqUK}TU#qfK`UEB%b(qff6duHzWhH?@5HM5=1z)E4*E{U zrtbgV(A5gkwnz-{-Zrf3E}e4<68SW93V;?Ibz;Y$0TKMgN(6oi$(A^y8|>;=W0%!Q z-+{njv|0SvuK*w9LvCz>S#3>Vp1dC?(`!DxKHskpdU!8{z-BeZWC(C!E1~)5o4y_(TKp1UNks=x53=RZs+NWA3{)OXwSn%+fk-r0HQJ@#fKH?UQ z^a(9+e?V*~VqC)W0{W|gOPBO3_aiLqxeZVcVe-zSDHAE@)6XQ9|n=9SgI1D(Z6nu?n$@Lw@B1n?5} zLN&xiaXN%opd>*FP{0$zz@3mX)*s+6;=D`Hj2S16z=dhCtZ zuhU_F=Sg1-;!A)_&>5xg6{)>MsU2rGPiA7F3tNz`)OT=qTPtjsqOj!QHIiG_sRK`d z>+!e5wCyJeQgnXQ(huL7f zYWv=c@VEsmn~1Upd3nQ=aOH8Y=04dxbli;6DT9_al6a;0fp%97^n&LyI_QqO%HnJi zTn^_0_ef0j@UoK8uK5y~*;}pxg!UyJ7)$6t76fZ2PN8XX(&2bjG4b=F<-;<}t~(6c zjAvTk8Jbu{lj3Xbee7j=IeSaq*n>F0kB9nsajO(zB5M`|(#hREwATcY3*Ts#?Zq8f`mOg`8a?!HRnqe>udtem=(<_j zOvR>ksxNj~>sZ$R^vQhczp9;sV{n5$ry_pTrVqqP+r&xJYAAh?mi-V+C9>o&K@Hz8 zXB}ipO3rZNc>#-J5PwY9iJCX${PK@LuBW;#4cDeH-T9|V_*A1}vFPVO82)jx{C|gU z|IeF^hX3S0=>C15KVLU?+JYy`T@LQdm~9X9*C=s_18VlbIAP0ZsAR zq->z9fm*U$uhNgkn#nsfTLc`BuiQvlNp_ufO107S*s+J6yk5}aGQ7|Z+_?;5(3h*g z>IQ74a9mi}>M{hE>WZ@74Mx~ZzglR>@EJan*!*#hW}(>q@$Oq=C<=veY_P2Jv(2?` zkIBBl(VMf&HBZ0sqz0P<|z4~1xI;_ zNJm01qwE@0n6QH&EQ^kXx-ze%jedRvWEp{BI#tlk>*S=H5^>CW0_?0XN`zeq5e73* z!`E|=H{>FXZf0(E;+jm6bJk6-)Y4gv#$HDX(#>^X`P`7FxkR{RS;ANuVPJelcIVwX zX%*5SN=Ukdm$UV3CO6b*4+ED1Y-);9JvjxO9~iCYvo=}_3asgSYT2h$x2Vn7jys7( zQ6E2EtU*2+OY3WBc}_6T7Zdc6S7^Y5VDEsRrD`|I z@z|Kd=D=G{EX`>DOt0d)p60-!WjBxO$6S5B2WOt~r={~IHa^AKX4jJ_(LhVzn_iH^ z_aU@xHyJ^1DVfR=w*jM>bYWR-qG@@H8P50Q#$n5X*c>d4*X3} z_X=&=LP_C{$b603h95p{LmB>A{L~v3^a*`1$p8mtr4hW!fHGE<@I}_$w|sjI5%Q#n zFl48ld!Y=i?OSkH8Xc*@wEpz4v)k8t53ErK$QT^Dz-20syribFjXGI{V&3M zaDT`CU3jlw$EHC(choD76yMeUtdQ2Mb|_EQbqJYV=+~}if)>*8wD;?c_*xb{hqA@2RDtr3FGR=4?;@|5*u?8 z7`I~Ls^h4}pz&WTo3lNtH}k%8gUR@ec~H)41Gm*;23WlY0V@yFCdVtcD}bD9yrtc^Z|9ZrE7NFKGK*7uk{E$>CXdXU|AweMQw?+kvQ?K`Jy$qA}hRtVZ6(4(J?MXd+@#>Z3EQ6 z8i2qe9MWGpr*Yuy`*RI^h}@&fb_ago3`2B9CylNU3~Y{Q8Qth>kjza+38_W+{D~(D z#(hC$H^3A&QP{%MO91f5Ff~D;$t5Hu#`!j&8sEQwNFqxDJL=ax8?%feNsn=LX?XWx zigFoAo*Z{`V3p}lIQld&q`eo+)fdVUhMIA&L+Wuykl6yF>RQI{2Q9-fTtIB;<1N9x z1NCoip(nmFQ!KJpSu7LKY_6&s?zuLwp>1>cEda{ipalGI{7Ou(dZ#`5>@;w`tR9DA_9^R?^(F}r9u@2d zIM%Q$QT98SSbX*RZ62j-KJY2n@=J21otxN}m0w8r!n7H}_DsNLhkGkjytmpxbxl}Q zs%!tSzhFRh?A(|KD+}|iUhu7ru@KZMlUnoK=`><)HArql^zkDw*5)b~#J~0`C)M4! z;(mrJY`Fj3{ipDMd=&rN{b%58Ze?WbK&NkK{y*+Q1!EH-TWdR8n;$WN;J?2A*L_$m zCkZ(~5AS`is>z1ikCYaCLm2>RLk;c`&?I9hAthnfo#Kgx+b0w*@2U+R0K^olAHrt4 z^J(7=kfsNphldXh&k*EE5?y8?3Y}U6Z`$8XpJ2Nf&_F3um8g|O$c4D7B5^E=TM9B; zMWicLLo91q40rTVa9~+X~OsC7dr{Nv&Kd8>JO7qM9pYqKAC#v(m zPN?$#Ukdo+j^JeMpl@Jh{J*Xr*OTokFDNLeAt ziOFgyWx0vqOSic{FD@+uX_`U|jJAMB$;bpn{~mylK<**MaB+_Evx_Hw8$F{tQl_jr zjPWsizZ(V-P|*nQk&&^!u|D9TslKAIv4OF^fj-EidH{DR=qr9`eS3Pl0CU=Zf&tG9 zkMdVPg>3!-1pen+?Z2|hI{&w&Hn+C3`uE)We-_&DC-L!Lwf|q&eON`(c99?cixtAX zEd*6jkfN5?k5opJsK2^cfm~1!5{{yb+a`0(xy9jXOkMS00KxtM?+z($Pk|UVjEN7D z;j%3mP`Id?h?c9dlWEthlZ)v&HdnV7pbe%n3YI&Zq0 z1{ab=7S*wV=pDLNMzCcQ>Rpf%E{H6fKIc7#?!}!68Idi7jA9o;AMA^Wb`!_Bi?1e7 zpwN0=mU?0k?XIKM7s7V2xLF4a#&*orI`AwdW8kShN|5l0;TV{cwo?A_$CWp8e-J_a zF{kb;fql7<=#vW#uS6tv|MQ#g5}sg0Mr|0f`erlKMD{&apqwQHY$Zbgxn-GmSb-WUsv80|Npi7 zKU7=JKd9G_@92Lzo2Rwh^^}&E`A$vT6UQf62?U-mVV|-#t&vzp$xnRPHR;ykKg_3nyXGx~>K+xAz7vx9p&GYWGfG zLng4a+zPR_Ufpk8k=SmW_NTRW254GO4z1lfp>FpwxwPHTQe8XmaA|w@20Yt83ZQz2 zj=kU9_vZ>oSPhmDBkdV%d9a(`z`< zd%A(A^(spHJ(SAVc}HjSLG?8q?CZMEr*)SF^?g3@qGtQ;&>ue$fd9YXhOR2HrSSPsnpO>j>YIX)R~Q@DlDp>0Yz=paNg zSQ5eArcJ92CH^*qs$FT@u9;l!H^JkJW-7VEAng8uWIdsT*1%y1R!}BgaRmB)NOnOK z-LV%&c^J`_9abX7aR^r%_H{_-5V~-b^C9O)Cf1Gql)cSs0l8j=O-~YIGhk1YYa~R$ z08I=sQu>QHadg@hs^XB6u$1C&5tbnRo9A?Bc};7Lq`hQWL}WPKS!@-3aq>xXyFrVakG?(CiYhc-tG@BBKE)ICyP z&+CyizPXa%^1|L0-lcUENQ-{*d6icb8f<~FM;B-FepYo=);Az|bw}4=A#Dxzi`6rc zr(wc*In%-xbtt>qFuJST2nCu^w7VQ%UcvC_&v!pIM1r6$RA0|ItmxqI$A_a+M-5HW z*l=l>sav1YajCL7z<2@b^GOfPUfH>`UuZjWDO70_%L5eqjJxF2Qv7&5PS5!Fsbq zKKMIDHZ8%8#};doW8o%xn8F$h1D*=&;`q$@(6Z>~n;|WixlM7*iR?o%g3|;HB^h1e z>Zg2G3mS_*V9h6Lry?|47u)D_Ye|B*dN3ik+|xvV+42jV$&_S-XK?M_p(dExfKPcw^>(mb~wy z%qe|Z1D!-k31NvmvB6O2g1h>Xg5XR+(9{bnHsF|`9lEy zZKP4Orh)}?6w}?rin9hi-q%W40%w%~-Ag+aKT%3D>)?&&kGhhbT%L(tP9wyIt$u0| zl+mcZ%MF1i|{(LgkCFd;-tojNE*ZO<@8OjU|xpK+ON85(8M6U&w{z<{?-F#w#Y zF|bkMcM`d>GRk##uxd(XHwM-6Ckot}N-!P9cV8uU#hBaa@hfx}>n>MzFx(P>)YN1N zJBXSRrAq@r8L~%UQbi$aNpC%+j;|tn9-~Y)X+&%2uh0+uK3}7jWF_?IG9m1>voh0X z;S>FbS>9z+LsGgKVZHb{szju_aVOLp@Sc-INVLpj~+_M$XJ(iQiJrhq)Q=N-W{5RG)dbCUT+7DoU88oz8M+u1FU> zDr7vp9Ht+?-FipufY!K$eevizgW7XmZq~&jcMYAoIDIODfxjKRiYaeF6e^E-)(_JNyh5EiR+gxRGe9 zb9@PubyU?)bmyW?SzLGtkeffj}VN%VDj`J&Z!-ObXMwx@$NU2Eh-t%YUC?&^3_3M}fVdD!Y!}ggA zL$%c^+WCVf)b%O*`R@Q zfrwy$vvuTPI65HXN76>fiwnHu3kwnJUiXIw7dwXhAx=4|quP9YM8{TTk>%Ak@>>=hW zJx*3&R-LD+$xOJ4O3*61ouXNq8F5xK%s$`5j?9^w;+1*CK^A-MZ@(0-m`u{b14?)n z8T>{sM)RU3J||RWOJY&bQ2^>}naD`PEqG^FZ&uMAhl27XVu(QG^crd?o**LLKNxH* zQJK(Gc~E+y_6qVG=s3KjSMoj5-&**dK?w2r)GcDGiPhQX=HXz_`_i4rmWuQuoNCQ2 z`dFXccJc~1GTs4p+JtMMlWIfdX+ya%SFu~&3G4k`NjTWwo<0RW5ReZq8LYY|je;9I z3h!`as5}MF)c&R%qz)u2hCn*PFU7kf=}@ z5v?Jt%HFiTThffcSD+HiQ>Tg|8eS-_K3P3jHPX0!mqr*Pzi(|%&4KQH8=do1XH-F> zT-ah`qxk2@&nEY1liRU30y8IW)_Jjbb2R}P%yM+?I1c1v}yWFjv8@IWxmAv0j!y|!PfDnY%PdNi9s}L zVC%T-&e}}^#c`h^!$iCk6`=x7zl1Q0d2X&WLUEYe0d>4lIQVuzGNMdDI6JL&V6jei zIIm1~7_eRrAyUacL#-+dRGAt`vIts&TSNaX;wvR-63 zeajuok&Kd3$-bwJ9|0{RfXrt~ZrG)Zy5GjBJsrE54(o2+@U#}5I}MGX2|A%_@rF0C z2Yvq!K%z{mdF&jgSqALp{nRZ<;C$U<4t{ZAOSd;@yA%DpOz+#+%;pxC33@|Hh(MN- ztn$pUS9<`RDy)gx;&lps6*m2}lqX&wLn^cJ_&5>DpaoB9-0jW!-z5tXOUx zmrzeG;zP%4=y~FMyY#6YZvK?HufM`qfC~*TyVpp+)aG^XDY=xDc!7!0*5WGR5{yS` z5+iwU@$3VziIr(*60B{J`iY==a#SYHQm;}X{Ui`WfOYb&tYh<|fzB5U%H@2@R}N>H zE@j=uL#8S#YmKdXi-Yi|;6kiY!L{6Mee$J(FZ<%D0NxIUOrjt1G0!HN-nnUME8SJ9`4l<| z2)v7?6xEDE_s;_2WN&!VLborty7U)XK8&rzyEX^>N?sOXeb)~Tn!bjG4?Mk2)+Z+E zWY$xx571kQrHOygjoFy7!UW_v%rgnYq=jXNwT?8XK1VzOHq7-k3@C^mt%FSJ#KVPJ(pYIAs+|-$TFe>P6*025; zCZnc8%a-Y>G`XO3h;LH>#oC`L4kglW0tv35T}O6+oQ-)f-+HXrq}b+!BrVbBdP<3S z2HM&?cE2sbNo%>JSeVnGYMpX(jJE1a$tA}GCJT4TII0Za)15Zi23zFmZ;pI<_TVgN zFzYMnbV*-KtHDGER`<~P-OwlWn7wdt^WWKi@%OzseM@(M-QB7FT7Pbn=haV=#XPnt zykeceRrhey%sKOxYWZ! z1#s3?ezGCg1MSGK6Mud{e&WBkAurEgN$B1~sMD~eOTH#*^A76nmTF0L^lb0;F0$ea z*o>`fjZL^NZ1-;J_Kvc`o4huBa#0a!Q4(P)_d`jAam)u_ncLPt2QwY`%??$uXT^@N zGU&DTYqC#LmQ|4J6(8E#j={{1#wuX5{MhFV-|>D?FPA7;J->2Pj&#+@uq+^RPxKD8 z{QfCO$5yS|qgscrM29bbg|IJhC{Av#6!Ieq(<$D&4>x_{WA zV61yvnfuq!#4Ec;O%Znd7^ie=@D*uBZ}F*pr6ZOb=fo}X#BH|RM7CT@iSU~cXcC`9 z5+6rC_I^+U56wg_Q{IPg!N)R$aS+mkvAO(L3c&F#;xXQ*NINIZ1Rqmg7n%ImaS-DQ z#PNF*`S*<9L(lKGKK^x4KE?P;bC{Q^@3HmRP( z?1dzjoN^v|>)o0_TavoczkUv5`IpknBrbw5ThL^E)pm?qr0dlMyeLbDe9RmTd44(H zXkW4sa<<`evV>k~_=4R81F}YvE2DCGeWJ;D8c3&x7f%o$v+xy(ckYZa2BT`q*X32` zA?FULiNxD-$&8V=A@O#x)~K-!Y8W73#@L0J+PDlR^)pN4ojM2r?t`m(`n<_oWUZ8) zSQUx?4`c5bWJ$EG?RIt9)n(hZZEKZn+paF#wr$&Xb=kJO1qtnd z7nEt)C`r(IBK<;541?bh z!F)}b1*I#1s?lS3JgCc(Do_Ikr$ zzZV>6Ca>uGrDn2naWA@%(FQJC0@;;cR$dIQF$&s9c;Wv?rtnC4ruU4?Jh8MHPvyE| z71;EIp*penK~m@%KoC=H`#XX$^CwhS5wiA#geMUN1fE2uY)LCufLH7(oK|6i1GdBo zQ66?ouY!Z@bmP&EG6Gp%C zQ$OZ-%@XUGV6_zT+~Odi!h4#PEG;_lK206z9FIJ{t3oPmF}}8_fD24e@2wF65_zU< zeynM@l2sTpP(4i?C2XA5fi~66C`cToHDQuJySR~Yv_F#j#<0n}SyZn?Fj}efhM~NC)&7}Z zUPUxD$)Q^Q34cH-6qR4szwQpG#pp7KRtKcD-gBo@`=NL17D)avnzZbXi7~aZc$j_% z;`7g{>OG80Smt_u3Q^i32$4jP$U=PHY;1m%pw)sg$jJgV7fg{l)Nu9hT-mrjUmnB* z--_sf2c*oOa|-eeNt+L#$)J!ioQGKuU(C%LN|{%@KL_3^nZtOsAYT$TKk5=Ay+Ks; zF>oV@?BQ0Y1ufLW4Qo+Gb~Ui^;NM!O9q`Y;xBLqU-Uzw4k8(x_i0ruR`k35X2+QzF z;)?W0K;&!BfLe%jMcg#sI0nCal#)T@xlOq(FF!*`dvFr=a;(;mI378C!>sTGYd@!S zmaq~GYzJ#f^JQG|l2td7f$Z3f-W}#jW>iU4#hZyDGEc>{_Tq96EqJT4;*PL4_=V_542td%&pZ{9qe-gt&}ja0fjSUGd9 zcB1V{+KLIIJ`h<|yd7p@yj6i6r*uDMYV@KV_foG`Cggb?>W3RL$c-7}u%R9oE;!eX zTk9{mK&~63Ry0!u_EgyIUchMfkp_V&&v(hPVPOeay~cDUd)vBUR6njI@)LSNZxdx2 z*zky9j5W7pud>D?Lo3Dh8v-e6O6xcxSV=niQq?ghB}OH;pX|Z#=pKfnOJM^z~Q*=>zo`G7w%ZB=jReajLjEFXuuu2KGrt=;6gd&b8Fgu1! ze^`3>6mj!tqFf1jOiS~ddh?&SG~fY;1VBM#)TjT3&| zve(1%Oj{FD?JO_ov^v4A;vGt+kQC*tSW#pyn$;7{3`n>raSIf;YjMR{xU9=h!NPEd zUC57c<2V>yf9SMk(pPxygd2^jtZR^L`%jWF`4AJp9IcPeu#VO+&AA77MFGFEu;v&N z*-8`wLyF~cFo!7qu3qq~mIUMMkjrf|_mdrR2b*=^@d@Zat0v9GZ6(DRIqqyOc#SWm zYZ3A0UBX&mLx4T1X+?9XMc=fmI&Q~p<;5r%AeE{MQm`6Rq<&tws7GF(MMXC|R`i() zRx%JHVtZ*bYL(4cOj5HWLDdQa5@QK>2ZdBoH2~Hz`jKNCs;>8gYaG3KOij-ZRV^13 zB%NIcl(lporqsny(Kv9;Ab}1Ec~S8oB7l~ZEI*){*+f}^Zi7F!av95W=YFgfZH>BU z)So7Pyirp!4%R@Tyhsfp@z-Wzq`f(&)E|aYQc#EH#G%#&eocLd!ZWkzIW6Oa;j8o~ zvehn&g6&ib1Ws=bQ zZ1PrLW+hiKHWI;Y*1cci;N03jtLcAO_ZgP_;QUQ%x!W@212F}o|=b#KB0YqW;&?>zmggDoMd%tuCf@QY;$3)UT!J12VT4gIIbh` z1T;i>!URb4UAVBKLj#I(Eifm88&`)#p~5Ko?jszoyeTm1o)M054Kh%;XIR0i=y9h# zcDjuMO|AA-%m}_)8mXirazb0HnVdXetx<&=D(rOfVO;!{@pFN<^+!?nYal17MPAiI zD_T2*^Zr>l`s~1W!MF)x*3e%(#Yr5SU{~{aC|g-tRt$mG0yh<&P7~~mtVU1;-kk~a zRy@Uz7{G5ZNnHy>Ey02S{G0R%cnpG1#t`3RkXjm&DTuYQsI1s0fcX(wVoT;87N0|> z-Fg8FaJd7v$yXG5o5Ac-yX_D-W-xfEht!Ovf9SO3U#Pfin<^FWx_uiH8{k_%mZ!!a z{vm0ZA|w%tj{~yr8l0B(^PacQD;DhNkXL`Y&oN8SBL2JLHyUA@9{qO-W3LmU^lW_b z;%|FZDyAyhc&bS)zxK3;X6#P@|4)?SKkJU(XP4ZjsUj5gMIcOs zQCt1q{lfGXy_F>#1JlGk7Q=xyFK0GtnLk;e?gq_FCx+2G_0*nB#!njNzExgGC#>vi z;&lp&-$>%k;mnlMPaI+O+WhoroE3IDP?O01Y3X1`tGvpsn;0fOP|_@Y3x$5KvN`l< zyF!n4CkzyK;{ zD+AB>>3QZD?Y9)RGJ7RG3;Sj)hz8@iU@OTV@hkyvml?!L%Pe1#4EDg4!1x-Ab9HjO zDJhsIzZ~;s&GV^tfW3|__-e%b=+wo>*iIq7)oR+#{$I$i?{bu$>D$J9 z;llGe>)qbh)cFYT@L3{ zOJYH;j1}QkuQuLUKS(Aube&{u(X9nb1*3jCV54q4YVk;|I)Ir|nS`}Cd7 z-2i`CzZJ{xrzBoPST;_!Sl<^L#rq(?qi8rv^Aln+*=!-4P1HXuFbM&Ds!yH~m5)Mg zab@+-Mtw<5M_x-&!@j(ukfE)q>)*WUtLf_Et1TY^iS<7_w|X+f=s4x462srs_ndvO zQFUg77?GsU;6xNswO(L}$<4*g5H(i$2v}Gi8BYlHz4J?LrgDH5JsC}EUL_=K$lz!- zmbjH!1pSKRhhTO)ws=Sh8c}>%S ztKusmo+!_ZwG0sG%f;&8t*+B1e}O4iwXxh46Y3-wF^jeSFycCthrp2hJ|jxmP zW!BOUb{t8gC%?v>^CO@b2Z=&BviM!2aL2wS%ii!o zgAqj{NpGI{Wr(50rPWqB3WIdzeAuErd#dz$5X>A zKY|)_X|S6(6$e79+-z^`1{IGGp+Sk>18!^6xgx3$;^;|q*o{au8#e=6-86FzbO=Wq zWFb&Z)lBEZVp;O1$*1GV#6k^69`(_~3R@FuNoI@4x;krO1D7FDjYmsJ%;OMfcwEU5 zxt+sa%x9!p?&^^ zgru<(Y{g(i)sRY1!*uXCDKjY?Y=!jV4-9--D~~doTgiYLrbb{r*KnA-QA_=-FCaG^ z^*UTj)E1V3x3ZC`tfL9nTvIk6_m^+}Q9~^--%+Ap@@UN@7ito?^`|wAtl!;86;-}E zYD=);NYzFLG)A_kA`wxY+Z?9+bpL2QySzQUD$our87BGuezGitD`N)SR4;|wod)-+ zdUi|vQrLmkoxU733cR|r;~3GwZk}#j_iCJYjc}EbjIQg1R@n_PGm`&W8}#ow(s+pq zy@8rR%zI^Kc4^FTD`HCH6;A5$BL%yoCX_X4GRp|iw3Z`Esghwy&7I^nKl><<1hLYz zP|{!FO>sG+FzaRj2P~M1{(g1%5sP$=kr1_y~?EbZ3zcwtzvnU?J!{^M+nFsg# z5+sR(H%!LiR>zog1#Dps^@bAHi~0sbZh!SnyDybiW;#kpDRfUHiV{n&(#TYXNSi0~ zSh&|v(9Btk@&eWhvy9^@aNLFyWls?oW=d|D4&n4?+PtS#^d(~+>O+}| z6Sx;p2oy~vc|#&1_-Ua~O<4=+GT% zDC~n8{ne9?Cg zgn*YGR0L8t`QBt1+>nz66?>&@Pa0>3MJ>|-O>w6(F7u)FT`Yku+ab=KtiTRslv~Tt zvm1T75>DIB+ur)F61yPKogRC}vi8&P!*OU^g&UG_996Cv16bSHY)Dd0r>gVtvyps$(uAy#7(~n&lp=Fi-u^_Btc*9keQ46uSfQslXTMczlW4A2 zm}{oOlU!wy?K4ZSP2$~W(ES6K_r(fUa3eTkj1A70*C}TuaOdj zGTu4++DBerdxui8vA5bQwrrhD9Ntvn_Q5$!A6~SE<(zA{MOiCj!7xeB^0RLaE1Fu) zeRVn6qF(Qwm-Tw*?#8ZMKk(wxgU`!ISyJB|;cf>3_+2&^zpYOaPmwF+5~j=}xL0}t z`o#N>maYO&OIkcdD-o>87f_U*jtvtd*20p_O(lt?8!#}`C@3-J)xt|;rCn=P;pXPs z0c}#|GTx2f1nm37-ztYTGsT`+WjkB}`4@(gC(ytR%PQI&MrtE8Yq6fL^VQuv{&y80 z%VC^lnCQ(nc|@FXHXY$%DCzW!M2qvV=9hh_9c9c2Rww z=5E>Zy^7cou`~8~T5e3^v(fwM>fR{N=E9)tehI8AoiVpsK+Ci_0rrsFeBjq0P#_*p zLlQ5cd3M|Elkr%zwa3-%5VppP?5NWDtvyD&=#py{bh(K=A~jmo8o9dg<7sI3Js(Z#bxH9$&P5W+hsL4RSo{{<-3HWkSf=%5#x%MP*+}gQ zpiSv~x2`cq+U++ETxE8SsAHw(@t2o9C_l69L8f)SY!2Berw3*~l%O(x?`d2w3|@N+ zt~OQ z*UZkkmUrAt%B{o)Oi#rktN6NGpo<;U^8kJ$R3{{Stba#c#JD#!%^snt?N9)=Slybs zrr+@`s|LFGx}%%;`WCB!7uQzaivGNxOV(L(3URlaYdkSbH^5*6xx?%NrMZrKP$bub4u+ zw`U`f_e5SJd5bGy%QMguZVIQ+-B0Md@!?mAS(r=Y>SPJwh_*ZK;{30nl3j1V2X6+V z^j7mu7v@(rPH|A?32uh4s!zt?Wez)H;OUgHRaLk1mN_#nHz@(?A|e&ufP9RUd#3)i z<4N}WT8!j)H|#FgSjHc`cPX78C<+w%6kae({t30%JKOkqk_ zMPWPIMrznTR7UH;%}Kfp(B;<)j=`QOD zOY>M_O)2GiZnL+s4EXNw+m;59yu4*uakQ{9s`I;I-db;+_Foe#{#FU%n%B3i} zO%UG~`kFObI61N9PBLHJ6aJp^jr4mt3jbIU~p-Com*)=Uu3SntHklKS?80{fQFji!W$ zKF^@*Um$b}ZkOcLreny65oq4faRA*=b>1GIzBH|e=^pN%@W!wRModA7CY zou(Gkgn;ITaKEH-qcK?@F_clQ_)4rThH+nzrI0@vQ008yd?NlMlpolF{nYs`muV#Z zpV^WBtoZo96aW6JWai&Od4R36gW-R*dn{6gbW>VH`Lbmk%aF!hMM6xbCzMjz^G78h zBu2o@B2Gu3R2(F5hXfvw&U7CjENXVC*{sxv&|IXfb79CO#+S6V6sX#4)VS2CT5E5% zIH&!b@n#y6M(kap)7{#f=6UA(tA3RQzTI*D<9EU$HN01AUlbNkE95q-og=ErJ}R3F z=1Iy`6)yTq^n*>pjO*b&4_mkG4mj??jtl$<@ZIX+unq7rX6rxz;l*8V5Esu%fB>)% zZlXcWbe%lh) z&-rKY^>1QqU&NP}gpa1DpF_R6n{IQx0Gp4gfRfutKhuUA*AF4#?1X`Awi|yz7t4~F zmg0h{hA#WEelK12InCqid)KOlGymPKE&fu~wYKx~_WoZHIr4J3E!7Hab)nmEfkHUD zYK0RTxjSc&AT&YP+a7;OeYNqmmIoP*=MCd_Zk$Hz&pFq1!B2ta`CU$40_u0vn{&pGVY^DH z3U%cIqz#vL1K$z>cGyb`Wg?D#i&{DkdKy8Pr6CUwj$Z_X0*j+K_^Qfi@sareWiU$1 z&;|0B5nUOyMxKsmR(~Me`gT*^&~}Nni6{dQa-`0L&0O?UMJe{>nl$a)L1ELcznqp+ zhD+&f$tKncsp*XCbu32jEijHkd6lKn)Kx@e$^p}rz|w+ueTH5GaY~8oR4mC3x0CaiUpK(1|njR%YYZ)gP?UdE`D(nIpWSbCPaDm2ExUBc&GkG_#G+ zTXrP>=)<(8sKc-(i9Te(wW`51l_9lj9H1L;LTVm_W<@9|O-3(QBXoHU{Bh`k-Uu)q z1JFYaZ&i97i#aMMPA8>{+AIgkZE6 z2o(^ZLY#efBg%hub|$UJRZM;UD=NAd$=*SsQln(XLm5O!T(dsIouVoWM+ z9NJfb4f5i_YXI(hvC&E5_;uc|hA;RgRK*E&M3O=vX4SXSuf(AedJVb79I-4q(3fhR zRRwK<8uU}(7^5$qAZ2y58BB(I{E)nYa?Pb%T(lQrrKL)^UVLrtxilMGdHoY^+)er@UN8%@on4Hih zu)@X|Tvsg3?n+`S-o(g8OhFFrQZm0%rPxgp|1bJ@XNS;)F_Z;>oAR0$n>pLmFP9jbqS!iM&enal9$Sv{H6L z^eHzlwvNiaM!i?gum(|gHk&$tViENrP12hhd4XMEWzkQEl~msDb46XFY<}iAQmBS) zG^&0-IG1iVs%?P5DBEOhu>_mh3wL+QjZnIRoNZZxL}SAUyV zvsoHl%=W{1KWo}VE$5Hwy%R_AV>~;9MFb^fXMr`H!fohfTqC7LWTP{`I`FIVbOEDF zzY@tyfo88s?Ty6Xm^;nsoJM{gU-6u1FY1FAn8|)ZB|`>Teqa^H#dB=`dlscrNb(}j zpIkBl8uvc@GP42LeFE}r_VQQu0$C#Ry#5xutx36S5NB5YoX4rTfkNO5pjMy@2F>PH z4dvy}gtic`L?P}E{gka7h(q5#uiCxJRs+6w+Ge~X&TSKW%N7UO1Izs-R5M^`bJ;~7 zVJv;dXo=_C?*KUsD-2q2GpqoXPje0N`;uQYR?Dg{G=lMaE3t8pokvv z@RvFMqFCuwM)Oak5na=lHAY`4g$aZ~rmS-eG#Dy)-$P!mL+LS5+Jt=WrFTyAxJ$qc zJB1jeP;8A29kH3l?RuTFXA?6o-m0Vw8y;%YIZU_&kE5Ex_r-f2SXA_e0R4H2-!*O$ z%lE{tJkx!QFS`nVEqMxeJA5`$iHdPO@{lCN-mN!`Z!(UVAu#DctW~uLd_WPQFF#nz zp60&N+Z;# zSyF~+m#I!z5iL|vgdsS^?=@}|ggzF6h;tm0TK+tb1g}SmJIKwQ7-%ekEhP_br{S(H zNv_K{Ihl0J*fT<4W zY5BDG@LJ8dEMSz}21ed`V}U$g%(SB02p=(@hrI{>2ftg7sCza%B{Z_26)(u6+}ub~ zVqCgV9fdszRO)A*LW`=Nd1fw(G~ABF+5<94PVoU#>0pD?j-zzKF~#4XSr3G^DJgFI z-IHr?P-7lRAYGy|HGq9Ar=5&em}~iSO{d*;>2g<=woB^7Byf1=g;cVPdcWdR?Dz146;;Ox zsWn)ysJ|(PbGjdo=+DcLx8pq;HqFK~EFrOZU`kX}9?q70;YS_ft2WFjZBM(>1nnx& zvt*{1y-xaF$@zd&%iBY8b5nIMfm)8pD#UcwlwewnYH`@nfFF}eHaDhB(n(R+EPkLo zcqAXNTICK5fJ6OeO8zEF;VQ~LE#+{Mau}J9U+a0}EJ@H9BSpkVP;>i&NTerk#6zwu z=Nk^*w^d6Icjh8w9I9S$klo?5vdfKA!be>6uwM7{7!DXK`a2fUZetMrmUoOQwQ7g6 zM9X{aZi3TuH4yk>(lR|6iv)k+7Ov)ujSDXp?mW9_MYiAmNef38x44=8M(`b>|IgUr zKV`uGI~e=_6Fb=c7hu2ZyDcU1vAYkSxk`gZ6oNQ}8iEOs{-C6IX1_Q-p4KqLswg&? zVZ4AwVUV%vmbQKHT3A-$)FCU6eMUlIV-(gzD+*y@^*n26fB1m+SnfSb{)wi0v#0qD*NNDB zy$?TrL-{ou!#B6h2WR&x_i#(H`BDOeygMWP(T3-nm*9)htGinx^AXkkQH7@qr-$<; zi>J$QtMQ}Z_L;OBlOI8MeuVGkHm3c>+55HR#}~$5M1GR5CYZm$zN(1Z@^624M|>%- z|IVfSecJbRI`nyyg4$K9lHtXwRoJiv1icfC4 zQ*m`1odAT{(V63!BqWA_d@jOLvzTEboX-(>vG|V5fx1wCX{Xh?E*Hk~>#ag};sK|} z6>5OD0{kiL#yHo!%W_?oOODV?BECr2aKULQPDD1rC)v4!QUiraiQ*+>M+TuBzMd+f z5AitCw4CpptQgYmw6JeI)!cVN^e(m>#{f>O?}8!MPHLP$W=akxd1s(ScM01c9+wyM zR8mgkt)uu#LL?60e})aADeElqhKz$o)yfhdxz2E{=7Zp-m*y#*W;xCcut2Airt~jx zW&@j0^XSmuH!5P=d$Lb=POmV4{SidxHd6Jw)wuxqnXEwg5HVbAPR7&4TD8&JB|e<_ z!l+(F{?RP2(qNF#o_5@2jcnXcZl-V{XiU?XMLgqreskdSlza+HhGJR$6>`T(mlQHk z^l~#6zOpLGd~pyGaMS<;5iPCajv<(!JYQDE*zOFSl}3I3OJtk#KHST-h((I4fXAL| zGpDd=i_O@KZRK$(&m|h(BwT-8nJp-h!<_a|yKMy2vbf(Vv0}quE$6$zUTfB*?IMnJ zn~+`+;i;!#-P358cw}}*b8JB5Cj4pHlCfvnGU07wGf6kiRZSBQE*V)8ef)Sb$w(U9;5W~;k zQf&ieTRtNiT65K`zBPL9G*t6RB~gv6hx6%(D1dJ^h;xfy{22jf&`Fx&8b|L$JXS{s zVp!xpHSUPLDB)tx*`=H-nJi;Kb?WH+U4f7snrqRjF)wpl0Q^B|%AM0A8B2SHi&%`< z)6Ly3dr8`nX1=cB6_CHQr=>qA61K^t%`BBPR^K9pFwtfO&Z12FbErYqS5P{ep%IGO<4*UG`M|gc)txa{2qZ+vJ_Fq;m;Q2zJU%;qA~Fk;?vc< zZXJ*TCq1aM%_Vt%VcbQsQI8ao|{^mErODbCT-4ILOA*$?A#@I zKMw2MF)r5!Q6ig1r*B%tZdr-18iaWZR}a1X|k~etLThLQE6^?>Z`< zg1PtJk-NKVhYr^&hI=O;qN>}*iPYmzW0tx`sQj*+nDe@FABl^uF7eh>g>+s5o3y)# z#LWF?YqKJxt8u@Zi_vvx;qy((-OC)LibP+2-D|WLG*uCnlSfWt_~q4=0_FreGRp0j z=6zfpFSg9>{7^JSu;{Md>yCA7)lNzoh2(P`o-?;B=5Ba9Z~_nG<`jDyMz?$aUtp%; z5&WrdL^PJZ^mEZzIblW8WQ)HwsAI2EHy*RxZnzh}VMU@k31HP+2uyWQk7@yjX2YCcEiqiwjLfyDF?xL4 za5uUX;njxiVPcl-+@T}fR#n7WgSt#wbV3j??0e)Th~RgmA#2pG&~UrfznMI^tg5N< z25<>}l8Nb^B8+n;_xuFV8m!$()%L>CzZS5xA)l?esg? zxyDwPGJOc9X+zA%4@Sxq_&kf;JclFv@|k@MQ~HXbSk!Ih$t^r)o%To$8WMqmA((VJ zmiLGZsS2rz&z!-&Ty^dCauS3G?ScFXh^wB+HUW?6&T&j$e?NiA<7@n@R*0T^)<94i zV}Wg|QkY~|LMK?DmE?`*fz+CYqFpW1h zWjWy)gwy{-_{=e#25T3(hhth5V8}TtNy5q9FF+c!CNxgp1;%W=jU8iO3PhRE*il&e zNo9jN70Sv-;@#)>@w|e_m1{cnS7MtifJk$nvV-I>AYD6wUGMRWUvjG4c{Bah9>GSE zgDv=J(g)mo9$0PS+g?kh9OY63zZpnX#I5SlB6hD#DQQ?3N3di70?Rg93=S)*{&}|t zW)e39OcOk;Zrw^?rqze2OFDOyXQEW-9XJ!?@U+i7NjCdijw5s}bY`S=L7b_TaVm^? zK!Ot^F-ko#3Re=R?TmMam|}Q?d049h%~4d;T<$Pv)6-4y(8JoG?dst`Lqm<0NUU0S z|DGxHlll*zTpO*71g-O-RvV+uK{d~=aY`MDx2nn_-$OPpbaj0}VLNT3bbodWO4isvRlJobLF}J{O7%usL7I&cTHeH-n)M^z zBye=U0A6ZSs?R0n4zdl0gw(nl^bw+Pc0Ei6icJD)RUxYNig;BZQ-!@%Yc=d}r#Ll; z+%PQDn$`O%`VvCu+ll(CNWfKoP?hfDbK0eVM9dG@zxn_@iG@8Hk}GRf^T-;fq?n?$3$5G>Q<{3!yrUNT0-6o+hZdNgc6)Tz~0PWqqldWg}V46vR|_^)VDs zo*?)ny~1Q}UZcmPpty)zbP}dprW7Euv6;uVGxP4V|ISu&u4q5XcS|+$CiUT24z|r* ze5ju{#o_T_==A_xq~Nn5Z+AO@2r+MwophOS`ejS`8MU% zBSRO$MPLAkimRN7Lzu?dkABWDG+0}p=&P`AJ$8bhPHYq#G_lNPXM~%L+s&d69tl{v zqej%^8~e6ywMJIahzhC6bVO0~%jYny(bgX`Fkh@4#k}Oqi%B8zn1O!UqM(jj1RBEv zd(kY7b6UkduGZIun`()idxH67fa{7?3$WhgbkrnfwRqI-hBD)c*gEtN_ST~2Nz<31 zfMJK}>P0yWdDWl^H>tyS`@e&xhp+}`rPeoMZfWcC-)EG*PL;;ez!X<4e6U*hcxE4= z(AU2mStBpPNvqx)$FkL}*vA6-d;IFz^;?_NO=?J7MoHLciLqN6gk1#}!u8XIJ5b6{ z{2+C2{Te|$bR~!LK!#UjI@>xdM2DbL;|&GRX3EAAd9+uQ$(NqvU`+H>a(2QHf-7+V zdp_=*4#*rQpH^0pPnoxX@1XO-;L;gQX8T;%7?p5f&k9%#+4lb$s>SQcBAMN({4rlK zJ54nmQ5#%)FM>=(gOL|xj9i;tkb;A&+dIQa)%nOc=~Gc!t%U1W=DjtExIbmH`$QKkt{9uYVNR z=@o?9LqA({_XbA6WD-KTnd#5mU(8(w%ISy4rAO_pGhFm+4DKpw>rIm^V z@3lV&RnMu>bMrKG9*EXm-*7%R2O$Y}(+TNLq~VN27zhZx$iB%w5{oXXp{78#))EVq zC1WIy+iDD9tm};`7qkpkO(f;HWiK@ge}vnD8l5^5#eidRCu{Jr9xXH%3YW~_Fc6I2 z(;$(s>QJ{LE*5))pow=C!Ei32Ja6&sI|JaLfnfsZ=HKTW2Cwy;TIsOfcSL>ovj*yGsBK^s4#^FjkVWiXa(rAYl-9x^a$9k`cRhXbauL>D|g#08t9>UuNPZrA(sN<3a z!0VY2S?ZkmXBz3Nc&)ECmwrPBY?_C!mDlA*7N3%_HVjO;IW*A9yT4%O~(8JgKjm*H;HD} zh7K5Q1bVBV@mw z_5bIf{JyhwF#V=f>KmFF(^=V?nts#V|8Zrupfj{}F#i7d2N;dc!qL`-4)~w&!GHYt zd*FW_{|z7f&&-|p_xJz%ktM%}|2O&n-<!xgE(d zDRm1@d8Z&;hyNYGB@?Pe?+iew5RwbmmhTmZvjmIpn$WVjS{C=t+LQH+wYU!-sBi#o zum>njF&g7bAu5QeHxX!0v91EIFxLJ3HccR6Fp_tpm_U#u?uw;XNj&D#*{JK(HYuS@ zlh9=12k)Avr&zAg9dyw|pS7>Wqri5cTr;JZ)B5wnrWinA+Mcg42aP#xxej4!>^`eU zQ(fAmMICUrCQq7)%xYO99Zcq%swTN%0bku`b~CkA*vmZYs|2yh{v(f`(4BkpcSw#) z@S%H_RM6M47z4{;NP73gh;Zued)+BKI3q&npdDu?gc)8y0E}pNgdF{owv)NIc3$p* zlL&yRS;-(uc~bbLTYh6ZAg*aXNt~6sZZy?qX@XqCF_y{5`vKS0%=|Pk&$GzFeK=W- zNh?6sroY~5MwO^CZa%IiRoP?DB>7WaC3C0+;_btJc2MOwoBVxZdKfdHWI)G3vY%jd zmX)o7P#gz$X*NKWIdecA1<$-S$Qic9K1AQA&raI`iEkz97Ir;MD&M{(`LxfCNbr`f zI}*!gqqcRsm6CVq29j6#HZ6FjPZ^ozgxs7x#wPee>LIa^j@fDK%bd$&7THWAT_M`M z*qpzmWe#iOG0@R>qL69v`p>>om}jS%TG4}|J>UfQ(O85X=9A1!iZSBr(y^_sxbWJN z#&IMGmrVETNw4+kgQwm$sLwGPZek^~RJu8IzN%Lb5Qo58~ zGGFaGuV#y&{6#)i>9uP0Ws7!;`F29HCV_)l2vu@dtQ>Qpm~L2aZ3gEzc2sox^U{ZG z3Slatj7-lH;s88b2R`~)=LJj%xJy+m$>vZD1TWVVUXnV|Bl50V)`RD=K1iN9HYh2WpFS6+QS=t`9BWGF*-4|( zvgyf}3=YoVV2&Xk$r(7qP?e2nHQJ`0c#(FCbGL?|Ip`%ENhk zV4ys^9g)kEXS9bFq4B*RNz%f-C3qm;Mt2mgs{NvKqa+@)4zboFI6LLDXrc$c^Bh1X zY1s#{U{Ag=4>}h>P1T?(=sGvZ(w~*WjIJ`ofFT|X_q9&)uR=eNaeI~ncJ77L#xG71 z`6`ebxX&$T3grUYdM6v0^x`$X1wl*4)Brf>RQT`fIsR?RvOo!=E2)ce3hw zdwz?yF-;oLZSk^mTFqr#N2`wV(JS!0PxH<4o!1PBb+NT6t(gz=o8{yvfH_Vtipmg4 z`pt$c;1VeZqse;bv#PhF9)vmmQaHzJ)PPw$A8TMYSbMW|4<%^n`F3f9GHu+^ug9Q9B`1zMIQ};b^Lgb)GElt%b!Iz7+-JgeLxs4fpJT) z0tFaV2zN<>uxt!tqMm4Oj88LSCXPX4ifr_0k*bW{xc;jJORDIz`u%qWT*&tX`|nNk zKPQ*!|8{cOSvh}i+>Za)tzC>AoamI??Y>dT|GYPLa3mIVclz(gf6copfTk^?0P+{y z|HIo`24%J-+oDyt74BZRySux)ySuv-?(XjH?oh~wySuwP6jEIF-reVP_kFi-pLj1G z0V~#8KfZ{MnKS3e%#kChtklgVHLDgqQ7F-zrRTxtip3?F=)bEJ?Rcw|jKvx!p9c*W zko?B;mfs8D{fTGHB^XA1-;3_Pe0S02?MTDO>+AjTbsOQ5b69__mwMerFVD(wY)~5u zMZibYJn0;=9Ea3Et6g7$Z^hXH`Y$!fi0+lPvVhv{FrgQHrrihGB)PySP^>0`Q#JDZKoqPe zh?*lGaEPLnIHbpq5A^I4$g7+vq~v1NURFCYesGrq$9EzjDxBl!Q&-q`!Rd_4|_kv>wjqi zFiRVUn2uIV&2SmgOTDUogMRidJ(YwH%ev8Ao7Nd;9RTd#h^-=T7^>-#mtB*ZEa|KF zL?ScP3@Z9npj~T2`~HNC>i)p_aG%Jo=l>U*{M42H-)(Zu=2K3ZJ0W5tH8D6Dbu>#s zg62oukCJ2wVjxKJ-DC>H7_0_oR)@uz)v{yVUg#vgUEpWTST~Vz4g_ljH@^E`N3I6b z$;rucpZ8xU&_7;V_j-H7Bd~BC)E?vpq|sWml(gp|CWB`wHi-5snqc#$Bex{_v?R@c zc`aW_G*GuAh#qR%lV|MA3I2xaGkHG8VtnQ=EA~^EqRq{|zrtJt_ zqDeD<=CP8%)tN__4GAKNogtx;XgV#`Lypyia437P$cOEcTbtvQ5Kv}ZUvHIrqFFFY!nd97%_*JKjzR0_=;VhjEAIvu;Zs7@Q1+BqB;e)iG4RK}U3gUjXivd-GZ%p# zDvC%wHy$akK^?Z?38RB8Cirkq4&rkhBvq7{;n&xe9}T&qsFKvT=}GNFX6iCsHwZ!I zS+=53_JbUfZzyaI(HFlWdm^DRbOwkAp=z{Et|a^`T1`CZhU8-kge!NLBzpb~In0yu z5KulXbL`(*rs4lb-cr%n(AmM<$z9ID*2Vl&!~ee=>0h3+Nm2R_(R1%LHv7F|ChPBV z-Oxq*1$so=KQxpn5X6MZl?q3{*$|=@ix1a~Y87Go zMcQU|fG@!^9heNI%UCE0RTH6FhoFRv;@S={!1`aDvIZWCHxP8B{3at}vX21_N^wz8 zg5BiafW7Wwm4`{h$vhOzx#|Y%QS)H$i?Ed0NDKGQAh>TaBu~vX1}iAk7~<*2(F*$G z3D9(0?;S6XNQI5byV??Jnb?T^l|zO*As)kYyecwZSxl^zpiA}Zeh{EqThVpC)_g!E zv9TitAAMxUdw7?7-ip#C4vIQ!q4j6d?#_`cOzq676{%)}cG-CR#t^WeUE#XW5)etP z@&SF7iojqqavU7d(T`pXlK-*;^qp}}Y-9?;bX@%c%Y;Wd_6gC!962_A!UA$k4}cTj zCT1#fh>#aHs%)tnn>N4lUJ$BP?ij`s!9`r3lJHEaCVov(jevS`&T(NQ)EcIVV6zA0 zj&rNg8sfh1`{z6*d4cJC!cUup2K~nq{$I)QeE(CMmHYFg=eIJ~cQpQ6W-2I7Qnrr| ze#q2atrzXny3p~!3D6#MNx7Nxh=_8f%SeLf6o%T3R){Z>18WX@;kH82No#h9mSsp%460rngrba+!O(icB=>>pG|jh)UfqSZW}`I$ zY7~+a5qrfOV3iP|1j^dJ;lYmN0xJPf=ZP6K3hAIOaR>d<-?8umS@2@D6V*8eg`wDK zkaeth_hUV$Z)JvLrV+Xi)=Ep&3cGV-+=~;B73vvHrCszXdW*4z!OYlzo5K)E?p5Dm z$6{QAK~FqRI)PRXy7Z$kCSKO40A54pRH~A%L{jBn_S0S-n}bY5c-+BH5upj$`UB@D zkqY2(enK&r&&B#bLouoU=|b5#*cuu;I@&tW{PX1Wj<|fysre+n-)kO(7O#lVD z{QP1;(~~ir=hoB4>gwYChY3lBbba8LldF_0_aWD=D~~N!_m?2>n6GNzlS5_#*HFCh zBN5ki!bQC3BH?zT6}-@0gYD=dW3~&Rcu;$X>{UT>ev%5da!S>D?(fI?dmg+hLfIro zJO$bH`1k9N4BH4K16l_hB2DWA;+CuhiImbPnSEJyBtL&9mm=iajY+Js(?^%I-0sP z2&#+~!f@9Z7|KZe>QNaJ8kqAfPQGg6$2%W4nT_yFE;^;EP~;gOP{pw*u8WU6jc$Y$ znxA+XxnPt9MkGiYQ8ShuITR-yW9A8v^e%`D*3u$h15TSEo;AmH5NWUI7(9;nK4dml z3ooS36a*N{idxK)zaMSpZ(TB$20NFKN-SMx?g}ZkZ!pGAq$gKBJ*EPyC~W0xviFZe zP=zkATdW?PmgU43BNgb0@!ga{Yau%(ap+-z%w3ScsgD^+X*NLeP=z74tYHt|H=8_S zCa1+6T9kKa;TLu^kBLV`l91q+{!qUx*C$zJZN8K|RbNZW7urhMatfqgkBk)K>-#>o zM+MKz4hdQ=f@SRMvP?%QD%s&N;s$URm2|sYar%BzmCluJq!OyJXlOaYjn!C5=;xoq z?sw-H%wedR+c+d<%;fnq-%jLQX(h806u8}ZBsT+zl1@Z2$K>Hy74A5#aFeJ@=Y;ed zweU)L3^)lLwR!QJ$E-_Ma&m^YSi{C5wYx(|Hdh=?jRGpP&DjsGV-|v7yZbf%Chjk!Z9(vRTz*ySbEHE>4>yUcKdgj9&vp$ErA#lkdr-wQ*6&GZZ2<2z_R6QKTEDS;l=Y$;K{;KmCV=;b_V5e|LlWCR7F zGKxNee1|qEy|sDd$|eAX7p8_3(lUDyRd_SH6m~fo+FTl|5srZ z$l33%$)3(CovIBeb$lq$fR%C3ay2T0@=~OSaj0@N0>kopv3Lc5!VLa23$qHmSt^+( z)7AJ&^5Co;h|dOcnlFZBhWtYP&)I}B|CP3=9$t_`87+B8s_gwB4k=$HVGaqCMVWC- zK*MV-R#cln_y}t;228Pf>7kgO$EWlKuj$!)khVJ7S!0}KS^aSR9KAy_$%J~{4RdxU zRK-dntmWXCipP~o|78NVxqd%>4>Z$4)EP1g;nHeO(-WsOO9rCvWUGoR$;Eo(gvr=! zE5=>5NlL2g`vQu(p>?*i?9XINB%GLmzC`YMCiZu@bP+Ik1}h6C#4wE&3ZbMvOc&KXb^)ER(%dKxcyndd! z3iYnry_gF9rlNwj64Rl;T zF|EEjq4iv2Banr|G#px%=oX%|%YC;hAX;F?3R96SqJ@4Lj&5nl7$(tk6azr7krPO~ zIiqMQLsg5a3s|yhfeIQ&ub3~9e0ex2j4;(0X$L6f4z%XNVjn_t}<*i}uLH}aNWing~P)gA-|u{56VcLxU+tf2}w zp0X(2+L2U&gGVqUaSOZ!`GVBvwDnu+qm;bWw6T`0xSnr}nWmu*Dt5-O`e?Tx5pK60 z+3y6|1~^mpkUD(}Hj^H;C>dhdQwCY!d?>5&=aaCf0&y%7Y^GNMzlXbEY^?+^M-9Qg)qcWyFkK9*`R{v@$*CAU@tiK*=#zHSmu7s zm&Ru~r4uDpGjh4eBamYj#ei*0EO57CnrnslbfRFae?uCI1sH01V<#8%ot0&FV5oRP zlqdwF>obPNPJYR2kP|cR5F{QjMXPflBW^OTg+w5kI;%rlnl3`!>w>l6qu{iSCncNU zNhgXdSdOtYPfTMv{@R)Nm>t4-!w~%zEm=iWJhpS-4qJntExE@rYe%n}HspmuU(|oW zuNQhA5M9xw(fa_Uv-j48YBiEV;g;pU1V{f`y7zru8q`+qS_IVA!7f_z+&%n?<0@n1 z4Q&1RAc{&D&i?(!nce_Zb^}5*JaZUC51p@0#5l3l`+SrR>~VKDWvwKz*|ICpVfx8 z;O{aRPzm4;un4GieKLe>9fA1U1L3Y5sBUdKhuSDXHsrRw*YF+Oc;UVr4t-I%Q|Y^h zN4p?;?i(xB~k3}Qx1-wBiPMt{ys1_enJL_9)7354o=9>0M4U772iO>AKEWz zz>Uth%u?K3yhXAP=~)KX>kHl}8)cZM9TIGDnoP-E#z&($Z_g(0mu;X&>}C7h^Pe<+ z>yaa&NMt#g%|lj$rA8FF-$wdsMew)K{0vwa#5&)Jt0z}iK@z3YK1R#t`SIz3emh8c zTeHcW3WGRN5RL~Tdxjx22vDw0Q#1xc8iPkjTgy?;m`a#;@SXLHtun&`1$9S9PF)2K z7@{B*-L+=^^r2Nyk$UC}G$3-Dn69laUEfsv*FW(*cJwcH>A;^~O8JBhT~R;JLxmlJT&;>__4q zv`(3m;gqs*JUh_5)<3SMB)mQU`UU;NXMfjBz!qjGH=?NK>$ld;A6Un#bofrJd!gIO z{`}uNtMtfZO#1B$N8xEY~6%G5}rDr)ZX+o-gI1|P6(G_osbp>BZJ9w2z) z>8a(A0*kYa);)tl(Ij15b*69HoXu+K*bH;ABQq%kzpzH}CHDs$^x1kMakd(!gpfIWlZOYw~4+Nz1pi|$kouZ6v%om0erWCMV#WyhpL^HARH>(9Y`XKkp?ZgPET6X1IO9Zw4>7|4(+X0ky|rB9qRyA!dJzfqVriK$_^0x zX6@hp^OtQg;n%F2=1w!dd64tuAa)uswC}n=2Jz-_37KFSi!SXajf~$Hc>Jx!8x$Kw z3TvTp8p~0Dfj9&?kr)p-V`828)GWF2;Fs^BCCyoXnIYy?85|IXCgc(Tf>q3?TKj5d(Jaxs)64tpCrzftY&qCN&Dzi>lni0ZT1vnI-@)1|WILJa zJ^NJ{XpYDTPQjt)5&Dmv4f#?XBmX(oTnyqLUG=|`RsP__{6}P!|8mvlpDLbzZ05gm zJD)q**;wVTcYiCdsaPw1PB{0WiM2vR6$)IPZ>FJ^01~6xmPC@k`pO^n^_%}f^P@={ z5%ieN@;O1|-qR!LJ=$~A1)B=TTy)NB!D@B~Bsv6)UmWDqCihb(_mTBej_=1C)=vl) z8=+6;fA+(ykv61*e^le@!eSDOIH%#yj&VD!{l{GS#jtUBZp4E7z?#=z zyu$*n<#YfJ@>|8>=}GPO5zp#UL;+Y|6>cyVN>9zngO^oqomiGVWwFUeZ0&Uxql289nvL%m_`w+^ z%=!6P&=j}^@_;YNWMmY$`r?2Vx619X@T+TX!J%FzvS)sP;#;Xd;nek9x5Vsl=GaK= z<6F?%q+$zxh*CU)M-#6|0 z8MJIFrOQ^M&18eC)ueT0QaiO|M(A;Ol8rl*Q#>rxHfNAdx(p>w!|)cj^Zb{sFIhN> zUC)ApKQ-SVraQuULlyY#e($)Pr(oJ8t!J}ZmyM8Itk_w3No8E${yl7ChYWe zLBiKZ!oJC>wTl7p=FX@YS-H6%_`r6=4v>%hc~6lYSkGiTB8KS3)X&&_MgXUKDlt_E z;p3Vqgo_u_aXfUQrUu{w+O~J%+$YnK&B@&5F8vR0h&?XjVocVa6O`g7>zwqn3=UBA z;WdO3BukKT%{!_}0kvRQ$5{f+ggo99Isrd<0!%Wr_!jc@HI-9Wzgo^v@)l;Y;jK7MVS()^D7@a!Kg` zrOZV02w(})?mC@{`sSFJ)fgm{$lA{gbqFII-w@UX zO6Ki@0c0-RDRl)JMt6y7F-23KGJ;@I&PK!Lg!jr%ix=wt=5$c1g zBEyi2k+qg@Lxc8v^5QScu!z2CMaJhi^!)x4t(sN5X8u7l2>(Q^|DE6d*FpsQf9e7i zj6X>Rf6Yq$oX7l^w~LD8hWe~P1Z@qZKF>ku2w=5@E~`PQ_~(+QQth?tkBr8m5-ZO5b!}-E?kzMMggyc7%c0!(Uw@wOqvyT(IiC>m}>1<%w|EMAyt%9+NP~ z6Y3hWxYKW~>()UM5#0i#);!}FyT5jJI5CpHNrD9E?&>Deh1EK&M?D!6w~s&sg3u=- zdWh|X__!h&{n=0EWH?*TYc6C|5?6yLGe$Bo=p&* zOBODK_m$?7A4!^yWZ>95EX=ag{kU3?d~rkiq-jG7pBlHDwH2+J^*{5ph!malot*zxYpePj3!K|C0|&hKpx8}N zSUY%(3JnG1Q$*fC;Qp%skw}6`vv%__O@rX&UG_1O328 zO8Mz&HAhKB`^(bR74KK69e&gjdI~@)@*XCKzKPs)tbdt-z^OQjqJnHiYte2q)0Gij zMz3~oq@9p(>sP_6@S~K8CB`HT#@89nuiRxVx-1vT4OyX)o&A6z#`L zP)g9NPkG?1rf@jMCE!oo*O~%6VRU}80X1z9Rv1X3wjTL*Ar~>28kEmJri6#cv)PU(YDFZOo zmSax(UJH4O$sALed9GVpR#2#@H$VP0{>c1*k3ZfirY@$CzCI$5z8xBXz6Sa#;RA{$ z_9&0MtVy)OX|&>*X@WOB!Lv(nfg#UDgTNvnxm!0K50f|@zYKY+(1JBgYbKhV{@ZVU zkY~1S99L-%3$f5)Wmx4g_drINC81g75tpMIn?Z66`&@BYDCSmJs$EH|Uk-STi26x^ z!PoJ6Qn!~}%NAto=R~UBfl;qJ%n(Qe63ARP!YIOhh_vE#1jaoztel~#9mXo&ADhH2 zOXsNWGqe>1|3?@2uVl0TSDWOY`Pxd>vPk^!KFwX-S;DzLLi4vhH6>&V2F=3cA)|<* zFyXK;d8wBkmJdCa)}j6I_I%;r`SNG*wqqD3wP~TG!c8$7psy?%pj z(_EGg@2G$Yqd+D)4CiO|N}wiDsW6tBI_gu^X3E}s zW|QL>GJRO9j>&0tg}FccsOs_SDFgQYF1ce_Fggr$4e(lu_Do`SVJ~l!^-xS->HPal z>r>?q7p@EC!mx0II~wI|-XaEj=2qJA;Y=J{d5o%i$rfs@^3>Hm75sQ7R|WTd`rd21 zb4M(o^+`bh21i>!RB=p&0wORaBiFB`4tk1-owlqGmyq;Ufu3CKrW9DIWsG{{`m#Bq zsaXlaiN42_n4hpCVtVmL91b-4;YQtfKg^K{axumSN2VaDGP7Pl!xkkDAV%PTAr>I? z+wf2b0~fI;ghEAUhw9m)C5X?oYwjI(E%Fu_Z#)X6cnBmtt4Q#&e!(wCv zp>WW^{_(_Yanj+CVTiM}DyZTjc+o_&;;T-@X*|u|mrl2L;l zd(m~mFbI`a( zF~$2c_poqEv^@+AqNNDr@L8MbidH=_=O)@u8u>=PH4Q*CG3q{2uAcIcl&E&du!?-C z*}BHuNIOJyZkA0(?PBfJ>Mt-tLq&aulJ*W;H>0JJIQ9es6}ZruxQcbel-v#i*H2tk ze)`rUoW|O!@Lg91NzL`EA8+;EDn(n*qcSnYYU|W<zeV%9Z`>7`mCa(9}A5)iL3o#oRNj4$GHG9k_5!5`n{y$&w@NRrzvDG-p zu3u$8$Ty;W!mgIP%%V47#tbG(9^1M{;KydHn?)mVXKmpPSm?Bn z=wcopoow&_#_+h;IGxYn;eL{{avj%19%rh?qZ+l>nRd2A73D7K>pgGP_nf0pVx9hMh? zHq!cfq${IUu6sAttsckaxwO~7X97I-eS5rZO1Isum`IQNU@~dMNCWr5AQYx^%*Z*O z3zoJfTfrtIkS!3+)%%%G(?od7GVN{S>X^(Gm9fD13`XkP{GawJq_+kj#g+Z;~ zZWy6}pMh`+=7B`@_t3k=twMr(;(34di+RKW_=Lx zGv?vg#21lqk2L$xKKNxt>`xMuYhl;;-oA1#)yFH9v?DL^|9COKA32sp4oaGB5IKn{ zQ%GD*RKe5{G+z-H0vmaci1(B((Q6}5&M^4r3xk94J+d$Y@%q8l5(JBU#zLPcIMqk^ ztpghZ4$()B#P4{Sf!hWu-m(AfBGMf>DUYm-FN+nsH52+~GKCe}WRr{%ds~{d%=AUn zN|DX>#3?etG?Qy@AA@v?&3$l$Q6}5|_K#Pcy>T<{;Vk5}7{HID?IwY%{$D$;x)#7y zaGeqB_}$clo~W}DZ=fPo^*Vv}P|$0Bx`7T-(&_m9^~%3DVTKX;M0eQq+p+G+>4Y5b z0~AyJ_vu?RHhKn#C-b0J?X32zBTtN$;a1^6Y6hD)`-n(QqjiEk)W5yL)WS$2!<64{ z0DHT#&=ku+1jhA-xV|+bs&j|`?cev2P4n}aX0IdiilKY#|KX;(H)RG}IK%wP+0R9D zH8gYe;>-881kG;_UA8?~4EUNi2Yv|`3kjaUB$~JMMhh%=&&SnBjk?iU*c(j^B+6bO zAuJQ}7@K{=3kP?PqwbnnTW$6I>)+oIZ3)OW1=PI0bpV#=i8n9TgmGD+{2QOzgkB{* z!tsY_6$@SC)Z1cwgsh`L`NKGc^f|tM&(>ThIicMa26h;3g->4F(_HRc4Rw8qguuf1 znz(R7?1Aq0qJdK&n)rM&@K-ek9uY@4^b@N3xcRC?%(HZ|90H} zbrh-){nYSE6yn~R7nguj_f%4&S9CO^>|lpw4!Jjct1~W z5{yzicR6FhynDvXS4Ma1OZGLq9DDZ>8Enu-g=b_sc@8c`p=P~=_&1uDAjG%CPYy@KtLV+Sh zHrzI-mkQwI%i*ru7gM^@U8^rgb~;iz$OX_8JSAVC8k>z~YtyB<6X+SB{LeHsGFXH? zT%1`R?i-z)&n=>utdCW48_CJ6Wr!J@vm05@Ocw1F^)^-K+O4rv6!?{mTDnzjhgavqJA9McEvH87a<_9F8*-H*Tf&#zRSwXg+gs;^TiWtfhds zHsMMb)_y!tBWso8giV7;8TP$bL@=z;kFMLQ*7OAVYL2IPX`4Uli5V5kmK`u^OrRm{sk|Qr<0E+ej zhiaFKR(TJjR_5I&PHG)+Yal=lGpZ+l8+mG@8FOjAG$$k1dHX3`Q3{UO1~a#9l>QNE zAb@m4$`DYuWzwx&YYcR1wqi*{ibt&@sHI4!4+fQPA?k5&v_cVPpsr&=k0}f|GNyT2 zE5r5%MQMr%2gFg%WsoY>Hqc&}8EaD*W4`z{8Lf*Q zK1oE$^OTr1r+b{gIK?k1gefu#bEL})vBW!C{NRnF1@}vSmnXCyQZG~X;s>CW9ame; zMw3QP+(>0^ZY4?;TWM#@O|wNK&nVUN;#!Jjs9zdkavXFh$E=c{efhf1km*z+76S%~ zHE4Jdb!}E(7Q9(WO)%P_dXL2l(F|ZhY=fBQ2qE__&%*4MQ`a1TiCBIjvo|=7!7|yh zt7(e#Nf3{Z?xpr)%sxk2GzJ@{W8-c&Ubr^K6z|r$!BnqwPwX_Y#S4(ZPnQUl5F|!Y z=I>-aS^|)ZR|G&!LAXW3^m`@&pIE++&gL6oiVD{y?_ew2*M!r?DZ5fw3JbHvE2#TP z(xNV*ta}g!Ba|_S-$NB6%M~(;V*H|iNwFHCsL_M7U!z9nXNbPAIf@Rrf&>@~HQW}}m*^d&B9YHQuYgWs?;+6Uh> zhJAy^agIWd7pNrNBx=zm!s)$*j7`fQe0x@na47$=f(y`W!C!zRZVcWii>83am2WiviV5cpGTAPw4? z3{5zA&q3bwnP!KAky>_rR6U)w(|}b;_kbOmSjiQvdRp3a+ec?pm)zFlS?g;OD^s=9 zko6l9TI4)g971$Gq)xNtOxYzlUrSTD6`rA?s|ujGa$&ZT_z%}rG>h~rclmt+pn z9N9|c1kOlIK>povtY>% zxA0=XHT(KT{Hv0tQvrc1_T^pAVeq z6?eR!1hSb!lmyP@`x8st2vkN7-=)?LKgjAC82tem zP^Km6v6jIVN0aq|BbK2)_z@>`?D!O68ZD0a&Tkm2-ZLDcBD<6~;3SG>mI|WWP?d>Z z!`o2!>PsMrmTbVhSgY46{%Bw@7`?Y-YbO`0<2M5^QO(dsgW)~LT92|TGKv{dVRS?l z?aoDZ^su(K6`Nrlj^#sGuqRNA`6h zL$Aq)cDEl>f=(~}Wc{2_1fJiWEbvW}bovzbOJja&Im}-PJqipM8FA9+1b@Zor5UKh z^2{`2`6YARA^~C)-=h?~k3xda-f3#qWNX%HV&=xF9a2S5reJWuUY{Xg5h9pk{wg`N z?VOY8mjQlLJ`6fu^jNXh?|ei@>vck4b7EI>55m18IV3MXBlDM{&lnPegN?Iqe!Jc+fGM)RVk<~B!gVl-ZFq@WZATr#-|7KB^*>xk)ZZ%XbE zB?UM3V|HKM%%iTrC%T7Mp2I!D)CkdISyiMFuxz}Rft^Xv@`>#pk|2uv( zx3;tTgU{wL8V`%nwx>J(8wj|JJ1&ZqG-$IF9m-_Fjjtv_YJAQKaoNAdj~FzuD% zmu2!tV_BVG6d>Qm4E!5~Fies5@^c zCJ&aZHwGQLB@>@y-5#hhauYLU;pb^&pGA=NEaJ}yX}8bX(h0%EfWg!yvl9IBr_r9t zk`5NY@H&Q9fO-Je8p+l1r{7A3gE{hT9UYmUNiLRNYUCCkENefZs$%rEEtZ;z%bTIy z6{ju?GiCZ&`219f`F#E>cUq+S z>iOBqS+&1>Qc#bSjhGaq_8a%XRaL zn-S0J{?Po(()JYvZj3-LlKjB65%Pqa0ix$tsGc+O)rPhut=mV4~R zQZ%L#v!lJUOT4VNx3kJt7AdS=n4ig1qdBf~Wx1b9yS_=Q@szrYdrf0?4Yb|-f%QzC zn_iEpWa77vOzc^F7ELTJB{Ad#946wuAW{zZ_h&Sex&f^^iX`!sinMVx?;L-*iZmvo zlCsE|G`w{iHEtUoi`5Ab_WT6$&L=RzN51efb#@;*$T@~|#efy3yWo8q0!#7F-lSSB zh)bJ=0SOj4J1M*i8(Eiu1LwL3C}pc)>jpsxMrIY>V1_Y?Arh%{as}b!4f9p&WcQLd z{T-(@4*~xNd{vV1$f^xoDIgKGM3bSzS9|V@rUh&6?$RB5I zc^-Wx7?ftI&mNciG$H$zq@Bf5KItAWnUPl73oZG_=1Y%RB7Hh-9=kV@mYTa-j^8-} zK`f}jf*_;m){%>}S9Si)vPxdS`3?Gb9 zsQTQa`zTx6v6;sXO3gcQa62+fhfkGkHuM%Z_ex>fa7T+SnKH2uSu(}2+J$#7YheU~ z3Cq^S$d!%mTqHTF^hSc>8)l{xwA1dh{p-aLDI82TC8iJaW4bcgj@QS={TcG2`l~kT z{YmMk+>VC5!*PJ>BKaL#=w*I6Y7ek%aDvVmJRGoulQ{fptlFNXm;K~WpAel)ssc|k z+Dx6DXoXcEgpT_Jo!o~lG=jsJ@G#^afobi;R7w7J^rA%uSDN>C z+7wds%H1KUOevNWgkCInQ|cbW0or5L)p z>il8Hc&TLSN#hQLwzj~OkyM9Ghdiqpi6Wz^*1HJ z)c%WKu*!Pr&e3yFFqO@brkuHgvRCO&%5zdMik^vY)eh@(RWOXyw=Tp?;t7t%vgfQ| zYB95C?%%mPG0zFXuQ%QP7<=al+pi75pG{3rKvB-KuNlGMb*jC$5j^6|TvRta1a+02 zW|Vhm-uVj=q6c+jdn^8TOW8eM$Z_j{!W*NAKpAzBlC+cY2vjZA;3XvFYJ5Po(2)pK z!TSBOkSx{FGD>{17(mTQSV5jwzm1fZ#Hgt=2P*qw1M%q?4G*>oTRCPDdx1rhO0q<0 z$Ut*!nUayE{wNy3)Lw=to4GQ#E;H^{7YL~7mti^64Tr~C(_UZ4DfFj2p$|W5Rt#$1 zvIl962aBaqJQPh#Q?xTv{>Ws;y88;d2hZvA&eC{Iqbxtb_zhOO?|0K1!8bkftD1g? zkM8)Vd6LZ-ZwI(i5?a3T@$_$sIC)+YyEBlkUxSh0 z+}x3OCw#_9Bt5LWHgvg=%%tK7X3ZIobDak|3$l6eKTeW)d_fC@+Lp)16 z8^P&aXuy)a8bY}lT!{d1&`0zEM|YF8I}y8qg8@c&jl=OH$hi<&vGEYoix%eq%fYZ55`fB+nW>mPnt;9C0n|t-Rf# z><&FQs8KtnQTvvjXdP?n%oA)1&mr+R?f_0>nv8PTD3_Nq!%!Q-azzBVGD+I(uk*Ag zzNEZWX649G#vcDAlj0^ri79|wufXmVd%mJ+RNfb2{aQx3SYT&94wo`R2?HUd&>h)4f@^Ct+acVo?Jv4!_qui1YrPMptBuvS3ERmoR0ok_e{TR6M`d-byG^(BhywO|-rW zo`rW0afI*NORN?dEI<;eu^|`dHZX(cq zg8N2*hs_Q=|A}SDL9fuF0u;w}Ir_tT>~+j=JTa}S+x-)5sF01x=wPmP7Yd}vi8O>C zx|)uuQI9O7N@QmfEyNHlTtCTQ{eF^RV7V>3%3=Htz25e=MwP`aIg_&Q*QUd&!Gk-PI6c;_URAd_0%`vF{k1LB%Yn+zUH04di_toL9-%X=OkSLFJV z=dSpa{dipfcnEB{Nqi1R!##nZ(HJ#&NOR|5*m0ADyj!i?EJ+dfRmO(SfspK%GaUhC z?+*~~CHo*&W5;dOpb2L3a3htakj#=Y5Ge2RcM9F(kje0BI5(k;^-wA#)nN28ransp z#i93D4nfFGA89PEDovbQIZ;f{Fx0C0{=f`Tr9lu8(IZ_*s`a!+GRJNe_^oGgg^awJ z#sJMbDSE@vz9%fzR{l}`C$@{U=5xgJPB4`X1t>#~%iXS+JG154kf0bCt{HojV>A%i zWjYQV0@90NbcE1`8GC4LCW6Vcz@IcO<9%@)=E>h{lo7$SJHL)YclUiml!dPquIB;_ zZ7-LCAX3LOZ3fkjeDFG>BR-aEAq--QN&}95+!tTT z+lG`1;|^ zME%et^#$7q<0ax1%U)3x@)%sXs7}~g-I#D9?@9ZLlp%njnuHVGcpLK%T1DciI^)=P zN4NAZT+e^k!YKX6Yn^{ak+_Yy)87H(NTg`&XXQ{BIBcjwR()g}-QZ(gGR8 zWOSES6p>V8zsLzP(Fz2Diz$#)dzP?RL-+N7+&4zvqE5?{UnDyg@PSFq0Ptf<#kI@g^WbFeFvkgne zfXAp}DPqk-#gosoe4vNO*=}^-l(wj~{xuNVZ!Vj1$N@_R$A5(P%L~>pFyd zSkD`piA(V2MzS~4LVgw;uRsEsLyW&uXos8xSWB{+fKMkPb!OOYG}1Wqt)#Rc7R{Gr z!yMH`*|60tF!rtBgMFZdEIaf2i-&m7s_8f=xJx=rD2(pkKq3AH?;kzO4LX)=iEDzf zEDEA+mf|c%b(Bp?-&g?y+7&@J{=C0$~z_L3y^igeY{hqt)`0)B?ganxCKl>h|= zO<^H^kkoS)Wx}q*xImoUX*tqjg6BDJZw^htp!DvexKd zJ{H8A+-8J=@`vo`IwXHzD~fpc5@?uPOFh}3HNeD-mz5OXwRn(D3B4?WM*mSOE5UB= zMw@utEqJ9kXy-LqLW`g*eNx?{b4QYsSkW|V*vmM0T9~Y^Rmg78z= zzsD|vq){r(v;oy%A!AL+eVNv>Y`ye=y=_9`o3g~=Xuuwji zrVz2!BMgf%m+FxAdhJ?#jb==Zr@W>M;B(eT_(eNMTzKec3vN7Qg`%}y^DIIEdIH8+ zngRMC*R(!QuYm%BbzLGSF_%P_Pcdsf#Ms$#mu~U&?4VWYM=k+SHIcN!(0y>jvV!o! zCqEXikcP7~MkS}Y)D3Tmb|0?1w)83zsXZQx6J(yiN3jdtzs4(ckUV3c-_D}le-Tyw zdmwWDuLDu)FXrxFK__i%Ucwr4;)ROfcI>ON^B1Z_DGPC{yBFWpH`hZLdj-sNUEyx@4@o`cD z46f)1UDs4Lwh+@TTF353I6pNFPt=^Td3R)fjb7B7@jvK8{qCdR>~w412hS-L^mjw7 zdR8BY9kGkdpLdYz$U<%N%d7>A%?!Xl#igh8p}D3i?Sa#6#-eN$&RkepT6!iCv`WTe z%$n4QSs_Dh34V&QU7zDQ&j5-?l-slHQ~PE30(GapOo`SxFo~_dVw2A|b;!|RnN~v@ zr5*97BPKq%fO)ODmsyuqZDDu?~G0eyd{ATX%%7yy_GsI&}j! z=&8gE*L~{F&sI}rtE?TP`l+7iPGLeYm9f;GAD58oh=X=fLDkV_m2vQ=B*SrxF-zOH zuA@b$VzO|rH#F>ZoPH7g+)V2d6$Z$SSVB~Y&b|3bs?iT`h_b+?jGuA&Bzd0=TM5&% zS;|za1rWtDy)$>9(NUjjf+*)0BJmu?3+)!Tk!xy%hSqde@1|7hkGgvgU&@(0`K}TA z_EE1AT4beUmlTQA4*x6iz#>%hXs7dw|)UVjWL%qbOqM+InwcN^st@2+<5fFmRlFkz3uNtvtU# zg>g3oErG3RVe-!2%)XFbF$mT|*=8w`7=`JF=%KI;(*}?>CHsqJE8*z^BzJ@3VdCrT zNb7|AvV~BI$)&BJ*E#DG+u6PMeq?;2-@u+!=LN!LrQ@mOw>aaP@)mRi0Eu&+7m0_{ zV(guVbXJ&zO$qd4?Y8oF48m!;GWWqZv-j01zK8!RiH|2btqn=nDTLxbHfW7fjv8D) zVaOf^)HsF69;VhnY^=$90R1aQA8#9DIlp5x>tAB@-)GqW*{J=`!}2>ugF(m|Ef8q&E3Rp{+@-Zys09JB6U&5@r4PLe@``)XEm4u6#e=Bg0BYr{!^# z8p4zs5v^&o)zeIFX&o&LCIblsKzEBbj#QyUr9<` zsLphuC^ib>6Rux8`q%e&S=Jr#(J6spCK%9$c~BlJGvZLFlLLNPG;latY`6qkC_gLz z-s1d~jd$<};J7u?(;~_5{6hV-2$^rOQ}~=u0baf|pg)@nFifFZ=N7$4?P2Rs;ncIm z(2*ZxDF`$nr>^8(f`Q-3%jUy_X{`t(Xc&A@xW3RG$y;&G0kCe8V zxjso(b|;6;Z@5!UQ!LC*n%q!~IHAO6%?rj|Vnr>Z84X9v&1&p9Vv3Ur_T$lZA*q75 zK9LVXUJDr80BL@+4?FX`oxoGD#wO9(EKsdI4YmVr9nt5|EzfvJ zfZ^;N5#4H8;9j-Lm)aV1>Q*Lmb5XHzyndY9J6%wvHj__ezAGZa69t-}8NuTxytLE4 z6&)Qt)j?-p^@=6g7Am*gt8!1j{Ne5xZH(>g%fV79tuqD+^ETY0C6!mdU}TMpBeuUD z{{G;#R6*+ZUc#g*h`^S1^c#XC>_UC&bK(eCPpcHQmTKu^&jo78+RNLOzPisb7Qq>I za?ohG?K8>YIWWO>{7X+Q0C4qt>=yZ5kAX8u5aCf}j8)#Y z%F;Wu0qhm6q*>&A(%WPk#^yZ4nY*%82*6^;T3kKDxq{(RH=4#a6~_lQWB4QnYe!IE zaS~aEFe!eBc06G1xPa4cBA>|1-|Iq~V3b3OGQ|)nisdL+c7>@_$0b|oZVk6q_Sl$P zRq8noOjfgfr@rXB`qs>sLt6l@a2pSoE{LA$-@5}octwO+VXZYjQct0L0t$q0zUZOl zKrB&YpU^Ri?$qKz#BQHW44ZzzY&-{6Z9^YW@i2D5PB`wXWH@9Y)ZZc(Ez@d7fqie6pcFp?}3Nb%r%{iAIo*huo?`~_He0m zinl04BwCx;2$t)eSQf))MH&7M`^eUQMF@4hk$fNM_uPcJnpeHqZDnWD!fAB>!uS<> zU&gqUPSn0i)NZ?mbe#80?Ttz)(`b+_dkty*EWDFy)|NOO;cq^K(G0k-F5}zT(g>NIUVWP&=~x zRC412ZSgbQ7kSoAnzzWTvjms$M)tnp^ETo(A+3m8Jf;X@EL_2#a}C~_B%E+Q;n93d z3kFj9IfR5!@C)#-B;2M3fC>Ap+@FX3??SYHPs0EC9_pV-Sjo)6*7Ywr-#1au&HcaU zUZwT#<^=A-pHHe4p>D&Fenat9}fW zw#jf4LPgC_LZgYer20tw8+$Wod@stD$o;De z9HhoDCd%wB$mfyf?w6uDn3MX=v(a(2h|SxM%3`YwfZg8;l;bpkj<%SJQCN79YWTLB zlO!0albpb33i7QyCbTBAQ>>ff)i}d0^P}CMFHaPOFxm7~68Fzo#dZeS!IVo@>l~~~ z%3ZO5p$N8CRe)HC(Dtbp9tuJ`z6? z;Wm||faHSFRp9lu_rE-k{SaTp>|g@%O=Sg}9~jrUneEI$|iWcmoEZZ4*R;8jgt z%x9*Na)TW7fkC+TRPYFF8U_}zo#Z;=Si0sT^MY>ElHcEZD!pf}{Tz-xYv>-u~3O5<)o1p@Tj z?ta<9{b;!X1qXE9vB5%^PVvYx#$R@BhI(o*Zo^G9AtsT=Ni>7KR(89_qy@C}c{~3v z04{uAo!;_y*I)lHUH`v}IsY?@-oo1LpK~)sV=H6BZ-xQCk+u2X#Y?ubdg3gDdYWP=cYU?W5hww)QBZO3Tv(IB7@8~0U z2W1G{IFzo#*7{x6lM4$j&&La^pLmt|4jsd@ct5g~os>y@zY@qi79&Q@UPj1yYp?uV zp1unEF`JFUgyqQ~HE>t;E({9WrNf5dOlLH;ISBHuSP0`G^^JfPW{jP%G{+otRI;~g zIR1Pbi+RqpUG<+AX2FHvHgf3o%0;S{lBsg){(CQTuNWp2F4nkpe&(fcVs6Ve6}v=z zcHAw~m4IK1J){wH_U59?XbO;9h!q93R&DijPAo;;6f9Qt2V*(pf0%bQC1Ru1A>eG3 z+%D}1prWvTQpb3%msEkK94F8sTWLfWcKkZDYBBYA3pXSWv0(?g@OHI!JuZIKDYXQ0`G`HFp!|wBA6;iPPG{AMG=Ds(cOSge@E(#Fk?sTjOi6-Dtg@#41A*?}-qp zUl2Q1?oe&<26HIZYGhf3=xmVQZ`{?a8up$bgI;Eezk+X-)aGJC3Qg(JHM#=FO$9KQ(VZr6kv*ix4p692+hc zwsbz;C~w|+A-z}S?X2YLw^A&xY9C9EL@1Bg$ac zneQ9ff;Z}W-Wf&rP@Uq(kGqW4SNS5}P#gnXl4f|LlNPZF5cirm9{x2Z@kAo&{2+8M zQFukCH!!EH-lw1}J`_{?7^1OI3p4HY?mOz={bBa#?&xjzQG%XIMsZj6}c|I@nezYOOYbU5n61!y>nLl~m*?TsS!cRPd zhjbOs|8QOsgl3({d^aGx|6>C}^Ph(V-*Njr+5Tqx|2>D(0Qb^TUgRZZOlM8+q>)-{ zMAYCAHk+41Av2al%_uSlH?mY%1A#DRa2GF;HknhGm{UM0FSEK7*o4QYh@i?SQGzo< z6awadl;#uCf>#nsx$?dAbWay2(R}fFne=|zbe-ltexG)j?x2PBwtLGKa>Dvr7c6y< zf$?Np?&pwoymM-svb&Rl#U0XtJ-+#N0DGEo9($679*f!5+2(Ywhkz)Fg;N*T$DOH$Cb!uJj^kP&r?l;m``1Qi`R;7OkkBABQvKLo~h8c z3Cgmle>*a5o#kursAec*fO0SNRL@m8IF3wO+puhGTpq!&y0)`d-LSwmT|a7F?petrLo#*A?MHGU z?M4>+W8pr{z;p?jTrNH%V(3=fka9OB@)ASm_^t_hd!;kQ-8txc1z&e6c&LUO@gR?1k$Q)zPmc2W8|MW-P8O%&2WP z<{O`9WE@3|t({euE?UcA*O=Lq*RE-7|H?O^R@t<(P;?&5sD40pUev_QtXN*stEp_( z-)ui4DVbX{t16^gL4VQN(eWLGWRF9 zWq`k=fD|UoH=;5TLNH!j0+Mp61{3WISC)$DBgRb6Ql4cAG#9aEGgu()(2QOQ(X&j& z&kz;tt%>ecQ@gC@H!WbqGNr)K?2}_MNwPk_q_$)+;7oR!7o;alqpPq+hlEUxqAiXK z5d<-NU@7EI`y-(=@J4`7!jnkOY4%tO5H$1Ht{00Sy+19;Oo#*V$TuMzTsYZGlt`?O zQr$-zr3-x@3Dm)#i)?Fr8%_B;@CD-M_`a#_Q z`KG049qp_}_e6d2^5neS5U(B~1iMM_kkx4kOO+{>@4(UBWjCq6!0~1+-;Ir|MpC1S zJfQ&V`o*GV!ppJfokrZuF8EI$qR+{0a_rh?ETsv;JecRR^x5Z007j+iK(Dx}D4lhF zM>Om+Ok}T2I|`Otw(g10p_~OlLW3t|V5eu4Oc(|rQ4nD9rURuB49Nw#S#1lfwTkR} zWB3B=!HDyWO{5wle8OFP#wX{H0SceOONHJ~;ku+coj-@*Mk(+l#^PHO5H;rL0TzxZ zZ^_@gWwCOp&CVMN#Wm1>UtcRV$0do1#=05RW5(mtPg~z`qY$LogzDfC){&pDNK!SW z^4YqKA!utm_X?FE2HB;WowNAqbG*LKf>`~+m3*~{B_Xt~PlnB`UyXxO<;tiRL8ikm z8NBpHoEVN2ySx#N`+i>q= zexrL_WJZRByeMI1-Nf}5>84eg1zi`tx6xpdB0mZJppLE}%M=_Q;>8=krG>i2GgYou zZ=48Y(Mw$-J{JEz4#Lmi1E2$Pf}BtJy2fRMA5S}*fC*6gBMWT&?kRm!QQ1&DIS5L7 z{adq4dTj&?#>rPXM`jEt3`-%!7^BQDNf6;Os&mR1zS_sOGm99$ipRD$O(P`|>BYr8 zjZ6sALF;c4%4jF=)?G2=!#K;&oE*B-tY#avcdjpU%mt)6m-4?hPxo~RzLLJ+q~?>^rBrn>#mpZPz-!*1hbVCVYz zcH|=5vS~^w2MW3uUi3ecr(j$Nx=M4TjfJy)C%b2#;j?iMx6ke|J%mb0PsFo7`EAec zX?}-ia|kX*7vKfnEOdx#9S=X-mlW@}k6oK&>``%S3bO7I*NT;vp6X}k#2>leq?#5# zB{0>B-32hw&h=w_$sChDkAg44x;{B2lYgED*H6iYlhOb=my2s#$fst^%H{N&4~!Ka zRvQ_Wo!=|JW=zT6F>?GSS>n2cJCm;4Z$OOTRaqoin9e`RlzZQkYwRG!;D^vm*IB2| zg*Yucvz1sN8F#De?4lG>l?h(k`WbpkSt^vPA_GIKKz}GKf|4WkfC~_^=T@&QEunpV zZO?+U$`L2iU3GW&4j93aty|<%QqMR?P{EuYhh;%5n#}RBsWMsNfS6XK_-D(IRF_e= ztLX0P#kizk6tzU^bGMNWYp>s6;C%&D@`D*WzRZ9kbB2G8F?Q+xjaGjtK@F`#n}ouu~LI%1BPMQC2>ty zMAfBWlXr(jk?JxC%CoPkBz{$seG+dw|Bm;CI(z%b_w-))6#=4W6i3kDdy`E}T1>`- z`9V;)Qx&Rh$?2)6Fj=Swt_%GnW^Dl0H1jY=xj*m_RBc2}8obqc&>%dbA6_=sEhgEZa`Uu_Oyf7Vfmf zcH|>OhCa%gKiA!@i^R-Hl#nndJLe|pEe?%8mv9IgkUcaC?YJ8H3B#Jin9#|zg0gD# zohPU3y$JSQTU(@vaJC#~=8&uFm&jJIR{oS;6@mVi>h6}5YFK(-#q9BG|L{F=;wuat z*EVv@fWBDCOEB|3%^w+|N&KS9z9?N32Aseg_MAeK=jQ&TO_N5FUgOzogYr6aSL@Od z)agqIl3%zkrH8QH#K&y7==Jcs2`4DA&PExJEEO=$z0}kXVYx-#TXit2oBEv7ho#)I z?0=Ry0&hGX01u+dBsm%%C9n1S4Vm>S?B-m?N?Su*)VoNM$1(sIOu0HC$IRhYx#T!K z6)bSp!u;m#z)E%Yb1lW!EX3FmwBklf%tHejCg17zun=C%`mR9JyWyqf@Qm>oidjH2 zl7ZpYN_$tM)TB1@&Ace_Vuhv?pSXZ~hKGz`sV2>O5^(4me;Q~>55JH2D%%JM`7lD`PL8Ie*3C0vK^m#}vVzBZBfbE*Y`4N!;Yk!Y)JFJKM@? z$gobQH`#TzcZfdrN|8ykSeZmU1Cf+l_RZHfO7WIJhaf&n-4$kVOo3+{j)EhG1Sx-( z&gxeeE0!{NFL-DRibzU^ADz}(cFdNJeeaPanTvsOuQvlMzKBB4Fd)fzt*c+r+r(cW zOmB#Sc~F2UVMOK#by1-zuwNrju&*)X0ZE%T$1ZhPAMOeBAj+3=+}+zNh^oi{$2P7dVPf~4~x)(%F` zjrXnUOSYe+S(EjOBzU3HfUOZyRVvK`V2-J{1=E%2z?TbE-SZ>e{b z0+7)>+E$-?B({H1`tIlY`eRbgFsH|=lxzEZ=Mxt3?lGQqC(Zrf$K(c5+<2q3KLCdn zS_(-^Sg9t^eI~1#;HHrJsNMbBAK-2}W)U)~;WIG}R$D_UG-@ zT29M1q}1sWZ*ooawVG)?lb6rY2EC}Q6csw*3I#JBa0an+16aGXKhv})@os0_ac5X? zDjoEqOLTj9lSg=%5vc)F+C-fg&t<=Ny)X@V0R)E*6ebnmbRv-d2oz=pex((=G6Hr6 zu*9Ks+THJcFML_j7Jpvb$;iEV;tP$6(>E@rZ=x`L=EfLyhQJ)95~q=zOH5M3D=nH1 zGN~iNize67F9NiDAk~{S`LdAEd(~C`^ha{CC6BdV%;?J=tC>f<>?T%a$*4dcZc%Xs zE}d=6opENiv0(Q88}G(~?7W3=J!1Z-c*~Cy^hUo=A=0>99YxhrK$Z|O!h0=0dkzCn zkOFF0j46I6YCpo4T`I{Pn&BShlsL3EuN2cnohb>j{iUq)!P{GjMZTjLAGKU!i_+!zsxte36-uOIx~)Kl%90 zAC-1!hof0TyWQNLm|?vKfT|o|bssDCD@-+WxQ&7Mt!AtpmvQ2W7f@q53zw^W? zbc-lfDBCw9i{HjA9ZV-h&YhXCFiz#pb-Ox=Kp0gCbeF}i;pj2Dsq{Ox1bI_<@n>T* zi=Cqc%(SZd6Y|Qb@>nr1-|uC;<>d>loX}iz?z)4IAA?F8(qhC7%&))$-f(c~RxSF? zzaFAP+MCJz$S}emcxStStF}RwzCZ%M^in;CO=!~3Qz;q_^>fTd%gcDhU^TsJgHaN| zWN&K5y8>mb?SIT?9HErDy5HettEfUPl|p_Y&s8NIA(>MYmnWDsF(LP>kR?P1H<0CG zJF#`du`(5bup-;TB-e$e*wbWBa8&P^OK5bD=J*sBCFhV^^YmRUqmB1@bmxoOA=|J2 zC_!9S2Q66_Q#gREp6&ZV9!~w^H1GHb5 z_fgG|__OPt?R|uB`-AF}vue_1ir>PF9O6&ukb`L*EVzT;k||uipTmnCAN}-J2%kkH z-S92!X*k{3MG_s1TM~?Z4q!)oAD8ud&0_r~m+gF7GbZ^g;5Y0~AEm^PcRIx^2fAw< z3{ujkH10z<*A##Ou8HCqv!uE+2>@J7iJUA9~9Wn1ZT<*C@Q0{pU3ec+R&L*qz$2fiu1lTVG zz$y+P0G)c^Ff~9VH`YaWR`yU}v_w~6H`O_+8o)1R@=i#rEnt=__IuAkPZYOqs~aEU zz}w98&P>wkcMdQ+inL|Emw6JUPi4&)UNyi@7NQ@%;7$o^Z?FoIkQK#@=YWG=ep3!| z-lG6(1n6ENR#2veRk_=;4aL4NIabQasP#K-t>7idR=_U3OA0yI*T%ScOH^lH*M~kD zil7ee#w)VcIzNFqQL=ZfMHRXDu*t^j-tOn&(@l2u>y)*`qtK8Pmd7vlERY|G_B_UR zL4*Ve`+T{nk4z3e7|jrEgL*Q{l3U_>Gt09zPZUpdr%dONy-+rLOex_q)`X8aPwE%mTp1IFTjl}k%DZ>En1 z`lP~qzBpVZ2J})zv1uRI1|^>hAaLUq9&hqfKYSERK5x%-`9s(}?TmUs=K8j=^UKWd z+gb>q8$&xx75v8Asj@LG)P|G^WKZeR2A6DyncTo{*_OTJNZMqVHg#y-nB6ijb6LU@ zL#DKj|IsGavYh8*H}6t~7i7q-so2 zzBL2WKEB28DHr(;+6sej9n)!u?~TU3RmzU>feQB(JLQf_MCjV$YF)OTTo?YBAvZi6 zv^E0eT(Ci$M)I_)43tJP-W1rVs1t|!()i(|)5f{;bL{5=W$WB~;DRYnkg>~Z%4#)V zw+GsNv0Nk@%nafWZt$7uLW#>_jLX8w&PahyOd4+^gTAp#H!PXhT2=&;t)E&G7c zFr@xPtP27;!Yi#lC<7^C{5F;-5HA^^L+`iCcv)JSr`;`qPota+e-kRoV`ssP~^zrq9`$WR~b$8+Y z1JsT)24G^~7jmk>Nxx)g+e9XyZO!%3A(~EarM*W7#SZh9q?Xo!G%}Pe`!U6iAQba}8BGYC9mGH7uNFrjp zytw3@LODgL@^6KF;%}WsD$Qw#R5VMa(%fBzG@*&d-085DF!i{|53kcq){eSfQ239GN0o<46?(y}Ec7S5&lo z1ii{6&i0#57Sk;{sBKXIgud3iK3o;Puv$*O?yN+Gc1kH#xzi*=5rTOSMB_m6-Khe5sbz{+zeU*eYK4b@N^*w5D2O0a zp;-j;7@P!=DH)Q3N4jlqP{HhkhCE9Nu>&V8%x|J{#)SN9TUE5?3J7$HRvu%vwdT=F z1qNp`=AWxq^-(Sm8R?dhSRF%T5-H>p)NU~wV{lY!L-Vd3~YaJoF-84fhK7{GVqkj%k zA(20U>6)SI;pI?`VhSxiMa^jvdYfI11`p-jt+YL@xV7(MBTaSlexYP^sp^1OHt?T7 zk-ikJ%pvjNt44d&<6losQr&w_vcV*F*V=XV7BsY@-A086ClW4OA=#tfvKme#aM3Fb z)9zf2&IYs~U^*c~H}T ztZ)XU!@8sT{Qd+%eIgJ!A=_m)>DrmKMIJ@oP#u>)CSm}UzTWjX;S%)IjHj`rQ zhfy)a{0PCw%UcBl;O;D&d4u~c43p`JO>$pdr zgwcm>TCa;)TL%*)WrSi_B?-Ya8kVl#gR$=nEHw*JGwqodQ~a8s80ESCQy_7AM#zZ? zNYpL(?qC6auIP$CH!mq0mP5x4?@@3M_6G;&)j>VGtl|1Ma*{Z#u|xVTUXC+)!@?as z3?)nd?`}YvJ^#pWSbLv7ZmS&Q1}JqOcCS2c>ouyh9d0w2D-*;RfQYm;ewfCD(D51;N&mP;rf z5lLRxywI~mZL?36S|I2Iom8U<@kOjrnVlkBbuzy{m;@b|d@8j>{6_mkoWb)r_0(K9 zAERBQ^=|-14+zLYDWt2AZ2O`p;COHGBR&v#mCIdt_23EF52TSGaUTLk-5_xn8i{|h zc+=td9x>xTaQK=%rR(p~?jhs0e$?}Z{h9tz|B8+z^k|@)GIk3rOG2IB&7NqYIaU-0 z$rWr~+8svPGwlb~oKPQ|yW=Z7REJ8>AzHD58Pn^4q%BH1M*aEm53hRTR*rGux5VW7 z`$YJEvyT2VhIG)|GbW}&Lhq+Pc77)Q_#$)&4oGHYCe&}JZ;>t(4C?{fE1Fi#HzgOnxz!_9 z->=sY%_wa@Bp{#wXfQ2%?%^N+h$YcAGUTHtA+JPh`L+bRLGBj>Ld}UgZ6;mI#6(E4 z-R)}Cg-ILMnv~HkPWr^#ivqp18wXoTL|`n))}3bNh^eHM4-CN@bBZ;M@x z1kYy(?25FYqWgmYG3j~MN$W&1a^S)fd6KL`LvsmTDGUS=Rha}!vvntl&b=G8<8Z*y z`4?u1W}Oyo%bFz3rq0Zx3PBWMx`|rJw8-B&;>Y4_%-p&3*~Ie=?8(!l9VRhCW)m(K zdqF{J$V*DeLMbO^_WdO)LC~D%8G{L;`cq2d=~|WzDmQu_GQ%8|+6bE4PjS-I=Xkqn zG~ndK`9ma!N%BmLuBMaJ@m$^%Nv(z+>f?!YD4hI`Cy9igby54S_;CB`=b`md?Zq1_ znTS$y-tdIFw+u^BlW#h{JB#D$N}bc)@9@aPR+P^YeTS^Xiu57a$ce4B24MXZH2Xh+ zVU@h1ZI$i|BnMlbWd?t=n{7d`&)ZYQzR8w{*<-G+p2C|TZ}yquKH8xn`Dx@fEd5cC z5f)Gz6fQftlYRcxjW9DDh_#G;L5V%Z=Kj<)nx?zi$RK>CwddO`(09Gdk94(Q)>M0H zhBL6BX8ry`B@~-k?sKj)>I5-dvL)M|2qH1+Y1wSaVUVMc_;FvNQ}EQ~QXl?=j<Ko5cR9fa9-a{yG4>X5? z;E9{~g*N2w4;X<>0FWHH=Y6W98TtfNSDpGdp8a25%;A8>IvpKq$@ z@Kf+`SkZe{7|^Z3ELC#0^G=~Hz{hYG%y~G=VTvWbpiTPU-$^5(Fm+`<*P2}*la9~R zRyO~({jq`a`Fs-E&r4B7k^;!QT5ko^5(fy<`0;?_Xj&+$Bw=oNw5F^f$TV|D6f{*LCq2Kf^AXe!zB4Qz_Nf5v8)=G4mp|}9 z7B0T%nKvLvtbj2mVVdMtG?0WaFX2@_U`T9|l%~8_iB>RDv6U6#UX04bHT!E|M&0=j zg=^7{&DbP_D#I^8!LI~U@w!3PAj$|5S@jfZXmYD@)kp(<#7=p7U29QA#B zcUvm)obG`!CMRQS#Qj?ISouS}Mrt--^}>*L==bR3don{zTB-Aqp2KM77_`>1B&OQy zW3QW)00`(yZg*s;%2|>eRj)VpoijHSitAT{6=D{K7SSa>KuZs+ABt0%ddh^$LLw)}e5A4>({s@5{)A@7cBeX5>s{u^*-eS@ zfjS}6Qyyl0RvC6xGZtfU?~GyQTGl7)EI=S89+R-EIxj2R3PBJEm!xyH>NRO~99uaF zGZYg{#`k`_rX!NU!3Y`m$x-i2o& zDGG=O0n~}a{rwt*T5@T6am%8G{jsB5oT;>XTc-<9#xxYFG7ohzS976lcf>tkRF9%7 z4U4UUvT$VH%`o%i_ln-_=NY4Wjc$XhSrriRHO13sjapMtWWi)utr#;9lv&qOL6VxZ zG`r@fWyB_1Dr4;^DYI&1R#iVt(m&|I&X)CJvpc0mJWuJ^okBha)*;&Z)}N$#mxQ*W zS%v04AYDg1VhKHfho&Zaw*To{5$6bur(+bhmX^>A+? zR#i8@Edad^RnBP2+HW_nW%eAe{|@!-2moml-mCg*`89^vuW`OMyCR`NxQ}v|<#<&B5n*09b86qvJ z{mpnst~8{03cd3sLV5uV5w0Dio6mg%Nl=>?>?^>=6rVS`q;2L{;TXel*G>2u^-6DX zycolez|q8Faj|S0_a|>j{DRv;`ww-yD;W2m^|iy?#vq)7kzOwK=0EG1W$JJ%>w)GO z=-1+{vD0?hV67qY8+ke>eyqVgnVCGs)Y`D8uqfgi5LlA_FXIGbg}G1977wJVu-8cD zJLL7l^K?9=^T->DbJRX)Ail&C+V}6_ker^s=)Vpzti3M@3VI*4?=Rn{AIlL}aUlF`_hV|W_9~{Gf)Z#WC>LITg;DO3xjzQhvYNwWAM5c~ z-1z>L9VK&u+#9~LV>ZlWlg1}jhyCKvGKcmEj7s+AipXs-r6SZY#tUQl z-wj#Q;rYN=H7Gl%gq6!9;Fx9Ark~yv^NR>4zMf)+{%rKIu4U;R<@cZDkN=)V{uP3O z^04*SYe8iUimCnn(_sIC3jKF0+xMj9KLA(%E}#E?Ez*3<_Z~`>N^g%_^Yhig})j@iDRF5Q6HR`qG0QT@;aLC<$t~4u+draqEda%(nhUULD~-nn zoB-veDvU*_8!Xz)_L6}#l3x*ykce#el%3rs2Ri-ORUOALn`!l^+iNb4$LlqkDglR5 zeiP2LHIi?qw$(dDwk`I!ZtNk^BclT~UqK9%VlRW608c^V{B~1fY$So3^u%oDa~QS1 zsBF4$UiVe3Nwr2Eqa3--xW{&eNuJF+pi8eKo~AuA5=N15sriE(d0+Afnb{U_tVrzI zsS&4He%wSAC=l*G6zO6oTz7(l#StSK@R;mPLG7=~DtEQU3OmLi_=gab7qbujU;&ev z)vo!1x%4b!P6~Q6kJHxs zZWkRaI%*e~SUG2)LiG;vv9qw1{i%s_;xAq;7$N@ zw4I-uHV{@&?WFe{g=5w@A5$Cf_hdCJrI|iJq(z&R{tr_i65Nhyk{UI($YUxheRaM2 zcx?3%JjytWnnoLPU1=>9islY{I=r;_$bJE+JFz+9F&MJ(fK>_UzFNe;<6KKU->9N$;hpKnM5@m) z8g|9VXQ$|>vt_N%u-e4oKJZNc2?BH=w-2=~gvqlLdhkN8`3bJ>BcYOOZ@@DQ z)zu^H74Gg8Z0r?n`3z#ai?TJ;0?nKN`jaXgYqpS4^!@ag2sYhh+5>C5dZ-bD_ynYf zl8AGlr`s2ov!QZ|Tj!W~POE>aT|fzt^cgO1@RIL87Hx78IduYmCt&FR&vkr%XBq_) zLuMuhroSuHZ!DR!p_8+NvC&^l2w^K@>u;;x-*a4*|4Kk6osUD0CH7H05Y5HTF`%@JD`tn+p`>R6{jCT-NN3XZaQXFvVB?g5Ahz+l5bZ2$+PujPn>o-xI= zrY1O0Nz0W8bWEnQ93MHi+a@l3KAwhif4Ct)+B@ZE@j*;Wm@Cmtj~-ef7`pL<+e;DA zhm*JcAI9D>$dWkQ`Ysz?wr$%sy4YpgwyjgPZQHhOqs#7cbv-pR_eR`15$`)UGEQWk zjQo_5@z0%muk~A9d57A_(6SetxqaYMlDQgq7%tj|;dGiMI(E#?)3i};qD;4Rot!jk zGH`bl%l5$p?&O1#oz1xTHv6oRs=JL@;uf{0--EE_YEwD)KWD?^$*O)a0n^G;sEar11LGiZs29ZJ?A{>a}|?&ZcQ*5yJD95ETZ&W#M5=3LdbU?yjeP*1mpd< zTJRNo<^^P{>MiXQ{8mA7?vjK99d*QuY^lU2OIOogx=^l$bv)4rS7wA?+zmdPdA@45 zD0REI<|2ylE_caf&ZNA0ruyjuT5Bq=VadB$a#G~XVUH;R_ju3{fNu=%Ok%V5?dvYI z+=Hq4wtC+p>y|iTwS}TUoZP_-`n|hkaktPy6SVYRXkfk=#Jt*>#coeH>Vej#d0K~2+!EuZ7>Ehqh)vJbC(0`cn9mFS z5X631z71~TkN_9+kbW1@T?#8O35#iIg}+z_A5PA93~~E<2aI1Zh>6vLa8MyHya<$1 z4g1mwcO=pY(X2<3?BQak$wakr4@{b|hhQ3{jk^}9X~_eS;aj4tjyy`_KQ{%V4M4dE zFZ&?4F>MJYgtPXQNvVTyB&Ek+pt3pU@{{d|TrYBYx;gT#TJywgD>d;{;}1|DaZW$9 zCQf-sU!O6L1oEc*hA6+FjXum|Z}nOla7ar$5{QR7{C(ldE~%@dk0E{H8jQ5oL;g~X z_ey5i4juRr4LfIX|D|a2RV(=d3)Qq~lkN;UO?qohEONyzKNQYJtqahAty@z&4l?8D5?c49Jkn%)4y1KatRi3 z4e@G3@B?7Bq&Z+@NzOHG10K7OllQG6`StNnv%liV$tdsly2bs!KCA!T!zTQHt&o(B z94+jf|Eo^=ZzIls^J=o?CM`jPepCU-D=XvpejoKWMx9D^Nr7+$gFV5H)ML3}m6({K zey}0F`g^NLGPIv0*>*&oODwNGU!nBDEP{vyBq*{w0#fueXM;;eMxK%cWM^lXh@(rzO6P;bM(szSx*m*^mgX+prK39Y zX7`y5KR6j){Z@Vf=}GHjF&s`EdQ3%mkp|I2J6Kh6N7wsK45`2Oz+)&q+d3g7#Lg@|7BWcJ>ws;pU|aB_O>M`H(F0(|{9LxkJGdSO$VWQwA7$cDL-m zm(&W~P-#AepIJy|3Aowbp6fqD!>fL-Mqh}puxEL@65i5M?B*NT)Ly&SiZKrO%S;n41X94*mu-FCN*H9eW%XVBR>jy7&XYkmAEmY3! zT!TIO?kVo-iSznX#O*7-tCMCif$=yjjV+n8i4pGCohj4p_@&V}woGHX*sbryqA3=c z_5sJ-rCC4KgV>9RRByKe&%jgaIO3f~VOy{iBj`m*FrcW4DhwX3rswK*935R9hH#;x zw?qQWj-V2_P0@K1si%?PGiNZe`>;6}e)Wj)bl{D`lVVZVWFIcB^NDsZ)deSWtztFb zuj{^2dLq{uL8l^0m5vTpV?R}kgBu;D(p^0biq6IT)aBG_x-u%UiO~v>%r)MDlg|j1 zEjAZ9OvZ8`-^zAQp${ELnR@NH)lu22is3bd1i%r7m+Ye19zD$cT)-#*kSG~T*z0B9^z{Y-E zn(ORRp<5I4y=#0PFBLvFV(Z+2FHi~V;V}hZ%K{Q$pR3k{k!t$z7}JGY{+Orn;mM#` z_ht(CX3wkMnN`ty7D#f7%9Q{Vj-~>wVYq!u4u5m|=I1-Dr?tu^oBb8wGcE?UNkmtZ zZHmm7gYz1yQ-^yWs?&pm9GasK4Km~$YOB&l!sFUQ@6K8`i%6@Y@v}mLh(Oj8!$x8| z$2=@RO1>M4@0XomsXd}1xAcp#$UHp0kJ+@`&j1-j%EIX}Jqd)m0n@~$dkF{VHE7XJ z_AOe6_FR;)?l_#u3S?4B1Uyu->h{-$Ja)1o1j=vOXZBF9$Xc##csLtw)pXi=@(1}8 z^?XwidS;v*uc1=$%M}h)yHZAO9F#{dEM72+YTgQUEMyH*UpVC^jVJDIH`FC4M+KAw z(7{3m*At-W^2O)|+U7F&=&Ci8Z7V1i2pG!_V_0{F;B+?9;rBa+h6vWD%{G5a4H6i^ zk_AEM{x&ZL+r$HDwwE5wU2uo>JNa3CxvzA7fP|KYB9wB;eXasRfONFGGS|?MwP3IB zazzuYXIvZN zzyG$F^qsx?GCsl3N(k>|*KIKb6>Tty6_10J4)SMqT~)`@x^!lGSW_&)Dx57iHJNm_ zpiUuDoX(caM(&Rq-c4jq9ygm%lS`##B#n|MWQQ5mUjyh$^O=l!2Q$T@FcSEC zr7`migi33-!Gl8MyEA65q0*u5V&|VbN*#?`Zxvm4uDfFc&NlVE&!5g@?xz*+rpE)S zAJXJ}93T$4yBqdi*!ReqUNkhrVa*S=c1Nl|T-@xh?-^I{qRg-{6zFb$)1lKhFoyM7m+^gQ7 ztMH(0J)T;PX8&8XLp5V&EzaV4*PdyIRwj!56F)~obZ#Pjl+afT^dhsVvvo@uWgE3J zLV|d4PB(dSlQS~+wa>#AuMc0EVi0~U%Ev$H=@1AFsytgMB+1>Igt%BFsX&Q48eynt zX}p~iF!rhQ5$p8zvpl{PdLnRxW-05y$xHbGj+%b;lr6$SRFauJAGV{Mx;kU>>ctli9>)e+&MRCbv)pp#Vt z*ISeO$2e)`g|4I1=7@YotQXPTvX4d3;+{D~YqROj`U(W8{cS<MEc9FxIFQ=DQeP$ zVY=QfNGW{?v@I`kdKf!ha+zh#Rbz81a1*sUV%$*+>Q6`T`8SG9Hsm|Htz30dwmNQs zD7kx?S-DW@JZZhNtuLW1TqbfxzCBkcLkO?B(+%d2U7@X#Ym5dt%LGg6B&P`SZy5fP zt|i$1%9{?Y6X$KR@0!%+Od zpo7S?rN5dgDxx^p6b?mTKe;ey@C{W1r%gq#eA9h|f5lr^qTAGwk3bBDl5|A1#H|WN zs6wr#^2k7xoYP{tW;3#59jRI~SIyQn8viObFdN^?_&%>@v!=mZwf&EC{RNFs;|AwN z;mUEc_$l#gvO4%kKDlH%j}CaTFKK--M7)vWzIFuw#0OMClfc*Bm>a3 zMqt!NGt@@#Y_Hcxjyi-UOPywTOPYG}+e{r3BGH4U($Y)QR7QQ;o89WD!4Pj-4YtJ; z1J+WLUTR~ZnlmV2{I~UI_B7+IpENWhcr4i^UO~S4KY;Of6Fz@+$|oi1NbN zS=8`0{I=#YyKF-f=>yiZ_9CswDO%y=4l@j#2*&TM?Nuk&19muQZeu)tQ+HzD%SDb8I0;^elw^i8#51hTdQ~M zQM4wSw0(E~Fx+Z$<=b$QfKlAWw8C)Q2lt6PI4J-sI#){F)EzDj%mQwudw+c>JvamS z9-0I!{i5X3s$r<<&uB}_qt>SSYO^wjs|A%NcxArBEj<~x)2{P0I!iURR)wVeInTD4 zdAJqv^qFYn7)dOTSx%B+t`ejBaeBKIB?j?jp?Ui{`|3RB}*<|j6-QY8*}?8Cl$ zi)@CYvPx)W8dT>F{6eE&`?naVcaBQ|XTr;et~PzzY}o64<6<_lP<75Ou5 zh!&B-OXC4BMk8@FTaG^5xd!cPFj|)xVeo)o&Z9}youC)p5BKXlO zf=95whCIMV%{XO@?f0<9#T_ASk&7U4yH5#YQi0p#^M!V^Pbpo)MWFTo=TN5l=DN8%Lu zK@Etl^@5eTRYs450s$8s|LAg0+gf{&e0#Aw|9`#M|2bC7+Ro0(#hyXhz|}zZpNIdY z4N;SF#vR7`YstEhG*TGSGK{>*sLPlzXD%C!N1`#38ErD&AlMQP4&5ZqSD4~eve`Yx z&O@5UW}r7Ek3N;64;kma&*wN!m8$KuKQQUlZoeOwMR@d8>7{8T25~HQBd7Z5_xZ=? zOKtgWviIu+%U|w=GlpNbNKuj`AVS=F&=^J>`%hXN<-NAF5ezxvA}xM$9qEKcLzUzj zG6F-aR2wor&I_^-HVfy>0CYqmvYX@AFJ~l(lk6^T zXb?G8l9&1}ZRpVA1Ee>}J@7XLSx$nx<^fiO8Cg!EyY2z_iEn(^B5&8w;3RKX!a$|P z<6bkWuEIV%@EMm#iw~1fBU8f2&4OvcY_6&w~s;YG=0pHoHxW`a4 z-ryg(LD<-57*=Z*nv!0fyqaz!S;F?s99A&R(5Xl!+$0LP=Qw_YcyXKt*bcUmPV&ik z<}-!#oIW<02ZLVz!qKit>Cj#UH;UK`df;mF8_bN7tFGe3`JcOFV9b`JB*T*kb8mzm zweL+Bp(JtS$8ti$9FxWlNYKBBJ(ToC-u({grIV{pP0&t=y|gfZHHfW)4za}^f(1XL zZNWw7SkEs)3L%{(iWx&VM0!VMR}q~rfQsXo6@FKh^$cF^CTR9hm(9}|OgR#vw9%IhrXFP@t<8!J-&JTjh2a}sz1m=0i_KH+ z0cdl8RDz!@7-YdI;M*M1Ei&?~!C6?BeewZ2Uxm*sYk&)IdX2OKod63t>>9xlhpWJS zkCux+#w;&rzS#qI%$P%VEbg#ozaClyt<=@r%FTOz-h!^4j>8mL*Jiq4!R`C|k3rKu z2SzTqD4h4~=#LlHK5ggqjZb)n-Y`kR=6>h2x1OD)oV{Xo1^I|_SfKvt zyKhYCK<8UW-I?Cw>zcj(kk6~8x%kzg*R<`pQiggd6&b#t5vkI0T|xfHbm=bCX^~(G zw@Lze3d6`kg}Y7RM`wu<<(ag&bQMYlke{%A2cw7rQp;+^6Dj6y5L=~B>}NI+{A9K0 z#ERY*gz25#1I7e+efC)XUT;#cp7yRqzjRMY2cQ!NwZHeB!r>@XUZ>=Ax)C+5mpdQ@-=E_`HH{#YOcCToYWf2>n73(#z1<$!Tc+BKsIm;+$;s4>YI{bJXG0Ik~hv7{b3>6q25=ppSqde^{4pp z#aft5dwC6eg$>L|EMgK?bQvdf*m!YBa=`ppiF5c9+J<7X35Y!Y(5}#dwFv=h<6?^e zbzzSPZJ3qCL!ApHe4B7DE{WYjopSX*EvUzn%?f`&>71N&S1FTba5GC9iy~T>No=hrU_cO=w(?a~^^7X_aLjhQhj+LPF^@dde zc-o1TK;v#!)vvJqdBw=@*uzi$B17z&)wXIgfj6i>Yo&TfM+&|5xTy=7W4SSH(gG*B zttVi3(rJTD+FGW5En(5OYzU&AY(2$W{nZ(4pWxjK?bCIxHrM0KEzUQr0>d(KVygM! zQ*3;FY7iaYcW6)zzowA-88?66`7c$?m1YHu;!rNt)GSjBgZ@52*`7>?mR|pG?_On+ z>3Gfp`s$n3M;b1wC0mUpUxjAfE6!y;OqA(gtrcI3gfH`Fbk#DgJCr}H&>u-f2CQ_!S9WC@DhE8n;+j;2g*u=_~ z<+5vqV^>!Woui4zD`Ok4o1MY#Uc$Z&YY>IaC_)Js@mW4vz^RMdH1a9c27qmMt?Ji~ zPN7mEnTE4mVT+-Ai*{@D{9gPO?9ubis5761BM0`M%Y@@j_}L~?>>15z>QM2ByfgGP z1p>t|IM`S^iZP7Um{IW-)46V3_vi`4Zad^3!R{?*=3uULS`9wAIqZM|l*J0jmJ3Fe zdSinC5s^H7oE7DAnXs5b=bx!P%kndr**lP+Iv_h5_BgKXO^Es)J-`!>nyL?nRZdMe*Y)i)#15o=Tbx-`TC?c>p+=2?F`P z4nTH`F8CYE*4-<4qqFqEg~sQ>V@7gELnhb(sxIB74e*20Y~JCqlI#+v*y!~|L=pV( zqYlD*Gtu=WH=$L^_@DU~HrN3@Zx0NJ;*SG~9VQSfnwysIZ&LtEt_reIB(zEF>w}y~ zG%{s(P^)R-}#?w@`b%21*yda8HXp^z`S!-&|vU?$lwv(pTW zu4P+ikp%9cSWS%(2&;u4qdPVN>>YZw>(1~cJlX|-PtP}hj4-*|#QmScTJPF9D_#%2 zpMDw>$u2ogy8I#(UtG=G19u53)p>jbXQBmd>b5=UTWW^-H%HqbTVH$e&T2sY(p0Z$)>p5}J?cnuHlF7kZ_Aqdq`Oc96623 z_X|$Zf@2Z^yNTK+Trhx%*ImM#5NIl2qx||@DgPC?zR{Q9!oJd%s&rZi^O(h!v{%r` zwF%PLE>UCOmp|^0qAIUwKC?(Z2xM53U4hskYuJG3lcfDqbNUpe79@pX-2y9`(v|^0 zNm9}qOvZqutv$5I-!_yX8sL~ho{vfihxEOpbD8^2VSE(MFkA?%%zjlK9bgVlv#an#icFzYBmpjDaiv92@6eLDtuPc28YF4|Hjo zbn|*HTY~k$k%`y8|6+W#A?XI%?N8tB%`V^_hI*SxJ5vg^8Eb;(0BQ3IUpSi!J zKa{3{WGLegW(Q`W`HmnN9hnOdmrBigX*x>M63Pwus%n?QYt3iP)bFj*{O|9r=ab{< zBRNUM-kUF^>+cw7ui4k^;~cMRkB2pm-gQKvL{tf0C2~clKu`r)Ae@!EX%Jg< z$Hs6RPgnevhq=TTS0)blE!urkDvrq)8IO#Z7?N=TzRuI2@%ii^(ldQ*V2K& z+v0Px`dew*-N>Ic+t-KeW)IBF9f{8@q3-B}#-Z-y1kWLGVoJjyAk~+9&@6k*E$+g{!ExJY zv$c8MmrK@%T%|CCb4QNv$HLKi`=a%_?rG~gGi@W^l})g_KcvTbCy(DU7~n?MXSpJd z{+Ai)X2ffamZ$wS8T7{GpcX}+uAAJoGpjAL_W5q|J-cl*!mE8V*?;>5=-CtZ1*hj) zCin;cSQWnG!Cz5tOi+36;2Xb-pDsM>q*^J#m|DDk1i52W#zw?QVVE;3eXGu7plI*Oe|rc8lOGYcLxIF{;+ zC7J_*7?QUxtR9;_%U0b&!t3~t)pxn&D5dX!8MYIzRdI2F)z$OeJ;c|*k%y(2oxI)7 zj^)<1RV4H6vDgtr%_Q!15~+J18`;8qCl`q^f^)c6P@86(N#_YXFjsIQOPHqWyH;n2 z?hkB(d!#keJl6iJ5OiPeN=2RZqdZ|Y{F`!k#biC zq{_r$Gjq0D-C)6M$T?@9xl_b}ckq8x*zL+#Bw0()@X(MTbdc!A^-J!DIHzZS^?vRw zYE57Kkmutz4-#YgW4@;@^RZDN^wR$vrpR2uM;*R$KrTVA8{GE{wSyhFIaSY(Y5oi@ z;;R?tojPZ`)i|mJ5J^*EU1}R>Qoz5j64El?eiqr#^jn3`URUHuB2tLcG~Q^1w{hX znr7c?;t1FRu|P=}AyF&OVwjh&pIX7fuk5)J#EN6G>MRVL&#*Pk zKNhl=F79r~T4l*gi_QucY-nCA{nlV&#vWE?T89Z4P zXYOmk<$Kl&%nY=Bzs6}uX!r3XX{g9QLR{wOHg7^0c=x8JC-Zx(YfWCZbmk*~H+*N+ z8v{YaITU`6;L-EiZ4W`z^u>Rr6!@VB#Rw%o7;rnj`b?*;npR-}TlwG?XJAETQW#fj zb8)(AiR7*BWa<@HiS3IzO=c@fG|!qj>tQqf2e@Ewj$qQ7h;y}d zWOE&R;Q^An19EU15XXU;z=CXHNlF6CHcA?P(n0F@DmS3aMR zu+3dXL&DZzy&&tQM=2;3GPo%%eBWJRqp{p!{X{N@=TKCe!H&N>BPk)_&@cvTI^W_^ z0s3{+H;VgW2HADg#}>r-h8rS8m);oP7$LFvb}lDZ{g>P+1j-u17JZJd`3bvVCU_>2*nsbk>5( zXPMtFkrw1=?y*kgPyBMPl-RJu&)BK6a4Gw%J%xyo_)E$tYl}}s`{K$s^YLZPl0FHE z$*Q~1v9}5hx1Y5OZ{0A;4OL^7Nwj*!f4oBC3y#u<+E1U_Lz4A~m+j zdW-Q2<33&Y0$K{t8Vsf5{=C?>^Ig2-QOrq?T5_{_Y;IDKbG(UI;do!^dRP{;I~mTh zb;pg;8WI#Hl)X?D@qE4!9tNXxB_jg>jE7@RCNDoq@$eey$gS)wLxYol{~B}&1=+wO zqHBoeEH@54ACrDxBB9frRO&S52nuXbvsEyUYmWEuT~QK0TEHCTR9S=5QfW)ev@$>> zy9sg>O{JbASV=&JRx8(<;_Sd)h~gd`C_f z+BZcGZzU0Dw@}~>Q>*90?wB~XR{jccGN1l~_3myrx&iL3jP zmn3N^K`Q~}4QAZ%D&%jAaQ9AE#9Nc$259wy5iF<`j7D^=xvDz4k}|u@u!TEq2;(BM zmCc`KcP$*@ogXHVay_m&r#Gf*Mp;@183AP6?VdQh- z?!z?Ok%Zthx$Cs$H04=8$~S-o%#LQ1p|;c*34vw=!n){l(5nH4-N=&IR~}hAeA+ zrk7Qy71fcR_nFlvqn`Z>I>t2*VkxxBE1o>)KmKH>5p)s|C~tV1g+6YcZugaGP%Nlb zHf{}-hR!JNnhpMKUi{CQ*fz-hI;_j+66m;7{ zGo6aYw55XW61N2_rC3uq5j9Djdx+?zneapP<2P$zznf=iZS}ZWdSRHG!Op?DS#vjA zC8aojuARp91&Pv+Lfusk;>nI^!roZ;4%QV3TP0Zw$P88XvI)7}7YDKZ!=1hmy+Zuc zTeq=eVeu5~a+9#1nLgD$al8X6A#KLYc?Gx`)ZO>~C*Otmt8hASPoMb{BP3=m@gkA@ZmZ-g6uv(?|KZ zUT-rFQW-cn#j8#){Z4bBn?(*8?A z&?+`eU=4eG!eH}4=fPKd;6DstK;ZNRUK3*FHz&?2x(xBF+HI)xEF+)ce;0Kb-qpvR zVeH!PJ(GQl;gxi$z?0QC?oKu3SSeYGpFBGfbKh#TI$)c<#k+l+z(-b}jgd$M ztt`u$2%j!QLUs-ou|(L zg<{+yhUEh>9OS|eif)0h+!?0Dq++%_D4K65tl2OkA@3WUHQ>96{!64&-1Dz4(1>7?;@>~~8nPDO6zael3L!@ekPk17aL*~n5(~Q+ArnXg5dlxhW5AP0-xhxuSf@XtsM8~A%4%_qLSfIdLc?; z$ma(iU~v}V(Bmhy4aOb%_e$B%p6|&o^baQ{4c>R=@oLV5$!$$#CXrJ-=M-AYZ4Ts= z=ENQ8&5hp>-FMNJJdV#m556pTBm6|6zRE#v)v?cYj#J4{h*fv#AJW0?c%wR`QW{w- ziWZ3r@(W^mp-nn`C<$j9_U9N@96{B=+VYYgIK&5S7D70Z0biGcp@yM36_epeL#@tf zHR|Y>>A>l#LfNRY@=O|se`=)e&~G?_eV2lbiPz1e3sR7}ot3u zT8b}8XmP0oY#V7wu^vv}f*r!d0t&$T3?12vE}|Pi+nqzZ%?%~f%g!p(YhrPRH6OW# zy0{SLEYr)ES4_huGs|00%s>>+Ko;*On$nX+>oZJ9>qFU6yc=O~rZEq)^N))m>K+Ap zXk>1P>)jI9o)e3o5E|=2%E^6lN3bSB9mfqH)2C9r`o!L4M4Y(jM6_ zy+R+m%+OZ+(N-5cfuoR2yyc!|Ngx6Ok!g4M-erlqrCtk7N>l@V>A>)Fj-Y4CI*hIJ zD-`9t$&v1L5n$mc)JNf@m?Q}XRgxhv@urS-77!B_p(CYO`NkRh`ipRoG?%G_sFu(J zUbhS~9F-9Z31b4nf*y$c3(y`Bh)xO&%Q2c0XGEQ9Nvhyy+DUO$CJC`KhIKmiH74!;hEqYy9_KMmV4>U~<05sn1$+JKpMLP~h<+f42Ez(xa)mrW41KdPmwl zrS7&Z2A(H%qq&9|v|9>3OFIhy!a^2GCuLJLJtmp!`USLZ;p#jvk$Ss;SY73){eJ8E zv$Y?(CitrF+`h9(BG?pX=*l1Z+TC{rJStWF$TrBpHg&HvB6-~w1Ae;LNle6K1_2~n zBJa8G1bP)2=2(X2%C<8!cj;PMQ>@QRKOH0n-;F&L#e&Ak>_S0$YrUA1Y@fe<;mS4f zb&G3@3n*&KmU~+DXkv9sZ%5LT;->Ijo17&##QwOWL6UE}@|1izc~q(NmTWkAD7Ef0 zqOcoMjc_f)YY)}1E2w%Nr)7kL;_~H9NBw|Z(zSeZK=(@8a5Uw&Sr+Iwgx+j^fE!2U zPDB#px1v5TMrhPSKMB1*vjb5y21dV1J(g)C9ix^u+`}+gor*RL&5%i*v^KDi16mec zO(^UzTb8Ou0tSymbQ^}uaIHhvT1?`w52xy7Kb9ebS`>X2MaLcK zd=Q->K@AGxK6yO>12W>_@&VG8^o{Kg$XjxUA2+D62OO;yeq3+nb zNMW}=ceK95IfJ#s4=~{vNyc{t2^6|Y;*qJzhIf(7x?L5rXm*sNQ5?xA!OUog3g7K1Sl`b;0GImZVS zilBP-3Q{Gw$9|5udl9!}*@8Np_z!zDo+%-TOgIROjn-L_>9=fu9BuSQ4Wm9k%a8Q*EGx)CuP6%xvFW-~ zYVirF%B`HR)EIYC40NohI^v>Y(IThuxJ#;AD#U9M260bnN7ZW;CQhPKJ|W}D$vCRD+@z9;Z+X%j@{xJtV<7>bQJ zn&Wo^oYbT!wM_2OGgc*c%``W_zjnc~=JmApa(SIaVM##^u{B=6$IemaXnUR}cdmHW#JaHeilC0bTJ;UdnJ+ zx>(gZ3bI$G;z8S3BAssM8-L*Pw!af6SqhswWBmmr`<_SVuCwPi=<1iQ&*uGe8*q$P?Ahs4x^bCCoUOo&bKVSVnc0Dg$B~O*!jvQG055#(^7F;2&^tg^)e{In z!vi(*$U=p~pe3obK^`ofxmn`(f~_&IO(q`tmZC*&z}-9hQ7H-0R+_k!0m1&)a4gVoos4xV75b96d1%81!q9d|2a zpS{d|30=X}o0MFMRodHizb_v zxlo5Ejyg>FqP8VM6?sM}i^hWOX|ESjTu=oB^H^o$#9>r#nXHcXsBMBz(_WS37X7}} zIc}|Xa1F)6JDROr$CekI1mZ%PosNmeK$$khWlJ?qJ(YGMHA$5$+ez9}YL*ascwaQ# zZLB=$bMY!eWsb#avxuW~%bAmD&`4{+)R6V8?HE_#Bul|{?uE8XLT`5LPs3|!A&C)1 zU#q5E+1yy$pJn6(xG8SkXzu7*t-SHj@DMd?9tNcifnZ#k{;H<+`%t?fw^d?Ul0dk9r^eUX)CG}sA`9TzX`=g&LAFxZVz$P`5rx~Ojl zp{tBN7p3)2e79n+VcVN*layY=Y*w70 zo`X!a_)g&mh-~E6T7b^dzL6T7UgUm0fQwftZvC>q_mUh*7ysgPkO)uV7H!!gQM^1p zWx^|4wX}SQd!db(*ISOPybbUh6Cg%*7nQVA%H7l7>O6o-g(%J!W#9oN|3QF};eWRs zIv}H<%9omiJUQklX)dRsvC$#5fnK43N3YK7 zneNO0nU!v8o0E~b38C<3S9NZg6nDQgM3s801m3F$sKs0v!Bsy9yZ6ln^*@AU{utfV}vmt}a=iyPr6IyoF_ygktle(aejs@f; zaMBm^Nd6@~gFQ#B7AJMVHXG~Cn>oPMBz4Jgr>6f=4aq)pKwMoMj$jbCr!$}k^u&;W znlgf1`@=W11zZ%So{p{QWB${LQF+)JcwQL3n#l%V3+2(OmlLtu3*Y9!-3)jWCgPgJ z%gWp@0-zrL88P$Qn1$GAo9GTcK6f&hG=^Tgzq5_{P=3j0(w&eBDVCTDNkLMHIOn#( zeZ-iTsDZ*en0q5|Y^PL}dpBszR7&FXnNHt}=%=IhuLBI<4H$bbiW&bTE^pFi~<_0T;U@g=vY{YXftmnAX#FBZM zdwn`}sRCd_x5}X|8+z8dT|b1_w%L#gC!W7%QmOQ?yAJ2$GTNxu`s8-0A9T}(`jhPU zhF55@uum+3{owJCaVRiSO4N3CLiszoTdVsX)cp)}8IXYJNmw$>Od18caBq<`3v)iyCihhg5?-?tMEb?d&F2jPQ+@)y!WhO%Y(k_6R`;6k7pD7**NP>DjhOD|3_QUF{}$=~All(!`Q%1?l7fIfTA1 zv98IF@vd8`Y(}VF{&#=`u}D#<#A2he#8FA_4q;aEhaP z6M0cwBNq&%H0>wEKlJk-iEj46-x-8N-%t7fH(HG4|MY|_+c?|*uX1Es3))?4xS3xf z#l_@|T-R{)C&-W#Zk-8^8RXHAy6iMCT(f!--RGf2)-wZ#A z`%|I>K3T!*N6H8~B-3xMxjL9+h9o)4YX2*3Lb)*3?1iObE}^mrVYG?DF)25PdN`{1 zQBp{;wkCgchjd=@$wKWzD(p_fY+>zs`-;2NHY?N(6evE{ zZvcQgq;myWZr$Yl7-a=mbtOlnJ)-5u32fj#K0Uv`r%P|ByH@F*!Fzap%%j&bpaT#X zx#TR%IZjL#G_f;z)T*zHEiK_Cyw1CkYHL^Z2;iO{!G!tlb?e%9FaU2CB7cARcEr>(7B<2m|M0bod^+5`jtV{SG0=$ z_u&WZn4Ed6htEmvqnJ#){N>%~yqYN=AGWqWM-%0&@=lfBT^V~y(t){!pD8c3BW4rf zVAr|ua?%t6#6o~PF$bA6O;qR%c(?1=LI)+*wQyMYJ8{2%OdZIS`-*8V{CJ~y!Jft{ zI-H@3T^l~{vIIv2dTrmRJO8A*W;AaAL@zB)aI(4ocky=($L<{%$3%$$g4lM67^m=E zkBOik{v{BZ<=Ks)V|0RqG7rL~+6N7rLDR=xTYn#@uW{PduXIc1W@ALbS#E@w(R1w1 zcOymjhjndL2 z^n)yxSL>H&pOR)zR`fO`7Qohtt?m|~OF7L-V^n6%5L8{BH9=H~AIg?24^1~r;hh{NrUX}mt)v^l z*+RL&SFw$xNChWmW$|oet0jL~C*Vdv<@kK@V(Aw#=Aa92QYZ^mWM$<{_x*xmETIC6 z)>as$8NpoRP&rbCt)y}?2 z<=5;}v-D`4(BC(6`AK^AOs<@LqFU(DPvHt}5iF{|iDmbWu%CUpq<_PHm(*>RFSugO zo*8zCluDm5WevgIX#or?+4>8eWWH%P9Mf{?3Y2*qNAc6oqC<`!f@Uh?*dE!%vd?rm zm+4=`zC_-n5iP!PJO8%OgS)7X8Z|bw9Nu{CK#K9m4ws3x8)}x!@mSUDoAi%s-KTU}oGdKd6-21@6Zh zIsDmBE*}xU|hHeBA6PD(zw?}ZVoLVJBu#vwkU@p}4=*1_-jW8hJv8{Hr+By?+s%YV!x#;Riq>_uE6f{8>O!n*yYL_rZ13L3QIcW ziqyUA5ryV^Db`<@f)g{BclLL;>|CR&hc1n$A{b8L6a8Cg;`CV5TE(M`waRIZ6jU~q zSI_P_U%$&k7hGBw^7Buk-k?A`N0mkF^U$4@Vy1_vDua}ABJI3X-EXB6{kvMk2p8XU zeS?g$=aNGphhN&Y_jWA4vL`$DH_jbdHNPC$Ll63G>j6%w)d;~h%jm{G=b)HzRDzIO z^-J-tVXJ?8<68K7^XVZA++*anagU?vz=JWUAF!vT;Du8MR_)O*96`^o^efs1^%u7* zSd{F;VX{a^;MEUMJ)o6(i9Cl=EmRD)Z%%2jTQcOMxwJcbhImq? zX4cMycM=AB=I6Qoif$g6N*=L`afWd+J<{r>M}Q=;lOn@eY;msQDsvv^V6-^`ZMX+% zZr}viMyMK}-iMItpWn;^V$laUVl8%?Ql4kTb}Dul-lKdC+iW6)7#;|3acFMjc=0-l z3Pmo<=XEeh-yyvhEUOtmLJzz&({z3-q*AeqHBr*bfX^l%(sR@x((`AQ?kFt7pT<%v zQ$2);zr9i%}F}!wFi2;FO|k z96c;XiX-gzbus9wqDR91mBD6sBaw0SP3w@g^a;C!Z6C!t4{%-+Rd0Ohby!%DG5TR0 z%A1kj)!ToZfk;Piu2 zSJ8VshdAKw&zEfqlz;g6O^HnBOnns3X)n?rgdWEuX9Yp3zmfurKRk(ZI~XuhCN(>p zsjPCQRBXP3)cIq?-rHYsT$=eZ`1)_<8+0zX7|`Ugf*f}0<xDNa$NfD5RhcICep^)4jG%UVnQkm5;Wg|B|%f8706U@mSmfHcsw7-ul zEHrJ6M<6+5NDK34VYEaLiN;II9gl!3MCgteKY%*o;v5CEPl+rOI=PnoD0NG=;W!}= zHj>SC1wCFv&DR(l%%%`DH@ztB;;P(_;1jL@=LOcl%Xa}Ce>+l1fwKal=pkF-mk2?_ zD$Nm~?$oAqLCIqSAkdc5?`j&*{Gy{z0x%KPm0kHYf-a~%w-9#H{79+*WCPBY8r!-t z1)#QHvn8Ck>Eczkc-3&7&-B6|dz~e6M0cT=!6Z_{%i`kZ_*E_-(1bO^dRWw~B67u& z&Q+GNOeq5mGyQ1NA!p#YpnmEZJXSrci9#AMp`7#!J&5}h40&q_gSZfFnMZEHHKFp@ zfGgt6fyet6NrT#_EeK4oa@YdT_CwB z-tr6wfJYrL+nOc;q$92eDxPtxOvIGalL&Qo<&+FK>BxpE#5WvUcU>=|J+Uc46VE1% ziaXT2rL@kJpHnAT{U72+e4ird;8Ig>%Xo_n4kicjUeFrdX_1K-bh(@}Cx+ z;6RnmR1j_m`8hoa3rbg1UV(=Y3tux?o9v16aW~XXmelU5z9W0iiN}U; z;ig~ow436Q*YZ@Sj;r*F@N4C%&Rn_U6cTjj!ggsDy8+Ej!Na)@ zuj&e-?M3i$>d|d6{Aq1MadknYJD_aca8X?8%fR!G4ay!R-TUPYzUYOP><%vQ&pcb^ z;OIgJh7rJEhv!$$unocUdMq?(%ChrlB04ZtateAt$1BRT1&*lC)fCu7eXx^C%5Hu) zP@l8C(?v;^ZOol0EWQYEqCWY&13uF)!q2e_Dt0m$5hXj&ZVB=i2<_S^_^N;`+IA#f z`*TL*=LpJu<+4Z?dPz%3NlT-r2-l> zgD9*6jZ*o9TwbpeatUTx$H{GqlQ*|tSQ?bpRiGZ(^L}(QH|T-k+5YXSq8$aF6m^v@ty1fr}LwKJL6j&w=I5v zFxH2Q`5~xk)CTZ0fxG?!jrCwDYT|-_)GJ;Zc81}Ns>NzcnJ2EJNa8vM3O$0}mU@37t2*OCqVDwCt^-08Um2V1a*t+9Ty3 zJf|#DMw#z2MzdgIsDfak2LCHO zOu6{Lx&H~OMc;P=o28yFzDyr7R%2=@%+azk@VIQrT> znuUp0`jux}|*W$P;WQbSk>pWd7^!VzwM zYoVv#D61&xL=zbRzhkL#cjJ8mi+v#;Y!9yR?_PLO2z(b6)!|Up4(<5m?SvRE=Uuwz zhGNoFVm^_XELKjYp_=@WC_71x8seEI`vCmiXz_?=Eke4f?hYx5|+;R{2eU_yqQWjeP)Q`=2H>;&1!D)&~uA(hr2J>lyAX{C1 zU$r*L1f%92(DjpWS^&R)>u;7R?iuKpLPMUs#;8m(+Atpf0L>sC_-sNQpG{f^K;H_R z%vN?Yhutf$S~3P(wAQEHuO~*3dpD6hzaoSLnus~& zfQf-WWK`pp<3fI}BtG@==9b*yWYr$e(};}?LMM1}K=J*h_)^w%b#Y{0qG}@-`jz8T zE%vuE@I44Fje#0fB52Y8%HvG% zdXzinMYk*Zx@GL|)DvhA7*g(x)0;2V>wh#QiO6)DGLZoQ@Yw#V_V+&xY()Pp?a#@{ znqJw-TG-Ck)WXcg(ZJcl&Q{dj$i)7im;dzAP?VJ(6hQD%-as+3`gzI;+#i591GkeR zR6t4HEv|g9SDd9MQ)COiY2^dJ{eJUHWfcVwJRRa4AJji=8yz1!T;cW+a?z#K>4{ZF zvE}1YSDJ7ru`QEzbaRoM_S%7+A+ z>dJ~O8DLinmmnpI5oQb%es--5TpX9V6VJ$I*0su~4d7-de_AS@W@-I4=KNDatuX?& z_hXF$F$JpUTW!lxe@wXnQVX|1aqHkdcUlmJWER>9G_He~>Bw2bFmF`Vx3;$72ikq; zM}@P6b9H}6R-w~;(pwjyu0*sy@WE3rR8h4iH1BddEw&+97j z^KGWK7tkF$nWckaD~5$HZm^w&Z|IH1lz}=F+A%G$#lyo^a8T4jGbyE*g>Rst>#;sW z8mK(I{p^ex9aPK=r&Wi+Qmot%&AL>lrNV?0Uzgs!XK$r@pdiEab<9~Fs%cGb?3T8a zs?N!DtIY((I#3a!UI)$9!*>IP1loeWaf!;l5N@7!%bBVQ5#|_m! z;Bx2k)%L3WL3!hutEb7iL1M*oj1AUpj;6gtKJ5-M-GE$@MmLw$(jZNkwr$mNjHWRN zi_Yp4St6Issz&l$mWkWGUhkZ)}qd$7YkTA*SJMh9zQ!JHbM= z2aevetQJ%*J=U3Zr_9OEnEgyv6~=AeCAyPlNkU9Y;C+)L8waw|mV3mKIi@|?rSTA1 z{CzSzK~tI1;#DNiXO2ppQe-6wkBKDnXLMYTbQaEnZxo(2wFm;DM!Du}$tD;2!E~#x zyTo`v0J9^8oBASicvB$W`7`1SO2%3rO_MUB)8P1GJQBm9^nigN<6oxYGRjZFU$`vv!Cs z`^hqe3T3xig?dJj`FhzQWu_A9YO`eO_@6*5_me z@H${{#xk07tY-#PIPrpx}yEYJ`SdWg&0pij0mRHoCJFn-b2tbO^o zIJRKIe1=EjF~&hg=~&M9nFYQIdk{o0VH_`ZP2NNhIP-z-|viIEgQ) z#Mnp@)K>9sa+JAW{pDiElEo#O@m{yEf3gEkwpB z!DvB4nZQ|pbAxb3w5uV)*^!w>xgY2WL|g@|gy0gdf5*`a-SDpIly&PgJ_iV-u8yS= z`+H*fdnU~n_>(Prk}9 zn)Jl6^4W>h@GiXS{dT=~Hze|Ms~|d_iZXOVOq&{;uj^%7s_VMcNF5Z>449#6q^6DQ$Vj-eW zzjp}EsaO_g{WHCrctc*&k7#@HTQz&Rt*bjxzEeS7P_ZAZCik%|@AZPhgF_V1-1m8( zzVQqaVS;5q9JL_QA$q#yGY^Z9DQV09M(f?rF8%ZpEqS&EBLoDz0;Y584)W)pLd2eD zg%w^FI0}y&{{sCJ;eP`g!@2&n;nMz(91G!pI~}Vyx;Qy2|1V*_T5ZcoSrp~34WH+R zeLkT=oq{zbkd0Ed0JnirjQTb0yJ2 z9L!>ezK9&P3bG&`bEVzlL@Eb$wPx@%6S}F!I6`#dWyh@>8z|oj6VOSH?wmU@QnX`} z3sGaOow2e^_*V>Umr-6|p@8+Fni^U%=1yNH5c-P5@G%P&YrTQyBgtSA%unxn4D!;0 z)8vEg0K*Z7eHI`sMwj|p{RZJ^yNaAruL__-GN5n&82>u_fxj*$xQZ{A4ozzFZXxwa z$AGNXZN>E9Cs8~w#p%gvP1}x)DhPxz7YocwJNHv1N%*7bbM@e^LNiUCBS(Z}V7313 zJ@MTSx>j4_(9|CR0{8N49@K7Dvy7b+l4j`jKIsFq#b~qbGyFQF<=3y-x0k;GEvY`e zvj71(B9nhF77`HbQE!0qPHst->||l4ZWQ#pVY%sGZfveDX^;%GjZ4iDFq5kRbr3CG z*X-}8P#-4SOh`>Wu~`!4!XmjV>!7fAWUk7O4Kt#gt*>w?5kobUGfVQ3vuI&pms1ck zH3T<>F_zuzs|&x9pn!#kFyAM0B)hMZoiv;t!tCnnG1;e?#-vC~1K$uZ zHQEj_{p>Ruz-CE&J#T`Bv6-~*Za%7^vX{twGHDq?*OQ6uL@u`Wed|}pxvb)CLph2- z?#8xut9ZKBPyGhs{xf3Wu|U+V&TusGGUX0 z3p`>Dz3GJ!d1MuxkuP6uE+*4Kk+9q`{3%Z1GdTvFAOlRJCx+*@wvzw)5_KF zl;_#-*?B$Z+3<5s(2Rgni64mf6;#MmTlf*Rkb z3)Cl0Gp-$Q=YM55#~ERXGK3SU&=o>f{gO+d|Ul4R)qDJ()#EXQ2Iz1ZARRDc+@*v{!hI;=APN)(uwy1 zy+kzq8&NA`P;FfQ3N=Fv4f-mC-eJ$U9lKsZP1KxmdsCX95xGONBYWT;R1r&%shG-e zYlhs8CA#UGz_4f--J-jma&fd5J#&z{w@zOrADv;6^*8!IaXtc!8Nux*&X4{#Yo`BM zb}9T@abCs9{=Z!VCHbEVVg^P(8NlOTXZvCGe~~WXNHAr<+A$UtXzP_S0kFD?Ec+k| z7R`URguiTuj3I!9q&qVy&aHb@ckk%G&yVuCB-b1%Ew)VP>2$x&mwso|tox7=1|cBK zHNP`_{FqMX`n)}FpGl$k1OCp;F;JzVp0a@)76}h|FSjIU`(8^6U!QDBa~iO98-Do^8bODEYS>R z6lFu zDYaR`$`q=jecoq8~0c(faI6UB$o~;XZ4Pn_GM4ci$VdU@y(ld|`@y zdi=Ar@k3OFh40!dt?CRVB4BN#JFs1ZJ2X0I7wtaMw!y0FO*rBm9bJTbY~stEe;E8- zd|2$;1^H`|@H1xYxl_pLmr3^ET)+KkzpgIK(~-*%f}R>7qdRr;Cl2)6bwO-s16|gd zwrj;KD}z+C2)LbA{j)6G`iiJ_uq!N`vtK)@W{Kv-^|V|_w7+OfKS%ePncjr12u4PPfG2o3J_W{S0ieNCO3^w)dP?(X&D$+Bi z{thQbdo(rS9(UQ`45?C%XX*?VP66E!{x^*%!Zwg-pN#mUvgL8_guFrVR+fqqm*Ugs zW12yTr zG3qn+w#Fii$mg6uWo&?jRJ=%^K|L1Q`$es)U*-WOJXh!fVVFw)6eF82WognShxl4FCbCXY<0 zidqBFp{e-;hwsF6zrB>G#v&}b`HC-f#$-a?$Ye+m>%1puRQ&xsww|)b|LACpO92=@ zcsYVMY@Hczly5OneWA=?XK=74KSfs@y3-%_61=G))7*^T0Q&<|@fq54wHCv$HO{zq z59I?F=>wRl)5eGai2bZ~#MGKl3z}Z&lmw&&5luUsYu4zYMfnrO2auX?!@n*%C1$jK zLChjAk5sZZ^sT#^BS?2u_MM}n^2+=XsN*dgao=Umn;s_=)cJ298KBp-f|@Q+0njtl zDIu7k{2NN$4V+C*BT-&#E#Svl`2b*n^VdmYh+W;hE4Mc=EcrS&+XK()SVxqYoSK8u zXn1NOnVgza!!gyeT=LSSKAYZL*8maR9ub@Y_c4{%h*3?884hA7?*T>fJ_6l7LW_ev znvi<{h0pY?FP>0@tCNKtH>aFDF|XCBCM&Fdd#K+A-f^>6B%Y_uMAcA3tNEIhc1bO8 z2DkYmiZ_SOjx@svboHXVnmfyN%X3Voc~3y-IBn{4qL&_jJM?n}^g1|$d93iNh!OGB zaz0>ef-`gURoNT-KiP{AHm^wF$5?P0;lJuo|Nkc$>TwGGs#vVq4+XVP zNJ39?(|vf``4^C3L?FL%R{0cpemw|wCQu)FJ5yGIB=na&2_lr zaayu*EKx`sU&CyBszqm*GM{@xv&QJUGI}6!xA-qy%8AEVP^$d)@WO4u9895D)UB)b z?kWB0h0DOh+SRCfKO54BTf8pPR;x?acW=EgK@-XPy|NSpBp!$h2x&s{P~jqNk>5X` zjd2FpZt^FkyZ<+U%KuFIa{t$)Z~rekA-&*_MVjMJZdZ2pur`r1u=z*Ib2V}NAs3R! z{>+2eIvf1!J5H(S$|DP+@Cr*yOTX1oXo(7f(&9HT8hTR@8WJPY1Zgaw8&1~2O~hSU zGjm6t-Q4F{k7~8shJmCp4H`?!b=(Q!ZLwq-mH&)iO^^ z>{Ci4tjwjyr%Qb6cpGvaLZuWQUDiYUDBW`fEsfr`S?fS+v#BSOp^M2>w9-zVv6-Y#o5)rrMvg)e}Wj@4DA(zZNA6S#wbK>=E2R9(OF`d(X+biB4~37 zE$fwNV}4HCiG1p*Bk*TXe1i~`P!$<)@HAH|GdgCwnOHTlbg^}$ zoCUC#&$G)+;F>SZmvp;kq|qh(M)wZHn_Yo>-f6r(oQ0i9p}3lE_JlKEB{JDyPk(U^ zBrxR3yo*@3Xdbo%f0hzGmfxa3QLznFBtuqw1uLyU3 zBc^sjoQjBu)I~P-&WR&&mjL^j5DpXvX0KCCDCvwSGs)++&&TK#VW1bx%(N97Ckn&N z?Q4}gOl-s`xKl^!(brA#9rPUOU2ppm>1HW-Yif=`2xCzk*@n0xyyk~V9O;HUb!}Xc z3;}bZS))_#>_dD2h~uM`^6wiJ_uqi`WLn`EL!boD_ZWl>7rG=7csfM1|>*1kW`GU{~Y}cqj6^ zWNVD~wsUUWLnI|aoBg`ul(znB!Fz4!X!w5+pn8AwYH$d-^E2b%AMHBtCwBbr`ZdqL z{R0Ra7@7YE6V61;&e6u;Kap_R>Q*W$E2!VolYKC$k$pjc{ov*@IA9QA5w8+jIb12B zOcX-v`>1q-tPkgtxPcj|s@R!L8El7pg_aBA86hm|f6SXC*V9H8i!3s8WwkSx_+6{{ zd|S27_)hdjBJ*@Bt5{F6x@Y)4E=OBmcy)RlzHI=c@4|zyya&VWr0Vv5p;b8i2{$7# z-qp@}Z9$&tV4&&`KGAW{Y1G>tjP&Nnx&w*gm&4r~oP!B8=sh1`MDH1F#!s~eB7eKp zMc3PZ;USMdec?Fy$olk$=09ZbnOx)F&r*NAHJbKHt{r(Dv7-A7LauenE`7DnfagE5 z+_v9?$sNs>;B-hKY%Of;-P&0`hHqkVab*F=NXsQGrNojvl@i&h3QDN(F*Mu<6TT~n zp+nNz*t@Z^$Z-sVmSH#~U2H1}VynChLW{P(XHRT+!u-pz`6YEad(8}!KK0%FZQC)h z)uOwWuM(OhQOA`x+ALwudey>S^~6qF58M(6(~t+WrTZPzEKSC4WwG#mwm78~a@mto zGwmB_Y|m2mADQrC+#!mTQYrG|HoEZr>Z;~>J zzd*J`7=IZF=E-Kxy-q9K;h<7@j^GXH@S)*q33#qe3m4fST!r1izn>B?9&7={KSGG< zR-qFK`J5b3gP}+iY@>9zdcM<_OTzTIDhnW!I~`9MwVwb@itK&SJxQRSEYHv6Lu3zOG9v14ko{-pE7#99P>u&O-fp&FWr&EK&5_SnLY zq6jQmL6|2ErV_E+#8@CYJ*`8t!~|H11ZioarQ9Umm|{rvD=PodRGSK#9C^f*MG2KK zxT7V|)>=F?3c%9D`92@}iHR*QXF$Kz8#9{vLj6zJK5YdlrriN9CjTgX*v{-Ki4h35 zNmpbf)Ak^JxTdl)@qv%dK6wHYUtg`U&hfVIpRacS{IOLqDvfee$*Xyji3_#G+N3)x zZyF~Qn;H2&&= zu6sIO$_e(tfg@t_Y@8-?!kLbc{?iViUYlutmfb!oLzSuA6XEcur~Tm1-CVt9571!@ z@lM)i=^Hn?56d!P=t!VFL5%n1Fb~cE5KkZ!k2EEAF-Vtypl^JDYZ{P4Ru-4wan4Yn zbHyYBqW)0o&_p}9KG{mTh6B0HX{igJHFDAP^^h7l%K8+cez_(_PJ@*_6!JG)FMwO{ zS!uOB3fFNgp15m%poB}Xk#D{*uR?0N9k<4bvzJ;skGBVsW6zheAxe#->RlQN7tiz; z6ewA6fvV=PCgo&J(GH~X>d2)_g82TT^s4$)rqw^wm8`-ZM1eF|?vr*lH$S^S8#(Fe)% z{m^t5w$a(`3nG#KN?h~`BxEUstewK^r~|#y?H&&3ooq$ug9@;nqB(uSrx(h#G)74d zx6qUuJ>S5>D~9+jw}hYZ+Y5q9z92Djrm>cn`fN41hFe`85po?8FC0QGlkg<^kOwX) z9Cn3~G~~St3gp7*FL1A{FoZk$IzQwgOdmNzvcuL{Qn(BgeNiYAlxtAlG_}yI>+C+T}tQNfuD24X{w^o;!x0D z6>@WyDOVtD_q^<1j?dJEqq7u$<_a|^(SjtWs}Bdn_YirW0MrLKgYfhzQP)+f;k=;S z7A{EyXqZGzX}E`$K1*(sQj?U~=l8PKsb@RsYnAM1%88`m&QNmr-G5zL_LB58|KpSIj{Xa^Ks z;q^=+&vJq2=^89`Oj%!vwM{9%sn0-k`r+ol-_8v>mgwT*qN4(=%*VPzXor)yJ=N0I ze21*LDjB#~{eEy}PBeegp72;0J9BI*#NuBQ?xkS{b?s=zDWn$0XRxDZ8a)935 z*HSKPQ$2CbS7tMo$<}!Zy_*7c9s@D&hUo|K||s6c$IH`9s_6M*Odb z!2ekV3H;lKz@Jfglm7&6{(tq)zv`Z9El6)|7u>(!>qYb)J~k^g;9E;g&e|zW6U)(n zHkeJit*Giv8S#)1!^2M~+=jh=mPL);B0HQoF!B)YNiy=2?v*l) z-!?^=-7-V+x9(|THr{5z_Qu^w^U&{sVxqdwh3HGZHb+r)Q5+z3k%Xk0bOorJbcO6l zyjH`I>!FwVlJC7RZMMyX@Q1y{8onyieMj}KzAfp4lKLgiMfE~MZT}h0d=16@JJdV$ zykqzpi}6ieh-e3Cx|4DnllGUq&0}NQ8yB_G$ndEq=)gO(Z=Mi|8V`$7y1+V|21yf= zfWjs}4$TI#qCO4npp&-3E_8VT^>hJ(nLQY&a|5{l7eNab&Xux@ZY0wEki|HkpUbb- z@O+f-yZE*@7O5Cypz_*kbLJl_|5u5{z?@= z!Y@LQGS7^_s8kkUv>X$W{WDK*FjYK+y7zz{B#fmU9bF#xXIe5YyLpAAa3tMPlfWFq zNMh}1;%k!s;pzO_DmP^VNvU( z3Da9nC2}~BYXypCN3p0V&s2#t1}5CQ$uvU=>_D!Fldc;gGMlnNyVa-kI8#JO8(kl%JVFNG>Dp00N?s*$Q8>+pX#wqgrf>TGjuFG(q8p8MGls)UD%8(K=5luG#&g^FB7Hb;|F zG@UjeP*;EJ;52g7c@(Z$->IyFxXfY1)!x_1Tu`40Qa*o;C3Nr>1p{M= z0`k@=v@=(PTKF`L=&|WoCf`FPe>Zb=bWMv8TvbY?c(!~9@v4h5Ps;8Tg#H0lO8}ZP zFd8`o(uH=7JM_XL7uy&VA9EvhC7r;`JjQ|1ybIIBs5F!fhowF2xCRTD-k)nPs< z6fLTl7imp$nOwe!3dNjbuv{T3RLx*Blr6&G$*o7Q+zD#7pqb+s18%-bzULlEZoe6- zWu92@G|&Z|pEDsbMW+-DJ7p8n2L!b|%#(dGBO4D}7RGNfgAF5nb~*ot;zXj{x{WRj@%{^YoH2Z>I@unKJyLic~kKWSVIVJXoG*!5`ERflyLdb@=A=~C8yhJyYTg+~z?GmJ`jbD2icC!-Bcr)Qp zTFLzm*vkzaw(G6Nm7UsNw$Zg>Z(*yxud%YYceEvQz4;U=-9WXCd3lCHHD)e({HDbe zZ7|w5%AwyxS1jD5eRPia8VKiJPWqMbX^;dvRuej9?_W&Ok7bV;jx#wR=6v4)Er51> z@2foCgCttOxa$&siuU>mbl^>W)6OG*y))x=&Fik)$4%Gp78&a%Tz7}3aX~dsHI5fF z%nD-lLf{A|fwiOEB?+Wr97^h43vko8dS}@NW)MdLucnDwc3xOG~;1*zT zTns+8G0kJO*_?xB+dXLy7j}(gLaa9cJ*gi?#I z2@mhxA)wD`n~ze2H8kvS0~$Lwxxz$0E~?!Eq6emym6cVve-H290Pq|wd)1L-lJ=xi?>`Jm_m9E<7i1FqKLg$zWd&KDO zda%8qzg|VcoSB@u2j_Q3Ox$7hM6JO3R|gNBF#U~Y-khk1_*xyNMoTIWhSCY#3Sq7` zNnH(;*1XJIt*1L^v<~U@H}Fl96{F}yQo2)|jJNmLQ=~wuG2c64OuD1kBgQ82PU^R( zwWC^^m%(i>qZMbW4jv zP5r>j8i}U|zHE()Y*qe6Ex8KC7cP%khw9A*`JsjUEEht{Q}ifT^{diebrEj=(WeeO zl3C1~drw?^?L5YThm-C*o&i+b0!h34)ECCO_{U34I0?-dRRi!!#Aw1TPY) zRB(J8Y`d{I;21}+<6d4@QkklW;fyF|%}JRQ@m)XR9<=vK2#K9MBg0Cg-u z?Y5GlZ9BG^elI#6ae$irXH{zi^ihiA1;F$gbo-{3-CAhCqI&bbDzev73ZkkCqm}|8 z3Y8G$ln5#6pfIV1pow{j=Iy+7;O&u&80p^^QSY%^|K}orjYJ@8cF?jsNUt}&f%}Je z7Z_@i%|CwI1}VY)n@KEb*21_Z*Wj}>G$TGBQ`YgcbZ%1wYQ>r`st$adsLbYki5&!@ znI@8kFkOYcTD$|yY8Bkf?s!kgb zO>^C`ZjNuRa!UJTs|%&&kbL0{8jWdejnFs9Ae#0$Gz4M8yClzIqZyN zlmJ%AMSeSrNjjJQPPk;R(POIJpmxTe^E z&fxN--u<|kkk4Fr*dBTWihkC@#qI^3B>lzzr*u-U4BVUgxfz&3_w>KjhTsu+K>S*FM`gHwd^5ET^sn`FZU%IDScl9aTCwAWXa z1Pn557icrL>N+Whxg*@}0?_HGwnO^ahYbP-V3>RUoCeZ!9Yn!TpC*2SM==NNtQ8f{ zCN08cKX3Ltd`;hUW;cGFtp`g3EblVYcXXR0)MGFL#zxo|j>hU;?*1S_O1MQY2W)%x z80mbn)0YauYdh|mb8GXW8yz}_hOi-q~hFpdj-h*(HKPjyUhB_rr>PLvbbQvfpi z7xK<4x^wbrQCKHMMC8Wq2uTYt!-Fcw-SwGq!m&$)qWQ|mh-Bqb*-W%qAK!K73_L_) z%$csPT4a^VYflaA*)f5kge6s$lAoO$^cjsDd&Q_t6p87qcpJ*^J#6P};LFj3tpI^2 z*IH1OV_9O?Blz-QhC*Zx0K`uxp~BX}4Cl*oCdV60%F@GCVFKd!i49rVW5Z#5bvb7% zv|Fl1$9@;OO}e?wg9e7ACs7V%Lf1!Pg&!k|wqB4Ut|zHA0}355noxZ;GqqLuhU_M3 zV@8-PB*81ymP;m=rX}OysEB*qKDaxkFj=~7IC|?(CbiQ?vWSxF1|u7$vAKZF{XeX| zV{|2IwGv2jhJPC}K#-`tO!`pv_O^ynh?7ez@X8AdDy z6UjD+YJ;yL4KFD1?xJ1y8x`-0box_oC+nKEznc2_uy0RjGb~`?h zToI18)cQj?7;D9$#M2>M1(4-jl0=i-Z&kLBxA^^~tl6+Ab9n;aV%OkibXt0_HuSK? zou;e4_+YoqN@@UauOYqB)}^tj%U#~p(acEQsInje>l$4_X>gPybhcCB$6n$a@H^>S z@8ItFF`?RSA`<L0NowRpRj0Ilx`2mEVw)pV(X{AhERhwRWYDf@B8q$_D=a76_2zsX0j5k5>jAU&2Sf+X8dOOi(L=+!3YZ- zC6R!pAM(XR9#|6h@oy)xWlYBYO?Ao9A-xz$CxZ zUjmnfvi){gy6UgO0y^Kjm+f%)+U|-erf;GMa1dwj5OjM!X+jmbZ6~HwC&=y1anm)aR$UWbvBq~5ZP7yF3Zj)vdaqgpy=+F7j z&CIGlFuu%tq2%P`Ed&q<@SKT+ca#$zEZPM6iY4l!wN-}UHKl1U$QS?x5eWowHRmL) z@wAv_nE4}J@C2cw=T3oEBkITfkWPD^gV(H6K1Clv@4a7M!vtQVHs!FgiJ*NXOP4ex zcld-lNZdel`_1#tVHM5gjqueHR0>&V=6W>Q6M3z@jbtI|DmZdtWtpcxQsuq&BK zN5<2gX(-S2J_=rddDYz=60&Sl`hCn;6NcL;cx#L{3X3?~wJ_Nc2K4X8jkTLX%YUOC zq;URhvV0zTdH)yPw14jT1pnK`O2)*+#Ogm-^r^qNs;C3raMPQPDk$sAZ9ZowP$}v^ZFa2!(DZW$=uqdLpus9=?T?Y*(5e-^< z{?YN;r}sM4^a|csVf{LtB`GmVW>D2$&vKOM{kS?~d*ywFd)4g$+xv3O33x1B*&8zT z>JLb2Re#?o*)GHsZQXKq@bcOSkl$6-tsDWTAxMn*TD6;J$QLP2cEd`;bMRb>nKN{x zBGUQ9*S$St^pqdY2-ur&(|-37RqCd3)w@#~L?iIRFWK)}fXhxyw3P@hAv?&pJ(6MO z*aeP#MEaX`!E9Ih+fqL@Z~Us+<&F0ik#d()%2vA8@r!?muD0`B-$^cRKCJcz>rOU$ zjwN7mro{hMDB+ix9wzvYGqALto$5jV64^#NHC%duW%%gdH zD3Tfv7bwETp8Yh+dv}|MA$MBmh*v8e!eW_>KKJVni6nDfEKI)@tjI>Dn$nDKHZl!` z5V#jHRFrO6kW8QDdON9J{moPEGVN56jT+%HRGF$H-vZ8QUU7~=Wfh5pH6NR5(pUuj z5^0?B%M6D_;^xQZ`OgGq_h}UPi-NjDUrPlXJ%KDEF6O=_&TAhgZ5(wgY|4H)wP)&P z)>+Ttfle6EC3{a!8D$I)7qr8wBMw1q{Aw&^;K&eKqSR(1Q*mw%3MJs4hq3#E-Q)z;I4pFYraxRuj1EEe z7!%Gp$YOeBr3+wh8nYzsqJ7lHtYFWH&JiOe7i&o$YJqI&9^uSu$f*t$U011dwpWv9 z^-RT&;dqR+Zt6X0v^479p0}e07sh@V*~;|$0Cg*^lO4?M&DQFT0>oVD07k($bhI{S zZTr?4lwfc6XA*QcQmH@z$snFgRj`G5=&}~N8ePrxnsqU@Y%&3U<bD#mA}yV;(A&cYp& z&V1qkN1W+Be}8p$?ZFuISB(L3_aA}-@^;_#cLuFTFph5TaC8R%h+l_h*k18I|7qY1 zXYGa=vS;=h>eu46^sAKqk*B%ze32$%PcoFtE+@{9h%Mj~|9kFE%oEy0J4yx4=SmxS zg;V_-Sj)5$yIe+GwS|P#fzMC|*l*4gNx5g4*CZKSC@|Wi%dcR#;H(wQ@<(QykVnn* z5zUo?gC;;DPfN>z9SLP|VKZTM-ja6SBqk%5A5lr}FJ6k$o{kM(#2WnKxCdj{44+CA zaZ`+Gk(5Wy?)lPVep4X1etpaP7ynJ;1WUfuYaROBHz%_~HiYH_m( z)M`!q6HV8RmK}Tc3$x!V(;cmEOIL2RDLQW3*k_*7jPm6pMN<}DUH4D+99oslBHy6eCOR@uG?F~@)a<6`MyD!z{+q6_(ap;&Xl051P^-@6cMD-D6_Xns` z{67wlg5m=qt;?;Z)VvhV9K8XX=KE^w9WK# zLQSdfsx#{Q!IK`}d1`C1P*ol537ILMYke~JYmd>{d~V#IPQ?_CwD^*oq~Bo5Uv=#X zOq$a5I+ByVUp^ihGr&BLxq`N|&)(&dhz(C|L(-ve1&L00pDs}8#@!wBy>h1Orm%jh z)@W<`E@)h-r{s*(Ya&U~${F}=u?8PtS7Q0CU!~>mkBe6FA@hZ(7RX(im|jw#_Hub* zJ)#b`M55^W^G|xBeT9C!m1KRmsew1x2tz6$q-UB7XIrz2cl?9mbZvA)>V}GvNxtmZ zihnd4K->Ak<8k9^xJTFuZo5-!wb`uVdcKJYmQr&awXD8V zv+ZhvDi`_*{i$PPl$T?Ur`=t#aD_U>aAL|J!0NhO?#{XK3YTYHXjqK_h>5vMXp16E z6bhFNm5KA$CmvI<3-_IKmNwuUhYy1?SESArlS65^S{i0yQPvfaIiFSPzGAt{R=<( zA9PoVTc7Yz7HkF|X2FFn!u*}f)BF%mJr%OL$u6mFdXsd= z)TCQK0x=si!{kqRfmDCd_wYVDI8C1L+$?rJV{^sbyYyQ&b?*9)GE*$hBiXy|y~8$B zx2#I=DXyOx@d`Z7V>t);jgO&+TQ&*T&REs5MxhpzI#e)CEeA~Z+LDxdcY=Hf0qO%2 z#0d_TYIhrRJd6-wY}b(pCRzCzXchDF=XPBaX%G0sA-^z_lHKd*`6Y83m7))mAf}gK zS&mA*foYH(61>@M*pd5M5^?;&zv|(eB3T0+wc#i1W3Wj+LeJ9pM=a`Vdv*(0(2Bqlt;m>MkCEWzp$taLgv2ZN*ml}eG!z|!P+KyY$ZK>gzt%7a>Ur4zJmxy zs-5T~iVW|4s$GWa)p!;_N0K+Jz+Y@75l14GPZWHR&842(`G*CR=13QZQ4K|lL6PCNL5hif1ha?&CJrD$@Tw! zv_F5@I+!sU*!=}WWwf$2GXvU~{q@ae!D#fUt-$ziQ0>3a*@A|K4kj)@gHJBjCqCOv z)XK#A6Qlj_|N7~B{Rw6;b0=f@7l5HjW#%v7_IvTB%eu8+xr#{X*IGk(dUzPoDh?{c zd5zgZ2tJ-o{PiJ|7Mm7`t9Sh23^RsQx9elUs2%!gF<4)| z8m*AA@d>*syYmt~|0a8tLED9xMZm}c@ly<2BTaB;op?}vD)G_AE9OXUoymCzy~~3s zfVgngdV>76*$7$G#$#y(d;obtbfU<8xt2co7q~sPfB!r-PdUSK_Vmr68hcXtrVE?> z%r(?z2M7Od-dx|LW;(D1##*iwQ7eWNOm)~C&j>3f0gl30W>~Q|(X5)8jzB&P8zUNA zW7s+Pbpw^bPE<3)^z4e3tOiXupyKtTy8wW|*7@+ht=&WEc}4A&+B- zq~v{ty0l;f^Er6fHgXJYdw;&gVy!X-fn1?bdamhVh(gQ#AyRZA4a@zy&;a>6&bNOt z*#Q?u!b9+sHZVRf1#6UCEIz)_mPjKuUTGVU$QL9bea0x1QN!tT;K=r}qSfd(8=vy^ z_=vEOu9uSJ1sm2&@N2gr$X0BhtMORLF7({T$sMiYAr^n9S*YqLp)D(YUW(V`RhDQ@ zPYkL-5tVdc^$B-+l3jKuGsFkcu*NB;AcTD%{q|&)ccbWK1D!~5&|NiGjK;(ZTscdXjfY$%P*19Os`tP#!v7Rho zAC7S#`0WN(^P3!mN-r`BJ7`8Qj3GkJXVsFf?wH!tMck6wl2{x>+74lv)`e%DheAzn z%4&FJC3YWAps2z!fKLI@W zZVWYdr+#+c7w#erXB&B1OMZ4|8(1h*E&WNq;@RuwJ`XY$p}vLW!I9OtWq>}9b>rdL zs=*_608Vu|`lImrJ!6ijhaNP$4VEtEj9*gIV=-~!cb3{W7It6rLn~3C)zb}1 zRhQE(8q2Jz9dkz|wl}c2Wb=f8#=cu;Q(mlIB6muAS^@q*1I?>gHleL`;;;hZ%UuHZ ztt~;4!2o2WGEL;jwY3dX;&7k8Ghj1h`8f771Fk-)zyFf}@y`tSuPtEyt*j_m831km zqE9LPb;oh|Hw%~|IOxNEXUl>@~-ceme#VnCUZ0-)cF`e-$D(AhH?@vVy#v# zhsP?9wZ22b!wL8zk!Pn_neU~OJR8k$JKAh2{-SY$E$ZU+wQe?{kMPh&&TIzT&W#|RwW^*Y3UqK zL9I^p8j)JY!p|DJ5sm3~iXz;uy=pXi9{l2OP`m?~kB#pXXmuAYpWP;Q?BEk4EuUj# zCic6NSh$W>g&&KCpmo18iS~mvhK*xj&!J#u%YNiYWkV_6V-YpGB<@Jrg+*au!njKx znVR2|MCO}8p^OvILOr-&!TVY?fpAv$F#%jQh!FZ7{SW?f40p4Z0h!Lt#=`y-<4R{T*c~s@=C9J-4;+{7NlkQDb;cxvtfQ_cv;I$9-WQ54Lndt@Fl_)^2f9 zWEqg1Id@3Ol%)(;lDTFRUph4zV`3Be49iv78ypfEv0<*(8CIz#(DwqN#7#KORamMh zmtiEIPl@Jjje$MEp`9;%o4!4d7ZEjCHA>x;#MRb02Er#{Rem_lesgw>CBQp<@Xw67f9X|Z``g=zv20hr7r+uvCy6tdvn_ZYqWsI$!(Rzx1$+%i;) zza(+p53ai0N@Rf3ac^8Xmc^2MdR(m7W0Ze>dSZxjZxdVV!jmo$JJqN$hwlhiD*6Yw zRL?Hm-|h-!5;7qMx}#Ij-&3g95>(OInh8u*8R1aY)M8K)2KVr}+>2xompuonE>zo^ zbkY=v4pU?6rP!x?xEqpNwI{>xn%28Zu)+;qT4VDs$&&}^k;hTeN6Kn#$&Wy>^^q8i z_XA6fIEok2=eDe+G?-3IY-q|cOkN}=!kKb$-l(T832G<1bg^E_%hT$HNP8tUzHV|Q zD-<#&F}bSfHePEx%T(wNW0PE_X8-uqTxUQB6?GwuI%8o~6I!o?e>;qf>QC|yqi{7v z5GP#paME(su}Y0jkEpVQlxN^tC`0I3sr%x3xcNgEe?KTM@YGy#0f&NybXks{OkCq~ zHrRT{mzX^%ZzYI3N-HuCj7N_=PaBVyZQ?gFykN?3tn)pwY@lDdR2?5IG2CgKYAuc> zdgaIz%QOuav`!z?MrH07PHL{0WwOZ}GBt<~NHMnvLB~&=sR%+#v)H6goc5ZS4C$`g zLsHzKH!$A(4P_~;kZs9@g!8A^Xpv&gd#JzdwllM~3KNLVFektZek-}Qb1HJ*H+&_{ ziKi$bJ=oolG>q1+hNQ?D*)#$GL5O6%gU)TvUvOG33AUtJI$_V?5W6KZ)f>_!HK5C_W=X4r!Rw!3eMxE z*nex+)hn?$#T?F~R<`fz1{%_5Feg)FU`soD zvMNgE7?T4oyM-Y+?e%f}WlcH{)Rc>mYy<;k8F$7ohs@0by;eFexr&@F z>v3?QR_ympcUuMLEjUF=^-1E#}c zo-~)2Ph@0tQS2U>9}hAW{OJ~qY~2emtySTHMG2%l?N`ydZx}Vhp6b`^sjG{>*4EtQ z)g8r+%#2(;OWcOPKV|mUsp-_F(ER>(I)6D~Zu8RGS*}m3;p_Yp@Eez28ozmjwdL`` z^f%)q9?4{MIXo*yv|2OpThs0MVnni$lLz8@G{xs%Ip-8aXD{TzGJ57}z}!POX+n{&smWFLo!+Gx-2N9~j_x!x?!R!3jG zKj`)wqnioWahMv~$`nbGW{N6k{NQ@B7uZjh)5LaAed*z>v3lfTNQihf;<0;Tfvp*S zkBaA28opv1zU!^v7JT-6)({&>CCM7FqTw4!3RB`=zKwZn$tK;6bKb~bP_Q}51ByyY z9YT*r@;_bZc{?4(BIL%wZ$oT4Bs@W&`!$nk=0Lx6 z?AyrBH8Ai-$7R7@9-t{^`K+v)$8nwY{m{!vfUZz2 zxcx>HhnFw{=V*f<;_;H+#uUoZRLAf7?b`vVF+MuQ$)PJ18}d5n4gsK=M2 z(4rii#8Jti6?SY&$Qn_Squ-d#>a3RugLob{UQ}1~Wq{j~l1SPb1(UtuMjVBV4!cYS zz{}e`*hhP4T<0k9c@SJB*FF_o@LX^D0cXs0gVffoY03Rp>b4j%rS=mk)242H0akAH+#yICq(bH60wFypBLX z%+E~Gq;EW$Y8P_uu3{4ww=cOZF^7-cbQW!Taa$ALD>pE*nph)NI8c+aoffoG>(k3Y zb(+@Uu$i_2 zWf>y-sw%dYz!b|00yF&dGLF1r=2^2jxaVZki1Zm8=7XR$&e3O*nHW zYd@xUSbxsEY;mPwguO^6nY__bfl#RL=B_R-hh1r_EsrlVF?t|}3ZZ+7cx_~;sgguc zq(LL8vb(T{hN<%LX2iiI2segpN;=dv)y$oA+|?%6P@Jwo2E57SNe4A|p1~)r{pNO6 zK^2jw)wFI^8tYtZH9Y0y+V!^x{L)I2I{Kl;ju{AZswEUy9@0u-4h`M(8#G(ZV+qvU z6fK->v~S+Wk*7K*%!P?hDk|BB<77uK=W4*1mR1AD^5T3Q8k(FAuOjA>yrP28nkxjb zQ{xf)Gi}z+>1<&&hsvg81s)%`LsjK9cEdaIIr>+uVE6)NvZjW4a~RbM9)tk=xsxv` zGQ63d^}B33%AIlV-^6)-f88@eIqWE&uV>&WqCA08OLSmEDyg@V%PKB#DKud_r^s>} z7OPdFR~$MM;hzmlFK2JVNZz|-C6jBNA?52{a2eOCyFxK=jaZj8G*(s0N@gdSCFUGZ zSTRs+nm)GgW;IckUSC1B$pu3-6s3~4SVevBvRkM4^Zco*xM7Y1q$`dSp$Rqv@{L4b z-2&+h((>%M+n#6D86q7ja~BeFMzhtPv11|@d44d*%^NiZRyU8x*8IrI>j_Xg`7~vm zK^R#5tt~ESl-w-``y9@^@o*%mhOYCDFzT4(5)m2;Nk+j+x8NK)3ToXxEBzs<=_fhJ z9As%+6a!|@?<+|Z(2Z;ytoA|o3^_M*@tWP+Vn@Omj@ycj?g;;8V3P(H`h>Eeyfrs< zjmS^u9WAZ(`HrS2P0P7c)IwFwb%iEZOGeA9 zfuFjKKXuKYeONoVIltYcOl5Fxy-a_+bYFG3p9et`g4N} zBijsD06L*+RIhnDbrEb8uEjbf5p2I~(}Q-ZUU$m&t>1jXZW(ne@jr1(@z=VsfxPOo zhAY3(g}fSg0pRsQ8+$4A;dx06hk!qY`p4`V!3jjm!_c?TK9LC&>4UgJ*p(>Qrx5vQ z4sQy2K|NC82~^BB1+ZMIDnz^tP8$jPr$y%ALWVo-@IsW+46>HD)aP3AKml^V}mcL+KA(Vmy|bCnBIZw0!m!<>*9_ zmC{t}4Kn?e%%D~m4OM4@)p2e9$44>q*2$+oomrmbI_VmMww#Xl+R6SlN6F^J5l`N zfN3I4KL*AJtw=|1{4z{H9iK%hDY7hya~fa0CkIsAr~)vJlES%gRQSS2$h2!$!`;}? zP_*#JR({$vtRF|;Yq%IM`bUnadLini+#mwB23w51w1!--bpTrfXe`||yUpKQsoL8TisK2d#fII^rU z?!ce3FIw=Ts;nH2Bb5|JP!;C7gs6D8IdJ|7kaPU1Q_2p0a*`_8*RN8=^ z5yEikJxgVw&F;6GxZI!T>x9mNj+A?FA?VmMrB9^qWP39-@BWd#S2c9Fpj-CXKFT+) ze6%|o4~?}nwcBD>99AKzp`83An!a``0Bxh}}sDMBUiFsG_!FX@g4EV% zGcm`&Qj8AOS$tFwj&-#j&)h66Ufs?7uo4A!TcW8w`L%p?(c<{c)*aEz%MBmRPkY?R zDOzcgn_U}ZVjRiHjSer<_K|qIoiWF8%iYUlIoigVxX2vdhj5NRPdNf8&C&g0l%Wn6 zt=6(^k&Ju}RBFQ#m=guXE>1bai-<+ZOUc??W8~4gi&;?78Jci^8fsm30p9H;9KARy&GELM-8n{8130!D>^8h zF!|R!Gkr*1v2jg#j3^E0)`s7$iRnW!8uX54vV}<YOxsk6308OG!Ta|fK=?7!f!>i z$acW==WCGZFzBEhGx+fhzUi_Ui(7+C>FqCYSH(bp`y{T22n>p!1Yap+j6rd18e^x9 z9oA7&!XFq6n~DYh-x1jR-dsK)-9zpq0IooIBnMoZk*ro+M?2at+vYoes9JVlf4S%E zz9{ltc9+=U&Fs?IM6Pt>GRN#e6;F!U%u=X0PMDJTt*%72nfJM`_)}FI3pKNBu2D54 z0hgw$HpQYZUOl<1huIg~128(wStX@;&8a1MyBZVsf7fQ{LG#bE-Af(~B%anPYX<2k zfj@6Hj6bx0X(SK$XM`YI<4{Qthpl>A1{|Ue0^yPZ~Vvfch-syR1oQ-!{qjTv9 z%M6zvAzZ}~9`dqsj23%(jhoid%-$(9ey0*mo%y}(-VAr|W{(dDS>OT5EW3j(<_a*D z)ZbgvhnT>+qFHkzFS`0B+w|d1mr^GjOrVBi;)ICSg~bVtPV_+PmxIE-v}@=>sP|6J=z)!S@gpVLst%!P9s>%z zSD+Cd&)EPY3fb*JU1P$%iEyeeq3-1k{hfxI8{L7s_Tu-P5oytphjJHCNBmlDQ+p0P zx;`5Mu4U$E{>rekw6vFv@$`#7YUZP$hxbj1@gj#TJ`-~KVUg!xEZjCw_Sn4nmbD^Cl3^Tfsv8hpO0C$tCdYb2HE?ejy zE)2V^-T*F)xYsIGP=mcGhB&dIf4) zsL&0lo3RgPz+9CQ1h?P~$B=0~>46cV;wDda;vbTL-wO*>w74h;&c30O#fjx{hV8$| z<_2*GFKX0Wf-XYJu9(mYG+1vqrqkR48~vQoOsrC$K!9k3w0D3~-4V4;nOJIURmHU6 z`-iOZQkB%NBiIk)>Y0{I4^;{0SNb-2lvbl%UN75SoOy%= zGb*v*eMyX9t9c8*Nvdf*!PBQFa17cp-o5@TPlxB?`r zT!qXv$ki_Yw;6_QZ+~T0QIve{rDYU9*)!y*y|yjn@g@`-Qp1A}A-b*M-kH!^a2^E9 z`qXYNK@o0QCjmD%5o1)Z;O>yM0^OkZp;SNV$3#n+B?qLyIh#Ob1=VH39b|z%6CuSw zUa~xolOAo=(~V z;@+T^Yz#~UNGiVvfGjNRmg*U!fMb(6`KEU!p*UX$GOSBf=N!7TD1kfnE#4T{7T>8K zZ)y3`l5ui-EDnZPd)Y-ZA!dFR;g3UJ7;fw8V9C=tv(4Mz2)j0`tlC9z5Rk*qm*YP^ z(Eit?1t(iuD@R6g6C0Di5Ito7Mzs4>x%`y({eR|A+m<4vBF7l6l{c@DIwOvnHE-?c! zsYEmYOOTW?;0ePrb(%a)HJW8;J7bkOWUS=qIV>LW9^s29JmcjJ;u%8nFV>gPs%Dg{ zX22Et={8W1R0&wwsBk=?>1ipoKM6!I>Ir2Ybk*64dccOd(>W+TKy@v2K!fd}PFLIJ z5@Nwp-NL->-7}z~>NbO%XLb)+r#J8zBxVlMvR?R7$W%adEp(@$@Fhm%vIFNLoe#dc zkUm;lRqr&QCGT{B*;XG#nkN~tQh(_i94P|t$4V^mo%`*AnAQr4a2aFYnzgv|E&guO zo#w%QY~F?*t_lbKkFFfDQ$UL~N^sl!A%*bo7Rs9t8aU^~+_?;8BM{+GVQ69hPU~B2 zgM2rnhfu!`0&odbp@m#a=6cY*tPq2G^bm&f5=9D?I*l99fUl5F^AcVtp~O*EDXc%U zMwq2i$)yW&;`$K05(8=`~1^+Vw{#iG^|Ce>+UlCvjG_p0a z0x}BQT3Z{~7|Q@{Ovr?sfmTkEHe^CTGZ7ObptZqYj!FO0?ff^`*SZZFGcy0QNz3c*G!*izi?pZMJaJr=ssD!=Z#KV#z!Z^Bc zd~P#te2!jxMpuu7dflLIk?qjXpQkI2(e3OIzGiK!4yuk71G@)fk|_bREwo5VTFc~`A5jFxXeEut)_(tP6;y*?-pzW z&-v?uNGB(dj{_9^3eZkTCpV@*1$pzsH~=zBzt;u&IT|*$c76@wuo9HO>N^=oN}bTC zRZsEQOemeO##8uY$1`<3;So%|k$*)(F126N&#@6H#?Vuos_*6EfgIyyOJ7MjXIN`DB?G*!&|Ft5mg=7rvptt4Xy~fl9T({-PnFCxURm?IZ0YSs}z_*Y8KL%Hwq= z5d0Do5)hoR7n1LWs@P8$!q_9&>LQI`EWfuF$4`v=_855J&0s$n&o#a_PURL^Yqe8L zyJg>F~`lG^17vUQmdM`~sG z53HDI zfpbx19rWsz_{0On8gtBPrRL1bHXOgqQ#@(&)FIki=|NdW8{QwF?I?uxjerEmR3Qn6?R^(zgf!zt=^$fEQYE( ze+31thYmJU_i$1C4Xa6)n;O%))(~^*4dMEwSN#jJ=Bh9k#wt0#H*-|7&f~L`uJ(Q(-Fv~BaQO{ZKJ@2UB=Gvm-$^3@ zq}4@ptVYBFNpVruP%q9T0j-!UiJk^jPL$h;!k$D~ZZ8N{cfrmkJKH#Y|T0&!hqeHoaj^ z$d48;Fz!}(i$PM2fsyp7O(b| zx+o0cN5ghgw?8?*Sr*?ho{p$aZW$vJ7&JU|zI^g(b66=kjyC~s4NUkr%>knh3GHo3&s)P;=vRhGc3J1Nr3GMjBi{v+ zo|`1}TBLgZMhWI6;J3egwje40>6`z5BlwifZ5{r8h;M41aM24R3jS-sU!6+O9ExWIMH#Ifuc0aH7d4GOJ z>{V{WN4KBp^S0um+V+bI;oz{gV%F$jNxUHt?w;c_rE>bK^|%;Qz$4r9n-%v$jy0(& z;UmCvq>swRhQCn|<7mb{Uk*dqwHZ~o49=U)@)eH@#iDu3o3|GaQqD8V!~XS<_@E=O z^Gl)C@75dp87e1ATOPPGECm_I8<%|xcH*+=HaUQ%EXOac_;sRHc&sa}zjo<3>M5}U zlyd$@Wte9Pw=GK^x?<)nkz|LagW1YE^w^F*8Q;Ker~6TuB%P{+u-l-*sr1)<`~0xB zd47+tD30DSDcIBeVGSD{(ukL7yU#Rp*()iBx#f;?F;TAA91N@GiE|=Vk?f0DUl<tC?iky3oo*+vx`x2-Qlg3?5_XKG$ecseV^k_i*B#z_deHaUg zdqPv~r>ch%waUsS4-=KLWZ@(9BhIWFhIX$_u;N>C#^O}f;s?iNp&MpJ;F+oi>XVvXo?yXrIIU+o4MSnt4}|1$Ip{tw%T9sGyCFt<&F5p^pEs z3T;x+l1EcSewVY=`e`WL7PhRaAO&yL21DcK2L=aJ2#81C8#sATNVam#*sSW~{P6qQ z|23CUpX_F7kdyF@b(niyYMh>#%(#Kov74LqE^C$h`&kiz()r%(&o<5Y8gWlljIi9-m_9QybQ9yF=P?ZFCJ#lFm>sij^ z)^>p_U>s4{?N_ggzzp&l>|iSTe9PgYjxb%?EpD+UOw{-w?8aafgvV^fHuFG+BOjjd z)!h5cvTOyN_V*81LVrPY5nhDv}XJx@Rv%?dad-03zU8fW|iL>(&Jnihb`F+Qn1D3+A~LTO-oF_ zu;0w`F*&IO_7EXNO!#h}GCP@SIzkd1ND%m8p@-`rQq<5ocJc%bdY2e1^ah@Mg<{ec zgPt$s1pv89dkxW2DAv)|Jm;HL%L8BZ> z9oRD31m<&?WS$QM`f*=Eth1IA4Bio>DqHFYzw5uD}>a_*b3-r_g<8*2O z0=qKJ=y>A&zW=C!Hfa_GEdsv!oY>~ivJC5gLBypyp)vpJJmmh<&O_<{AOj^#tnA2y zZLOTGZOG(5=T1{ATi1ULo>eM;Qzm{S>v}Fbbi#~Ei{2Djz>kOdmR3nDEK1Bbj)E57 zL@XOoi&wYoukCKd$A`|DKbZjjT3(tBH@|HX4?99zP&0N3!e0e(N4G`;z z5gr`I{;r;nsP;e~CdMrBtTFm2{=ISASZX+A#0()BHNQgBXugf3J-YK!T_4B_dCcyP zg!AY+cj!0Udf}?CahF4qgl6A-qU3WP@#bCkGN4EY-EXZKp4K~uprKkFr;*y>Vz@SR zDlP)uZjaB?)}S{w9;rQZ?*>&DtWSU~C46nfP&q3HG7 zrffX%n8P!7Uyfzv;Xqpc(kYAtN5yuPW^1>JhQU_}Y;}=PghGp}A&zdiHDb#4MKn|X zNqbCEXf3VVFLjin-A_2}^igkP5Q=v~ez&F~Aw{i+IY%J!POrM1#hrI&i~xk{;` zGJ_=!>WaMIZff>(R;#STn>IxuvkIGUcE6LU#IPRqLz4Db3LhkZz{(WcOS;|!lF^0S zvE3w$sm??=ODcvHKJP{k0)hNN5ER>qe|`?RO>cjpWi+X>?t@wlv17X+lEMAP!|`@0 z{X=BVUBZ+0>!-b4pnZW*S6@miHMdBBV^MH2YWSfOo*8&iN0=3pF4YZ3p^q_rgTfiF z$QhX@Jmhts8JE&tES)g2? zU62LWMH9*ziRtFzI7s~3NJy$UdSfLu&KN#i3iP?Rx=5g&a3OP@?IdD#IG|r;jg0Ph z%i;;M$1w=pfU5f}Eqrv$ZjmgbJ^+V?q47>x4wiW~t!Dl}*P zwA@&X?3H3aR*>H!z>qD~^UUV3`K(}+**}6r(Eq*|oRf*QbNgn5_7WVk`HY8LlVG5) zJRLyy{q(DURZ!}K3;PO8iFV{DjguiOJBBZYK-g-g3H!a%4>Wr~1hPeG^37_hkD#(R z()}@Oumu1=YqfQ|sg1Uq@N>!r($fE{-Fj97Y|H!`d(`|NVekLlDfj=)y!{vC_-_SA zS?)hzuJ0zBYcjf|U}4Ilvb3bv08|2308JqWMk1(~)ZTm!$LyYMi+*-10kwZDm|y@= zD7FN(l?XXG;%dxpk0+~NUVeYy*NvNqdx+e&ym5tPaS6-7LQA!%N(?_*3o{7ev;Av1LWP!rCGWk0S_lps>(sxlYtcuBYdtXLN%)#MFub)RSIU5JdRynF5CVp+d<%gN_Som$ zTt_0~_(MXA_>LY0j~Fm~b1ST%TX2aAroxEJ;rs)w(p$X$fVntC0D=F2xoiJNl2_#a z;h&;xWN-1`hO<_UNN2QDjIY{9DcT8IvZ*zgHAK!v2+f2aRv^5Pps_Z*_>jsuX-#RE zo{=@|)fg6wDP?xjGG2?rB~VgXi^FongF|8Dp(Rvy+8gA#vo2*H5-g=RzTItRWMPQ% z{D(Ii?KjWfr|n&T^JN@BJBa+__XP0a$fBq`Jd(oaZg0_%^40D-p#|a@Z*PIH6&{qr zV+IHNAyJIsw;1|)s&}>!#vWne^^KRm|GnU$;E!>Vy%uZ*@R|jduUS09?b4IgWDHC&O zTPZUYFHPgbqrZA1c!$H`-Lxpz?3V5mz?RQV(?Z))(YLH@ICBs0WUM@R2FDRywp_|8 z6V0pminG|5MHq#hrha=+rZ|$~%*-ApKv>O6o6MbxS9a@97vXypFUTefgAdI$(4`UT z8X)nPCTrW}P9uWyMo~>{O$=5gxhH1I66NacvN*yA1k^?KyD1?5^=~ey#Jit^Ei$Iq zz|ugu=-hDP5C4^v$8R}ZgcM`1Du2ehpEaM_0hk8R;oIg={{AXP3u;SbG$nuqY^;?p zO|n{hSDu>f34$~2OZuyBmuL%J9nq0*E6M55s|TF78;=rs62Yl;8!OzQ%gz0|h-@wyycZ&UPx&T``E zX!Mw$3QAKxU&u$q*Q;;tO5szyjrmBkZUX&lv@DxIC{_aqao*%Oc|lc=!%NrZl*Pf~ zrloSW)$^}|?TQ>ue%*EHXkeY-ybacEa?REWVno_B3rA`ATR+r{RKrz&xcwnev|r3u z1M;t|qTorM+cq&%G|(A~hQS(pup&&Rqh{X~e||oAjLmjX9fE$TDaF3$*jD=6Vj+)V zM_|*N5}X(r8^)P&p8b*ilSZ_joN$YuuCqO zTW;@jTu^tJ`D0j6rW{^dSpR_oUylqrD&0Hb&CYM80a;is$#W)lgfaNFRKBAvI%qc^!FHnUXlisN3qp?Mp1@DPNxq z(^gBAXixf0Rh>Tgd?eg_JG}%AY}=$%m~4(%(iT1 zmz{?G2|MgW>(cvfrk;nqJN%31s)7;gx~@Yr#P=H2hXnhf3SAJzOY~t|ad1LqapBK4)(J70*+o3V zDw)>>7hBuH3qcgbHYcZBvRH)|#;7C+?_XquO{zo|h9Wr)3s2^eXX@jTFzS644mm;s z4Zt=6fTte(tO7DmqbeB2d7#>nFI`-Wc=3UcV>qiEMXmokvPQeRpIR~3hUqkp0|~if z=DTFRB;)gQ7AwNFMky3p?ykPYs3?y3xg0@@N;W@B>V~th?bmNGLd$48%I!75NDZYG z=%KB=q-$n5HfD8Q;E&MjE9 z5bY&6s6-txOGY`B96>fvAv{3L;>KNxgoB1B?J9}5K$+%~S;(()SG=fo1vbvW*|mx) zjv`lW=w_dJkqC)%$+N0RCA3>ZqQq$=A)KO$E$4~1;JPnd*bC$V$L`kol3Ef5T2tVV zEefJeQ7{V?5=+3rWpt!=Vb3xXTHq9Y_ z??S}AfGVUoKoHwvmGn6J@x@~hUBA+={h|(a6wKYN0hL$0_F@AnHvJTDs4r7QiM*yW z^8Nz4(aJG`m2yvT)gtp=t5FT zW~*B+2?*>-?Ujw@?J53xdTerCS=t-AudXN&s+eLfk#m)v3!be+)RU*zrye;Cdt_S^ zzu`!e%%!L)Z1}j6b+lh|T-5Ih`{tK_?+)y~P)LIJwpmH4j>r=q5NtVuEz*;jfNeX1 z$F)2+*M*mrKuO#W0K=}6oNKZNdyr_BLYX#Mg^rF9oLucq|gZRII zu_>*zF*oB=L`=y(U%2U~)(@!u9mRZNMsmP3QEPG!3blC`l%90X3!jx_e)+42sB{I0 zzNLnj*mWS>Y9`zY3$bC$Bs@Nb#+@Ve#F6V}RE8@ICQWl>W^m;WIhdLyJ%H@(j4(x+ zD*s#SpLV;hI8=^UWF8Ou200}q-J+CO4(}|P(MQ8?t;Hz*1m7R>xkUd|&KxXcb*hkz zbwQPbyk8ORPeS^shZ^>J$FwYSx-^EoJ-%s5?KV#L>>IEyosFuaFdoi#^ma~ts>n5{ zr8E*%NFA9*-AI2a^wR6+jxBNIgN|pFCwHo3J&GqOU;6JHXcRRL@Nosa{HM*I^^ai_ z+PBTZ@qYwk{`V|AgVU- zl*W(l4uZk4RBW9N+`>>BkUFRils(Ep{~9C?}cVQ@^yLHG%7R3y(UHH1dE<2<}+m^TdA~p>TL4IR!)V}FH0#M zl(x2|NDrzcU8cA58kRVtP$&+mpZ<0*z0R2-vlXcKGtSJltYULJGVHZ2)LdF)kuffH zQ8Zt-4s#;H1CkCJ~dEj+u{MGKiW4mN0ao_p>6yV zNiN@?JyF!Ze)ixiq|`v;olXaYzXN>Nsw2bXzyu_op^$ffRezzljEaGw)T5Bi2Zzgz z=(e7ck0P2_QW=I}V6TD#zVL=VE!dzfW`UD*tf20iCk!_?^pZeLAjD|hp>ha21E1ef zl|g4RWI|w5%Pg4Zhmo7ug(dmrl^R(|r_och5HdQ|F19b;B*kn-I7-0ZZ&X zmS=DKqnZB{y=OIcr~AI)Ir9I2=l^?Viu3>Hr{UyaFXrLsWaj+ckZb>6pUAe4m7%H_ zs-qgwO|LBF1Ub_$NzmcUgb=*oEpTXLau9fAp}GWFLpE{}n4evQ)gD3Z)j?1ZmbwsP z%K-J!8N(pXYi)$zde648ecg?E)=#WPN^@gZ=xvcJCqk0zD1|9|F zQ(Nh}@4?ajPInks2F`b}vAaAkj7X-3?z%p6!2ZlmqK=ou=zRS5%=&&Vj{z`{_m#om zErFvwBS;6zCQ$sqIAq<_5Y3-O^etp`I%{o?d`uwu08xCs@7jWYq&q13_9G7w;KEd> z1c@V-f{r0`C=*+$Lt;>2XJ^p;WITY@X0k3v|0<}oh`NwylyYv;TnBTmBD~_O>xduD z^TU|@ICbe{Uc5!|WUnl$Wn@j*RrzF11c`?cx)P74cwh&6kj(Qa!7n@+mGJx5g>l#? z5hnPFV;y0v2POo}Lnvef%#$d^1k9r-COA$xWTU*KyC`V*%nK;V_)2>b6S6i@WMw=> z^C(OB0NtL9*-2_+ISgkL@tzE7a{z!ZIpR42wXic|KVm&D<1nH#?x)%9_uX?S51H*~ zTGelMjRPWE45s(d*v5b!P14DZwq?v?!ZlKw@hH)R^|~0WsSzgz;Vt;Pg5(aaOn52P zb>mQ|wtc_rN^^MjExoCkRQUcJ8&}l5DGDQ*cc;jZp87dA9eRvycaZVstn6&hX?Q}F zn+Qmqn)?A0<5n_xBSZz)5nPF!lZYjPJ1B{q{Rmb9KpNSs+XxW>AdYO-bwpbt=QQGh z01!yV;4&f>*O4KnHC9u5xvO6)DNbpqQPVK64ag~D2vBr_D&Zo#8vsT2gpjv$dIMP z=S}l01x{e~GvtNomzB^UV5`*Xy(h?rb*Jd=-%>dvL#7rJ0AO@ydrezT0%SGrN<(d@ zH-siA%U5mdvNcrGdTI&`T|pQ$8|+eocJqJ_tgEQB*VI>4k4`uWs`BS_FGkBSt7(4tpNqnOAQ zHV)0*f%Zy4Tq!gD>~u!#g?ZT`)EeSc^yB=7jM@Nf$|Y?+W`D05C(1N6h-%tN4|4*@ zj1eK@b$@ICUm(b;2Gml@cU_0(iK6qNc3osRh03(sXq;4!=FAX7YZvO*7e z3R_BQzHFLN!a|ry^pw;BM0pyN4IXp|27VPIwGH%&MpzIAnxqCn(?-;CylNdyg*dCk z!`eV@2|`wQRu}S}k~;guR*XsYWW6o)>iPlf#(JeKTf zjhnBd!OJy!-_7+FJ-wuyR8{8A^|`vjl|)R65Sf&&;FZFqnB*pGH%J7R4rK@N z@u(~n+0G%o)>PhSmpM>krqMe0(CzaCTyT`xn{M#3LZS(VLSS*VuKK+#_li5 zEgDFxy1W$wkCHyvw}mj`KN^W(>QB|4X=?MjCDcG`T&~xC1Dal)HbP_l)m3EFn$yzu zuyXOxswt^_>>?sKfkY0+Cbl7cKNh^7!s%{W2oIBp5;cUAKxFG=G?E8m@0_(!759?9 zRkw*M4BE*HOa95yY8n*f_yNJd@||g;)3w0Cu<8beO^Dal;8I^rSOGf#MQ9-OnE40c(G~0pqnD+hp5A)a zdEsj@bpg#t(#s}6V8XWk*TND0Cd2ku(A~&uvPf&`lnBBgYLnq%?FKUgM{UZaqALWR zAzO=zx)O8uD7ccFI>|?4KWZUKPbp{03j2|>i`bvqG+HOI^~z=PH)gO1E0qM#)@cPIGWO!7jd!BBWzB$Z)Khf!5AbIU6}(T*K&NVOtr0+D*w_)uKU zHutnN*sEJc>DoshaWK0@RYlgZq+;c_|IpLc6V+`3!lNgtB zs=?m-Oi}G(=F4U>Dc=gwZ?@?@Ifib2Pzjw3jl`Xa{MHa*73v(5)8G0jrkC`&^ zs6#y2$TcayWOah}(@4m%*E97nF?>FS}uw@FGUaZrG< z>f+<#9tkuFU&CMvp!RMA6F3hIb{vo9;L(o>M(R1+*XG00x2G%+A<<6JRZ|-@GgJHL zI;GwyPKL)XEPiQ4rl_y3r?-Txi3_hu1A zHBw;*7*TQT%};2Jnks8(6vqOpyQL*D5Ar0C=~aIHoH#L4b>}MT0QfW&|9~EtB?p9` zPzioby)P1cV{l(#H(Dy3WYdDMPo?DI1u>O>>nkrE$j2G;mNyQqE8A-7Y{e4zOucg! zq^+qYOB??DM8Odz?lA`K;VaU#I8jew2XE>zF7NmqEs{_qe0d5~0mN!-QC*i~=JEg^ zmG9%C%bo=RieD&j%?fmST(h)Ux7hV-6mH&k#<~&$bUrk&*f+>bgf^zc$;hT&cc@{K z4uKg*(vzDS;BiX)dl*P8d*eRZwdQ254omlT#A0etka&2!Vdf2aPugl~&QXoQ)B2f# zSq-QxWJL^A1dA~%E7{b0A~pe_=g7g#LVN^YzgWG&Jq9ji1E&F*WMDOE{Lo|-gLUMJ zDtfJ9xiE87L<$He4P13wwRV^e0UCVdg!Wnu3j*u3g!`fF7tbcwf`>1k%pKHOv-lb3 zG{NFsuLX%RzZ0@R_ZlK)`EM~?M& z{J=^I6pKX3q@zsr4dGvrPy}kvI;yWfV(M6FY1b(wIlv%7noONOq#^G`-bf2+6}46{ojNeRrAmZvBc67lEa{v=jSP+?ol z$9JAR@pf2hi1dITvg*Wm5w{);WwPZZN$ZN!E{o*u=U~$=b7(QwQHUM`JFe`XPSV=h zIY(zoGHNnxgcOp@MkxERSsFWx{*|cz3W}Ub!$Fj-vojsQR6y}Q?71a)TPX*!x*$G8 z_4df|(-O7;om(a_aYkp})368Q%)x?nZ*fkkSQ{~sltgEQId-5fA zKXFug4%F_lux^gF4+VO5qmd5DdL}}8TX`w2lbEl|QkN>to^saBC-lpiT(tcfHF`*P zN-mCqU{o;y;%X;zd^^jh%;P!6D)OhF+$t4x)EQF8F_F!cba{iPVNy99=@gJnmXPVq zr|61W+DwsuR8E;b54n4llLWKD#@l-`LIe^Aq|ExSGUI`>te^{&k59h+j}o7EkUX_8x`xfQ!N+|kChmOOMP z6Km!hL*so1Ct0GK%-ia7LVc9% zMl zcg=KKO&shaPT(jaC#k9&jb?p)(J_d!uE!h#2a3MltyiefCi1e*MuWYD(xzDIL*CDX zifWQTON%lXCb$r<2kgf-3Be~U(T}0<_XaG1qQ7HGSN%$FH%eCu6(3frZ>-k-ge#vx z8wTR7UqV;@;;sEfe}5}oIaGYuslFL3ml;N0ocmz2Yiz8Ye=3}O&MkjZl;sZnLsAih z4nONkbB3pXPTa`Rj?eln@cbL189c?x?&ljThX`{`Wz zv7$?@TVSK`Yc>yAUa&RqhZHIZy7^7f688=gsm>14f1h(hCqonKa4_D)_WDs4SR;a2 zxy@)jatV%tQog#ZNp4{t!0>-@Fb4!wS!5jfPkKb zZC9F35Ry#1U_>^q%k6C$w4wxWATl+HGxE-mVIKOc37;@Kkt;;_ zmzWu%M40GO$``c>Muf47nhbrL7rxl;($0kFl{0V1^HOF_PfL7JQavJ7j>Toeh%U&p zDZpS1o3NCHR(KP3NqpLRFc^j{s3c%AZk|H01`9KrJ-JGErG!R#Op<^&p_+3j;8Jy_ zt5LbO*N|PfU9}pf%gNyPcQ^dfyLuJ7GAGB)E|}HBG{FVKCd4`KM#hk6k}J!(J*>+> zWkOi!JX-v>uVMh1X9RJKn+a7RV1kP%>P|ExI679>B=VGG9_}rX4fBC8v4MrIFsRhD zi<{gZbb45Kv6=KRE9ASFgk$3=m=B&mwR$IbK64UmJ~f5q2UM7vuI#W>=6v9#<|Tx} zU;FXBm0z{$+^AMNKhgtZr$|r~INm+CjTkh-vP`Qb@I!)!JI31Ni3)qDSbPbufnLT< zg&)*xbz$X>(1-|!xZ`$y&!N9{bY!^5qR0ru(Z0)4Gj8{ihpPEKkzBGRX#2da$TXLZ zIa+7nBZ~_I8!B?wQUC-9{pdX%d1Y6ql0#EuK9tD&eE9aG6y0?T&F_J@r@kZ}9PbdDkRIu!4bd-ahAJ80tTU2PcUd3rwgHzPU2bzC}$3Z!z6YchnENRK(~a9-O; z{1xTyvI-6t=V(hy;a;z!kB_B!(;0cP7ZXwE6GeG`%={lm8T<+Sj8qg7*Fjsx_XHoD z0}tl{e=t3=aKW++_asy8?ZR}m4VSVF6V|}_Jz^2mbqZywq;VF(ML2&Q5JFGO;83~^ zGJlt}^&{~xf^O#*cz4e8cjDStQOGgnyz1VXAaJoxdAJQmBxY&QHf~1NgNY|)E3__V z8=6{~Je=A{jDJQ{kQC@ugaO%=?zEXVwevU=?)z8sNH+mO9#kTp$u_m~FZoT6iCW357~g?vS1-yk3fGM zbT@QI^B1A^?W8q8ST)o0f7TZ&_aqsz?jvZzje;&+En_ceUqgbkZjCS_z8-htOJFW-=3lA)h)exHq<=iI=Lr$RgGhM=aXV}51V zA$u6eXghe<#VVc>|C-V4P_MS+K{*0^cHl9ex)aY8n0*%FaAb3Lk)#!K_Yb1*ZHAF$ z%o9p9XXfMWz3zVF=En{AVi=jWg_o^u#YyHv--6{C5!;a!lW%Q71|}%&RDx_COwRfPHZ2r=jK)gE0ZFt%^FZ&8OAI#hSCw zUra}@bHi6Hawpx1B!mI1mG7C_{Rs~Ozs52Qti1U}@g|LU`q_tVHw2~6M|cdNHR;Gh zLV~Od_hF5O5rzUcMe%L12-ips_DS|bEkr^27*Y3a5bT@f_Q4b5fTUojQT851XK@x$`W|^_!B|m!FI0(iLtz5hytXL2TR7t z*J#0j{_)`(pyaz)%uuj#OaoAJALCz9a0W3?WTbJ(Ph_g7O46UOKxrlNS!AGbZw5&n zDl3qZS!0Vq8klR`=MhklhXpr+XI%Iatw~O=M5!{OoJlij)&)JeQ>1(nVdfN|$q*i$ zkn^+Z$VG|XA_A9NV|miENIp!ox91nzc=ZU4XS^mo5oY-ULANK z%P#t^6pMLU0XWcQ*Q!wqJ>XNLo7JE=5Oxjfkfg`>qgtz3FOQL4(L7RWo!cR+N6(T{KQK12hy+8mYzh%v1MXwdLu2rFp z)bhw}mAyrYZyRjYg-7x}dH~AvezyIYIAG8txn|xUcXdH5FzJWE;6vxTD%(5KhF(Buki5vAySaw*Lf~2M*EHbgfZ=UbMLl;>ZoYfCbjHn zhiHUZ#*zL?E~yt-s;Yuqk2P;}2L=n-^{0|69x*lzMg&u6mV`y3X_$SlFe8XG(WOMt z8AQ0Su}{3hp+|}GT&gehkUv{c zmzgYMt%pC8NK5$a3W_L&#VAQZuX*HnFWCs3i>*y{t?_x~X413L*0(_aYylqbZFlnK zEaUBU(PvD{CX}STMWMPyo0~rXMn!q5NNBN~#RoG#ubCg)fkja$qYfRNO?veBgRu`f zTP;d~V=?y~TP>C*I*+FLqselK8$&5eCeulyQmoUtw8>f7l7wVFzlM1xRiWClYv-VYCe(8K+cX|KGCTM2H2>(MyW3#e}M5F+V7&>GjlCV??HcnAU(40 zQNJUDJH+sd^vZGCWd`_B?{KJZ#i;LGEANOFhw4jX1*IhdV$hVmLNrFBXBTO^CPf!i zC?kaysl+EtnFIeOkgf|&rxA!%UW&d+S!~F3E#@VPzlpgwibIYNnIbi+|3y!q)c@w( zEjT6x4%FAbr@MIsab1CrwE3GCc)m>UJkVP=@R9YNr*cYgIbzBrjZgH;wCH&jIFrm< z2#-GdbvDpV&(5>cNw_@-k=SQ3l*c0<6Xc@u5CO9{20U^0&d)nU97(M9A#3ft@z^+uq%)!g+gEh4%8TnBy?cwRVn9$()a|93InW8o&37t=?0IxI+dCR}V{wc)rVqX|;RFl!9sXnCB|k}Ixt((2_}L?YmScoV zZPAt9Oxo_%-s|diq@Lf_{)yeW(tcIzOxn(}xx>ThL|c7T+j?F5_KRcCvv&Km-9?9a z8>_{|`DJ^<*GQ&4F0k*XaGL>M(~*pJt2gx{=~WzrL|iy|CepbR=wlKZiH>~Ge$$W9 z$q7Z`@_{=in(5@w22uH7jC(H2gr$8KEpV(!;||%`0GlJ(4zbxF-lIFmc)CESV_Og1 z*+7e9T@SIeq0OWi+1cQ^W1koCJZQm5h{Al(?fW7JEM^tLjaMhA~H0w+fd z>?0qxeug7RNUl&ru0z7fbr=((fM^KYAGBuMh}L!SY!WxnIwDH5V2&`t%(-f>f?0O=#8Be zSGTGHJyqF3dAX;K%J8Y)=B_RCmxMmYOVZH>kWFGwZ*1})VO2XfCQE2wPtLz(dIZ<+~&hjYrGob&#$BAeNT3fLPq1-&{XyT9UD9Dj%GpNS^swgnE_ zf{Bks)j`%23*q{XFs%~|di?WyW^07;spO%@H{=ZB%$YFI^Fku9Tzs$%+JvXZ;S?^y zoqAq<=vChaf9Ei2_ATb>XWTNyLh$%?vM_k4U!0DaFxyD{8#`etR$lv8*I3XpEu@wa z`U2=dEJUW&uQD8hmVmWJ;tvGLGJ}7lDLJ{0c615Jwl~ww;JL&V-f%U4t9fHS22h`k z)h!u5!axPnAu@#eeVX$?PF}@Nxnr3Yd*Pp4_hlFwrPBpQ5cRqeZC%c735yKIkQU_Z zz5G3v(@C6HH_aNCr?zOze!M`L8*pgcJrlX(p@dXU5?->i@dBJ>1)eSQgXsR)2$ zO-NX6`oP;K$1l14L%&Q?7`Aa@d{^uHVK9NU&-)M6F8*yHvEC@h2d(#>UN-5*u<9MI zY{I><{hbyug=mlYUId>+aCG9{flJRXXlzR14*VYuLxO>!q+cZaeSU|uUugMM{T1N>?o`3 zh&SXk%MNASw&an}

F>m_g^nRWK7i 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 z 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

y^OFYL07$x^yB(~-$B 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

9saXF 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%0Do5e9`^i5`zR)BJ7`#wh)dfhi`g@C=H~ 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

)9hs@pa|s~WIRp?Codsl4b@;htxy`Q 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

LdAd7}ztP$5Qw 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 \"#{logstash_path}/logstash-core\"\n") + gemFile.append(" gem 'logstash-core-plugin-api', :path => \"#{logstash_path}/logstash-core-plugin-api\"\n") + gemFile.append("end\n") + + File gemspecFile = file(pluginInfo.pluginFullName() + ".gemspec") + gemspecFile.write("# AUTOGENERATED BY THE GRADLE SCRIPT. EDITS WILL BE OVERWRITTEN.\n") + gemspecFile.append("Gem::Specification.new do |s|\n") + gemspecFile.append(" s.name = '" + pluginInfo.pluginFullName() + "'\n") + gemspecFile.append(" s.version = ::File.read('VERSION').split('\\n').first\n") + gemspecFile.append(" s.licenses = ['" + String.join("', '", pluginInfo.licenses) + "']\n") + gemspecFile.append(" s.summary = '" + projectDescription + "'\n") + gemspecFile.append(" s.description = '" + pluginInfo.longDescription + "'\n") + gemspecFile.append(" s.authors = ['" + String.join("', '", pluginInfo.authors) + "']\n") + gemspecFile.append(" s.email = ['" + String.join("', '", pluginInfo.email) + "']\n") + gemspecFile.append(" s.homepage = '" + pluginInfo.homepage + "'\n") + gemspecFile.append(" s.require_paths = ['lib', 'vendor/jar-dependencies']\n") + gemspecFile.append("\n") + gemspecFile.append(" s.files = Dir[\"lib/**/*\",\"*.gemspec\",\"*.md\",\"CONTRIBUTORS\",\"Gemfile\",\"LICENSE\",\"NOTICE.TXT\", \"vendor/jar-dependencies/**/*.jar\", \"vendor/jar-dependencies/**/*.rb\", \"VERSION\", \"docs/**/*\"]\n") + gemspecFile.append("\n") + gemspecFile.append(" # Special flag to let us know this is actually a logstash plugin\n") + gemspecFile.append(" s.metadata = { 'logstash_plugin' => 'true', 'logstash_group' => '" + pluginInfo.pluginType + "', 'java_plugin' => 'true'}\n") + gemspecFile.append("\n") + gemspecFile.append(" # Gem dependencies\n") + gemspecFile.append(" s.add_runtime_dependency \"logstash-core-plugin-api\", \">= 1.60\", \"<= 2.99\"\n") + gemspecFile.append(" s.add_runtime_dependency 'jar-dependencies'\n") + gemspecFile.append(" s.add_development_dependency 'logstash-devutils'\n") + gemspecFile.append("end\n") + + String moduleName = pluginInfo.pluginType.substring(0, 1).toUpperCase() + pluginInfo.pluginType.substring(1) + "s" + File pluginRb = file("lib/logstash/" + pluginInfo.pluginType + "s/" + pluginInfo.pluginName + ".rb") + Files.createDirectories(pluginRb.toPath().getParent()) + pluginRb.write("# AUTOGENERATED BY THE GRADLE SCRIPT. EDITS WILL BE OVERWRITTEN.\n") + pluginRb.append("# encoding: utf-8\n") + pluginRb.append("require \"logstash/" + pluginInfo.pluginType + "s/base\"\n") + pluginRb.append("require \"logstash/namespace\"\n") + pluginRb.append("require \"" + pluginInfo.pluginFullName() + "_jars\"\n") + pluginRb.append("require \"java\"\n") + pluginRb.append("\n") + pluginRb.append("class LogStash::" + moduleName + "::" + pluginInfo.pluginClass + " < LogStash::" + moduleName + "::Base\n") + pluginRb.append(" config_name \"" + pluginInfo.pluginName + "\"\n") + pluginRb.append("\n") + pluginRb.append(" def self.javaClass() Java::" + projectGroup + "." + pluginInfo.pluginClass + ".java_class; end\n") + pluginRb.append("end\n") + + File pluginJarsRb = file("lib/" + pluginInfo.pluginFullName() + "_jars.rb") + pluginJarsRb.write("# AUTOGENERATED BY THE GRADLE SCRIPT. EDITS WILL BE OVERWRITTEN.\n") + pluginJarsRb.append("# encoding: utf-8\n") + pluginJarsRb.append("\n") + pluginJarsRb.append("require 'jar_dependencies'\n") + pluginJarsRb.append("require_jar('" + projectGroup + "', '" + pluginInfo.pluginFullName() + "', '" + version +"')\n") +} + +void validatePluginJar(File pluginJar, String group) { + List validationErrors = new ArrayList<>() + + if (group.equals('org.logstash') || group.startsWith('org.logstash.') || group.equals('co.elastic.logstash') || group.startsWith('co.elastic.logstash.')) { + validationErrors.add("The plugin should not be placed in the 'org.logstash' or 'co.elastic.logstash' packages") + throw new GradleScriptException("Plugin validation errors:" + System.lineSeparator() + + String.join(System.lineSeparator(), validationErrors), null) + } + + URLClassLoader cl = URLClassLoader.newInstance([pluginJar.toURI().toURL()] as URL[]) + String pluginClassName = group + "." + pluginInfo.pluginClass + + Class pluginClass = null + try { + pluginClass = cl.loadClass(pluginClassName) + } catch (ClassNotFoundException ex) { + validationErrors.add(String.format("Unable to locate plugin class defined in build.gradle as '%s' in jar '%s'", pluginClassName, pluginJar)) + throw new GradleScriptException("Plugin validation errors:" + System.lineSeparator() + + String.join(System.lineSeparator(), validationErrors), null) + } + + if (pluginClass != null) { + + Annotation[] logstashPlugin = pluginClass.getAnnotations().findAll({ x -> x.annotationType().toString().equals("interface co.elastic.logstash.api.LogstashPlugin") }) + if (logstashPlugin.length != 1) { + validationErrors.add("There must be a single @LogstashPlugin annotation on the plugin class") + } else { + String pluginAnnotation = logstashPlugin[0].name() + + if (pluginAnnotation != pluginInfo.pluginName) { + validationErrors.add("The 'name' property on the @LogstashPlugin (which is '" + pluginAnnotation + "') must match the 'pluginName' property which is defined as '" + pluginInfo.pluginName + "' in the build.gradle file") + } + + if (pluginAnnotation.replace("_", "").toLowerCase() != pluginInfo.pluginClass.toLowerCase()) { + validationErrors.add("The 'name' property on the @LogstashPlugin (which is '" + pluginAnnotation + "') must match the plugin class name '" + pluginInfo.pluginClass + "' excluding casing and underscores") + } + } + } + + if (validationErrors.size() > 0) { + throw new GradleScriptException("Plugin validation errors:" + System.lineSeparator() + + String.join(System.lineSeparator(), validationErrors), null) + } +} From 5e1dc1f6a3453b68fbb6a8398f7cdc89cce8e794 Mon Sep 17 00:00:00 2001 From: Joao Duarte Date: Mon, 6 May 2019 09:28:12 +0100 Subject: [PATCH 0120/1126] fix javadoc warning for Codec.java Fixes #10756 --- logstash-core/src/main/java/co/elastic/logstash/api/Codec.java | 1 + 1 file changed, 1 insertion(+) diff --git a/logstash-core/src/main/java/co/elastic/logstash/api/Codec.java b/logstash-core/src/main/java/co/elastic/logstash/api/Codec.java index aa5e18dbb..4efa43c51 100644 --- a/logstash-core/src/main/java/co/elastic/logstash/api/Codec.java +++ b/logstash-core/src/main/java/co/elastic/logstash/api/Codec.java @@ -47,6 +47,7 @@ public interface Codec extends Plugin { * Encodes an {@link Event} and writes it to the specified {@link OutputStream}. * @param event The event to encode. * @param output The stream to which the encoded event should be written. + * @throws java.io.IOException Exceptions coming from the output stream */ void encode(Event event, OutputStream output) throws IOException; From 32934e6775054e4a763ebda866ed05e6f6c6e240 Mon Sep 17 00:00:00 2001 From: Dan Hermann Date: Fri, 3 May 2019 07:13:44 -0500 Subject: [PATCH 0121/1126] Clarify behavior of ensure_delivery flag Fixes #10754 --- docs/static/pipeline-pipeline-config.asciidoc | 18 +++++++++++++----- 1 file changed, 13 insertions(+), 5 deletions(-) diff --git a/docs/static/pipeline-pipeline-config.asciidoc b/docs/static/pipeline-pipeline-config.asciidoc index aa591fa9e..b833492ed 100644 --- a/docs/static/pipeline-pipeline-config.asciidoc +++ b/docs/static/pipeline-pipeline-config.asciidoc @@ -35,13 +35,21 @@ The `pipeline` plugin may be the most efficient way to communicate between pipel [[delivery-guarantees]] ===== Delivery Guarantees -In its standard configuration the `pipeline` input/output has at-least-once delivery guarantees. The output will be blocked if the address is blocked or unavailable. +In its standard configuration the `pipeline` input/output has at-least-once delivery guarantees. The output will be +blocked if the address is blocked or unavailable. -By default, the `ensure_delivery` option on the `pipeline` output is set to `true.` If you change the `ensure_delivery` flag to `false`, an unavailable downstream pipeline causes the sent message to be discarded. Use `ensure_delivery => false` when you want the ability to temporarily disable a downstream pipeline without the upstream one waiting for it. +By default, the `ensure_delivery` option on the `pipeline` output is set to `true.` If you change the +`ensure_delivery` flag to `false`, an _unavailable_ downstream pipeline causes the sent message to be discarded. Note +that a pipeline is considered unavailable only when it is starting up or reloading, not when any of the plugins it +may contain are blocked. A _blocked_ downstream pipeline blocks the sending output/pipeline regardless of the value of +the `ensure_delivery` flag. Use `ensure_delivery => false` when you want the ability to temporarily disable a +downstream pipeline without blocking any upstream pipelines sending to it. -A blocked downstream pipeline blocks the sending output/pipeline regardless of the value of the `ensure_delivery` flag. - -These delivery guarantees also inform the shutdown behavior of this feature. When performing a pipeline reload, changes will be made immediately as the user requests, even if that means removing a downstream pipeline an upstream pipeline sends to. This will cause the upstream pipeline to block. You must restore the downstream pipeline to cleanly shutdown Logstash. You may issue a force kill, but inflight events may be lost, unless the persistent queue is in use. +These delivery guarantees also inform the shutdown behavior of this feature. When performing a pipeline reload, changes +will be made immediately as the user requests, even if that means removing a downstream pipeline receiving events from +an upstream pipeline. This will cause the upstream pipeline to block. You must restore the downstream pipeline to +cleanly shut down Logstash. You may issue a force kill, but inflight events may be lost unless the persistent queue is +enabled for that pipeline. [[avoid-cycles]] ===== Avoid cycles From ec74c231d66e201245b797945356d561e484a8c0 Mon Sep 17 00:00:00 2001 From: Karen Metts Date: Wed, 1 May 2019 20:37:10 -0400 Subject: [PATCH 0122/1126] Fix asciidoc formatting for conversion to asciidoctor Fixes #10744 --- docs/static/azure-module.asciidoc | 2 +- docs/static/monitoring-apis.asciidoc | 4 ++-- docs/static/plugin-generator.asciidoc | 2 +- docs/static/running-logstash.asciidoc | 6 +++--- docs/static/security/logstash.asciidoc | 2 -- 5 files changed, 7 insertions(+), 9 deletions(-) diff --git a/docs/static/azure-module.asciidoc b/docs/static/azure-module.asciidoc index 96ac77970..b558d7eb9 100644 --- a/docs/static/azure-module.asciidoc +++ b/docs/static/azure-module.asciidoc @@ -168,7 +168,7 @@ modules: var.input.azure_event_hubs.event_hubs: - ["name", "initial_position", "storage_container", "decorate_events", "event_hub_connection"] <3> - ["insights-operational-logs", "TAIL", "activity-logs1", "true", "Endpoint=sb://...EntityPath=insights-operational-logs"] - - ["insights-operational-logs", "TAIL", "activity_logs2",<4> "true", "Endpoint=sb://...EntityPath=insights-operational-logs"] + - ["insights-operational-logs", "TAIL", "activity_logs2", "true", "Endpoint=sb://...EntityPath=insights-operational-logs"] <4> - ["insights-metrics-pt1m", "TAIL", "dbmetrics", "true", "Endpoint=sb://...EntityPath=insights-metrics-pt1m"] - ["insights-logs-blocks", "TAIL", "dbblocks", "true", "Endpoint=sb://...EntityPath=insights-logs-blocks"] - ["insights-logs-databasewaitstatistics", "TAIL", "dbwaitstats", "false", "Endpoint=sb://...EntityPath=insights-logs-databasewaitstatistics"] diff --git a/docs/static/monitoring-apis.asciidoc b/docs/static/monitoring-apis.asciidoc index 33e301da2..9209131f9 100644 --- a/docs/static/monitoring-apis.asciidoc +++ b/docs/static/monitoring-apis.asciidoc @@ -134,7 +134,7 @@ curl -XGET 'localhost:9600/_node/pipelines/test?pretty' Example response: [source,json] --------------------------------------------------- +---------- { "pipelines" : { "test" : { @@ -145,7 +145,7 @@ Example response: "config_reload_interval" : 3 } } ------------------------------------------------- +---------- If you specify an invalid pipeline ID, the request returns a 404 Not Found error. diff --git a/docs/static/plugin-generator.asciidoc b/docs/static/plugin-generator.asciidoc index cd18d1d67..8b30bf31b 100644 --- a/docs/static/plugin-generator.asciidoc +++ b/docs/static/plugin-generator.asciidoc @@ -8,7 +8,7 @@ can start adding custom code to process data with Logstash. **Example Usage** [source,sh] --------------------------------------------- +------------------------------------------- bin/logstash-plugin generate --type input --name xkcd --path ~/ws/elastic/plugins ------------------------------------------- diff --git a/docs/static/running-logstash.asciidoc b/docs/static/running-logstash.asciidoc index a7a1e70d8..cdda6db0a 100644 --- a/docs/static/running-logstash.asciidoc +++ b/docs/static/running-logstash.asciidoc @@ -24,7 +24,7 @@ Distributions like Debian Jessie, Ubuntu 15.10+, and many of the SUSE derivative `systemctl` command to start and stop services. Logstash places the systemd unit files in `/etc/systemd/system` for both deb and rpm. After installing the package, you can start up Logstash with: [source,sh] --------------------------------------------- +------------------------------------------- sudo systemctl start logstash.service ------------------------------------------- @@ -34,7 +34,7 @@ sudo systemctl start logstash.service For systems that use upstart, you can start Logstash with: [source,sh] --------------------------------------------- +------------------------------------------- sudo initctl start logstash ------------------------------------------- @@ -46,7 +46,7 @@ The auto-generated configuration file for upstart systems is `/etc/init/logstash For systems that use SysV, you can start Logstash with: [source,sh] --------------------------------------------- +------------------------------------------- sudo /etc/init.d/logstash start ------------------------------------------- diff --git a/docs/static/security/logstash.asciidoc b/docs/static/security/logstash.asciidoc index 2d7bdca99..a86a24dc7 100644 --- a/docs/static/security/logstash.asciidoc +++ b/docs/static/security/logstash.asciidoc @@ -54,7 +54,6 @@ POST _xpack/security/role/logstash_writer ] } --------------------------------------------------------------- - <1> The cluster needs the `manage_ilm` privilege if {ref}/getting-started-index-lifecycle-management.html[index lifecycle management] is enabled. @@ -133,7 +132,6 @@ POST _xpack/security/role/logstash_reader ] } --------------------------------------------------------------- - <1> If you use a custom Logstash index pattern, specify that pattern instead of the default `logstash-*` pattern. From f6723e7ca93a10f8e0fa0f6ddd444a82757defce Mon Sep 17 00:00:00 2001 From: Karen Metts Date: Thu, 2 May 2019 04:19:13 -0400 Subject: [PATCH 0123/1126] Remove return before callout defs Fixes #10744 --- docs/static/advanced-pipeline.asciidoc | 2 -- docs/static/azure-module.asciidoc | 2 -- docs/static/dead-letter-queues.asciidoc | 2 -- docs/static/security/logstash.asciidoc | 2 -- 4 files changed, 8 deletions(-) diff --git a/docs/static/advanced-pipeline.asciidoc b/docs/static/advanced-pipeline.asciidoc index c5e209c5b..7687e67ef 100644 --- a/docs/static/advanced-pipeline.asciidoc +++ b/docs/static/advanced-pipeline.asciidoc @@ -47,7 +47,6 @@ filebeat.inputs: output.logstash: hosts: ["localhost:5044"] -------------------------------------------------------------------------------- - <1> Absolute path to the file or files that Filebeat processes. Save your changes. @@ -732,7 +731,6 @@ filebeat.inputs: output.logstash: hosts: ["localhost:5044"] -------------------------------------------------------------------------------- - <1> Absolute path to the file or files that Filebeat processes. <2> Adds a field called `type` with the value `syslog` to the event. diff --git a/docs/static/azure-module.asciidoc b/docs/static/azure-module.asciidoc index b558d7eb9..1f2028771 100644 --- a/docs/static/azure-module.asciidoc +++ b/docs/static/azure-module.asciidoc @@ -125,7 +125,6 @@ modules: - "Endpoint=sb://...EntityPath=insights-logs-querystorewaitstatistics" - "Endpoint=sb://...EntityPath=insights-logs-timeouts" ----- - <1> The `consumer_group` (optional) is highly recommended. See <>. <2> The `storage_connection` (optional) sets the Azure Blob Storage connection for tracking processing state for Event Hubs when scaling out a deployment with multiple Logstash instances. See <> for additional details. <3> See <> for guidelines on choosing an appropriate number of threads. @@ -177,7 +176,6 @@ modules: - ["insights-logs-querystorewaitstatistics", "TAIL", "dbstorewaitstats", "true", "Endpoint=sb://...EntityPath=insights-logs-querystorewaitstatistics"] - ["insights-logs-timeouts", "TAIL", "dbtimeouts", "true", "Endpoint=sb://...EntityPath=insights-logs-timeouts"] ----- - <1> You can specify global Event Hub options. They will be overridden by any configurations specified in the event_hubs option. <2> See <> for guidelines on choosing an appropriate number of threads. <3> The header array must be defined with name in the first position. Other options can be defined in any order. The per Event Hub configuration takes precedence. Any values not defined per Event Hub use the global config value. diff --git a/docs/static/dead-letter-queues.asciidoc b/docs/static/dead-letter-queues.asciidoc index 5b63cd7c5..9bb3b7936 100644 --- a/docs/static/dead-letter-queues.asciidoc +++ b/docs/static/dead-letter-queues.asciidoc @@ -103,7 +103,6 @@ output { } } -------------------------------------------------------------------------------- - <1> The path to the top-level directory containing the dead letter queue. This directory contains a separate folder for each pipeline that writes to the dead letter queue. To find the path to this directory, look at the `logstash.yml` @@ -212,7 +211,6 @@ output { } } -------------------------------------------------------------------------------- - <1> The <> reads from the dead letter queue. <2> The `mutate` filter removes the problem field called `location`. <3> The clean event is sent to Elasticsearch, where it can be indexed because diff --git a/docs/static/security/logstash.asciidoc b/docs/static/security/logstash.asciidoc index a86a24dc7..d52f494f2 100644 --- a/docs/static/security/logstash.asciidoc +++ b/docs/static/security/logstash.asciidoc @@ -150,7 +150,6 @@ POST _xpack/security/user/logstash_user "full_name" : "Kibana User for Logstash" } --------------------------------------------------------------- - <1> `logstash_admin` is a built-in role that provides access to `.logstash-*` indices for managing configurations. @@ -258,6 +257,5 @@ You configure the user and password in the `logstash.yml` configuration file: xpack.management.elasticsearch.username: logstash_admin_user <1> xpack.management.elasticsearch.password: t0p.s3cr3t ---------------------------------------------------------- - <1> The user you specify here must have the built-in `logstash_admin` role as well as the `logstash_writer` role that you created earlier. From c9846fc9c34be63f0f676247a3a4cd3af0d4437e Mon Sep 17 00:00:00 2001 From: Karen Metts Date: Thu, 2 May 2019 04:34:29 -0400 Subject: [PATCH 0124/1126] Tweaks to callouts Fixes #10744 --- docs/static/maintainer-guide.asciidoc | 30 +++++++++++++------------- docs/static/transforming-data.asciidoc | 2 +- 2 files changed, 16 insertions(+), 16 deletions(-) diff --git a/docs/static/maintainer-guide.asciidoc b/docs/static/maintainer-guide.asciidoc index 7d3e0c9a0..ea4272a00 100644 --- a/docs/static/maintainer-guide.asciidoc +++ b/docs/static/maintainer-guide.asciidoc @@ -110,27 +110,27 @@ Please see following annotated example and see a concrete example in https://raw [source,markdown] ---- -## 1.0.x // <1> <2> - - change description // <3> - - tag: change description // <3> <4> - - tag1,tag2: change description // <3> <5> - - tag: Multi-line description // <3> <6> +## 1.0.x // <1> + - change description // <2> + - tag: change description // <3> + - tag1,tag2: change description // <4> + - tag: Multi-line description // <5> must be indented and can use additional markdown syntax - // <7> -## 1.0.0 // <8> + // <6> +## 1.0.0 // <7> [...] ---- -<1> Latest version is the first line of CHANGELOG.md -<2> Each version identifier should be a level-2 header using `##` -<3> One change description is described as a list item using a dash `-` aligned under the version identifier -<4> One change can be tagged by a word and suffixed by `:`. + +<1> Latest version is the first line of CHANGELOG.md. +Each version identifier should be a level-2 header using `##` +<2> One change description is described as a list item using a dash `-` aligned under the version identifier +<3> One change can be tagged by a word and suffixed by `:`. + Common tags are `bugfix`, `feature`, `doc`, `test` or `internal`. -<5> One change can have multiple tags separated by a comma and suffixed by `:` -<6> A multi-line change description must be properly indented -<7> Please take care to *separate versions with an empty line* -<8> Previous version identifier +<4> One change can have multiple tags separated by a comma and suffixed by `:` +<5> A multi-line change description must be properly indented +<6> Please take care to *separate versions with an empty line* +<7> Previous version identifier [float] ==== Continuous Integration diff --git a/docs/static/transforming-data.asciidoc b/docs/static/transforming-data.asciidoc index 769578ab7..9c2e8125e 100644 --- a/docs/static/transforming-data.asciidoc +++ b/docs/static/transforming-data.asciidoc @@ -535,7 +535,7 @@ filter { # using add_field here to add & rename values to the event root add_field => { server_name => "%{[server][0][description]}" } add_field => { user_firstname => "%{[user][0][firstname]}" } <5> - add_field => { user_lastname => "%{[user][0][lastname]}" } <5> + add_field => { user_lastname => "%{[user][0][lastname]}" } remove_field => ["server", "user"] jdbc_user => "logstash" jdbc_password => "example" From ba4207593231fc88978aab5d9fc643d9fce7de61 Mon Sep 17 00:00:00 2001 From: Nik Everett Date: Fri, 3 May 2019 16:48:39 -0400 Subject: [PATCH 0125/1126] Remove two other newlines Usually asciidoctor is ok with newlines like this but it doesn't like them in the definition list. Fixes #10744 --- docs/static/security/logstash.asciidoc | 2 -- 1 file changed, 2 deletions(-) diff --git a/docs/static/security/logstash.asciidoc b/docs/static/security/logstash.asciidoc index d52f494f2..c54910894 100644 --- a/docs/static/security/logstash.asciidoc +++ b/docs/static/security/logstash.asciidoc @@ -57,10 +57,8 @@ POST _xpack/security/role/logstash_writer <1> The cluster needs the `manage_ilm` privilege if {ref}/getting-started-index-lifecycle-management.html[index lifecycle management] is enabled. - <2> If you use a custom Logstash index pattern, specify your custom pattern instead of the default `logstash-*` pattern. - <3> If {ref}/getting-started-index-lifecycle-management.html[index lifecycle management] is enabled, the role requires the `manage` and `manage_ilm` privileges to load index lifecycle policies, create rollover aliases, and create From 1c64619ac024d268729a6812275f4050cae7d2d6 Mon Sep 17 00:00:00 2001 From: Guy Boertje Date: Thu, 2 May 2019 15:09:31 +0100 Subject: [PATCH 0126/1126] Bump JrJackson to 0.4.8 Fixes #10748 --- versions.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/versions.yml b/versions.yml index 0cf0238b4..e483a567f 100644 --- a/versions.yml +++ b/versions.yml @@ -21,5 +21,5 @@ jruby: # Note: this file is copied to the root of logstash-core because its gemspec needs it when # bundler evaluates the gemspec via bin/logstash # Ensure Jackson version here is kept in sync with version used by jrjackson gem -jrjackson: 0.4.7 +jrjackson: 0.4.8 jackson: 2.9.8 From a0d05b4da774c16a9bc5f07d6d88ec4354f312f3 Mon Sep 17 00:00:00 2001 From: Colin Surprenant Date: Tue, 7 May 2019 16:08:35 -0400 Subject: [PATCH 0127/1126] fix JRuby resolv.rb leak (#10741) --- logstash-core/lib/logstash/patches/resolv.rb | 32 +- .../lib/logstash/patches/resolv_9270.rb | 2903 +++++++++++++++++ .../spec/logstash/jruby_version_spec.rb | 15 + 3 files changed, 2937 insertions(+), 13 deletions(-) create mode 100644 logstash-core/lib/logstash/patches/resolv_9270.rb create mode 100644 logstash-core/spec/logstash/jruby_version_spec.rb diff --git a/logstash-core/lib/logstash/patches/resolv.rb b/logstash-core/lib/logstash/patches/resolv.rb index bdc1d0813..2c466c465 100644 --- a/logstash-core/lib/logstash/patches/resolv.rb +++ b/logstash-core/lib/logstash/patches/resolv.rb @@ -1,19 +1,25 @@ require "resolv" -# ref: https://github.com/logstash-plugins/logstash-filter-dns/issues/40 +# ref: +# https://github.com/logstash-plugins/logstash-filter-dns/issues/51 +# https://github.com/jruby/jruby/pull/5722 # -# JRuby 9k versions prior to 9.1.16.0 have a bug which crashes IP address -# resolution after 64k unique IP addresses resolutions. +# JRuby versions starting at 9.2.0.0 have a bug in resolv.rb with a leak between the +# DNS.allocate_request_id/DNS.free_request_id methods. # -# Note that the oldest JRuby version in LS 6 is 9.1.13.0 and -# JRuby 1.7.25 and 1.7.27 (the 2 versions used across LS 5) are not affected by this bug. +# We are opting to load a patched full resolv.rb instead of monkey patching the +# offending methods because we do not yet know in which upcoming version of JRuby +# this will be fixed and we want to avoid potential conflicting monkey patches. +# A spec which will break on JRuby upgrade will redirect here +# to make a manual verification and eventually remove that patch here once the fix is +# made in the JRuby version of resolv.rb. -# make sure we abort if a known correct JRuby version is installed -# to avoid having an unnecessary legacy patch being applied in the future. +if Gem::Version.new(JRUBY_VERSION) >= Gem::Version.new("9.2.0.0") + # save verbose level and mute the "warning: already initialized constant" + warn_level = $VERBOSE + $VERBOSE = nil -# The code below is copied from JRuby 9.1.16.0 resolv.rb: -# https://github.com/jruby/jruby/blob/9.1.16.0/lib/ruby/stdlib/resolv.rb#L775-L784 -# -# JRuby is Copyright (c) 2007-2017 The JRuby project, and is released -# under a tri EPL/GPL/LGPL license. -# Full license available at https://github.com/jruby/jruby/blob/9.1.16.0/COPYING + require_relative "resolv_9270" + + $VERBOSE = warn_level +end diff --git a/logstash-core/lib/logstash/patches/resolv_9270.rb b/logstash-core/lib/logstash/patches/resolv_9270.rb new file mode 100644 index 000000000..aff7fa5c1 --- /dev/null +++ b/logstash-core/lib/logstash/patches/resolv_9270.rb @@ -0,0 +1,2903 @@ +# frozen_string_literal: true + +require 'socket' +require 'timeout' +require 'io/wait' +require 'ipaddr' + +begin + require 'securerandom' +rescue LoadError +end + +# IMPORTANT +# +# This is a modified version of resolv.rb from JRuby 9.2.7.0 to fix a bug in +# UnconnectedUDP#sender and UnconnectedUDP#close +# see https://github.com/logstash-plugins/logstash-filter-dns/pull/52 + + +# Resolv is a thread-aware DNS resolver library written in Ruby. Resolv can +# handle multiple DNS requests concurrently without blocking the entire Ruby +# interpreter. +# +# See also resolv-replace.rb to replace the libc resolver with Resolv. +# +# Resolv can look up various DNS resources using the DNS module directly. +# +# Examples: +# +# p Resolv.getaddress "www.ruby-lang.org" +# p Resolv.getname "210.251.121.214" +# +# Resolv::DNS.open do |dns| +# ress = dns.getresources "www.ruby-lang.org", Resolv::DNS::Resource::IN::A +# p ress.map(&:address) +# ress = dns.getresources "ruby-lang.org", Resolv::DNS::Resource::IN::MX +# p ress.map { |r| [r.exchange.to_s, r.preference] } +# end +# +# +# == Bugs +# +# * NIS is not supported. +# * /etc/nsswitch.conf is not supported. + +class Resolv + + ## + # Tests whether we're running on Windows + + WINDOWS = /mswin|cygwin|mingw|bccwin/ =~ RUBY_PLATFORM || ::RbConfig::CONFIG['host_os'] =~ /mswin/ + + ## + # Looks up the first IP address for +name+. + + def self.getaddress(name) + DefaultResolver.getaddress(name) + end + + ## + # Looks up all IP address for +name+. + + def self.getaddresses(name) + DefaultResolver.getaddresses(name) + end + + ## + # Iterates over all IP addresses for +name+. + + def self.each_address(name, &block) + DefaultResolver.each_address(name, &block) + end + + ## + # Looks up the hostname of +address+. + + def self.getname(address) + DefaultResolver.getname(address) + end + + ## + # Looks up all hostnames for +address+. + + def self.getnames(address) + DefaultResolver.getnames(address) + end + + ## + # Iterates over all hostnames for +address+. + + def self.each_name(address, &proc) + DefaultResolver.each_name(address, &proc) + end + + ## + # Creates a new Resolv using +resolvers+. + + def initialize(resolvers=[Hosts.new, DNS.new]) + @resolvers = resolvers + end + + ## + # Looks up the first IP address for +name+. + + def getaddress(name) + each_address(name) {|address| return address} + raise ResolvError.new("no address for #{name}") + end + + ## + # Looks up all IP address for +name+. + + def getaddresses(name) + ret = [] + each_address(name) {|address| ret << address} + return ret + end + + ## + # Iterates over all IP addresses for +name+. + + def each_address(name) + if AddressRegex =~ name + yield name + return + end + yielded = false + @resolvers.each {|r| + r.each_address(name) {|address| + yield address.to_s + yielded = true + } + return if yielded + } + end + + ## + # Looks up the hostname of +address+. + + def getname(address) + each_name(address) {|name| return name} + raise ResolvError.new("no name for #{address}") + end + + ## + # Looks up all hostnames for +address+. + + def getnames(address) + ret = [] + each_name(address) {|name| ret << name} + return ret + end + + ## + # Iterates over all hostnames for +address+. + + def each_name(address) + yielded = false + @resolvers.each {|r| + r.each_name(address) {|name| + yield name.to_s + yielded = true + } + return if yielded + } + end + + ## + # Indicates a failure to resolve a name or address. + + class ResolvError < StandardError; end + + ## + # Indicates a timeout resolving a name or address. + + class ResolvTimeout < Timeout::Error; end + + ## + # Resolv::Hosts is a hostname resolver that uses the system hosts file. + + class Hosts + if WINDOWS + require 'win32/resolv' + DefaultFileName = Win32::Resolv.get_hosts_path + else + DefaultFileName = '/etc/hosts' + end + + ## + # Creates a new Resolv::Hosts, using +filename+ for its data source. + + def initialize(filename = DefaultFileName) + @filename = filename + @mutex = Thread::Mutex.new + @initialized = nil + end + + def lazy_initialize # :nodoc: + @mutex.synchronize { + unless @initialized + @name2addr = {} + @addr2name = {} + File.open(@filename, 'rb') {|f| + f.each {|line| + line.sub!(/#.*/, '') + addr, hostname, *aliases = line.split(/\s+/) + next unless addr + addr.untaint + hostname.untaint + @addr2name[addr] = [] unless @addr2name.include? addr + @addr2name[addr] << hostname + @addr2name[addr] += aliases + @name2addr[hostname] = [] unless @name2addr.include? hostname + @name2addr[hostname] << addr + aliases.each {|n| + n.untaint + @name2addr[n] = [] unless @name2addr.include? n + @name2addr[n] << addr + } + } + } + @name2addr.each {|name, arr| arr.reverse!} + @initialized = true + end + } + self + end + + ## + # Gets the IP address of +name+ from the hosts file. + + def getaddress(name) + each_address(name) {|address| return address} + raise ResolvError.new("#{@filename} has no name: #{name}") + end + + ## + # Gets all IP addresses for +name+ from the hosts file. + + def getaddresses(name) + ret = [] + each_address(name) {|address| ret << address} + return ret + end + + ## + # Iterates over all IP addresses for +name+ retrieved from the hosts file. + + def each_address(name, &proc) + lazy_initialize + if @name2addr.include?(name) + @name2addr[name].each(&proc) + end + end + + ## + # Gets the hostname of +address+ from the hosts file. + + def getname(address) + each_name(address) {|name| return name} + raise ResolvError.new("#{@filename} has no address: #{address}") + end + + ## + # Gets all hostnames for +address+ from the hosts file. + + def getnames(address) + ret = [] + each_name(address) {|name| ret << name} + return ret + end + + ## + # Iterates over all hostnames for +address+ retrieved from the hosts file. + + def each_name(address, &proc) + lazy_initialize + @addr2name[address]&.each(&proc) + end + end + + ## + # Resolv::DNS is a DNS stub resolver. + # + # Information taken from the following places: + # + # * STD0013 + # * RFC 1035 + # * ftp://ftp.isi.edu/in-notes/iana/assignments/dns-parameters + # * etc. + + class DNS + + ## + # Default DNS Port + + Port = 53 + + ## + # Default DNS UDP packet size + + UDPSize = 512 + + ## + # Creates a new DNS resolver. See Resolv::DNS.new for argument details. + # + # Yields the created DNS resolver to the block, if given, otherwise + # returns it. + + def self.open(*args) + dns = new(*args) + return dns unless block_given? + begin + yield dns + ensure + dns.close + end + end + + ## + # Creates a new DNS resolver. + # + # +config_info+ can be: + # + # nil:: Uses /etc/resolv.conf. + # String:: Path to a file using /etc/resolv.conf's format. + # Hash:: Must contain :nameserver, :search and :ndots keys. + # :nameserver_port can be used to specify port number of nameserver address. + # + # The value of :nameserver should be an address string or + # an array of address strings. + # - :nameserver => '8.8.8.8' + # - :nameserver => ['8.8.8.8', '8.8.4.4'] + # + # The value of :nameserver_port should be an array of + # pair of nameserver address and port number. + # - :nameserver_port => [['8.8.8.8', 53], ['8.8.4.4', 53]] + # + # Example: + # + # Resolv::DNS.new(:nameserver => ['210.251.121.21'], + # :search => ['ruby-lang.org'], + # :ndots => 1) + + def initialize(config_info=nil) + @mutex = Thread::Mutex.new + @config = Config.new(config_info) + @initialized = nil + end + + # Sets the resolver timeouts. This may be a single positive number + # or an array of positive numbers representing timeouts in seconds. + # If an array is specified, a DNS request will retry and wait for + # each successive interval in the array until a successful response + # is received. Specifying +nil+ reverts to the default timeouts: + # [ 5, second = 5 * 2 / nameserver_count, 2 * second, 4 * second ] + # + # Example: + # + # dns.timeouts = 3 + # + def timeouts=(values) + @config.timeouts = values + end + + def lazy_initialize # :nodoc: + @mutex.synchronize { + unless @initialized + @config.lazy_initialize + @initialized = true + end + } + self + end + + ## + # Closes the DNS resolver. + + def close + @mutex.synchronize { + if @initialized + @initialized = false + end + } + end + + ## + # Gets the IP address of +name+ from the DNS resolver. + # + # +name+ can be a Resolv::DNS::Name or a String. Retrieved address will + # be a Resolv::IPv4 or Resolv::IPv6 + + def getaddress(name) + each_address(name) {|address| return address} + raise ResolvError.new("DNS result has no information for #{name}") + end + + ## + # Gets all IP addresses for +name+ from the DNS resolver. + # + # +name+ can be a Resolv::DNS::Name or a String. Retrieved addresses will + # be a Resolv::IPv4 or Resolv::IPv6 + + def getaddresses(name) + ret = [] + each_address(name) {|address| ret << address} + return ret + end + + ## + # Iterates over all IP addresses for +name+ retrieved from the DNS + # resolver. + # + # +name+ can be a Resolv::DNS::Name or a String. Retrieved addresses will + # be a Resolv::IPv4 or Resolv::IPv6 + + def each_address(name) + each_resource(name, Resource::IN::A) {|resource| yield resource.address} + if use_ipv6? + each_resource(name, Resource::IN::AAAA) {|resource| yield resource.address} + end + end + + def use_ipv6? # :nodoc: + begin + list = Socket.ip_address_list + rescue NotImplementedError + return true + end + list.any? {|a| a.ipv6? && !a.ipv6_loopback? && !a.ipv6_linklocal? } + end + private :use_ipv6? + + ## + # Gets the hostname for +address+ from the DNS resolver. + # + # +address+ must be a Resolv::IPv4, Resolv::IPv6 or a String. Retrieved + # name will be a Resolv::DNS::Name. + + def getname(address) + each_name(address) {|name| return name} + raise ResolvError.new("DNS result has no information for #{address}") + end + + ## + # Gets all hostnames for +address+ from the DNS resolver. + # + # +address+ must be a Resolv::IPv4, Resolv::IPv6 or a String. Retrieved + # names will be Resolv::DNS::Name instances. + + def getnames(address) + ret = [] + each_name(address) {|name| ret << name} + return ret + end + + ## + # Iterates over all hostnames for +address+ retrieved from the DNS + # resolver. + # + # +address+ must be a Resolv::IPv4, Resolv::IPv6 or a String. Retrieved + # names will be Resolv::DNS::Name instances. + + def each_name(address) + case address + when Name + ptr = address + when IPv4::Regex + ptr = IPv4.create(address).to_name + when IPv6::Regex + ptr = IPv6.create(address).to_name + else + raise ResolvError.new("cannot interpret as address: #{address}") + end + each_resource(ptr, Resource::IN::PTR) {|resource| yield resource.name} + end + + ## + # Look up the +typeclass+ DNS resource of +name+. + # + # +name+ must be a Resolv::DNS::Name or a String. + # + # +typeclass+ should be one of the following: + # + # * Resolv::DNS::Resource::IN::A + # * Resolv::DNS::Resource::IN::AAAA + # * Resolv::DNS::Resource::IN::ANY + # * Resolv::DNS::Resource::IN::CNAME + # * Resolv::DNS::Resource::IN::HINFO + # * Resolv::DNS::Resource::IN::MINFO + # * Resolv::DNS::Resource::IN::MX + # * Resolv::DNS::Resource::IN::NS + # * Resolv::DNS::Resource::IN::PTR + # * Resolv::DNS::Resource::IN::SOA + # * Resolv::DNS::Resource::IN::TXT + # * Resolv::DNS::Resource::IN::WKS + # + # Returned resource is represented as a Resolv::DNS::Resource instance, + # i.e. Resolv::DNS::Resource::IN::A. + + def getresource(name, typeclass) + each_resource(name, typeclass) {|resource| return resource} + raise ResolvError.new("DNS result has no information for #{name}") + end + + ## + # Looks up all +typeclass+ DNS resources for +name+. See #getresource for + # argument details. + + def getresources(name, typeclass) + ret = [] + each_resource(name, typeclass) {|resource| ret << resource} + return ret + end + + ## + # Iterates over all +typeclass+ DNS resources for +name+. See + # #getresource for argument details. + + def each_resource(name, typeclass, &proc) + fetch_resource(name, typeclass) {|reply, reply_name| + extract_resources(reply, reply_name, typeclass, &proc) + } + end + + def fetch_resource(name, typeclass) + lazy_initialize + requester = make_udp_requester + senders = {} + begin + @config.resolv(name) {|candidate, tout, nameserver, port| + msg = Message.new + msg.rd = 1 + msg.add_question(candidate, typeclass) + unless sender = senders[[candidate, nameserver, port]] + sender = requester.sender(msg, candidate, nameserver, port) + next if !sender + senders[[candidate, nameserver, port]] = sender + end + reply, reply_name = requester.request(sender, tout) + case reply.rcode + when RCode::NoError + if reply.tc == 1 and not Requester::TCP === requester + requester.close + # Retry via TCP: + requester = make_tcp_requester(nameserver, port) + senders = {} + # This will use TCP for all remaining candidates (assuming the + # current candidate does not already respond successfully via + # TCP). This makes sense because we already know the full + # response will not fit in an untruncated UDP packet. + redo + else + yield(reply, reply_name) + end + return + when RCode::NXDomain + raise Config::NXDomain.new(reply_name.to_s) + else + raise Config::OtherResolvError.new(reply_name.to_s) + end + } + ensure + requester.close + end + end + + def make_udp_requester # :nodoc: + nameserver_port = @config.nameserver_port + if nameserver_port.length == 1 + Requester::ConnectedUDP.new(*nameserver_port[0]) + else + Requester::UnconnectedUDP.new(*nameserver_port) + end + end + + def make_tcp_requester(host, port) # :nodoc: + return Requester::TCP.new(host, port) + end + + def extract_resources(msg, name, typeclass) # :nodoc: + if typeclass < Resource::ANY + n0 = Name.create(name) + msg.each_resource {|n, ttl, data| + yield data if n0 == n + } + end + yielded = false + n0 = Name.create(name) + msg.each_resource {|n, ttl, data| + if n0 == n + case data + when typeclass + yield data + yielded = true + when Resource::CNAME + n0 = data.name + end + end + } + return if yielded + msg.each_resource {|n, ttl, data| + if n0 == n + case data + when typeclass + yield data + end + end + } + end + + if defined? SecureRandom + def self.random(arg) # :nodoc: + begin + SecureRandom.random_number(arg) + rescue NotImplementedError + rand(arg) + end + end + else + def self.random(arg) # :nodoc: + rand(arg) + end + end + + + def self.rangerand(range) # :nodoc: + base = range.begin + len = range.end - range.begin + if !range.exclude_end? + len += 1 + end + base + random(len) + end + + RequestID = {} # :nodoc: + RequestIDMutex = Thread::Mutex.new # :nodoc: + + def self.allocate_request_id(host, port) # :nodoc: + id = nil + RequestIDMutex.synchronize { + h = (RequestID[[host, port]] ||= {}) + begin + id = rangerand(0x0000..0xffff) + end while h[id] + h[id] = true + } + id + end + + def self.free_request_id(host, port, id) # :nodoc: + RequestIDMutex.synchronize { + key = [host, port] + if h = RequestID[key] + h.delete id + if h.empty? + RequestID.delete key + end + end + } + end + + def self.bind_random_port(udpsock, bind_host="0.0.0.0") # :nodoc: + begin + port = rangerand(1024..65535) + udpsock.bind(bind_host, port) + rescue Errno::EADDRINUSE, # POSIX + Errno::EACCES, # SunOS: See PRIV_SYS_NFS in privileges(5) + Errno::EPERM # FreeBSD: security.mac.portacl.port_high is configurable. See mac_portacl(4). + retry + end + end + + class Requester # :nodoc: + def initialize + @senders = {} + @socks = nil + end + + def request(sender, tout) + start = Process.clock_gettime(Process::CLOCK_MONOTONIC) + timelimit = start + tout + begin + sender.send + rescue Errno::EHOSTUNREACH, # multi-homed IPv6 may generate this + Errno::ENETUNREACH + raise ResolvTimeout + end + while true + before_select = Process.clock_gettime(Process::CLOCK_MONOTONIC) + timeout = timelimit - before_select + if timeout <= 0 + raise ResolvTimeout + end + if @socks.size == 1 + select_result = @socks[0].wait_readable(timeout) ? [ @socks ] : nil + else + select_result = IO.select(@socks, nil, nil, timeout) + end + if !select_result + after_select = Process.clock_gettime(Process::CLOCK_MONOTONIC) + next if after_select < timelimit + raise ResolvTimeout + end + begin + reply, from = recv_reply(select_result[0]) + rescue Errno::ECONNREFUSED, # GNU/Linux, FreeBSD + Errno::ECONNRESET # Windows + # No name server running on the server? + # Don't wait anymore. + raise ResolvTimeout + end + begin + msg = Message.decode(reply) + rescue DecodeError + next # broken DNS message ignored + end + if s = sender_for(from, msg) + break + else + # unexpected DNS message ignored + end + end + return msg, s.data + end + + def sender_for(addr, msg) + @senders[[addr,msg.id]] + end + + def close + socks = @socks + @socks = nil + socks&.each(&:close) + end + + class Sender # :nodoc: + def initialize(msg, data, sock) + @msg = msg + @data = data + @sock = sock + end + end + + class UnconnectedUDP < Requester # :nodoc: + def initialize(*nameserver_port) + super() + @nameserver_port = nameserver_port + @initialized = false + @mutex = Thread::Mutex.new + end + + def lazy_initialize + @mutex.synchronize { + next if @initialized + @initialized = true + @socks_hash = {} + @socks = [] + @nameserver_port.each {|host, port| + if host.index(':') + bind_host = "::" + af = Socket::AF_INET6 + else + bind_host = "0.0.0.0" + af = Socket::AF_INET + end + next if @socks_hash[bind_host] + begin + sock = UDPSocket.new(af) + rescue Errno::EAFNOSUPPORT + next # The kernel doesn't support the address family. + end + @socks << sock + @socks_hash[bind_host] = sock + sock.do_not_reverse_lookup = true + DNS.bind_random_port(sock, bind_host) + } + } + self + end + + def recv_reply(readable_socks) + lazy_initialize + reply, from = readable_socks[0].recvfrom(UDPSize) + return reply, [IPAddr.new(from[3]),from[1]] + end + + def sender(msg, data, host, port=Port) + lazy_initialize + sock = @socks_hash[host.index(':') ? "::" : "0.0.0.0"] + return nil if !sock + service = [IPAddr.new(host), port] + id = DNS.allocate_request_id(service[0].to_s, port) + request = msg.encode + request[0,2] = [id].pack('n') + return @senders[[service, id]] = + Sender.new(request, data, sock, host, port) + end + + def close + @mutex.synchronize { + if @initialized + super + @senders.each_key {|service, id| + DNS.free_request_id(service[0].to_s, service[1], id) + } + @initialized = false + end + } + end + + class Sender < Requester::Sender # :nodoc: + def initialize(msg, data, sock, host, port) + super(msg, data, sock) + @host = host + @port = port + end + attr_reader :data + + def send + raise "@sock is nil." if @sock.nil? + @sock.send(@msg, 0, @host, @port) + end + end + end + + class ConnectedUDP < Requester # :nodoc: + def initialize(host, port=Port) + super() + @host = host + @port = port + @mutex = Thread::Mutex.new + @initialized = false + end + + def lazy_initialize + @mutex.synchronize { + next if @initialized + @initialized = true + is_ipv6 = @host.index(':') + sock = UDPSocket.new(is_ipv6 ? Socket::AF_INET6 : Socket::AF_INET) + @socks = [sock] + sock.do_not_reverse_lookup = true + DNS.bind_random_port(sock, is_ipv6 ? "::" : "0.0.0.0") + sock.connect(@host, @port) + } + self + end + + def recv_reply(readable_socks) + lazy_initialize + reply = readable_socks[0].recv(UDPSize) + return reply, nil + end + + def sender(msg, data, host=@host, port=@port) + lazy_initialize + unless host == @host && port == @port + raise RequestError.new("host/port don't match: #{host}:#{port}") + end + id = DNS.allocate_request_id(@host, @port) + request = msg.encode + request[0,2] = [id].pack('n') + return @senders[[nil,id]] = Sender.new(request, data, @socks[0]) + end + + def close + @mutex.synchronize do + if @initialized + super + @senders.each_key {|from, id| + DNS.free_request_id(@host, @port, id) + } + @initialized = false + end + end + end + + class Sender < Requester::Sender # :nodoc: + def send + raise "@sock is nil." if @sock.nil? + @sock.send(@msg, 0) + end + attr_reader :data + end + end + + class MDNSOneShot < UnconnectedUDP # :nodoc: + def sender(msg, data, host, port=Port) + lazy_initialize + id = DNS.allocate_request_id(host, port) + request = msg.encode + request[0,2] = [id].pack('n') + sock = @socks_hash[host.index(':') ? "::" : "0.0.0.0"] + return @senders[id] = + UnconnectedUDP::Sender.new(request, data, sock, host, port) + end + + def sender_for(addr, msg) + lazy_initialize + @senders[msg.id] + end + end + + class TCP < Requester # :nodoc: + def initialize(host, port=Port) + super() + @host = host + @port = port + sock = TCPSocket.new(@host, @port) + @socks = [sock] + @senders = {} + end + + def recv_reply(readable_socks) + len = readable_socks[0].read(2).unpack('n')[0] + reply = @socks[0].read(len) + return reply, nil + end + + def sender(msg, data, host=@host, port=@port) + unless host == @host && port == @port + raise RequestError.new("host/port don't match: #{host}:#{port}") + end + id = DNS.allocate_request_id(@host, @port) + request = msg.encode + request[0,2] = [request.length, id].pack('nn') + return @senders[[nil,id]] = Sender.new(request, data, @socks[0]) + end + + class Sender < Requester::Sender # :nodoc: + def send + @sock.print(@msg) + @sock.flush + end + attr_reader :data + end + + def close + super + @senders.each_key {|from,id| + DNS.free_request_id(@host, @port, id) + } + end + end + + ## + # Indicates a problem with the DNS request. + + class RequestError < StandardError + end + end + + class Config # :nodoc: + def initialize(config_info=nil) + @mutex = Thread::Mutex.new + @config_info = config_info + @initialized = nil + @timeouts = nil + end + + def timeouts=(values) + if values + values = Array(values) + values.each do |t| + Numeric === t or raise ArgumentError, "#{t.inspect} is not numeric" + t > 0.0 or raise ArgumentError, "timeout=#{t} must be positive" + end + @timeouts = values + else + @timeouts = nil + end + end + + def Config.parse_resolv_conf(filename) + nameserver = [] + search = nil + ndots = 1 + File.open(filename, 'rb') {|f| + f.each {|line| + line.sub!(/[#;].*/, '') + keyword, *args = line.split(/\s+/) + args.each(&:untaint) + next unless keyword + case keyword + when 'nameserver' + nameserver += args + when 'domain' + next if args.empty? + search = [args[0]] + when 'search' + next if args.empty? + search = args + when 'options' + args.each {|arg| + case arg + when /\Andots:(\d+)\z/ + ndots = $1.to_i + end + } + end + } + } + return { :nameserver => nameserver, :search => search, :ndots => ndots } + end + + def Config.default_config_hash(filename="/etc/resolv.conf") + if File.exist? filename + config_hash = Config.parse_resolv_conf(filename) + else + if WINDOWS + require 'win32/resolv' + search, nameserver = Win32::Resolv.get_resolv_info + config_hash = {} + config_hash[:nameserver] = nameserver if nameserver + config_hash[:search] = [search].flatten if search + end + end + config_hash || {} + end + + def lazy_initialize + @mutex.synchronize { + unless @initialized + @nameserver_port = [] + @search = nil + @ndots = 1 + case @config_info + when nil + config_hash = Config.default_config_hash + when String + config_hash = Config.parse_resolv_conf(@config_info) + when Hash + config_hash = @config_info.dup + if String === config_hash[:nameserver] + config_hash[:nameserver] = [config_hash[:nameserver]] + end + if String === config_hash[:search] + config_hash[:search] = [config_hash[:search]] + end + else + raise ArgumentError.new("invalid resolv configuration: #{@config_info.inspect}") + end + if config_hash.include? :nameserver + @nameserver_port = config_hash[:nameserver].map {|ns| [ns, Port] } + end + if config_hash.include? :nameserver_port + @nameserver_port = config_hash[:nameserver_port].map {|ns, port| [ns, (port || Port)] } + end + @search = config_hash[:search] if config_hash.include? :search + @ndots = config_hash[:ndots] if config_hash.include? :ndots + + if @nameserver_port.empty? + @nameserver_port << ['0.0.0.0', Port] + end + if @search + @search = @search.map {|arg| Label.split(arg) } + else + hostname = Socket.gethostname + if /\./ =~ hostname + @search = [Label.split($')] + else + @search = [[]] + end + end + + if !@nameserver_port.kind_of?(Array) || + @nameserver_port.any? {|ns_port| + !(Array === ns_port) || + ns_port.length != 2 + !(String === ns_port[0]) || + !(Integer === ns_port[1]) + } + raise ArgumentError.new("invalid nameserver config: #{@nameserver_port.inspect}") + end + + if !@search.kind_of?(Array) || + !@search.all? {|ls| ls.all? {|l| Label::Str === l } } + raise ArgumentError.new("invalid search config: #{@search.inspect}") + end + + if !@ndots.kind_of?(Integer) + raise ArgumentError.new("invalid ndots config: #{@ndots.inspect}") + end + + @initialized = true + end + } + self + end + + def single? + lazy_initialize + if @nameserver_port.length == 1 + return @nameserver_port[0] + else + return nil + end + end + + def nameserver_port + @nameserver_port + end + + def generate_candidates(name) + candidates = nil + name = Name.create(name) + if name.absolute? + candidates = [name] + else + if @ndots <= name.length - 1 + candidates = [Name.new(name.to_a)] + else + candidates = [] + end + candidates.concat(@search.map {|domain| Name.new(name.to_a + domain)}) + fname = Name.create("#{name}.") + if !candidates.include?(fname) + candidates << fname + end + end + return candidates + end + + InitialTimeout = 5 + + def generate_timeouts + ts = [InitialTimeout] + ts << ts[-1] * 2 / @nameserver_port.length + ts << ts[-1] * 2 + ts << ts[-1] * 2 + return ts + end + + def resolv(name) + candidates = generate_candidates(name) + timeouts = @timeouts || generate_timeouts + begin + candidates.each {|candidate| + begin + timeouts.each {|tout| + @nameserver_port.each {|nameserver, port| + begin + yield candidate, tout, nameserver, port + rescue ResolvTimeout + end + } + } + raise ResolvError.new("DNS resolv timeout: #{name}") + rescue NXDomain + end + } + rescue ResolvError + end + end + + ## + # Indicates no such domain was found. + + class NXDomain < ResolvError + end + + ## + # Indicates some other unhandled resolver error was encountered. + + class OtherResolvError < ResolvError + end + end + + module OpCode # :nodoc: + Query = 0 + IQuery = 1 + Status = 2 + Notify = 4 + Update = 5 + end + + module RCode # :nodoc: + NoError = 0 + FormErr = 1 + ServFail = 2 + NXDomain = 3 + NotImp = 4 + Refused = 5 + YXDomain = 6 + YXRRSet = 7 + NXRRSet = 8 + NotAuth = 9 + NotZone = 10 + BADVERS = 16 + BADSIG = 16 + BADKEY = 17 + BADTIME = 18 + BADMODE = 19 + BADNAME = 20 + BADALG = 21 + end + + ## + # Indicates that the DNS response was unable to be decoded. + + class DecodeError < StandardError + end + + ## + # Indicates that the DNS request was unable to be encoded. + + class EncodeError < StandardError + end + + module Label # :nodoc: + def self.split(arg) + labels = [] + arg.scan(/[^\.]+/) {labels << Str.new($&)} + return labels + end + + class Str # :nodoc: + def initialize(string) + @string = string + # case insensivity of DNS labels doesn't apply non-ASCII characters. [RFC 4343] + # This assumes @string is given in ASCII compatible encoding. + @downcase = string.b.downcase + end + attr_reader :string, :downcase + + def to_s + return @string + end + + def inspect + return "#<#{self.class} #{self}>" + end + + def ==(other) + return self.class == other.class && @downcase == other.downcase + end + + def eql?(other) + return self == other + end + + def hash + return @downcase.hash + end + end + end + + ## + # A representation of a DNS name. + + class Name + + ## + # Creates a new DNS name from +arg+. +arg+ can be: + # + # Name:: returns +arg+. + # String:: Creates a new Name. + + def self.create(arg) + case arg + when Name + return arg + when String + return Name.new(Label.split(arg), /\.\z/ =~ arg ? true : false) + else + raise ArgumentError.new("cannot interpret as DNS name: #{arg.inspect}") + end + end + + def initialize(labels, absolute=true) # :nodoc: + labels = labels.map {|label| + case label + when String then Label::Str.new(label) + when Label::Str then label + else + raise ArgumentError, "unexpected label: #{label.inspect}" + end + } + @labels = labels + @absolute = absolute + end + + def inspect # :nodoc: + "#<#{self.class}: #{self}#{@absolute ? '.' : ''}>" + end + + ## + # True if this name is absolute. + + def absolute? + return @absolute + end + + def ==(other) # :nodoc: + return false unless Name === other + return false unless @absolute == other.absolute? + return @labels == other.to_a + end + + alias eql? == # :nodoc: + + ## + # Returns true if +other+ is a subdomain. + # + # Example: + # + # domain = Resolv::DNS::Name.create("y.z") + # p Resolv::DNS::Name.create("w.x.y.z").subdomain_of?(domain) #=> true + # p Resolv::DNS::Name.create("x.y.z").subdomain_of?(domain) #=> true + # p Resolv::DNS::Name.create("y.z").subdomain_of?(domain) #=> false + # p Resolv::DNS::Name.create("z").subdomain_of?(domain) #=> false + # p Resolv::DNS::Name.create("x.y.z.").subdomain_of?(domain) #=> false + # p Resolv::DNS::Name.create("w.z").subdomain_of?(domain) #=> false + # + + def subdomain_of?(other) + raise ArgumentError, "not a domain name: #{other.inspect}" unless Name === other + return false if @absolute != other.absolute? + other_len = other.length + return false if @labels.length <= other_len + return @labels[-other_len, other_len] == other.to_a + end + + def hash # :nodoc: + return @labels.hash ^ @absolute.hash + end + + def to_a # :nodoc: + return @labels + end + + def length # :nodoc: + return @labels.length + end + + def [](i) # :nodoc: + return @labels[i] + end + + ## + # returns the domain name as a string. + # + # The domain name doesn't have a trailing dot even if the name object is + # absolute. + # + # Example: + # + # p Resolv::DNS::Name.create("x.y.z.").to_s #=> "x.y.z" + # p Resolv::DNS::Name.create("x.y.z").to_s #=> "x.y.z" + + def to_s + return @labels.join('.') + end + end + + class Message # :nodoc: + @@identifier = -1 + + def initialize(id = (@@identifier += 1) & 0xffff) + @id = id + @qr = 0 + @opcode = 0 + @aa = 0 + @tc = 0 + @rd = 0 # recursion desired + @ra = 0 # recursion available + @rcode = 0 + @question = [] + @answer = [] + @authority = [] + @additional = [] + end + + attr_accessor :id, :qr, :opcode, :aa, :tc, :rd, :ra, :rcode + attr_reader :question, :answer, :authority, :additional + + def ==(other) + return @id == other.id && + @qr == other.qr && + @opcode == other.opcode && + @aa == other.aa && + @tc == other.tc && + @rd == other.rd && + @ra == other.ra && + @rcode == other.rcode && + @question == other.question && + @answer == other.answer && + @authority == other.authority && + @additional == other.additional + end + + def add_question(name, typeclass) + @question << [Name.create(name), typeclass] + end + + def each_question + @question.each {|name, typeclass| + yield name, typeclass + } + end + + def add_answer(name, ttl, data) + @answer << [Name.create(name), ttl, data] + end + + def each_answer + @answer.each {|name, ttl, data| + yield name, ttl, data + } + end + + def add_authority(name, ttl, data) + @authority << [Name.create(name), ttl, data] + end + + def each_authority + @authority.each {|name, ttl, data| + yield name, ttl, data + } + end + + def add_additional(name, ttl, data) + @additional << [Name.create(name), ttl, data] + end + + def each_additional + @additional.each {|name, ttl, data| + yield name, ttl, data + } + end + + def each_resource + each_answer {|name, ttl, data| yield name, ttl, data} + each_authority {|name, ttl, data| yield name, ttl, data} + each_additional {|name, ttl, data| yield name, ttl, data} + end + + def encode + return MessageEncoder.new {|msg| + msg.put_pack('nnnnnn', + @id, + (@qr & 1) << 15 | + (@opcode & 15) << 11 | + (@aa & 1) << 10 | + (@tc & 1) << 9 | + (@rd & 1) << 8 | + (@ra & 1) << 7 | + (@rcode & 15), + @question.length, + @answer.length, + @authority.length, + @additional.length) + @question.each {|q| + name, typeclass = q + msg.put_name(name) + msg.put_pack('nn', typeclass::TypeValue, typeclass::ClassValue) + } + [@answer, @authority, @additional].each {|rr| + rr.each {|r| + name, ttl, data = r + msg.put_name(name) + msg.put_pack('nnN', data.class::TypeValue, data.class::ClassValue, ttl) + msg.put_length16 {data.encode_rdata(msg)} + } + } + }.to_s + end + + class MessageEncoder # :nodoc: + def initialize + @data = ''.dup + @names = {} + yield self + end + + def to_s + return @data + end + + def put_bytes(d) + @data << d + end + + def put_pack(template, *d) + @data << d.pack(template) + end + + def put_length16 + length_index = @data.length + @data << "\0\0" + data_start = @data.length + yield + data_end = @data.length + @data[length_index, 2] = [data_end - data_start].pack("n") + end + + def put_string(d) + self.put_pack("C", d.length) + @data << d + end + + def put_string_list(ds) + ds.each {|d| + self.put_string(d) + } + end + + def put_name(d) + put_labels(d.to_a) + end + + def put_labels(d) + d.each_index {|i| + domain = d[i..-1] + if idx = @names[domain] + self.put_pack("n", 0xc000 | idx) + return + else + if @data.length < 0x4000 + @names[domain] = @data.length + end + self.put_label(d[i]) + end + } + @data << "\0" + end + + def put_label(d) + self.put_string(d.to_s) + end + end + + def Message.decode(m) + o = Message.new(0) + MessageDecoder.new(m) {|msg| + id, flag, qdcount, ancount, nscount, arcount = + msg.get_unpack('nnnnnn') + o.id = id + o.qr = (flag >> 15) & 1 + o.opcode = (flag >> 11) & 15 + o.aa = (flag >> 10) & 1 + o.tc = (flag >> 9) & 1 + o.rd = (flag >> 8) & 1 + o.ra = (flag >> 7) & 1 + o.rcode = flag & 15 + (1..qdcount).each { + name, typeclass = msg.get_question + o.add_question(name, typeclass) + } + (1..ancount).each { + name, ttl, data = msg.get_rr + o.add_answer(name, ttl, data) + } + (1..nscount).each { + name, ttl, data = msg.get_rr + o.add_authority(name, ttl, data) + } + (1..arcount).each { + name, ttl, data = msg.get_rr + o.add_additional(name, ttl, data) + } + } + return o + end + + class MessageDecoder # :nodoc: + def initialize(data) + @data = data + @index = 0 + @limit = data.bytesize + yield self + end + + def inspect + "\#<#{self.class}: #{@data.byteslice(0, @index).inspect} #{@data.byteslice(@index..-1).inspect}>" + end + + def get_length16 + len, = self.get_unpack('n') + save_limit = @limit + @limit = @index + len + d = yield(len) + if @index < @limit + raise DecodeError.new("junk exists") + elsif @limit < @index + raise DecodeError.new("limit exceeded") + end + @limit = save_limit + return d + end + + def get_bytes(len = @limit - @index) + raise DecodeError.new("limit exceeded") if @limit < @index + len + d = @data.byteslice(@index, len) + @index += len + return d + end + + def get_unpack(template) + len = 0 + template.each_byte {|byte| + byte = "%c" % byte + case byte + when ?c, ?C + len += 1 + when ?n + len += 2 + when ?N + len += 4 + else + raise StandardError.new("unsupported template: '#{byte.chr}' in '#{template}'") + end + } + raise DecodeError.new("limit exceeded") if @limit < @index + len + arr = @data.unpack("@#{@index}#{template}") + @index += len + return arr + end + + def get_string + raise DecodeError.new("limit exceeded") if @limit <= @index + len = @data.getbyte(@index) + raise DecodeError.new("limit exceeded") if @limit < @index + 1 + len + d = @data.byteslice(@index + 1, len) + @index += 1 + len + return d + end + + def get_string_list + strings = [] + while @index < @limit + strings << self.get_string + end + strings + end + + def get_name + return Name.new(self.get_labels) + end + + def get_labels + prev_index = @index + save_index = nil + d = [] + while true + raise DecodeError.new("limit exceeded") if @limit <= @index + case @data.getbyte(@index) + when 0 + @index += 1 + if save_index + @index = save_index + end + return d + when 192..255 + idx = self.get_unpack('n')[0] & 0x3fff + if prev_index <= idx + raise DecodeError.new("non-backward name pointer") + end + prev_index = idx + if !save_index + save_index = @index + end + @index = idx + else + d << self.get_label + end + end + end + + def get_label + return Label::Str.new(self.get_string) + end + + def get_question + name = self.get_name + type, klass = self.get_unpack("nn") + return name, Resource.get_class(type, klass) + end + + def get_rr + name = self.get_name + type, klass, ttl = self.get_unpack('nnN') + typeclass = Resource.get_class(type, klass) + res = self.get_length16 do + begin + typeclass.decode_rdata self + rescue => e + raise DecodeError, e.message, e.backtrace + end + end + res.instance_variable_set :@ttl, ttl + return name, ttl, res + end + end + end + + ## + # A DNS query abstract class. + + class Query + def encode_rdata(msg) # :nodoc: + raise EncodeError.new("#{self.class} is query.") + end + + def self.decode_rdata(msg) # :nodoc: + raise DecodeError.new("#{self.class} is query.") + end + end + + ## + # A DNS resource abstract class. + + class Resource < Query + + ## + # Remaining Time To Live for this Resource. + + attr_reader :ttl + + ClassHash = {} # :nodoc: + + def encode_rdata(msg) # :nodoc: + raise NotImplementedError.new + end + + def self.decode_rdata(msg) # :nodoc: + raise NotImplementedError.new + end + + def ==(other) # :nodoc: + return false unless self.class == other.class + s_ivars = self.instance_variables + s_ivars.sort! + s_ivars.delete :@ttl + o_ivars = other.instance_variables + o_ivars.sort! + o_ivars.delete :@ttl + return s_ivars == o_ivars && + s_ivars.collect {|name| self.instance_variable_get name} == + o_ivars.collect {|name| other.instance_variable_get name} + end + + def eql?(other) # :nodoc: + return self == other + end + + def hash # :nodoc: + h = 0 + vars = self.instance_variables + vars.delete :@ttl + vars.each {|name| + h ^= self.instance_variable_get(name).hash + } + return h + end + + def self.get_class(type_value, class_value) # :nodoc: + return ClassHash[[type_value, class_value]] || + Generic.create(type_value, class_value) + end + + ## + # A generic resource abstract class. + + class Generic < Resource + + ## + # Creates a new generic resource. + + def initialize(data) + @data = data + end + + ## + # Data for this generic resource. + + attr_reader :data + + def encode_rdata(msg) # :nodoc: + msg.put_bytes(data) + end + + def self.decode_rdata(msg) # :nodoc: + return self.new(msg.get_bytes) + end + + def self.create(type_value, class_value) # :nodoc: + c = Class.new(Generic) + c.const_set(:TypeValue, type_value) + c.const_set(:ClassValue, class_value) + Generic.const_set("Type#{type_value}_Class#{class_value}", c) + ClassHash[[type_value, class_value]] = c + return c + end + end + + ## + # Domain Name resource abstract class. + + class DomainName < Resource + + ## + # Creates a new DomainName from +name+. + + def initialize(name) + @name = name + end + + ## + # The name of this DomainName. + + attr_reader :name + + def encode_rdata(msg) # :nodoc: + msg.put_name(@name) + end + + def self.decode_rdata(msg) # :nodoc: + return self.new(msg.get_name) + end + end + + # Standard (class generic) RRs + + ClassValue = nil # :nodoc: + + ## + # An authoritative name server. + + class NS < DomainName + TypeValue = 2 # :nodoc: + end + + ## + # The canonical name for an alias. + + class CNAME < DomainName + TypeValue = 5 # :nodoc: + end + + ## + # Start Of Authority resource. + + class SOA < Resource + + TypeValue = 6 # :nodoc: + + ## + # Creates a new SOA record. See the attr documentation for the + # details of each argument. + + def initialize(mname, rname, serial, refresh, retry_, expire, minimum) + @mname = mname + @rname = rname + @serial = serial + @refresh = refresh + @retry = retry_ + @expire = expire + @minimum = minimum + end + + ## + # Name of the host where the master zone file for this zone resides. + + attr_reader :mname + + ## + # The person responsible for this domain name. + + attr_reader :rname + + ## + # The version number of the zone file. + + attr_reader :serial + + ## + # How often, in seconds, a secondary name server is to check for + # updates from the primary name server. + + attr_reader :refresh + + ## + # How often, in seconds, a secondary name server is to retry after a + # failure to check for a refresh. + + attr_reader :retry + + ## + # Time in seconds that a secondary name server is to use the data + # before refreshing from the primary name server. + + attr_reader :expire + + ## + # The minimum number of seconds to be used for TTL values in RRs. + + attr_reader :minimum + + def encode_rdata(msg) # :nodoc: + msg.put_name(@mname) + msg.put_name(@rname) + msg.put_pack('NNNNN', @serial, @refresh, @retry, @expire, @minimum) + end + + def self.decode_rdata(msg) # :nodoc: + mname = msg.get_name + rname = msg.get_name + serial, refresh, retry_, expire, minimum = msg.get_unpack('NNNNN') + return self.new( + mname, rname, serial, refresh, retry_, expire, minimum) + end + end + + ## + # A Pointer to another DNS name. + + class PTR < DomainName + TypeValue = 12 # :nodoc: + end + + ## + # Host Information resource. + + class HINFO < Resource + + TypeValue = 13 # :nodoc: + + ## + # Creates a new HINFO running +os+ on +cpu+. + + def initialize(cpu, os) + @cpu = cpu + @os = os + end + + ## + # CPU architecture for this resource. + + attr_reader :cpu + + ## + # Operating system for this resource. + + attr_reader :os + + def encode_rdata(msg) # :nodoc: + msg.put_string(@cpu) + msg.put_string(@os) + end + + def self.decode_rdata(msg) # :nodoc: + cpu = msg.get_string + os = msg.get_string + return self.new(cpu, os) + end + end + + ## + # Mailing list or mailbox information. + + class MINFO < Resource + + TypeValue = 14 # :nodoc: + + def initialize(rmailbx, emailbx) + @rmailbx = rmailbx + @emailbx = emailbx + end + + ## + # Domain name responsible for this mail list or mailbox. + + attr_reader :rmailbx + + ## + # Mailbox to use for error messages related to the mail list or mailbox. + + attr_reader :emailbx + + def encode_rdata(msg) # :nodoc: + msg.put_name(@rmailbx) + msg.put_name(@emailbx) + end + + def self.decode_rdata(msg) # :nodoc: + rmailbx = msg.get_string + emailbx = msg.get_string + return self.new(rmailbx, emailbx) + end + end + + ## + # Mail Exchanger resource. + + class MX < Resource + + TypeValue= 15 # :nodoc: + + ## + # Creates a new MX record with +preference+, accepting mail at + # +exchange+. + + def initialize(preference, exchange) + @preference = preference + @exchange = exchange + end + + ## + # The preference for this MX. + + attr_reader :preference + + ## + # The host of this MX. + + attr_reader :exchange + + def encode_rdata(msg) # :nodoc: + msg.put_pack('n', @preference) + msg.put_name(@exchange) + end + + def self.decode_rdata(msg) # :nodoc: + preference, = msg.get_unpack('n') + exchange = msg.get_name + return self.new(preference, exchange) + end + end + + ## + # Unstructured text resource. + + class TXT < Resource + + TypeValue = 16 # :nodoc: + + def initialize(first_string, *rest_strings) + @strings = [first_string, *rest_strings] + end + + ## + # Returns an Array of Strings for this TXT record. + + attr_reader :strings + + ## + # Returns the concatenated string from +strings+. + + def data + @strings.join("") + end + + def encode_rdata(msg) # :nodoc: + msg.put_string_list(@strings) + end + + def self.decode_rdata(msg) # :nodoc: + strings = msg.get_string_list + return self.new(*strings) + end + end + + ## + # Location resource + + class LOC < Resource + + TypeValue = 29 # :nodoc: + + def initialize(version, ssize, hprecision, vprecision, latitude, longitude, altitude) + @version = version + @ssize = Resolv::LOC::Size.create(ssize) + @hprecision = Resolv::LOC::Size.create(hprecision) + @vprecision = Resolv::LOC::Size.create(vprecision) + @latitude = Resolv::LOC::Coord.create(latitude) + @longitude = Resolv::LOC::Coord.create(longitude) + @altitude = Resolv::LOC::Alt.create(altitude) + end + + ## + # Returns the version value for this LOC record which should always be 00 + + attr_reader :version + + ## + # The spherical size of this LOC + # in meters using scientific notation as 2 integers of XeY + + attr_reader :ssize + + ## + # The horizontal precision using ssize type values + # in meters using scientific notation as 2 integers of XeY + # for precision use value/2 e.g. 2m = +/-1m + + attr_reader :hprecision + + ## + # The vertical precision using ssize type values + # in meters using scientific notation as 2 integers of XeY + # for precision use value/2 e.g. 2m = +/-1m + + attr_reader :vprecision + + ## + # The latitude for this LOC where 2**31 is the equator + # in thousandths of an arc second as an unsigned 32bit integer + + attr_reader :latitude + + ## + # The longitude for this LOC where 2**31 is the prime meridian + # in thousandths of an arc second as an unsigned 32bit integer + + attr_reader :longitude + + ## + # The altitude of the LOC above a reference sphere whose surface sits 100km below the WGS84 spheroid + # in centimeters as an unsigned 32bit integer + + attr_reader :altitude + + + def encode_rdata(msg) # :nodoc: + msg.put_bytes(@version) + msg.put_bytes(@ssize.scalar) + msg.put_bytes(@hprecision.scalar) + msg.put_bytes(@vprecision.scalar) + msg.put_bytes(@latitude.coordinates) + msg.put_bytes(@longitude.coordinates) + msg.put_bytes(@altitude.altitude) + end + + def self.decode_rdata(msg) # :nodoc: + version = msg.get_bytes(1) + ssize = msg.get_bytes(1) + hprecision = msg.get_bytes(1) + vprecision = msg.get_bytes(1) + latitude = msg.get_bytes(4) + longitude = msg.get_bytes(4) + altitude = msg.get_bytes(4) + return self.new( + version, + Resolv::LOC::Size.new(ssize), + Resolv::LOC::Size.new(hprecision), + Resolv::LOC::Size.new(vprecision), + Resolv::LOC::Coord.new(latitude,"lat"), + Resolv::LOC::Coord.new(longitude,"lon"), + Resolv::LOC::Alt.new(altitude) + ) + end + end + + ## + # A Query type requesting any RR. + + class ANY < Query + TypeValue = 255 # :nodoc: + end + + ClassInsensitiveTypes = [ # :nodoc: + NS, CNAME, SOA, PTR, HINFO, MINFO, MX, TXT, LOC, ANY + ] + + ## + # module IN contains ARPA Internet specific RRs. + + module IN + + ClassValue = 1 # :nodoc: + + ClassInsensitiveTypes.each {|s| + c = Class.new(s) + c.const_set(:TypeValue, s::TypeValue) + c.const_set(:ClassValue, ClassValue) + ClassHash[[s::TypeValue, ClassValue]] = c + self.const_set(s.name.sub(/.*::/, ''), c) + } + + ## + # IPv4 Address resource + + class A < Resource + TypeValue = 1 + ClassValue = IN::ClassValue + ClassHash[[TypeValue, ClassValue]] = self # :nodoc: + + ## + # Creates a new A for +address+. + + def initialize(address) + @address = IPv4.create(address) + end + + ## + # The Resolv::IPv4 address for this A. + + attr_reader :address + + def encode_rdata(msg) # :nodoc: + msg.put_bytes(@address.address) + end + + def self.decode_rdata(msg) # :nodoc: + return self.new(IPv4.new(msg.get_bytes(4))) + end + end + + ## + # Well Known Service resource. + + class WKS < Resource + TypeValue = 11 + ClassValue = IN::ClassValue + ClassHash[[TypeValue, ClassValue]] = self # :nodoc: + + def initialize(address, protocol, bitmap) + @address = IPv4.create(address) + @protocol = protocol + @bitmap = bitmap + end + + ## + # The host these services run on. + + attr_reader :address + + ## + # IP protocol number for these services. + + attr_reader :protocol + + ## + # A bit map of enabled services on this host. + # + # If protocol is 6 (TCP) then the 26th bit corresponds to the SMTP + # service (port 25). If this bit is set, then an SMTP server should + # be listening on TCP port 25; if zero, SMTP service is not + # supported. + + attr_reader :bitmap + + def encode_rdata(msg) # :nodoc: + msg.put_bytes(@address.address) + msg.put_pack("n", @protocol) + msg.put_bytes(@bitmap) + end + + def self.decode_rdata(msg) # :nodoc: + address = IPv4.new(msg.get_bytes(4)) + protocol, = msg.get_unpack("n") + bitmap = msg.get_bytes + return self.new(address, protocol, bitmap) + end + end + + ## + # An IPv6 address record. + + class AAAA < Resource + TypeValue = 28 + ClassValue = IN::ClassValue + ClassHash[[TypeValue, ClassValue]] = self # :nodoc: + + ## + # Creates a new AAAA for +address+. + + def initialize(address) + @address = IPv6.create(address) + end + + ## + # The Resolv::IPv6 address for this AAAA. + + attr_reader :address + + def encode_rdata(msg) # :nodoc: + msg.put_bytes(@address.address) + end + + def self.decode_rdata(msg) # :nodoc: + return self.new(IPv6.new(msg.get_bytes(16))) + end + end + + ## + # SRV resource record defined in RFC 2782 + # + # These records identify the hostname and port that a service is + # available at. + + class SRV < Resource + TypeValue = 33 + ClassValue = IN::ClassValue + ClassHash[[TypeValue, ClassValue]] = self # :nodoc: + + # Create a SRV resource record. + # + # See the documentation for #priority, #weight, #port and #target + # for +priority+, +weight+, +port and +target+ respectively. + + def initialize(priority, weight, port, target) + @priority = priority.to_int + @weight = weight.to_int + @port = port.to_int + @target = Name.create(target) + end + + # The priority of this target host. + # + # A client MUST attempt to contact the target host with the + # lowest-numbered priority it can reach; target hosts with the same + # priority SHOULD be tried in an order defined by the weight field. + # The range is 0-65535. Note that it is not widely implemented and + # should be set to zero. + + attr_reader :priority + + # A server selection mechanism. + # + # The weight field specifies a relative weight for entries with the + # same priority. Larger weights SHOULD be given a proportionately + # higher probability of being selected. The range of this number is + # 0-65535. Domain administrators SHOULD use Weight 0 when there + # isn't any server selection to do, to make the RR easier to read + # for humans (less noisy). Note that it is not widely implemented + # and should be set to zero. + + attr_reader :weight + + # The port on this target host of this service. + # + # The range is 0-65535. + + attr_reader :port + + # The domain name of the target host. + # + # A target of "." means that the service is decidedly not available + # at this domain. + + attr_reader :target + + def encode_rdata(msg) # :nodoc: + msg.put_pack("n", @priority) + msg.put_pack("n", @weight) + msg.put_pack("n", @port) + msg.put_name(@target) + end + + def self.decode_rdata(msg) # :nodoc: + priority, = msg.get_unpack("n") + weight, = msg.get_unpack("n") + port, = msg.get_unpack("n") + target = msg.get_name + return self.new(priority, weight, port, target) + end + end + end + end + end + + ## + # A Resolv::DNS IPv4 address. + + class IPv4 + + ## + # Regular expression IPv4 addresses must match. + + Regex256 = /0 + |1(?:[0-9][0-9]?)? + |2(?:[0-4][0-9]?|5[0-5]?|[6-9])? + |[3-9][0-9]?/x + Regex = /\A(#{Regex256})\.(#{Regex256})\.(#{Regex256})\.(#{Regex256})\z/ + + def self.create(arg) + case arg + when IPv4 + return arg + when Regex + if (0..255) === (a = $1.to_i) && + (0..255) === (b = $2.to_i) && + (0..255) === (c = $3.to_i) && + (0..255) === (d = $4.to_i) + return self.new([a, b, c, d].pack("CCCC")) + else + raise ArgumentError.new("IPv4 address with invalid value: " + arg) + end + else + raise ArgumentError.new("cannot interpret as IPv4 address: #{arg.inspect}") + end + end + + def initialize(address) # :nodoc: + unless address.kind_of?(String) + raise ArgumentError, 'IPv4 address must be a string' + end + unless address.length == 4 + raise ArgumentError, "IPv4 address expects 4 bytes but #{address.length} bytes" + end + @address = address + end + + ## + # A String representation of this IPv4 address. + + ## + # The raw IPv4 address as a String. + + attr_reader :address + + def to_s # :nodoc: + return sprintf("%d.%d.%d.%d", *@address.unpack("CCCC")) + end + + def inspect # :nodoc: + return "#<#{self.class} #{self}>" + end + + ## + # Turns this IPv4 address into a Resolv::DNS::Name. + + def to_name + return DNS::Name.create( + '%d.%d.%d.%d.in-addr.arpa.' % @address.unpack('CCCC').reverse) + end + + def ==(other) # :nodoc: + return @address == other.address + end + + def eql?(other) # :nodoc: + return self == other + end + + def hash # :nodoc: + return @address.hash + end + end + + ## + # A Resolv::DNS IPv6 address. + + class IPv6 + + ## + # IPv6 address format a:b:c:d:e:f:g:h + Regex_8Hex = /\A + (?:[0-9A-Fa-f]{1,4}:){7} + [0-9A-Fa-f]{1,4} + \z/x + + ## + # Compressed IPv6 address format a::b + + Regex_CompressedHex = /\A + ((?:[0-9A-Fa-f]{1,4}(?::[0-9A-Fa-f]{1,4})*)?) :: + ((?:[0-9A-Fa-f]{1,4}(?::[0-9A-Fa-f]{1,4})*)?) + \z/x + + ## + # IPv4 mapped IPv6 address format a:b:c:d:e:f:w.x.y.z + + Regex_6Hex4Dec = /\A + ((?:[0-9A-Fa-f]{1,4}:){6,6}) + (\d+)\.(\d+)\.(\d+)\.(\d+) + \z/x + + ## + # Compressed IPv4 mapped IPv6 address format a::b:w.x.y.z + + Regex_CompressedHex4Dec = /\A + ((?:[0-9A-Fa-f]{1,4}(?::[0-9A-Fa-f]{1,4})*)?) :: + ((?:[0-9A-Fa-f]{1,4}:)*) + (\d+)\.(\d+)\.(\d+)\.(\d+) + \z/x + + ## + # A composite IPv6 address Regexp. + + Regex = / + (?:#{Regex_8Hex}) | + (?:#{Regex_CompressedHex}) | + (?:#{Regex_6Hex4Dec}) | + (?:#{Regex_CompressedHex4Dec})/x + + ## + # Creates a new IPv6 address from +arg+ which may be: + # + # IPv6:: returns +arg+. + # String:: +arg+ must match one of the IPv6::Regex* constants + + def self.create(arg) + case arg + when IPv6 + return arg + when String + address = ''.b + if Regex_8Hex =~ arg + arg.scan(/[0-9A-Fa-f]+/) {|hex| address << [hex.hex].pack('n')} + elsif Regex_CompressedHex =~ arg + prefix = $1 + suffix = $2 + a1 = ''.b + a2 = ''.b + prefix.scan(/[0-9A-Fa-f]+/) {|hex| a1 << [hex.hex].pack('n')} + suffix.scan(/[0-9A-Fa-f]+/) {|hex| a2 << [hex.hex].pack('n')} + omitlen = 16 - a1.length - a2.length + address << a1 << "\0" * omitlen << a2 + elsif Regex_6Hex4Dec =~ arg + prefix, a, b, c, d = $1, $2.to_i, $3.to_i, $4.to_i, $5.to_i + if (0..255) === a && (0..255) === b && (0..255) === c && (0..255) === d + prefix.scan(/[0-9A-Fa-f]+/) {|hex| address << [hex.hex].pack('n')} + address << [a, b, c, d].pack('CCCC') + else + raise ArgumentError.new("not numeric IPv6 address: " + arg) + end + elsif Regex_CompressedHex4Dec =~ arg + prefix, suffix, a, b, c, d = $1, $2, $3.to_i, $4.to_i, $5.to_i, $6.to_i + if (0..255) === a && (0..255) === b && (0..255) === c && (0..255) === d + a1 = ''.b + a2 = ''.b + prefix.scan(/[0-9A-Fa-f]+/) {|hex| a1 << [hex.hex].pack('n')} + suffix.scan(/[0-9A-Fa-f]+/) {|hex| a2 << [hex.hex].pack('n')} + omitlen = 12 - a1.length - a2.length + address << a1 << "\0" * omitlen << a2 << [a, b, c, d].pack('CCCC') + else + raise ArgumentError.new("not numeric IPv6 address: " + arg) + end + else + raise ArgumentError.new("not numeric IPv6 address: " + arg) + end + return IPv6.new(address) + else + raise ArgumentError.new("cannot interpret as IPv6 address: #{arg.inspect}") + end + end + + def initialize(address) # :nodoc: + unless address.kind_of?(String) && address.length == 16 + raise ArgumentError.new('IPv6 address must be 16 bytes') + end + @address = address + end + + ## + # The raw IPv6 address as a String. + + attr_reader :address + + def to_s # :nodoc: + address = sprintf("%X:%X:%X:%X:%X:%X:%X:%X", *@address.unpack("nnnnnnnn")) + unless address.sub!(/(^|:)0(:0)+(:|$)/, '::') + address.sub!(/(^|:)0(:|$)/, '::') + end + return address + end + + def inspect # :nodoc: + return "#<#{self.class} #{self}>" + end + + ## + # Turns this IPv6 address into a Resolv::DNS::Name. + #-- + # ip6.arpa should be searched too. [RFC3152] + + def to_name + return DNS::Name.new( + @address.unpack("H32")[0].split(//).reverse + ['ip6', 'arpa']) + end + + def ==(other) # :nodoc: + return @address == other.address + end + + def eql?(other) # :nodoc: + return self == other + end + + def hash # :nodoc: + return @address.hash + end + end + + ## + # Resolv::MDNS is a one-shot Multicast DNS (mDNS) resolver. It blindly + # makes queries to the mDNS addresses without understanding anything about + # multicast ports. + # + # Information taken form the following places: + # + # * RFC 6762 + + class MDNS < DNS + + ## + # Default mDNS Port + + Port = 5353 + + ## + # Default IPv4 mDNS address + + AddressV4 = '224.0.0.251' + + ## + # Default IPv6 mDNS address + + AddressV6 = 'ff02::fb' + + ## + # Default mDNS addresses + + Addresses = [ + [AddressV4, Port], + [AddressV6, Port], + ] + + ## + # Creates a new one-shot Multicast DNS (mDNS) resolver. + # + # +config_info+ can be: + # + # nil:: + # Uses the default mDNS addresses + # + # Hash:: + # Must contain :nameserver or :nameserver_port like + # Resolv::DNS#initialize. + + def initialize(config_info=nil) + if config_info then + super({ nameserver_port: Addresses }.merge(config_info)) + else + super(nameserver_port: Addresses) + end + end + + ## + # Iterates over all IP addresses for +name+ retrieved from the mDNS + # resolver, provided name ends with "local". If the name does not end in + # "local" no records will be returned. + # + # +name+ can be a Resolv::DNS::Name or a String. Retrieved addresses will + # be a Resolv::IPv4 or Resolv::IPv6 + + def each_address(name) + name = Resolv::DNS::Name.create(name) + + return unless name.to_a.last.to_s == 'local' + + super(name) + end + + def make_udp_requester # :nodoc: + nameserver_port = @config.nameserver_port + Requester::MDNSOneShot.new(*nameserver_port) + end + + end + + module LOC + + ## + # A Resolv::LOC::Size + + class Size + + Regex = /^(\d+\.*\d*)[m]$/ + + ## + # Creates a new LOC::Size from +arg+ which may be: + # + # LOC::Size:: returns +arg+. + # String:: +arg+ must match the LOC::Size::Regex constant + + def self.create(arg) + case arg + when Size + return arg + when String + scalar = '' + if Regex =~ arg + scalar = [(($1.to_f*(1e2)).to_i.to_s[0].to_i*(2**4)+(($1.to_f*(1e2)).to_i.to_s.length-1))].pack("C") + else + raise ArgumentError.new("not a properly formed Size string: " + arg) + end + return Size.new(scalar) + else + raise ArgumentError.new("cannot interpret as Size: #{arg.inspect}") + end + end + + def initialize(scalar) + @scalar = scalar + end + + ## + # The raw size + + attr_reader :scalar + + def to_s # :nodoc: + s = @scalar.unpack("H2").join.to_s + return ((s[0].to_i)*(10**(s[1].to_i-2))).to_s << "m" + end + + def inspect # :nodoc: + return "#<#{self.class} #{self}>" + end + + def ==(other) # :nodoc: + return @scalar == other.scalar + end + + def eql?(other) # :nodoc: + return self == other + end + + def hash # :nodoc: + return @scalar.hash + end + + end + + ## + # A Resolv::LOC::Coord + + class Coord + + Regex = /^(\d+)\s(\d+)\s(\d+\.\d+)\s([NESW])$/ + + ## + # Creates a new LOC::Coord from +arg+ which may be: + # + # LOC::Coord:: returns +arg+. + # String:: +arg+ must match the LOC::Coord::Regex constant + + def self.create(arg) + case arg + when Coord + return arg + when String + coordinates = '' + if Regex =~ arg && $1.to_f < 180 + m = $~ + hemi = (m[4][/[NE]/]) || (m[4][/[SW]/]) ? 1 : -1 + coordinates = [ ((m[1].to_i*(36e5)) + (m[2].to_i*(6e4)) + + (m[3].to_f*(1e3))) * hemi+(2**31) ].pack("N") + orientation = m[4][/[NS]/] ? 'lat' : 'lon' + else + raise ArgumentError.new("not a properly formed Coord string: " + arg) + end + return Coord.new(coordinates,orientation) + else + raise ArgumentError.new("cannot interpret as Coord: #{arg.inspect}") + end + end + + def initialize(coordinates,orientation) + unless coordinates.kind_of?(String) + raise ArgumentError.new("Coord must be a 32bit unsigned integer in hex format: #{coordinates.inspect}") + end + unless orientation.kind_of?(String) && orientation[/^lon$|^lat$/] + raise ArgumentError.new('Coord expects orientation to be a String argument of "lat" or "lon"') + end + @coordinates = coordinates + @orientation = orientation + end + + ## + # The raw coordinates + + attr_reader :coordinates + + ## The orientation of the hemisphere as 'lat' or 'lon' + + attr_reader :orientation + + def to_s # :nodoc: + c = @coordinates.unpack("N").join.to_i + val = (c - (2**31)).abs + fracsecs = (val % 1e3).to_i.to_s + val = val / 1e3 + secs = (val % 60).to_i.to_s + val = val / 60 + mins = (val % 60).to_i.to_s + degs = (val / 60).to_i.to_s + posi = (c >= 2**31) + case posi + when true + hemi = @orientation[/^lat$/] ? "N" : "E" + else + hemi = @orientation[/^lon$/] ? "W" : "S" + end + return degs << " " << mins << " " << secs << "." << fracsecs << " " << hemi + end + + def inspect # :nodoc: + return "#<#{self.class} #{self}>" + end + + def ==(other) # :nodoc: + return @coordinates == other.coordinates + end + + def eql?(other) # :nodoc: + return self == other + end + + def hash # :nodoc: + return @coordinates.hash + end + + end + + ## + # A Resolv::LOC::Alt + + class Alt + + Regex = /^([+-]*\d+\.*\d*)[m]$/ + + ## + # Creates a new LOC::Alt from +arg+ which may be: + # + # LOC::Alt:: returns +arg+. + # String:: +arg+ must match the LOC::Alt::Regex constant + + def self.create(arg) + case arg + when Alt + return arg + when String + altitude = '' + if Regex =~ arg + altitude = [($1.to_f*(1e2))+(1e7)].pack("N") + else + raise ArgumentError.new("not a properly formed Alt string: " + arg) + end + return Alt.new(altitude) + else + raise ArgumentError.new("cannot interpret as Alt: #{arg.inspect}") + end + end + + def initialize(altitude) + @altitude = altitude + end + + ## + # The raw altitude + + attr_reader :altitude + + def to_s # :nodoc: + a = @altitude.unpack("N").join.to_i + return ((a.to_f/1e2)-1e5).to_s + "m" + end + + def inspect # :nodoc: + return "#<#{self.class} #{self}>" + end + + def ==(other) # :nodoc: + return @altitude == other.altitude + end + + def eql?(other) # :nodoc: + return self == other + end + + def hash # :nodoc: + return @altitude.hash + end + + end + + end + + ## + # Default resolver to use for Resolv class methods. + + DefaultResolver = self.new + + ## + # Replaces the resolvers in the default resolver with +new_resolvers+. This + # allows resolvers to be changed for resolv-replace. + + def DefaultResolver.replace_resolvers new_resolvers + @resolvers = new_resolvers + end + + ## + # Address Regexp to use for matching IP addresses. + + AddressRegex = /(?:#{IPv4::Regex})|(?:#{IPv6::Regex})/ + +end diff --git a/logstash-core/spec/logstash/jruby_version_spec.rb b/logstash-core/spec/logstash/jruby_version_spec.rb new file mode 100644 index 000000000..c8d8d2066 --- /dev/null +++ b/logstash-core/spec/logstash/jruby_version_spec.rb @@ -0,0 +1,15 @@ +require 'spec_helper' + + +describe "JRuby Version" do + it "should break on JRuby version change" do + # This spec will break upon JRuby version change to make sure we + # verify if resolv.rb has been fixed in Jruby so we can get rid of + # lib/logstash/patches/resolv.rb. + # ref: + # https://github.com/logstash-plugins/logstash-filter-dns/issues/51 + # https://github.com/jruby/jruby/pull/5722 + expect(JRUBY_VERSION).to eq("9.2.7.0") + end +end + From 5eb569719c3f96281eda23f37da6e5e3902ef95c Mon Sep 17 00:00:00 2001 From: Dan Hermann Date: Fri, 10 May 2019 16:46:34 -0500 Subject: [PATCH 0128/1126] Include G1 in JVM heap metrics (#10728) (#10784) --- logstash-core/lib/logstash/instrument/periodic_poller/jvm.rb | 3 +++ 1 file changed, 3 insertions(+) diff --git a/logstash-core/lib/logstash/instrument/periodic_poller/jvm.rb b/logstash-core/lib/logstash/instrument/periodic_poller/jvm.rb index ba095b6f1..0c6f59844 100644 --- a/logstash-core/lib/logstash/instrument/periodic_poller/jvm.rb +++ b/logstash-core/lib/logstash/instrument/periodic_poller/jvm.rb @@ -153,12 +153,15 @@ module LogStash module Instrument module PeriodicPoller old = {} old = old.merge!(heap["CMS Old Gen"]) if heap.has_key?("CMS Old Gen") old = old.merge!(heap["PS Old Gen"]) if heap.has_key?("PS Old Gen") + old = old.merge!(heap["G1 Old Gen"]) if heap.has_key?("G1 Old Gen") young = {} young = young.merge!(heap["Par Eden Space"]) if heap.has_key?("Par Eden Space") young = young.merge!(heap["PS Eden Space"]) if heap.has_key?("PS Eden Space") + young = young.merge!(heap["G1 Eden Space"]) if heap.has_key?("G1 Eden Space") survivor = {} survivor = survivor.merge!(heap["Par Survivor Space"]) if heap.has_key?("Par Survivor Space") survivor = survivor.merge!(heap["PS Survivor Space"]) if heap.has_key?("PS Survivor Space") + survivor = survivor.merge!(heap["G1 Survivor Space"]) if heap.has_key?("G1 Survivor Space") { "young" => aggregate_information_for(young), "old" => aggregate_information_for(old), From 7c32f0fcf3aca6aedc892cfb105bb0f1daae9260 Mon Sep 17 00:00:00 2001 From: Dan Hermann Date: Mon, 20 May 2019 18:10:45 -0400 Subject: [PATCH 0129/1126] Expose Metrics API to Java plugins (#10761) (#10802) Expose Metric API to Java plugins and migrate JavaCodecDelegator to new Metric API --- logstash-core/build.gradle | 4 + .../java/co/elastic/logstash/api/Context.java | 8 ++ .../elastic/logstash/api/CounterMetric.java | 32 +++++ .../java/co/elastic/logstash/api/Metric.java | 14 +++ .../logstash/api/NamespacedMetric.java | 73 +++++++++++ .../ir/compiler/JavaCodecDelegator.java | 50 ++++---- .../org/logstash/plugins/ContextImpl.java | 15 ++- .../logstash/plugins/CounterMetricImpl.java | 36 ++++++ .../plugins/NamespacedMetricImpl.java | 107 +++++++++++++++++ .../logstash/plugins/PluginFactoryExt.java | 31 ++--- .../org/logstash/plugins/PluginLookup.java | 50 +++++++- .../org/logstash/plugins/RootMetricImpl.java | 36 ++++++ .../ir/compiler/JavaCodecDelegatorTest.java | 16 ++- .../plugins/CounterMetricImplTest.java | 41 +++++++ .../org/logstash/plugins/MetricTestCase.java | 67 +++++++++++ .../plugins/NamespacedMetricImplTest.java | 113 ++++++++++++++++++ .../org/logstash/plugins/TestContext.java | 6 + .../logstash/plugins/TestPluginFactory.java | 2 +- .../logstash/plugins/filters/UuidTest.java | 6 +- 19 files changed, 647 insertions(+), 60 deletions(-) create mode 100644 logstash-core/src/main/java/co/elastic/logstash/api/CounterMetric.java create mode 100644 logstash-core/src/main/java/co/elastic/logstash/api/Metric.java create mode 100644 logstash-core/src/main/java/co/elastic/logstash/api/NamespacedMetric.java create mode 100644 logstash-core/src/main/java/org/logstash/plugins/CounterMetricImpl.java create mode 100644 logstash-core/src/main/java/org/logstash/plugins/NamespacedMetricImpl.java create mode 100644 logstash-core/src/main/java/org/logstash/plugins/RootMetricImpl.java create mode 100644 logstash-core/src/test/java/org/logstash/plugins/CounterMetricImplTest.java create mode 100644 logstash-core/src/test/java/org/logstash/plugins/MetricTestCase.java create mode 100644 logstash-core/src/test/java/org/logstash/plugins/NamespacedMetricImplTest.java diff --git a/logstash-core/build.gradle b/logstash-core/build.gradle index 307ef48ec..13ddb05ff 100644 --- a/logstash-core/build.gradle +++ b/logstash-core/build.gradle @@ -70,6 +70,8 @@ task javaTests(type: Test) { exclude '/org/logstash/config/ir/CompiledPipelineTest.class' exclude '/org/logstash/config/ir/compiler/OutputDelegatorTest.class' exclude '/org/logstash/config/ir/compiler/JavaCodecDelegatorTest.class' + exclude '/org/logstash/plugins/NamespacedMetricImplTest.class' + exclude '/org/logstash/plugins/CounterMetricImplTest.class' } task rubyTests(type: Test) { @@ -81,6 +83,8 @@ task rubyTests(type: Test) { include '/org/logstash/config/ir/CompiledPipelineTest.class' include '/org/logstash/config/ir/compiler/OutputDelegatorTest.class' include '/org/logstash/config/ir/compiler/JavaCodecDelegatorTest.class' + include '/org/logstash/plugins/NamespacedMetricImplTest.class' + include '/org/logstash/plugins/CounterMetricImplTest.class' } test { diff --git a/logstash-core/src/main/java/co/elastic/logstash/api/Context.java b/logstash-core/src/main/java/co/elastic/logstash/api/Context.java index 607c55589..69cc2225b 100644 --- a/logstash-core/src/main/java/co/elastic/logstash/api/Context.java +++ b/logstash-core/src/main/java/co/elastic/logstash/api/Context.java @@ -15,6 +15,14 @@ public interface Context { */ DeadLetterQueueWriter getDlqWriter(); + /** + * Provides a metric namespace scoped to the given {@code plugin} that metrics can be written to and + * can be nested deeper with further namespaces. + * @param plugin The plugin the metric should be scoped to + * @return A metric scoped to the current plugin + */ + NamespacedMetric getMetric(Plugin plugin); + /** * Provides a {@link Logger} instance to plugins. * @param plugin The plugin for which the logger should be supplied. diff --git a/logstash-core/src/main/java/co/elastic/logstash/api/CounterMetric.java b/logstash-core/src/main/java/co/elastic/logstash/api/CounterMetric.java new file mode 100644 index 000000000..e58949ab7 --- /dev/null +++ b/logstash-core/src/main/java/co/elastic/logstash/api/CounterMetric.java @@ -0,0 +1,32 @@ +package co.elastic.logstash.api; + +/** + * A counter metric that tracks a single counter. + * + * You can retrieve an instance of this class using {@link NamespacedMetric#counter(String)}. + */ +public interface CounterMetric { + /** + * Increments the counter by 1. + */ + void increment(); + + /** + * Increments the counter by {@code delta}. + * + * @param delta amount to increment the counter by + */ + void increment(long delta); + + /** + * Gets the current value of the counter. + * + * @return the counter value + */ + long getValue(); + + /** + * Sets the counter back to 0. + */ + void reset(); +} diff --git a/logstash-core/src/main/java/co/elastic/logstash/api/Metric.java b/logstash-core/src/main/java/co/elastic/logstash/api/Metric.java new file mode 100644 index 000000000..8f96a52eb --- /dev/null +++ b/logstash-core/src/main/java/co/elastic/logstash/api/Metric.java @@ -0,0 +1,14 @@ +package co.elastic.logstash.api; + +/** + * Represents a metric namespace that other namespaces can nested within. + */ +public interface Metric { + /** + * Creates a namespace under the current {@link Metric} and returns it. + * + * @param key namespace to traverse into + * @return the {@code key} namespace under the current Metric + */ + NamespacedMetric namespace(String... key); +} diff --git a/logstash-core/src/main/java/co/elastic/logstash/api/NamespacedMetric.java b/logstash-core/src/main/java/co/elastic/logstash/api/NamespacedMetric.java new file mode 100644 index 000000000..ec487c413 --- /dev/null +++ b/logstash-core/src/main/java/co/elastic/logstash/api/NamespacedMetric.java @@ -0,0 +1,73 @@ +package co.elastic.logstash.api; + +import java.util.function.Supplier; + +/** + * Represents a nested namespace that metrics can be written into and other namespaces + * can be nested within. + */ +public interface NamespacedMetric extends Metric { + /** + * Writes an absolute value to the {@code metric}. + * + * @param metric metric to write value to + * @param value value to write + */ + void gauge(String metric, Object value); + + /** + * Creates a counter with the name {@code metric}. + * + * @param metric name of the counter + * @return an instance tracking a counter metric allowing easy incrementing and resetting + */ + CounterMetric counter(String metric); + + /** + * Increment the {@code metric} metric by 1. + * + * @param metric metric to increment + */ + void increment(String metric); + + /** + * Increment the {@code metric} by {@code delta}. + * + * @param metric metric to increment + * @param delta amount to increment by + */ + void increment(String metric, int delta); + + /** + * Times the {@code callable} and returns its value and increments the + * {@code metric} with the time taken. + * + * @param metric metric to increment + * @param callable callable to time + * @param return type of the {@code callable} + * @return the return value from the {@code callable} + */ + T time(String metric, Supplier callable); + + /** + * Increments the {@code metric} by {@code duration}. + * + * @param metric metric to increment + * @param duration duration to increment by + */ + void reportTime(String metric, long duration); + + /** + * Retrieves each namespace component that makes up this metric. + * + * @return the namespaces this metric is nested within + */ + String[] namespaceName(); + + /** + * Gets Logstash's root metric namespace. + * + * @return the root namespace + */ + Metric root(); +} diff --git a/logstash-core/src/main/java/org/logstash/config/ir/compiler/JavaCodecDelegator.java b/logstash-core/src/main/java/org/logstash/config/ir/compiler/JavaCodecDelegator.java index aff529b89..afa91d538 100644 --- a/logstash-core/src/main/java/org/logstash/config/ir/compiler/JavaCodecDelegator.java +++ b/logstash-core/src/main/java/org/logstash/config/ir/compiler/JavaCodecDelegator.java @@ -1,7 +1,11 @@ package org.logstash.config.ir.compiler; import co.elastic.logstash.api.Codec; +import co.elastic.logstash.api.Context; +import co.elastic.logstash.api.CounterMetric; import co.elastic.logstash.api.Event; +import co.elastic.logstash.api.Metric; +import co.elastic.logstash.api.NamespacedMetric; import co.elastic.logstash.api.PluginConfigSpec; import org.jruby.RubySymbol; import org.jruby.runtime.ThreadContext; @@ -20,45 +24,39 @@ import java.util.function.Consumer; public class JavaCodecDelegator implements Codec { - public static final RubySymbol ENCODE_KEY = RubyUtil.RUBY.newSymbol("encode"); - public static final RubySymbol DECODE_KEY = RubyUtil.RUBY.newSymbol("decode"); - public static final RubySymbol IN_KEY = RubyUtil.RUBY.newSymbol("writes_in"); + public static final String ENCODE_KEY = "encode"; + public static final String DECODE_KEY = "decode"; + public static final String IN_KEY = "writes_in"; private final Codec codec; - protected final AbstractNamespacedMetricExt metricEncode; + protected final CounterMetric encodeMetricIn; - protected final AbstractNamespacedMetricExt metricDecode; + protected final CounterMetric encodeMetricTime; - protected final LongCounter encodeMetricIn; + protected final CounterMetric decodeMetricIn; - protected final LongCounter encodeMetricTime; + protected final CounterMetric decodeMetricOut; - protected final LongCounter decodeMetricIn; - - protected final LongCounter decodeMetricOut; - - protected final LongCounter decodeMetricTime; + protected final CounterMetric decodeMetricTime; - public JavaCodecDelegator(final AbstractNamespacedMetricExt metric, - final Codec codec) { + public JavaCodecDelegator(final Context context, final Codec codec) { this.codec = codec; - final ThreadContext context = RubyUtil.RUBY.getCurrentContext(); - final AbstractNamespacedMetricExt namespacedMetric = - metric.namespace(context, RubyUtil.RUBY.newSymbol(codec.getId())); - synchronized(namespacedMetric.getMetric()) { - metricEncode = namespacedMetric.namespace(context, ENCODE_KEY); - encodeMetricIn = LongCounter.fromRubyBase(metricEncode, IN_KEY); - encodeMetricTime = LongCounter.fromRubyBase(metricEncode, MetricKeys.DURATION_IN_MILLIS_KEY); + final NamespacedMetric metric = context.getMetric(codec); - metricDecode = namespacedMetric.namespace(context, DECODE_KEY); - decodeMetricIn = LongCounter.fromRubyBase(metricDecode, IN_KEY); - decodeMetricOut = LongCounter.fromRubyBase(metricDecode, MetricKeys.OUT_KEY); - decodeMetricTime = LongCounter.fromRubyBase(metricDecode, MetricKeys.DURATION_IN_MILLIS_KEY); + synchronized(metric.root()) { + metric.gauge(MetricKeys.NAME_KEY.asJavaString(), codec.getName()); - namespacedMetric.gauge(context, MetricKeys.NAME_KEY, RubyUtil.RUBY.newString(codec.getName())); + final NamespacedMetric encodeMetric = metric.namespace(ENCODE_KEY); + encodeMetricIn = encodeMetric.counter(IN_KEY); + encodeMetricTime = encodeMetric.counter(MetricKeys.DURATION_IN_MILLIS_KEY.asJavaString()); + + final NamespacedMetric decodeMetric = metric.namespace(DECODE_KEY); + decodeMetricIn = decodeMetric.counter(IN_KEY); + decodeMetricOut = decodeMetric.counter(MetricKeys.OUT_KEY.asJavaString()); + decodeMetricTime = decodeMetric.counter(MetricKeys.DURATION_IN_MILLIS_KEY.asJavaString()); } } diff --git a/logstash-core/src/main/java/org/logstash/plugins/ContextImpl.java b/logstash-core/src/main/java/org/logstash/plugins/ContextImpl.java index a8ff8411e..d2b23290c 100644 --- a/logstash-core/src/main/java/org/logstash/plugins/ContextImpl.java +++ b/logstash-core/src/main/java/org/logstash/plugins/ContextImpl.java @@ -3,6 +3,8 @@ package org.logstash.plugins; import co.elastic.logstash.api.Context; import co.elastic.logstash.api.Event; import co.elastic.logstash.api.EventFactory; +import co.elastic.logstash.api.Metric; +import co.elastic.logstash.api.NamespacedMetric; import co.elastic.logstash.api.Plugin; import org.apache.logging.log4j.LogManager; import org.apache.logging.log4j.Logger; @@ -16,8 +18,14 @@ public class ContextImpl implements Context { private DeadLetterQueueWriter dlqWriter; - public ContextImpl(DeadLetterQueueWriter dlqWriter) { + /** + * This is a reference to the [stats, pipelines, *name*, plugins] metric namespace. + */ + private Metric pluginsScopedMetric; + + public ContextImpl(DeadLetterQueueWriter dlqWriter, Metric metric) { this.dlqWriter = dlqWriter; + this.pluginsScopedMetric = metric; } @Override @@ -25,6 +33,11 @@ public class ContextImpl implements Context { return dlqWriter; } + @Override + public NamespacedMetric getMetric(Plugin plugin) { + return pluginsScopedMetric.namespace(PluginLookup.PluginType.getTypeByPlugin(plugin).metricNamespace(), plugin.getId()); + } + @Override public Logger getLogger(Plugin plugin) { return LogManager.getLogger(plugin.getClass()); diff --git a/logstash-core/src/main/java/org/logstash/plugins/CounterMetricImpl.java b/logstash-core/src/main/java/org/logstash/plugins/CounterMetricImpl.java new file mode 100644 index 000000000..095eb0264 --- /dev/null +++ b/logstash-core/src/main/java/org/logstash/plugins/CounterMetricImpl.java @@ -0,0 +1,36 @@ +package org.logstash.plugins; + +import co.elastic.logstash.api.CounterMetric; +import org.jruby.runtime.ThreadContext; +import org.logstash.instrument.metrics.AbstractNamespacedMetricExt; +import org.logstash.instrument.metrics.counter.LongCounter; + +public class CounterMetricImpl implements CounterMetric { + private LongCounter longCounter; + + public CounterMetricImpl(final ThreadContext threadContext, + final AbstractNamespacedMetricExt metrics, + final String metric) { + this.longCounter = LongCounter.fromRubyBase(metrics, threadContext.getRuntime().newSymbol(metric)); + } + + @Override + public void increment() { + this.longCounter.increment(); + } + + @Override + public void increment(final long delta) { + this.longCounter.increment(delta); + } + + @Override + public long getValue() { + return this.longCounter.getValue(); + } + + @Override + public void reset() { + this.longCounter.reset(); + } +} diff --git a/logstash-core/src/main/java/org/logstash/plugins/NamespacedMetricImpl.java b/logstash-core/src/main/java/org/logstash/plugins/NamespacedMetricImpl.java new file mode 100644 index 000000000..912412b8a --- /dev/null +++ b/logstash-core/src/main/java/org/logstash/plugins/NamespacedMetricImpl.java @@ -0,0 +1,107 @@ +package org.logstash.plugins; + +import co.elastic.logstash.api.CounterMetric; +import co.elastic.logstash.api.Metric; +import co.elastic.logstash.api.NamespacedMetric; +import org.jruby.RubyArray; +import org.jruby.RubyObject; +import org.jruby.RubySymbol; +import org.jruby.runtime.ThreadContext; +import org.jruby.runtime.builtin.IRubyObject; +import org.logstash.Rubyfier; +import org.logstash.instrument.metrics.AbstractNamespacedMetricExt; + +import java.util.ArrayList; +import java.util.List; +import java.util.concurrent.TimeUnit; +import java.util.function.Supplier; +import java.util.stream.Stream; + +/** + * Wraps a {@link AbstractNamespacedMetricExt} that represents a nested namespace and adds + * metrics and other namespaces to it. + */ +public class NamespacedMetricImpl implements NamespacedMetric { + private final ThreadContext threadContext; + private final AbstractNamespacedMetricExt metrics; + + public NamespacedMetricImpl(final ThreadContext threadContext, final AbstractNamespacedMetricExt metrics) { + this.threadContext = threadContext; + this.metrics = metrics; + } + + @Override + public void gauge(final String key, final Object value) { + this.metrics.gauge(this.threadContext, this.getSymbol(key), Rubyfier.deep(this.threadContext.getRuntime(), value)); + } + + @Override + public CounterMetric counter(final String metric) { + return new CounterMetricImpl(this.threadContext, this.metrics, metric); + } + + @Override + public NamespacedMetric namespace(final String... key) { + final IRubyObject[] rubyfiedKeys = Stream.of(key) + .map(this::getSymbol) + .toArray(IRubyObject[]::new); + + return new NamespacedMetricImpl( + this.threadContext, + this.metrics.namespace(this.threadContext, RubyArray.newArray(this.threadContext.getRuntime(), rubyfiedKeys)) + ); + } + + @Override + public void increment(final String key) { + this.metrics.increment(this.threadContext, new IRubyObject[] { this.getSymbol(key) }); + } + + @Override + public void increment(final String key, final int amount) { + this.metrics.increment(this.threadContext, new IRubyObject[] { + this.getSymbol(key), + this.convert(amount) + }); + } + + @Override + public T time(final String key, final Supplier callable) { + final long start = System.nanoTime(); + final T ret = callable.get(); + final long end = System.nanoTime(); + this.reportTime(key, TimeUnit.NANOSECONDS.toMillis(end - start)); + return ret; + } + + @Override + public void reportTime(final String key, final long duration) { + this.metrics.reportTime(this.threadContext, this.getSymbol(key), this.convert(duration)); + } + + @Override + public String[] namespaceName() { + final List names = new ArrayList<>(); + + for (final Object o : this.metrics.namespaceName(this.threadContext)) { + if (o instanceof RubyObject) { + names.add(((RubyObject) o).to_s().toString()); + } + } + + return names.toArray(new String[0]); + } + + @Override + public Metric root() { + return new RootMetricImpl(this.threadContext, this.metrics.root(this.threadContext)); + } + + private RubySymbol getSymbol(final String s) { + return this.threadContext.getRuntime().newSymbol(s); + } + + private IRubyObject convert(final Object o) { + return Rubyfier.deep(this.threadContext.getRuntime(), o); + } +} diff --git a/logstash-core/src/main/java/org/logstash/plugins/PluginFactoryExt.java b/logstash-core/src/main/java/org/logstash/plugins/PluginFactoryExt.java index db71fde14..c2f6c1756 100644 --- a/logstash-core/src/main/java/org/logstash/plugins/PluginFactoryExt.java +++ b/logstash-core/src/main/java/org/logstash/plugins/PluginFactoryExt.java @@ -274,7 +274,7 @@ public final class PluginFactoryExt { try { final Constructor ctor = cls.getConstructor(String.class, Configuration.class, Context.class); Configuration config = new ConfigurationImpl(pluginArgs, this); - output = ctor.newInstance(id, config, executionContext.toContext(type)); + output = ctor.newInstance(id, config, executionContext.toContext(type, metrics.getRoot(context))); PluginUtil.validateConfig(output, config); } catch (NoSuchMethodException | IllegalAccessException | InstantiationException | InvocationTargetException ex) { if (ex instanceof InvocationTargetException && ex.getCause() != null) { @@ -296,7 +296,7 @@ public final class PluginFactoryExt { try { final Constructor ctor = cls.getConstructor(String.class, Configuration.class, Context.class); Configuration config = new ConfigurationImpl(pluginArgs); - filter = ctor.newInstance(id, config, executionContext.toContext(type)); + filter = ctor.newInstance(id, config, executionContext.toContext(type, metrics.getRoot(context))); PluginUtil.validateConfig(filter, config); } catch (NoSuchMethodException | IllegalAccessException | InstantiationException | InvocationTargetException ex) { if (ex instanceof InvocationTargetException && ex.getCause() != null) { @@ -318,7 +318,7 @@ public final class PluginFactoryExt { try { final Constructor ctor = cls.getConstructor(String.class, Configuration.class, Context.class); Configuration config = new ConfigurationImpl(pluginArgs, this); - input = ctor.newInstance(id, config, executionContext.toContext(type)); + input = ctor.newInstance(id, config, executionContext.toContext(type, metrics.getRoot(context))); PluginUtil.validateConfig(input, config); } catch (NoSuchMethodException | IllegalAccessException | InstantiationException | InvocationTargetException ex) { if (ex instanceof InvocationTargetException && ex.getCause() != null) { @@ -335,13 +335,14 @@ public final class PluginFactoryExt { } } else if (type == PluginLookup.PluginType.CODEC) { final Class cls = (Class) pluginClass.klass(); - Codec codec = null; if (cls != null) { try { final Constructor ctor = cls.getConstructor(Configuration.class, Context.class); Configuration config = new ConfigurationImpl(pluginArgs); - codec = ctor.newInstance(config, executionContext.toContext(type)); + final Context pluginContext = executionContext.toContext(type, metrics.getRoot(context)); + final Codec codec = ctor.newInstance(config, pluginContext); PluginUtil.validateConfig(codec, config); + return JavaUtil.convertJavaToRuby(RubyUtil.RUBY, new JavaCodecDelegator(pluginContext, codec)); } catch (NoSuchMethodException | IllegalAccessException | InstantiationException | InvocationTargetException ex) { if (ex instanceof InvocationTargetException && ex.getCause() != null) { throw new IllegalStateException((ex).getCause()); @@ -350,11 +351,7 @@ public final class PluginFactoryExt { } } - if (codec != null) { - return JavaUtil.convertJavaToRuby(RubyUtil.RUBY, new JavaCodecDelegator(typeScopedMetric, codec)); - } else { - throw new IllegalStateException("Unable to instantiate codec: " + pluginClass); - } + throw new IllegalStateException("Unable to instantiate codec: " + pluginClass); } else { throw new IllegalStateException("Unable to create plugin: " + pluginClass.toReadableString()); @@ -397,7 +394,7 @@ public final class PluginFactoryExt { ); } - public Context toContext(PluginLookup.PluginType pluginType) { + public Context toContext(PluginLookup.PluginType pluginType, AbstractNamespacedMetricExt metric) { DeadLetterQueueWriter dlq = null; if (pluginType == PluginLookup.PluginType.OUTPUT) { if (dlqWriter instanceof AbstractDeadLetterQueueWriterExt.PluginDeadLetterQueueWriterExt) { @@ -413,7 +410,7 @@ public final class PluginFactoryExt { } } - return new ContextImpl(dlq); + return new ContextImpl(dlq, new NamespacedMetricImpl(RubyUtil.RUBY.getCurrentContext(), metric)); } } @@ -444,8 +441,7 @@ public final class PluginFactoryExt { return this; } - @JRubyMethod - public AbstractNamespacedMetricExt create(final ThreadContext context, final IRubyObject pluginType) { + AbstractNamespacedMetricExt getRoot(final ThreadContext context) { return metric.namespace( context, RubyArray.newArray( @@ -454,7 +450,12 @@ public final class PluginFactoryExt { MetricKeys.STATS_KEY, MetricKeys.PIPELINES_KEY, pipelineId, PLUGINS ) ) - ).namespace( + ); + } + + @JRubyMethod + public AbstractNamespacedMetricExt create(final ThreadContext context, final IRubyObject pluginType) { + return getRoot(context).namespace( context, RubyUtil.RUBY.newSymbol(String.format("%ss", pluginType.asJavaString())) ); } diff --git a/logstash-core/src/main/java/org/logstash/plugins/PluginLookup.java b/logstash-core/src/main/java/org/logstash/plugins/PluginLookup.java index 73137bbc2..eaaba0fce 100644 --- a/logstash-core/src/main/java/org/logstash/plugins/PluginLookup.java +++ b/logstash-core/src/main/java/org/logstash/plugins/PluginLookup.java @@ -1,5 +1,10 @@ package org.logstash.plugins; +import co.elastic.logstash.api.Codec; +import co.elastic.logstash.api.Filter; +import co.elastic.logstash.api.Input; +import co.elastic.logstash.api.Output; +import co.elastic.logstash.api.Plugin; import org.jruby.RubyClass; import org.jruby.RubyString; import org.jruby.java.proxies.JavaProxy; @@ -8,6 +13,9 @@ import org.jruby.runtime.builtin.IRubyObject; import org.logstash.RubyUtil; import org.logstash.plugins.discovery.PluginRegistry; +import java.util.stream.Collectors; +import java.util.stream.Stream; + /** * Java Implementation of the plugin that is implemented by wrapping the Ruby * {@code LogStash::Plugin} class for the Ruby plugin lookup. @@ -93,16 +101,48 @@ public final class PluginLookup { } public enum PluginType { - INPUT("input"), FILTER("filter"), OUTPUT("output"), CODEC("codec"); + INPUT("input", "inputs", Input.class), + FILTER("filter", "filters", Filter.class), + OUTPUT("output", "outputs", Output.class), + CODEC("codec", "codecs", Codec.class); - private final RubyString label; + private final RubyString rubyLabel; + private final String metricNamespace; + private final Class pluginClass; - PluginType(final String label) { - this.label = RubyUtil.RUBY.newString(label); + PluginType(final String label, final String metricNamespace, final Class pluginClass) { + this.rubyLabel = RubyUtil.RUBY.newString(label); + this.metricNamespace = metricNamespace; + this.pluginClass = pluginClass; } public RubyString rubyLabel() { - return label; + return rubyLabel; + } + + public String metricNamespace() { + return metricNamespace; + } + + public Class pluginClass() { + return pluginClass; + } + + public static PluginType getTypeByPlugin(Plugin plugin) { + for (final PluginType type : PluginType.values()) { + if (type.pluginClass().isInstance(plugin)) { + return type; + } + } + + final String allowedPluginTypes = Stream.of(PluginType.values()) + .map((t) -> t.pluginClass().getName()).collect(Collectors.joining(", ")); + + throw new IllegalArgumentException(String.format( + "Plugin [%s] does not extend one of: %s", + plugin.getName(), + allowedPluginTypes + )); } } } diff --git a/logstash-core/src/main/java/org/logstash/plugins/RootMetricImpl.java b/logstash-core/src/main/java/org/logstash/plugins/RootMetricImpl.java new file mode 100644 index 000000000..da7b4271f --- /dev/null +++ b/logstash-core/src/main/java/org/logstash/plugins/RootMetricImpl.java @@ -0,0 +1,36 @@ +package org.logstash.plugins; + +import co.elastic.logstash.api.Metric; +import co.elastic.logstash.api.NamespacedMetric; +import org.jruby.RubyArray; +import org.jruby.runtime.ThreadContext; +import org.jruby.runtime.builtin.IRubyObject; +import org.logstash.instrument.metrics.AbstractMetricExt; + +import java.util.stream.Stream; + +/** + * Wraps a {@link AbstractMetricExt} and represents a "root metric" that must be + * namespaced in order to write metrics to. + */ +public class RootMetricImpl implements Metric { + private final ThreadContext threadContext; + private final AbstractMetricExt metrics; + + public RootMetricImpl(final ThreadContext threadContext, final AbstractMetricExt root) { + this.threadContext = threadContext; + this.metrics = root; + } + + @Override + public NamespacedMetric namespace(final String... key) { + final IRubyObject[] rubyfiedKeys = Stream.of(key) + .map(this.threadContext.getRuntime()::newSymbol) + .toArray(IRubyObject[]::new); + + return new NamespacedMetricImpl( + this.threadContext, + this.metrics.namespace(this.threadContext, RubyArray.newArray(this.threadContext.getRuntime(), rubyfiedKeys)) + ); + } +} diff --git a/logstash-core/src/test/java/org/logstash/config/ir/compiler/JavaCodecDelegatorTest.java b/logstash-core/src/test/java/org/logstash/config/ir/compiler/JavaCodecDelegatorTest.java index 57ff1c7aa..7da86c699 100644 --- a/logstash-core/src/test/java/org/logstash/config/ir/compiler/JavaCodecDelegatorTest.java +++ b/logstash-core/src/test/java/org/logstash/config/ir/compiler/JavaCodecDelegatorTest.java @@ -2,11 +2,14 @@ package org.logstash.config.ir.compiler; import co.elastic.logstash.api.Codec; import co.elastic.logstash.api.Event; +import co.elastic.logstash.api.Metric; import co.elastic.logstash.api.PluginConfigSpec; import com.google.common.collect.ImmutableMap; import org.jruby.RubyHash; import org.junit.Before; import org.junit.Test; +import org.logstash.plugins.ContextImpl; +import org.logstash.plugins.MetricTestCase; import org.mockito.Mockito; import java.io.ByteArrayOutputStream; @@ -19,7 +22,7 @@ import java.util.function.Consumer; import static org.junit.Assert.assertEquals; -public class JavaCodecDelegatorTest extends PluginDelegatorTestCase { +public class JavaCodecDelegatorTest extends MetricTestCase { private Codec codec; @Before @@ -31,11 +34,6 @@ public class JavaCodecDelegatorTest extends PluginDelegatorTestCase { super.setup(); } - @Override - protected String getBaseMetricsPath() { - return "codec/foo"; - } - @Test public void plainCodecDelegatorInitializesCleanly() { constructCodecDelegator(); @@ -44,7 +42,7 @@ public class JavaCodecDelegatorTest extends PluginDelegatorTestCase { @Test public void plainCodecPluginPushesPluginNameToMetric() { constructCodecDelegator(); - final RubyHash metricStore = getMetricStore(new String[]{"codec", "foo"}); + final RubyHash metricStore = getMetricStore(new String[]{"codecs", "foo"}); final String pluginName = getMetricStringValue(metricStore, "name"); assertEquals(codec.getName(), pluginName); @@ -192,7 +190,7 @@ public class JavaCodecDelegatorTest extends PluginDelegatorTestCase { } private RubyHash getMetricStore(final String type) { - return getMetricStore(new String[]{"codec", "foo", type}); + return getMetricStore(new String[]{"codecs", "foo", type}); } private long getMetricLongValue(final String type, final String symbolName) { @@ -200,7 +198,7 @@ public class JavaCodecDelegatorTest extends PluginDelegatorTestCase { } private JavaCodecDelegator constructCodecDelegator() { - return new JavaCodecDelegator(metric, codec); + return new JavaCodecDelegator(new ContextImpl(null, this.getInstance()), codec); } private abstract class AbstractCodec implements Codec { diff --git a/logstash-core/src/test/java/org/logstash/plugins/CounterMetricImplTest.java b/logstash-core/src/test/java/org/logstash/plugins/CounterMetricImplTest.java new file mode 100644 index 000000000..8f698c679 --- /dev/null +++ b/logstash-core/src/test/java/org/logstash/plugins/CounterMetricImplTest.java @@ -0,0 +1,41 @@ +package org.logstash.plugins; + +import co.elastic.logstash.api.CounterMetric; +import co.elastic.logstash.api.NamespacedMetric; +import org.junit.Test; + +import static org.assertj.core.api.Assertions.assertThat; + +public class CounterMetricImplTest extends MetricTestCase { + @Test + public void testIncrement() { + final NamespacedMetric namespace = this.getInstance().namespace("ayo"); + final CounterMetric metric = namespace.counter("abcdef"); + metric.increment(); + assertThat(metric.getValue()).isEqualTo(1); + assertThat(getMetricLongValue(getMetricStore(new String[]{"ayo"}), "abcdef")).isEqualTo(1); + } + + @Test + public void testIncrementByAmount() { + final NamespacedMetric namespace = this.getInstance().namespace("ayo"); + final CounterMetric metric = namespace.counter("abcdef"); + metric.increment(5); + assertThat(metric.getValue()).isEqualTo(5); + assertThat(getMetricLongValue(getMetricStore(new String[]{"ayo"}), "abcdef")).isEqualTo(5); + } + + @Test + public void testReset() { + final NamespacedMetric namespace = this.getInstance().namespace("ayo"); + final CounterMetric metric = namespace.counter("abcdef"); + + metric.increment(1); + assertThat(metric.getValue()).isEqualTo(1); + assertThat(getMetricLongValue(getMetricStore(new String[]{"ayo"}), "abcdef")).isEqualTo(1); + + metric.reset(); + assertThat(metric.getValue()).isEqualTo(0); + assertThat(getMetricLongValue(getMetricStore(new String[]{"ayo"}), "abcdef")).isEqualTo(0); + } +} diff --git a/logstash-core/src/test/java/org/logstash/plugins/MetricTestCase.java b/logstash-core/src/test/java/org/logstash/plugins/MetricTestCase.java new file mode 100644 index 000000000..1fc79b73e --- /dev/null +++ b/logstash-core/src/test/java/org/logstash/plugins/MetricTestCase.java @@ -0,0 +1,67 @@ +package org.logstash.plugins; + +import co.elastic.logstash.api.Metric; +import com.google.common.base.Joiner; +import org.jruby.RubyFixnum; +import org.jruby.RubyHash; +import org.jruby.RubyString; +import org.jruby.java.proxies.ConcreteJavaProxy; +import org.jruby.runtime.builtin.IRubyObject; +import org.junit.Before; +import org.logstash.RubyUtil; +import org.logstash.config.ir.RubyEnvTestCase; +import org.logstash.execution.ExecutionContextExt; +import org.logstash.instrument.metrics.AbstractNamespacedMetricExt; +import org.logstash.instrument.metrics.NamespacedMetricExt; + +import static org.logstash.RubyUtil.*; + +public abstract class MetricTestCase extends RubyEnvTestCase { + protected AbstractNamespacedMetricExt metric; + protected ExecutionContextExt executionContext; + + @Before + public void setup() { + final IRubyObject metricWithCollector = + runRubyScript("require \"logstash/instrument/collector\"\n" + + "metricWithCollector = LogStash::Instrument::Metric.new(LogStash::Instrument::Collector.new)"); + + metric = new NamespacedMetricExt(RUBY, NAMESPACED_METRIC_CLASS) + .initialize(RUBY.getCurrentContext(), metricWithCollector, RUBY.newEmptyArray()); + executionContext = new ExecutionContextExt(RUBY, EXECUTION_CONTEXT_CLASS); + } + + protected static IRubyObject runRubyScript(String script) { + IRubyObject m = RUBY.evalScriptlet(script); + return m; + } + + protected RubyHash getMetricStore(String[] path) { + RubyHash metricStore = (RubyHash) metric.collector(RUBY.getCurrentContext()) + .callMethod(RUBY.getCurrentContext(), "snapshot_metric") + .callMethod(RUBY.getCurrentContext(), "metric_store") + .callMethod(RUBY.getCurrentContext(), "get_with_path", RUBY.newString(Joiner.on("/").join(path))); + + RubyHash rh = metricStore; + for (String p : path) { + rh = (RubyHash) rh.op_aref(RUBY.getCurrentContext(), RUBY.newSymbol(p)); + } + return rh; + } + + protected String getMetricStringValue(RubyHash metricStore, String symbolName) { + ConcreteJavaProxy counter = (ConcreteJavaProxy) metricStore.op_aref(RUBY.getCurrentContext(), RUBY.newSymbol(symbolName)); + RubyString value = (RubyString) counter.callMethod("value"); + return value.asJavaString(); + } + + protected long getMetricLongValue(RubyHash metricStore, String symbolName) { + ConcreteJavaProxy counter = (ConcreteJavaProxy) metricStore.op_aref(RUBY.getCurrentContext(), RUBY.newSymbol(symbolName)); + RubyFixnum count = (RubyFixnum) counter.callMethod("value"); + return count.getLongValue(); + } + + protected Metric getInstance() { + return new RootMetricImpl(RubyUtil.RUBY.getCurrentContext(), this.metric); + } +} diff --git a/logstash-core/src/test/java/org/logstash/plugins/NamespacedMetricImplTest.java b/logstash-core/src/test/java/org/logstash/plugins/NamespacedMetricImplTest.java new file mode 100644 index 000000000..c1b71b025 --- /dev/null +++ b/logstash-core/src/test/java/org/logstash/plugins/NamespacedMetricImplTest.java @@ -0,0 +1,113 @@ +package org.logstash.plugins; + +import co.elastic.logstash.api.Metric; +import co.elastic.logstash.api.NamespacedMetric; +import org.assertj.core.data.Percentage; +import org.jruby.RubyHash; +import org.junit.Test; + +import static org.assertj.core.api.Assertions.assertThat; + +public class NamespacedMetricImplTest extends MetricTestCase { + @Test + public void testGauge() { + final NamespacedMetric metrics = this.getInstance().namespace("test"); + + metrics.gauge("abc", "def"); + { + final RubyHash metricStore = getMetricStore(new String[]{"test"}); + assertThat(this.getMetricStringValue(metricStore, "abc")).isEqualTo("def"); + } + + metrics.gauge("abc", "123"); + { + final RubyHash metricStore = getMetricStore(new String[]{"test"}); + assertThat(this.getMetricStringValue(metricStore, "abc")).isEqualTo("123"); + } + } + + @Test + public void testIncrement() { + final NamespacedMetric metrics = this.getInstance().namespace("test"); + + metrics.increment("abc"); + { + final RubyHash metricStore = getMetricStore(new String[]{"test"}); + assertThat(this.getMetricLongValue(metricStore, "abc")).isEqualTo(1); + } + + metrics.increment("abc"); + { + final RubyHash metricStore = getMetricStore(new String[]{"test"}); + assertThat(this.getMetricLongValue(metricStore, "abc")).isEqualTo(2); + } + } + + @Test + public void testIncrementWithAmount() { + final NamespacedMetric metrics = this.getInstance().namespace("test"); + + metrics.increment("abc", 2); + { + final RubyHash metricStore = getMetricStore(new String[]{"test"}); + assertThat(this.getMetricLongValue(metricStore, "abc")).isEqualTo(2); + } + + metrics.increment("abc", 3); + { + final RubyHash metricStore = getMetricStore(new String[]{"test"}); + assertThat(this.getMetricLongValue(metricStore, "abc")).isEqualTo(5); + } + } + + @Test + public void testTimeCallable() { + final NamespacedMetric metrics = this.getInstance().namespace("test"); + metrics.time("abc", () -> { + try { + Thread.sleep(100); + } catch (InterruptedException e) { + throw new RuntimeException(e); + } + return null; + }); + final RubyHash metricStore = getMetricStore(new String[]{"test"}); + assertThat(this.getMetricLongValue(metricStore, "abc")).isCloseTo(100, Percentage.withPercentage(5)); + } + + @Test + public void testReportTime() { + final NamespacedMetric metrics = this.getInstance().namespace("test"); + + metrics.reportTime("abc", 123); + { + final RubyHash metricStore = getMetricStore(new String[]{"test"}); + assertThat(this.getMetricLongValue(metricStore, "abc")).isEqualTo(123); + } + + metrics.reportTime("abc", 877); + { + final RubyHash metricStore = getMetricStore(new String[]{"test"}); + assertThat(this.getMetricLongValue(metricStore, "abc")).isEqualTo(1000); + } + } + + @Test + public void testNamespace() { + final NamespacedMetric metrics = this.getInstance().namespace("test"); + + final NamespacedMetric namespaced = metrics.namespace("abcdef"); + assertThat(namespaced.namespaceName()).containsExactly("test", "abcdef"); + + final NamespacedMetric namespaced2 = namespaced.namespace("12345", "qwerty"); + assertThat(namespaced2.namespaceName()).containsExactly("test", "abcdef", "12345", "qwerty"); + } + + @Test + public void testRoot() { + final NamespacedMetric metrics = this.getInstance().namespace("test"); + final Metric root = metrics.root(); + final NamespacedMetric namespaced = root.namespace("someothernamespace"); + assertThat(namespaced.namespaceName()).containsExactly("someothernamespace"); + } +} diff --git a/logstash-core/src/test/java/org/logstash/plugins/TestContext.java b/logstash-core/src/test/java/org/logstash/plugins/TestContext.java index 82c1796de..2e8c05c76 100644 --- a/logstash-core/src/test/java/org/logstash/plugins/TestContext.java +++ b/logstash-core/src/test/java/org/logstash/plugins/TestContext.java @@ -2,6 +2,7 @@ package org.logstash.plugins; import co.elastic.logstash.api.Context; import co.elastic.logstash.api.EventFactory; +import co.elastic.logstash.api.NamespacedMetric; import co.elastic.logstash.api.Plugin; import org.apache.logging.log4j.Logger; import org.logstash.common.io.DeadLetterQueueWriter; @@ -13,6 +14,11 @@ public class TestContext implements Context { return null; } + @Override + public NamespacedMetric getMetric(final Plugin plugin) { + return null; + } + @Override public Logger getLogger(Plugin plugin) { return null; diff --git a/logstash-core/src/test/java/org/logstash/plugins/TestPluginFactory.java b/logstash-core/src/test/java/org/logstash/plugins/TestPluginFactory.java index 2eb8ed9b9..0c78ac865 100644 --- a/logstash-core/src/test/java/org/logstash/plugins/TestPluginFactory.java +++ b/logstash-core/src/test/java/org/logstash/plugins/TestPluginFactory.java @@ -36,6 +36,6 @@ public class TestPluginFactory implements RubyIntegration.PluginFactory { @Override public Codec buildDefaultCodec(String codecName) { - return new Line(new ConfigurationImpl(Collections.emptyMap()), new ContextImpl(null)); + return new Line(new ConfigurationImpl(Collections.emptyMap()), new ContextImpl(null, null)); } } diff --git a/logstash-core/src/test/java/org/logstash/plugins/filters/UuidTest.java b/logstash-core/src/test/java/org/logstash/plugins/filters/UuidTest.java index d2982a433..d038daafc 100644 --- a/logstash-core/src/test/java/org/logstash/plugins/filters/UuidTest.java +++ b/logstash-core/src/test/java/org/logstash/plugins/filters/UuidTest.java @@ -23,7 +23,7 @@ public class UuidTest { public void testUuidWithoutRequiredConfigThrows() { try { Configuration config = new ConfigurationImpl(Collections.emptyMap()); - Uuid uuid = new Uuid(ID, config, new ContextImpl(null)); + Uuid uuid = new Uuid(ID, config, new ContextImpl(null, null)); PluginUtil.validateConfig(uuid, config); Assert.fail("java-uuid filter without required config should have thrown exception"); } catch (IllegalStateException ex) { @@ -40,7 +40,7 @@ public class UuidTest { Map rawConfig = new HashMap<>(); rawConfig.put(Uuid.TARGET_CONFIG.name(), targetField); Configuration config = new ConfigurationImpl(rawConfig); - Uuid uuid = new Uuid(ID, config, new ContextImpl(null)); + Uuid uuid = new Uuid(ID, config, new ContextImpl(null, null)); PluginUtil.validateConfig(uuid, config); org.logstash.Event e = new org.logstash.Event(); @@ -61,7 +61,7 @@ public class UuidTest { rawConfig.put(Uuid.TARGET_CONFIG.name(), targetField); rawConfig.put(Uuid.OVERWRITE_CONFIG.name(), true); Configuration config = new ConfigurationImpl(rawConfig); - Uuid uuid = new Uuid(ID, config, new ContextImpl(null)); + Uuid uuid = new Uuid(ID, config, new ContextImpl(null, null)); PluginUtil.validateConfig(uuid, config); org.logstash.Event e = new org.logstash.Event(); From 822fef044fac4b2ce639430db4176c4160ec1083 Mon Sep 17 00:00:00 2001 From: Dan Hermann Date: Fri, 17 May 2019 16:18:54 -0500 Subject: [PATCH 0130/1126] Default stack trace size to 50 and make it configurable Fixes #10793 --- docs/static/monitoring-apis.asciidoc | 1 + .../lib/logstash/api/commands/hot_threads_reporter.rb | 4 ++-- logstash-core/lib/logstash/api/modules/node.rb | 3 ++- .../org/logstash/instrument/monitors/HotThreadsMonitor.java | 2 +- 4 files changed, 6 insertions(+), 4 deletions(-) diff --git a/docs/static/monitoring-apis.asciidoc b/docs/static/monitoring-apis.asciidoc index 9209131f9..a8e7ad1ef 100644 --- a/docs/static/monitoring-apis.asciidoc +++ b/docs/static/monitoring-apis.asciidoc @@ -721,6 +721,7 @@ The parameters allowed are: [horizontal] `threads`:: The number of hot threads to return. The default is 10. +`stacktrace_size`:: The depth of the stack trace to report for each thread. The default is 50. `human`:: If true, returns plain text instead of JSON format. The default is false. `ignore_idle_threads`:: If true, does not return idle threads. The default is true. diff --git a/logstash-core/lib/logstash/api/commands/hot_threads_reporter.rb b/logstash-core/lib/logstash/api/commands/hot_threads_reporter.rb index 384280b20..b9b1e06a6 100644 --- a/logstash-core/lib/logstash/api/commands/hot_threads_reporter.rb +++ b/logstash-core/lib/logstash/api/commands/hot_threads_reporter.rb @@ -3,11 +3,11 @@ java_import 'org.logstash.instrument.reports.ThreadsReport' class HotThreadsReport STRING_SEPARATOR_LENGTH = 80.freeze - HOT_THREADS_STACK_TRACES_SIZE_DEFAULT = 10.freeze + HOT_THREADS_STACK_TRACES_SIZE_DEFAULT = 50.freeze def initialize(cmd, options) @cmd = cmd - filter = { :stacktrace_size => options.fetch(:stacktrace_size, HOT_THREADS_STACK_TRACES_SIZE_DEFAULT) } + filter = { 'stacktrace_size' => "#{options.fetch(:stacktrace_size, HOT_THREADS_STACK_TRACES_SIZE_DEFAULT)}" } @thread_dump = ::LogStash::Util::ThreadDump.new(options.merge(:dump => ThreadsReport.generate(filter))) end diff --git a/logstash-core/lib/logstash/api/modules/node.rb b/logstash-core/lib/logstash/api/modules/node.rb index 66a087809..d0553fe01 100644 --- a/logstash-core/lib/logstash/api/modules/node.rb +++ b/logstash-core/lib/logstash/api/modules/node.rb @@ -13,9 +13,10 @@ module LogStash get "/hot_threads" do begin ignore_idle_threads = params["ignore_idle_threads"] || true - options = {:ignore_idle_threads => as_boolean(ignore_idle_threads)} options[:threads] = params["threads"].to_i if params.has_key?("threads") + options[:ordered_by] = params["ordered_by"] if params.has_key?("ordered_by") + options[:stacktrace_size] = params["stacktrace_size"] if params.has_key?("stacktrace_size") as = human? ? :string : :json respond_with(node.hot_threads(options), {:as => as}) diff --git a/logstash-core/src/main/java/org/logstash/instrument/monitors/HotThreadsMonitor.java b/logstash-core/src/main/java/org/logstash/instrument/monitors/HotThreadsMonitor.java index 1134d62e9..3856ce3a6 100644 --- a/logstash-core/src/main/java/org/logstash/instrument/monitors/HotThreadsMonitor.java +++ b/logstash-core/src/main/java/org/logstash/instrument/monitors/HotThreadsMonitor.java @@ -133,7 +133,7 @@ public final class HotThreadsMonitor { throw new IllegalArgumentException("Invalid sort order"); } - Integer threadInfoMaxDepth = 3; + Integer threadInfoMaxDepth = 50; if (options.containsKey(STACKTRACE_SIZE)) { threadInfoMaxDepth = Integer.valueOf(options.get(STACKTRACE_SIZE)); } From c22edf07f63cb7768150d3494c98d2f0a09bbb89 Mon Sep 17 00:00:00 2001 From: Karen Metts Date: Tue, 21 May 2019 12:36:44 -0400 Subject: [PATCH 0131/1126] Add structure for new windows topic Added coming notice Fixes #10809 --- docs/index.asciidoc | 3 +++ docs/static/running-logstash-windows.asciidoc | 3 +++ docs/static/setting-up-logstash.asciidoc | 1 + 3 files changed, 7 insertions(+) create mode 100644 docs/static/running-logstash-windows.asciidoc diff --git a/docs/index.asciidoc b/docs/index.asciidoc index 8f979c708..56f37fd57 100644 --- a/docs/index.asciidoc +++ b/docs/index.asciidoc @@ -82,6 +82,9 @@ include::static/running-logstash.asciidoc[] :edit_url: https://github.com/elastic/logstash/edit/{branch}/docs/static/docker.asciidoc include::static/docker.asciidoc[] +:edit_url: https://github.com/elastic/logstash/edit/{branch}/docs/static/running-logstash-windows.asciidoc +include::static/running-logstash-windows.asciidoc[] + :edit_url: https://github.com/elastic/logstash/edit/{branch}/docs/static/logging.asciidoc include::static/logging.asciidoc[] diff --git a/docs/static/running-logstash-windows.asciidoc b/docs/static/running-logstash-windows.asciidoc new file mode 100644 index 000000000..443d22c0a --- /dev/null +++ b/docs/static/running-logstash-windows.asciidoc @@ -0,0 +1,3 @@ +[[running-logstash-windows]] +=== Running Logstash on Windows +Coming soon! diff --git a/docs/static/setting-up-logstash.asciidoc b/docs/static/setting-up-logstash.asciidoc index b50b7649d..7a0ab5af0 100644 --- a/docs/static/setting-up-logstash.asciidoc +++ b/docs/static/setting-up-logstash.asciidoc @@ -13,6 +13,7 @@ This section includes additional information on how to set up and run Logstash, * <> * <> * <> +* <> * <> * <> From 9a06b204bf4f1c36fdff51f64dad5ac581047a53 Mon Sep 17 00:00:00 2001 From: Dan Hermann Date: Wed, 15 May 2019 10:37:33 -0500 Subject: [PATCH 0132/1126] Provide DLQ writer interface to Java plugins Fixes #10790 --- .../java/co/elastic/logstash/api/Context.java | 1 - .../logstash/api/DeadLetterQueueWriter.java | 12 +++++++ .../org/logstash/common/DLQWriterAdapter.java | 32 ++++++++++++++++++ .../common/NullDeadLetterQueueWriter.java | 33 +++++++++++++++++++ .../org/logstash/plugins/ContextImpl.java | 2 +- .../logstash/plugins/PluginFactoryExt.java | 10 +++--- .../org/logstash/plugins/TestContext.java | 2 +- 7 files changed, 85 insertions(+), 7 deletions(-) create mode 100644 logstash-core/src/main/java/co/elastic/logstash/api/DeadLetterQueueWriter.java create mode 100644 logstash-core/src/main/java/org/logstash/common/DLQWriterAdapter.java create mode 100644 logstash-core/src/main/java/org/logstash/common/NullDeadLetterQueueWriter.java diff --git a/logstash-core/src/main/java/co/elastic/logstash/api/Context.java b/logstash-core/src/main/java/co/elastic/logstash/api/Context.java index 69cc2225b..457903f5f 100644 --- a/logstash-core/src/main/java/co/elastic/logstash/api/Context.java +++ b/logstash-core/src/main/java/co/elastic/logstash/api/Context.java @@ -1,7 +1,6 @@ package co.elastic.logstash.api; import org.apache.logging.log4j.Logger; -import org.logstash.common.io.DeadLetterQueueWriter; /** * Provides Logstash context to plugins. diff --git a/logstash-core/src/main/java/co/elastic/logstash/api/DeadLetterQueueWriter.java b/logstash-core/src/main/java/co/elastic/logstash/api/DeadLetterQueueWriter.java new file mode 100644 index 000000000..81dce1160 --- /dev/null +++ b/logstash-core/src/main/java/co/elastic/logstash/api/DeadLetterQueueWriter.java @@ -0,0 +1,12 @@ +package co.elastic.logstash.api; + +import java.io.IOException; + +public interface DeadLetterQueueWriter { + + void writeEntry(Event event, Plugin plugin, String reason) throws IOException; + + boolean isOpen(); + + long getCurrentQueueSize(); +} diff --git a/logstash-core/src/main/java/org/logstash/common/DLQWriterAdapter.java b/logstash-core/src/main/java/org/logstash/common/DLQWriterAdapter.java new file mode 100644 index 000000000..6f4e93042 --- /dev/null +++ b/logstash-core/src/main/java/org/logstash/common/DLQWriterAdapter.java @@ -0,0 +1,32 @@ +package org.logstash.common; + +import co.elastic.logstash.api.DeadLetterQueueWriter; +import co.elastic.logstash.api.Event; +import co.elastic.logstash.api.Plugin; + +import java.io.IOException; +import java.util.Objects; + +public class DLQWriterAdapter implements DeadLetterQueueWriter { + + private final org.logstash.common.io.DeadLetterQueueWriter dlqWriter; + + public DLQWriterAdapter(org.logstash.common.io.DeadLetterQueueWriter dlqWriter) { + this.dlqWriter = Objects.requireNonNull(dlqWriter); + } + + @Override + public void writeEntry(Event event, Plugin plugin, String reason) throws IOException { + dlqWriter.writeEntry((org.logstash.Event) event, plugin.getName(), plugin.getId(), reason); + } + + @Override + public boolean isOpen() { + return dlqWriter != null && dlqWriter.isOpen(); + } + + @Override + public long getCurrentQueueSize() { + return dlqWriter != null ? dlqWriter.getCurrentQueueSize() : 0; + } +} diff --git a/logstash-core/src/main/java/org/logstash/common/NullDeadLetterQueueWriter.java b/logstash-core/src/main/java/org/logstash/common/NullDeadLetterQueueWriter.java new file mode 100644 index 000000000..339b94175 --- /dev/null +++ b/logstash-core/src/main/java/org/logstash/common/NullDeadLetterQueueWriter.java @@ -0,0 +1,33 @@ +package org.logstash.common; + +import co.elastic.logstash.api.DeadLetterQueueWriter; +import co.elastic.logstash.api.Event; +import co.elastic.logstash.api.Plugin; + +import java.io.IOException; + +public class NullDeadLetterQueueWriter implements DeadLetterQueueWriter { + private static final NullDeadLetterQueueWriter INSTANCE = new NullDeadLetterQueueWriter(); + + private NullDeadLetterQueueWriter() { + } + + public static NullDeadLetterQueueWriter getInstance() { + return INSTANCE; + } + + @Override + public void writeEntry(Event event, Plugin plugin, String reason) throws IOException { + // no-op + } + + @Override + public boolean isOpen() { + return false; + } + + @Override + public long getCurrentQueueSize() { + return 0; + } +} diff --git a/logstash-core/src/main/java/org/logstash/plugins/ContextImpl.java b/logstash-core/src/main/java/org/logstash/plugins/ContextImpl.java index d2b23290c..f795e3930 100644 --- a/logstash-core/src/main/java/org/logstash/plugins/ContextImpl.java +++ b/logstash-core/src/main/java/org/logstash/plugins/ContextImpl.java @@ -1,6 +1,7 @@ package org.logstash.plugins; import co.elastic.logstash.api.Context; +import co.elastic.logstash.api.DeadLetterQueueWriter; import co.elastic.logstash.api.Event; import co.elastic.logstash.api.EventFactory; import co.elastic.logstash.api.Metric; @@ -9,7 +10,6 @@ import co.elastic.logstash.api.Plugin; import org.apache.logging.log4j.LogManager; import org.apache.logging.log4j.Logger; import org.logstash.ConvertedMap; -import org.logstash.common.io.DeadLetterQueueWriter; import java.io.Serializable; import java.util.Map; diff --git a/logstash-core/src/main/java/org/logstash/plugins/PluginFactoryExt.java b/logstash-core/src/main/java/org/logstash/plugins/PluginFactoryExt.java index c2f6c1756..71132da87 100644 --- a/logstash-core/src/main/java/org/logstash/plugins/PluginFactoryExt.java +++ b/logstash-core/src/main/java/org/logstash/plugins/PluginFactoryExt.java @@ -3,6 +3,7 @@ package org.logstash.plugins; import co.elastic.logstash.api.Codec; import co.elastic.logstash.api.Configuration; import co.elastic.logstash.api.Context; +import co.elastic.logstash.api.DeadLetterQueueWriter; import co.elastic.logstash.api.Filter; import co.elastic.logstash.api.Input; import co.elastic.logstash.api.Output; @@ -21,7 +22,8 @@ import org.jruby.runtime.ThreadContext; import org.jruby.runtime.builtin.IRubyObject; import org.logstash.RubyUtil; import org.logstash.common.AbstractDeadLetterQueueWriterExt; -import org.logstash.common.io.DeadLetterQueueWriter; +import org.logstash.common.DLQWriterAdapter; +import org.logstash.common.NullDeadLetterQueueWriter; import org.logstash.config.ir.PipelineIR; import org.logstash.config.ir.compiler.AbstractFilterDelegatorExt; import org.logstash.config.ir.compiler.AbstractOutputDelegatorExt; @@ -395,7 +397,7 @@ public final class PluginFactoryExt { } public Context toContext(PluginLookup.PluginType pluginType, AbstractNamespacedMetricExt metric) { - DeadLetterQueueWriter dlq = null; + DeadLetterQueueWriter dlq = NullDeadLetterQueueWriter.getInstance(); if (pluginType == PluginLookup.PluginType.OUTPUT) { if (dlqWriter instanceof AbstractDeadLetterQueueWriterExt.PluginDeadLetterQueueWriterExt) { IRubyObject innerWriter = @@ -403,8 +405,8 @@ public final class PluginFactoryExt { .innerWriter(RubyUtil.RUBY.getCurrentContext()); if (innerWriter != null) { - if (innerWriter.getJavaClass().equals(DeadLetterQueueWriter.class)) { - dlq = innerWriter.toJava(DeadLetterQueueWriter.class); + if (org.logstash.common.io.DeadLetterQueueWriter.class.isAssignableFrom(innerWriter.getJavaClass())) { + dlq = new DLQWriterAdapter(innerWriter.toJava(org.logstash.common.io.DeadLetterQueueWriter.class)); } } } diff --git a/logstash-core/src/test/java/org/logstash/plugins/TestContext.java b/logstash-core/src/test/java/org/logstash/plugins/TestContext.java index 2e8c05c76..5fa3117c8 100644 --- a/logstash-core/src/test/java/org/logstash/plugins/TestContext.java +++ b/logstash-core/src/test/java/org/logstash/plugins/TestContext.java @@ -1,11 +1,11 @@ package org.logstash.plugins; import co.elastic.logstash.api.Context; +import co.elastic.logstash.api.DeadLetterQueueWriter; import co.elastic.logstash.api.EventFactory; import co.elastic.logstash.api.NamespacedMetric; import co.elastic.logstash.api.Plugin; import org.apache.logging.log4j.Logger; -import org.logstash.common.io.DeadLetterQueueWriter; public class TestContext implements Context { From 2d35566ab2abf1162ac1faff498b5918b758a4d5 Mon Sep 17 00:00:00 2001 From: Dan Hermann Date: Tue, 21 May 2019 07:49:38 -0500 Subject: [PATCH 0133/1126] Document copy semantics of QueueWriter::push method Fixes #10808 --- docs/static/java-codec.asciidoc | 7 ++++++- docs/static/java-input.asciidoc | 10 ++++++---- .../java/org/logstash/execution/queue/QueueWriter.java | 8 +++++--- 3 files changed, 17 insertions(+), 8 deletions(-) diff --git a/docs/static/java-codec.asciidoc b/docs/static/java-codec.asciidoc index a1b4ad144..cfefc424a 100644 --- a/docs/static/java-codec.asciidoc +++ b/docs/static/java-codec.asciidoc @@ -241,7 +241,12 @@ example above, the `decode` method simply splits the incoming byte stream on the specified delimiter. A production-grade codec such as https://github.com/elastic/logstash/blob/master/logstash-core/src/main/java/org/logstash/plugins/codecs/Line.java[`java-line`] would not make the simplifying assumption that the end of the supplied byte -stream corresponded with the end of an event. +stream corresponded with the end of an event. + +Events should be constructed as instances of `Map` and pushed into the event pipeline via the +`Consumer>.accept()` method. To reduce allocations and GC pressure, codecs may reuse the same +map instance by modifying its fields between calls to `Consumer>.accept()` because the event +pipeline will create events based on a copy of the map's data. The `flush` method works in coordination with the `decode` method to decode all remaining events from the specified `ByteBuffer` along with any internal state diff --git a/docs/static/java-input.asciidoc b/docs/static/java-input.asciidoc index 0f99b7ed3..26f01780d 100644 --- a/docs/static/java-input.asciidoc +++ b/docs/static/java-input.asciidoc @@ -189,16 +189,18 @@ public void start(Consumer> consumer) { The `start` method begins the event-producing loop in an input. Inputs are flexible and may produce events through many different mechanisms including: - * a pull mechanism such as periodic queries of external database - * a push mechanism such as events sent from clients to a local network port - * a timed computation such as a heartbeat + * a pull mechanism such as periodic queries of external database + * a push mechanism such as events sent from clients to a local network port + * a timed computation such as a heartbeat * any other mechanism that produces a useful stream of events. Event streams may be either finite or infinite. If the input produces an infinite stream of events, this method should loop until a stop request is made through the `stop` method. If the input produces a finite stream of events, this method should terminate when the last event in the stream is produced or a stop request is made, whichever comes first. Events should be constructed as instances of `Map` and pushed into the event pipeline via the -`Consumer>.accept()` method. +`Consumer>.accept()` method. To reduce allocations and GC pressure, inputs may reuse the same +map instance by modifying its fields between calls to `Consumer>.accept()` because the event +pipeline will create events based on a copy of the map's data. [float] ==== Stop and awaitStop methods diff --git a/logstash-core/src/main/java/org/logstash/execution/queue/QueueWriter.java b/logstash-core/src/main/java/org/logstash/execution/queue/QueueWriter.java index d7c025823..854cb1e49 100644 --- a/logstash-core/src/main/java/org/logstash/execution/queue/QueueWriter.java +++ b/logstash-core/src/main/java/org/logstash/execution/queue/QueueWriter.java @@ -3,14 +3,16 @@ package org.logstash.execution.queue; import java.util.Map; /** - * Writes to the Queue. + * Writes to the queue. */ public interface QueueWriter { /** * Pushes a single event to the Queue, blocking indefinitely if the Queue is not ready for a - * write. - * @param event Logstash Event Data + * write. Implementations of this interface must produce events from a deep copy of the supplied + * map because upstream clients of this interface may reuse map instances between calls to push. + * + * @param event Logstash event data */ void push(Map event); } From 016f7318de700cdc6e57d4bf680e4db2e0095c0a Mon Sep 17 00:00:00 2001 From: Rob Bavey Date: Wed, 22 May 2019 14:29:58 -0400 Subject: [PATCH 0134/1126] Bump version to 7.3.0 (#10815) --- README.md | 16 ++++++++-------- versions.yml | 4 ++-- 2 files changed, 10 insertions(+), 10 deletions(-) diff --git a/README.md b/README.md index bb4b6d0b0..791a5fb60 100644 --- a/README.md +++ b/README.md @@ -28,14 +28,14 @@ These builds are created nightly and have undergone no formal QA, so they should | [deb-complete][] | [deb-oss][] | | [rpm-complete][] | [rpm-oss][] | -[tar-complete]: https://snapshots.elastic.co/downloads/logstash/logstash-7.2.0-SNAPSHOT.tar.gz -[zip-complete]: https://snapshots.elastic.co/downloads/logstash/logstash-7.2.0-SNAPSHOT.zip -[deb-complete]: https://snapshots.elastic.co/downloads/logstash/logstash-7.2.0-SNAPSHOT.deb -[rpm-complete]: https://snapshots.elastic.co/downloads/logstash/logstash-7.2.0-SNAPSHOT.rpm -[tar-oss]: https://snapshots.elastic.co/downloads/logstash/logstash-oss-7.2.0-SNAPSHOT.tar.gz -[zip-oss]: https://snapshots.elastic.co/downloads/logstash/logstash-oss-7.2.0-SNAPSHOT.zip -[deb-oss]: https://snapshots.elastic.co/downloads/logstash/logstash-oss-7.2.0-SNAPSHOT.deb -[rpm-oss]: https://snapshots.elastic.co/downloads/logstash/logstash-oss-7.2.0-SNAPSHOT.rpm +[tar-complete]: https://snapshots.elastic.co/downloads/logstash/logstash-7.3.0-SNAPSHOT.tar.gz +[zip-complete]: https://snapshots.elastic.co/downloads/logstash/logstash-7.3.0-SNAPSHOT.zip +[deb-complete]: https://snapshots.elastic.co/downloads/logstash/logstash-7.3.0-SNAPSHOT.deb +[rpm-complete]: https://snapshots.elastic.co/downloads/logstash/logstash-7.3.0-SNAPSHOT.rpm +[tar-oss]: https://snapshots.elastic.co/downloads/logstash/logstash-oss-7.3.0-SNAPSHOT.tar.gz +[zip-oss]: https://snapshots.elastic.co/downloads/logstash/logstash-oss-7.3.0-SNAPSHOT.zip +[deb-oss]: https://snapshots.elastic.co/downloads/logstash/logstash-oss-7.3.0-SNAPSHOT.deb +[rpm-oss]: https://snapshots.elastic.co/downloads/logstash/logstash-oss-7.3.0-SNAPSHOT.rpm ## Need Help? diff --git a/versions.yml b/versions.yml index e483a567f..2db949025 100644 --- a/versions.yml +++ b/versions.yml @@ -1,7 +1,7 @@ --- # alpha and beta qualifiers are now added via VERSION_QUALIFIER environment var -logstash: 7.2.0 -logstash-core: 7.2.0 +logstash: 7.3.0 +logstash-core: 7.3.0 logstash-core-plugin-api: 2.1.16 # jruby must reference a *released* version of jruby which can be downloaded from the official download url From ce0237b621b795cfdf7ec2f74baecb65298364f9 Mon Sep 17 00:00:00 2001 From: Karen Metts <35154725+karenzone@users.noreply.github.com> Date: Wed, 22 May 2019 16:41:30 -0400 Subject: [PATCH 0135/1126] Update doc versions for 7.x (#10817) --- docs/index.asciidoc | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/docs/index.asciidoc b/docs/index.asciidoc index 56f37fd57..cee564700 100644 --- a/docs/index.asciidoc +++ b/docs/index.asciidoc @@ -8,9 +8,9 @@ :plugins-repo-dir: {docdir}/../../logstash-docs/docs :branch: 7.x :major-version: 7.x -:logstash_version: 7.1.0 -:elasticsearch_version: 7.1.0 -:kibana_version: 7.1.0 +:logstash_version: 7.3.0 +:elasticsearch_version: 7.3.0 +:kibana_version: 7.3.0 :docker-repo: docker.elastic.co/logstash/logstash :docker-image: {docker-repo}:{logstash_version} From 089f369033bd82112864f59b2b34a74af54d7058 Mon Sep 17 00:00:00 2001 From: Joao Duarte Date: Thu, 23 May 2019 14:30:16 +0100 Subject: [PATCH 0136/1126] generate tarballs for docker images Fixes #10819 --- docker/Makefile | 25 +++++++++++++++++++------ docker/templates/Dockerfile.j2 | 2 +- rakelib/artifacts.rake | 19 ++++++++++--------- 3 files changed, 30 insertions(+), 16 deletions(-) diff --git a/docker/Makefile b/docker/Makefile index dd6653b74..673043f8b 100644 --- a/docker/Makefile +++ b/docker/Makefile @@ -20,7 +20,7 @@ HTTPD ?= logstash-docker-artifact-server FIGLET := pyfiglet -w 160 -f puffy -all: build-from-local-artifacts build-from-local-oss-artifacts public-dockerfile +all: build-from-local-artifacts build-from-local-oss-artifacts public-dockerfiles lint: venv flake8 tests @@ -48,9 +48,10 @@ build-from-local-oss-artifacts: venv dockerfile env2yaml (docker kill $(HTTPD); false); -docker kill $(HTTPD) -COPY_FILES = $(ARTIFACTS_DIR)/docker/config/pipelines.yml $(ARTIFACTS_DIR)/docker/config/logstash-full.yml $(ARTIFACTS_DIR)/docker/config/log4j2.properties $(ARTIFACTS_DIR)/docker/pipeline/default.conf $(ARTIFACTS_DIR)/docker/bin/docker-entrypoint $(ARTIFACTS_DIR)/docker/env2yaml/env2yaml +COPY_FILES = $(ARTIFACTS_DIR)/docker/config/pipelines.yml $(ARTIFACTS_DIR)/docker/config/logstash-oss.yml $(ARTIFACTS_DIR)/docker/config/logstash-full.yml $(ARTIFACTS_DIR)/docker/config/log4j2.properties $(ARTIFACTS_DIR)/docker/pipeline/default.conf $(ARTIFACTS_DIR)/docker/bin/docker-entrypoint $(ARTIFACTS_DIR)/docker/env2yaml/env2yaml $(ARTIFACTS_DIR)/docker/config/pipelines.yml: data/logstash/config/pipelines.yml +$(ARTIFACTS_DIR)/docker/config/logstash-oss.yml: data/logstash/config/logstash-oss.yml $(ARTIFACTS_DIR)/docker/config/logstash-full.yml: data/logstash/config/logstash-full.yml $(ARTIFACTS_DIR)/docker/config/log4j2.properties: data/logstash/config/log4j2.properties $(ARTIFACTS_DIR)/docker/pipeline/default.conf: data/logstash/pipeline/default.conf @@ -67,14 +68,26 @@ docker_paths: mkdir -p $(ARTIFACTS_DIR)/docker/env2yaml mkdir -p $(ARTIFACTS_DIR)/docker/pipeline -public-dockerfile: venv templates/Dockerfile.j2 docker_paths $(COPY_FILES) +public-dockerfiles: venv templates/Dockerfile.j2 docker_paths $(COPY_FILES) jinja2 \ -D elastic_version='$(ELASTIC_VERSION)' \ -D version_tag='$(VERSION_TAG)' \ -D image_flavor='full' \ - -D artifacts_dir='$(ARTIFACTS_DIR)' \ + -D local_artifacts='false' \ -D release='$(RELEASE)' \ - templates/Dockerfile.j2 > $(ARTIFACTS_DIR)/docker/Dockerfile + templates/Dockerfile.j2 > $(ARTIFACTS_DIR)/Dockerfile-full && \ + jinja2 \ + -D elastic_version='$(ELASTIC_VERSION)' \ + -D version_tag='$(VERSION_TAG)' \ + -D image_flavor='oss' \ + -D local_artifacts='false' \ + -D release='$(RELEASE)' \ + templates/Dockerfile.j2 > $(ARTIFACTS_DIR)/Dockerfile-oss && \ + cd $(ARTIFACTS_DIR)/docker && \ + cp $(ARTIFACTS_DIR)/Dockerfile-full Dockerfile && \ + tar -zcf ../logstash-$(VERSION_TAG)-docker-build-context.tar.gz Dockerfile bin config env2yaml pipeline && \ + cp $(ARTIFACTS_DIR)/Dockerfile-oss Dockerfile && \ + tar -zcf ../logstash-oss-$(VERSION_TAG)-docker-build-context.tar.gz Dockerfile bin config env2yaml pipeline # Push the image to the dedicated push endpoint at "push.docker.elastic.co" push: @@ -123,7 +136,7 @@ dockerfile: venv templates/Dockerfile.j2 -D elastic_version='$(ELASTIC_VERSION)' \ -D version_tag='$(VERSION_TAG)' \ -D image_flavor='$(FLAVOR)' \ - -D artifacts_dir='$(ARTIFACTS_DIR)' \ + -D local_artifacts='true' \ templates/Dockerfile.j2 > $(ARTIFACTS_DIR)/Dockerfile-$(FLAVOR); \ ) diff --git a/docker/templates/Dockerfile.j2 b/docker/templates/Dockerfile.j2 index 11694d50b..44e782d2e 100644 --- a/docker/templates/Dockerfile.j2 +++ b/docker/templates/Dockerfile.j2 @@ -1,5 +1,5 @@ # This Dockerfile was generated from templates/Dockerfile.j2 -{% if release -%} +{% if local_artifacts == 'false' -%} {% set url_root = 'https://artifacts.elastic.co/downloads/logstash' -%} {% else -%} {% set url_root = 'http://localhost:8000' -%} diff --git a/rakelib/artifacts.rake b/rakelib/artifacts.rake index 9c38cd3df..eb9935ada 100644 --- a/rakelib/artifacts.rake +++ b/rakelib/artifacts.rake @@ -191,10 +191,10 @@ namespace "artifact" do build_docker(true) end - desc "Generate Dockerfile for default image" - task "dockerfile" => ["prepare", "generate_build_metadata"] do - puts("[dockerfile] Building Dockerfile") - build_dockerfile + desc "Generate Dockerfile for default and oss images" + task "dockerfiles" => ["prepare", "generate_build_metadata"] do + puts("[dockerfiles] Building Dockerfiles") + build_dockerfiles end # Auxiliary tasks @@ -208,8 +208,9 @@ namespace "artifact" do Rake::Task["artifact:zip_oss"].invoke Rake::Task["artifact:tar"].invoke Rake::Task["artifact:tar_oss"].invoke - #Rake::Task["artifact:docker"].invoke - #Rake::Task["artifact:docker_oss"].invoke + Rake::Task["artifact:docker"].invoke + Rake::Task["artifact:docker_oss"].invoke + Rake::Task["artifact:dockerfile"].invoke end task "generate_build_metadata" do @@ -551,15 +552,15 @@ namespace "artifact" do end end - def build_dockerfile + def build_dockerfiles env = { "ARTIFACTS_DIR" => ::File.join(Dir.pwd, "build"), "RELEASE" => ENV["RELEASE"], "VERSION_QUALIFIER" => VERSION_QUALIFIER } Dir.chdir("docker") do |dir| - system(env, "make public-dockerfile") - puts "Dockerfile created in #{::File.join(env['ARTIFACTS_DIR'], 'docker')}" + system(env, "make public-dockerfiles") + puts "Dockerfiles created in #{::File.join(env['ARTIFACTS_DIR'], 'docker')}" end end end From d03f0ea4549e2deaa935564d3f82ff68fe90e6a9 Mon Sep 17 00:00:00 2001 From: Joao Duarte Date: Mon, 27 May 2019 12:16:16 +0100 Subject: [PATCH 0137/1126] allow skipping docker artifacts during artifact:all Fixes #10823 --- rakelib/artifacts.rake | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/rakelib/artifacts.rake b/rakelib/artifacts.rake index eb9935ada..cd778c4ff 100644 --- a/rakelib/artifacts.rake +++ b/rakelib/artifacts.rake @@ -208,9 +208,11 @@ namespace "artifact" do Rake::Task["artifact:zip_oss"].invoke Rake::Task["artifact:tar"].invoke Rake::Task["artifact:tar_oss"].invoke - Rake::Task["artifact:docker"].invoke - Rake::Task["artifact:docker_oss"].invoke - Rake::Task["artifact:dockerfile"].invoke + unless ENV['SKIP_DOCKER'] == "1" + Rake::Task["artifact:docker"].invoke + Rake::Task["artifact:docker_oss"].invoke + Rake::Task["artifact:dockerfiles"].invoke + end end task "generate_build_metadata" do From bd11485e0b4df1ecd1b821bf38ae785c514b8427 Mon Sep 17 00:00:00 2001 From: Joao Duarte Date: Mon, 27 May 2019 12:27:31 +0100 Subject: [PATCH 0138/1126] fix plugin doc version generation with default plugins now that default plugins are read only from the json metadata file and not from the lock file, the plugin version manifesto needs to be adapted so the status of "default" plugin is read from the json file. Fixes #10824 --- rakelib/plugins_docs_dependencies.rake | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/rakelib/plugins_docs_dependencies.rake b/rakelib/plugins_docs_dependencies.rake index 03db3ed8c..dda853eb0 100644 --- a/rakelib/plugins_docs_dependencies.rake +++ b/rakelib/plugins_docs_dependencies.rake @@ -1,6 +1,9 @@ # encoding: utf-8 +require 'json' + class PluginVersionWorking EXPORT_FILE = ::File.expand_path(::File.join(::File.dirname(__FILE__), "..", "plugins_version_docs.json")) + PLUGIN_METADATA = JSON.parse(IO.read(::File.expand_path(::File.join(::File.dirname(__FILE__), "plugins-metadata.json")))) # Simple class to make sure we get the right version for the document # since we will record multiple versions for one plugin @@ -87,7 +90,8 @@ class PluginVersionWorking builder.eval_gemfile("bundler file", gemfile.generate()) definition = builder.to_definition(LogStash::Environment::LOCKFILE, {}) definition.resolve_remotely! - extract_versions(definition, successful_dependencies, :missing) + from = PLUGIN_METADATA.fetch(plugin, {}).fetch("default-plugins", false) ? :default : :missing + extract_versions(definition, successful_dependencies, from) puts "Successfully installed: #{plugin}" rescue => e puts "Failed to install: #{plugin}" From 2646be8d20f7f3ce3cb5d80b4db47461dadb3f98 Mon Sep 17 00:00:00 2001 From: Logstash Machine <43502315+logstashmachine@users.noreply.github.com> Date: Tue, 30 Apr 2019 15:34:10 -0700 Subject: [PATCH 0139/1126] Release notes for 7.0.1 (#10705) --- docs/static/releasenotes.asciidoc | 74 +++++++++++++++++++++++++++++++ 1 file changed, 74 insertions(+) diff --git a/docs/static/releasenotes.asciidoc b/docs/static/releasenotes.asciidoc index 684348ea3..dc349560c 100644 --- a/docs/static/releasenotes.asciidoc +++ b/docs/static/releasenotes.asciidoc @@ -3,6 +3,7 @@ This section summarizes the changes in the following releases: +* <> * <> * <> * <> @@ -10,6 +11,79 @@ This section summarizes the changes in the following releases: * <> * <> +[[logstash-7-0-1]] +=== Logstash 7.0.1 Release Notes + +* Fixed default codec and buffer handling in Java stdout output https://github.com/elastic/logstash/pull/10673[#10673] +* Corrected the description of codec behavior in the output stage of Logstash pipelines https://github.com/elastic/logstash/pull/10682[#10682] +* Corrected settings file doc to note that Java execution defaults to true https://github.com/elastic/logstash/pull/10701[#10701] +* Updated JRuby to 9.2.7.0 https://github.com/elastic/logstash/pull/10674[#10674] +* Updated Bundler to 1.17.3 https://github.com/elastic/logstash/pull/10685[#10685] + +==== Plugins + +*Csv Filter* + +* Fixed asciidoc formatting for example https://github.com/logstash-plugins/logstash-filter-csv/pull/73[#73] +* Documented that the `autodetect_column_names` and `skip_header` options work only when the number of Logstash + pipeline workers is set to `1`. + +*Dns Filter* + +* Fixed issue where unqualified domains would fail to resolve when running this plugin with Logstash 5.x https://github.com/logstash-plugins/logstash-filter-dns/pull/48[#48] +* Fixed crash that could occur when encountering certain classes of invalid inputs https://github.com/logstash-plugins/logstash-filter-dns/pull/49[#49] + +*Kv Filter* + +* Fixed asciidoc formatting in documentation https://github.com/logstash-plugins/logstash-filter-kv/pull/81[#81] + +* Added a timeout enforcer which prevents inputs that are pathological against the generated parser from blocking + the pipeline. By default, timeout is a generous 30s, but can be configured or disabled entirely with the new + `timeout_millis` and `tag_on_timeout` directives (https://github.com/logstash-plugins/logstash-filter-kv/pull/79[#79]) +* Made error-handling configurable with `tag_on_failure` directive. + +*Xml Filter* + +* Fixed creation of empty arrays when xpath failed https://github.com/logstash-plugins/logstash-filter-xml/pull/59[#59] + + +*Dead_letter_queue Input* + +* Fixed asciidoc formatting in documentation https://github.com/logstash-plugins/logstash-input-dead_letter_queue/pull/21[#21] + + +*File Input* + +* Fixed problem in Windows where some paths would fail to return an identifier ("inode"). Make path into a C style String before encoding to UTF-16LE. https://github.com/logstash-plugins/logstash-input-file/issues/232[#232] + +*Snmp Input* + +* Added support for querying SNMP tables +* Changed three error messages in the base_client to include the target address for clarity in the logs. + +*Tcp Input* + +* Fixed race condition where data would be accepted before queue was configured +* Added support for multiple certificates per file https://github.com/logstash-plugins/logstash-input-tcp/pull/140[#140] + +*Twitter Input* + +* Updated http-form_data to `~> 2` and public_suffix to `~> 3` + +*Elasticsearch Output* + +* Fixed bug where index patterns in custom templates could be erroneously overwritten https://github.com/logstash-plugins/logstash-output-elasticsearch/pull/861[#861] + +*Kafka Output* + +* Fixed issue with unnecessary sleep after retries exhausted https://github.com/logstash-plugins/logstash-output-kafka/pull/216[#216] + +*S3 Output* + +* Added configuration information for multiple s3 outputs to documentation https://github.com/logstash-plugins/logstash-output-s3/pull/196[#196] +* Fixed formatting problems and typographical errors https://github.com/logstash-plugins/logstash-output-s3/pull/194[#194], https://github.com/logstash-plugins/logstash-output-s3/pull/201[#201], and https://github.com/logstash-plugins/logstash-output-s3/pull/204[#204] +* Added support for setting mutipart upload threshold https://github.com/logstash-plugins/logstash-output-s3/pull/202[#202] + [[logstash-7-0-0]] === Logstash 7.0.0 Release Notes From cac98642cde9f90fc2bb2e805bb8766ffb58b3b6 Mon Sep 17 00:00:00 2001 From: Karen Metts <35154725+karenzone@users.noreply.github.com> Date: Mon, 20 May 2019 10:34:21 -0400 Subject: [PATCH 0140/1126] Release notes for 7.1.0 (#10796) * Release notes for 7.1.0 * Add text/link for 7.1.0 security changes * Tweaks to security info --- docs/static/releasenotes.asciidoc | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/docs/static/releasenotes.asciidoc b/docs/static/releasenotes.asciidoc index dc349560c..de292a98f 100644 --- a/docs/static/releasenotes.asciidoc +++ b/docs/static/releasenotes.asciidoc @@ -3,6 +3,7 @@ This section summarizes the changes in the following releases: +* <> * <> * <> * <> @@ -11,6 +12,14 @@ This section summarizes the changes in the following releases: * <> * <> +[[logstash-7-1-0]] +=== Logstash 7.1.0 Release Notes + +* Updates to support changes to licensing of security features. ++ +Some Elastic Stack security features, such as encrypted communications, file and native authentication, and +role-based access control, are now available in more subscription levels. For details, see https://www.elastic.co/subscriptions. + [[logstash-7-0-1]] === Logstash 7.0.1 Release Notes From 682c050f1e52aca2eaa2a71a16f694519e7358ce Mon Sep 17 00:00:00 2001 From: Joao Duarte Date: Tue, 28 May 2019 16:04:41 +0100 Subject: [PATCH 0141/1126] release notes for 7.1.1 Fixes #10830 --- docs/static/releasenotes.asciidoc | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/docs/static/releasenotes.asciidoc b/docs/static/releasenotes.asciidoc index de292a98f..bc1fdd018 100644 --- a/docs/static/releasenotes.asciidoc +++ b/docs/static/releasenotes.asciidoc @@ -3,6 +3,7 @@ This section summarizes the changes in the following releases: +* <> * <> * <> * <> @@ -12,6 +13,11 @@ This section summarizes the changes in the following releases: * <> * <> +[[logstash-7-1-1]] +=== Logstash 7.1.1 Release Notes + +* There are no user facing changes in this release. + [[logstash-7-1-0]] === Logstash 7.1.0 Release Notes From 78607d2bbbd758fe06e839f4996628d821071f1d Mon Sep 17 00:00:00 2001 From: Dan Hermann Date: Tue, 28 May 2019 08:31:05 -0500 Subject: [PATCH 0142/1126] LIR support for octal literals in pipeline definitions Fixes #10828 --- logstash-core/lib/logstash/compiler/lscl.rb | 4 ++-- .../spec/logstash/config/config_ast_spec.rb | 15 +++++++++++++++ 2 files changed, 17 insertions(+), 2 deletions(-) diff --git a/logstash-core/lib/logstash/compiler/lscl.rb b/logstash-core/lib/logstash/compiler/lscl.rb index b4cdb4d0d..a382061cb 100644 --- a/logstash-core/lib/logstash/compiler/lscl.rb +++ b/logstash-core/lib/logstash/compiler/lscl.rb @@ -164,8 +164,8 @@ module LogStashCompilerLSCLGrammar; module LogStash; module Compiler; module LSC class Number < Value def expr jdsl.eValue(source_meta, text_value.include?(".") ? - text_value.to_f : - text_value.to_i) + Float(text_value) : + Integer(text_value)) end end diff --git a/logstash-core/spec/logstash/config/config_ast_spec.rb b/logstash-core/spec/logstash/config/config_ast_spec.rb index 769cb0a8b..17d0ba61b 100644 --- a/logstash-core/spec/logstash/config/config_ast_spec.rb +++ b/logstash-core/spec/logstash/config/config_ast_spec.rb @@ -143,6 +143,21 @@ describe LogStashConfigParser do expect(config).to be_nil end + + it "supports octal literals" do + parser = LogStashConfigParser.new + config = parser.parse(%q( + input { + example { + foo => 010 + } + } + )) + + compiled_number = eval(config.recursive_select(LogStash::Config::AST::Number).first.compile) + + expect(compiled_number).to be == 8 + end end context "when config.support_escapes" do From 3d84827174b410d9a230754dc4ec5a3c7ad5541b Mon Sep 17 00:00:00 2001 From: Joao Duarte Date: Wed, 29 May 2019 11:53:03 +0100 Subject: [PATCH 0143/1126] name rpm/deb oss packages as logstash-oss Fixes #10833 --- rakelib/artifacts.rake | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/rakelib/artifacts.rake b/rakelib/artifacts.rake index cd778c4ff..e0cf8d163 100644 --- a/rakelib/artifacts.rake +++ b/rakelib/artifacts.rake @@ -498,7 +498,7 @@ namespace "artifact" do # TODO(sissel): Invoke Pleaserun to generate the init scripts/whatever - out.name = "logstash" + out.name = oss ? "logstash-oss" : "logstash" out.version = "#{LOGSTASH_VERSION}#{PACKAGE_SUFFIX}".gsub(/[.-]([[:alpha:]])/, '~\1') out.architecture = "all" # TODO(sissel): Include the git commit hash? From 8685d1d48315a8333d9af0f4939c7da1b1a8fe19 Mon Sep 17 00:00:00 2001 From: Dan Hermann Date: Tue, 28 May 2019 12:38:55 -0500 Subject: [PATCH 0144/1126] Merge config values in LIR Fixes #10832 --- logstash-core/lib/logstash/compiler/lscl.rb | 2 +- .../spec/logstash/compiler/compiler_spec.rb | 28 +++++++++++++++++++ 2 files changed, 29 insertions(+), 1 deletion(-) diff --git a/logstash-core/lib/logstash/compiler/lscl.rb b/logstash-core/lib/logstash/compiler/lscl.rb index a382061cb..4b92a5045 100644 --- a/logstash-core/lib/logstash/compiler/lscl.rb +++ b/logstash-core/lib/logstash/compiler/lscl.rb @@ -111,7 +111,7 @@ module LogStashCompilerLSCLGrammar; module LogStash; module Compiler; module LSC # hash value; e.g., `{"match" => {"baz" => "bar"}, "match" => {"foo" => "bulb"}}` is # interpreted as `{"match" => {"baz" => "bar", "foo" => "blub"}}`. # (NOTE: this bypasses `AST::Hash`'s ability to detect duplicate keys) - hash[k] = existing.merge(v) + hash[k] = ::LogStash::Util.hash_merge_many(existing, v) elsif existing.kind_of?(::Array) hash[k] = existing.push(*v) else diff --git a/logstash-core/spec/logstash/compiler/compiler_spec.rb b/logstash-core/spec/logstash/compiler/compiler_spec.rb index dc9cf9dc3..8e614332f 100644 --- a/logstash-core/spec/logstash/compiler/compiler_spec.rb +++ b/logstash-core/spec/logstash/compiler/compiler_spec.rb @@ -252,6 +252,34 @@ describe LogStash::Compiler do expect(c_plugin).to ir_eql(j.iPlugin(rand_meta, FILTER, "grok", expected_plugin_args)) end + describe "a filter plugin with a repeated hash directive with duplicated keys" do + let(:source) { "input { } filter { #{plugin_source} } output { } " } + let(:plugin_source) do + %q[ + grok { + match => { "message" => "foo" } + match => { "message" => "bar" } + break_on_match => false + } + ] + end + subject(:c_plugin) { compiled[:filter] } + + let(:expected_plugin_args) do + { + "match" => { + "message" => ["foo", "bar"] + }, + "break_on_match" => "false" + } + end + + it "should merge the values of the duplicate keys into an array" do + expect(c_plugin).to ir_eql(j.iPlugin(rand_meta, FILTER, "grok", expected_plugin_args)) + end + + end + describe "a filter plugin that has nested Hash directives" do let(:source) { "input { } filter { #{plugin_source} } output { } " } let(:plugin_source) do From 6dd85ca2a84cd602b5e24bb009fea50284a51a8d Mon Sep 17 00:00:00 2001 From: Dan Hermann Date: Thu, 30 May 2019 09:03:00 -0500 Subject: [PATCH 0145/1126] Fixes unit test failures on some runs of ConfigCompilerTest::testComplexConfigToPipelineIR Fixes #10837 --- logstash-core/lib/logstash/compiler/lscl.rb | 1 + 1 file changed, 1 insertion(+) diff --git a/logstash-core/lib/logstash/compiler/lscl.rb b/logstash-core/lib/logstash/compiler/lscl.rb index 4b92a5045..d658bf257 100644 --- a/logstash-core/lib/logstash/compiler/lscl.rb +++ b/logstash-core/lib/logstash/compiler/lscl.rb @@ -3,6 +3,7 @@ require "treetop" require "logstash/compiler/treetop_monkeypatches" require "logstash/compiler/lscl/helpers" require "logstash/config/string_escape" +require "logstash/util" java_import org.logstash.config.ir.DSL java_import org.logstash.common.SourceWithMetadata From 8a2b7be32792d9af97841d97eaa1475ce68b5b92 Mon Sep 17 00:00:00 2001 From: Dan Hermann Date: Wed, 15 May 2019 10:04:29 -0500 Subject: [PATCH 0146/1126] plain codec for Java Fixes #10791 --- .../org/logstash/plugins/codecs/Plain.java | 112 +++++++++++ .../org/logstash/plugins/codecs/LineTest.java | 15 +- .../logstash/plugins/codecs/PlainTest.java | 178 ++++++++++++++++++ .../plugins/codecs/TestEventConsumer.java | 17 ++ 4 files changed, 309 insertions(+), 13 deletions(-) create mode 100644 logstash-core/src/main/java/org/logstash/plugins/codecs/Plain.java create mode 100644 logstash-core/src/test/java/org/logstash/plugins/codecs/PlainTest.java create mode 100644 logstash-core/src/test/java/org/logstash/plugins/codecs/TestEventConsumer.java diff --git a/logstash-core/src/main/java/org/logstash/plugins/codecs/Plain.java b/logstash-core/src/main/java/org/logstash/plugins/codecs/Plain.java new file mode 100644 index 000000000..ef2108c62 --- /dev/null +++ b/logstash-core/src/main/java/org/logstash/plugins/codecs/Plain.java @@ -0,0 +1,112 @@ +package org.logstash.plugins.codecs; + +import co.elastic.logstash.api.Codec; +import co.elastic.logstash.api.Configuration; +import co.elastic.logstash.api.Context; +import co.elastic.logstash.api.Event; +import co.elastic.logstash.api.LogstashPlugin; +import co.elastic.logstash.api.PluginConfigSpec; +import org.logstash.StringInterpolation; + +import java.io.IOException; +import java.io.OutputStream; +import java.nio.ByteBuffer; +import java.nio.CharBuffer; +import java.nio.charset.Charset; +import java.nio.charset.CharsetDecoder; +import java.nio.charset.CodingErrorAction; +import java.util.Arrays; +import java.util.Collection; +import java.util.HashMap; +import java.util.Map; +import java.util.UUID; +import java.util.function.Consumer; + +/** + * The plain codec accepts input bytes as events with no decoding beyond the application of a specified + * character set. For encoding, an optional format string may be specified. + */ +@LogstashPlugin(name = "java_plain") +public class Plain implements Codec { + + private static final PluginConfigSpec CHARSET_CONFIG = + PluginConfigSpec.stringSetting("charset", "UTF-8"); + + private static final PluginConfigSpec FORMAT_CONFIG = + PluginConfigSpec.stringSetting("format"); + + static final String MESSAGE_FIELD = "message"; + + private Context context; + + private final Map map = new HashMap<>(); + + private final Charset charset; + private String format = null; + private String id; + + private final CharBuffer charBuffer = ByteBuffer.allocateDirect(64 * 1024).asCharBuffer(); + private final CharsetDecoder decoder; + + /** + * Required constructor. + * + * @param configuration Logstash Configuration + * @param context Logstash Context + */ + public Plain(final Configuration configuration, final Context context) { + this(context, configuration.get(CHARSET_CONFIG), configuration.get(FORMAT_CONFIG)); + } + + private Plain(Context context, String charsetName, String format) { + this.context = context; + this.id = UUID.randomUUID().toString(); + this.charset = Charset.forName(charsetName); + this.format = format; + decoder = charset.newDecoder(); + decoder.onMalformedInput(CodingErrorAction.IGNORE); + } + + @Override + public void decode(ByteBuffer buffer, Consumer> eventConsumer) { + if (buffer.position() < buffer.limit()) { + decoder.decode(buffer, charBuffer, true); + charBuffer.flip(); + eventConsumer.accept(simpleMap(charBuffer.toString())); + charBuffer.clear(); + } + } + + @Override + public void flush(ByteBuffer buffer, Consumer> eventConsumer) { + decode(buffer, eventConsumer); + } + + @Override + public void encode(Event event, OutputStream output) throws IOException { + String outputString = (format == null + ? event.toString() + : StringInterpolation.evaluate(event, format)); + output.write(outputString.getBytes(charset)); + } + + private Map simpleMap(String message) { + map.put(MESSAGE_FIELD, message); + return map; + } + + @Override + public Collection> configSchema() { + return Arrays.asList(CHARSET_CONFIG, FORMAT_CONFIG); + } + + @Override + public String getId() { + return id; + } + + @Override + public Codec cloneCodec() { + return new Plain(context, charset.name(), format); + } +} diff --git a/logstash-core/src/test/java/org/logstash/plugins/codecs/LineTest.java b/logstash-core/src/test/java/org/logstash/plugins/codecs/LineTest.java index abf3afdc1..7873c050a 100644 --- a/logstash-core/src/test/java/org/logstash/plugins/codecs/LineTest.java +++ b/logstash-core/src/test/java/org/logstash/plugins/codecs/LineTest.java @@ -12,12 +12,10 @@ import java.io.IOException; import java.io.UnsupportedEncodingException; import java.nio.ByteBuffer; import java.nio.charset.Charset; -import java.util.ArrayList; import java.util.Collections; import java.util.HashMap; import java.util.List; import java.util.Map; -import java.util.function.Consumer; import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertTrue; @@ -191,7 +189,7 @@ public class LineTest { compareMessages(expectedMessages, eventConsumer.events, flushConsumer.events); } - private static void compareMessages(String[] expectedMessages, List> events, List> flushedEvents) { + static void compareMessages(String[] expectedMessages, List> events, List> flushedEvents) { if (expectedMessages != null) { for (int k = 0; k < events.size(); k++) { assertEquals(expectedMessages[k], events.get(k).get(Line.MESSAGE_FIELD)); @@ -214,7 +212,7 @@ public class LineTest { } @Test - public void testDecodeWithCharset() throws Exception { + public void testDecodeWithCharset() { TestEventConsumer flushConsumer = new TestEventConsumer(); // decode with cp-1252 @@ -341,12 +339,3 @@ public class LineTest { } -class TestEventConsumer implements Consumer> { - - List> events = new ArrayList<>(); - - @Override - public void accept(Map stringObjectMap) { - events.add(new HashMap<>(stringObjectMap)); - } -} diff --git a/logstash-core/src/test/java/org/logstash/plugins/codecs/PlainTest.java b/logstash-core/src/test/java/org/logstash/plugins/codecs/PlainTest.java new file mode 100644 index 000000000..52639a82e --- /dev/null +++ b/logstash-core/src/test/java/org/logstash/plugins/codecs/PlainTest.java @@ -0,0 +1,178 @@ +package org.logstash.plugins.codecs; + +import co.elastic.logstash.api.Codec; +import org.junit.Assert; +import org.junit.Test; +import org.logstash.Event; +import org.logstash.plugins.ConfigurationImpl; +import org.logstash.plugins.TestContext; + +import java.io.ByteArrayOutputStream; +import java.io.IOException; +import java.io.UnsupportedEncodingException; +import java.nio.ByteBuffer; +import java.nio.charset.Charset; +import java.util.Collections; +import java.util.HashMap; +import java.util.Map; + +import static org.junit.Assert.assertEquals; +import static org.logstash.plugins.codecs.LineTest.compareMessages; + +public class PlainTest { + + @Test + public void testSimpleDecode() { + String input = new String("abc".getBytes(), Charset.forName("UTF-8")); + testDecode( null, input, 1, new String[]{input}); + } + + @Test + public void testEmptyDecode() { + String input = new String("".getBytes(), Charset.forName("UTF-8")); + testDecode( null, input, 0, new String[]{}); + } + + @Test + public void testDecodeWithUtf8() { + String input = new String("München 安装中文输入法".getBytes(), Charset.forName("UTF-8")); + testDecode(null, input, 1, new String[]{input}); + } + + @Test + public void testDecodeWithCharset() { + TestEventConsumer eventConsumer = new TestEventConsumer(); + + // decode with cp-1252 + Plain cp1252decoder = new Plain(new ConfigurationImpl(Collections.singletonMap("charset", "cp1252")), new TestContext()); + byte[] rightSingleQuoteInCp1252 = {(byte) 0x92}; + ByteBuffer b1 = ByteBuffer.wrap(rightSingleQuoteInCp1252); + cp1252decoder.decode(b1, eventConsumer); + assertEquals(1, eventConsumer.events.size()); + cp1252decoder.flush(b1, eventConsumer); + assertEquals(1, eventConsumer.events.size()); + String fromCp1252 = (String) eventConsumer.events.get(0).get(Plain.MESSAGE_FIELD); + + // decode with UTF-8 + eventConsumer.events.clear(); + Plain utf8decoder = new Plain(new ConfigurationImpl(Collections.emptyMap()), new TestContext()); + byte[] rightSingleQuoteInUtf8 = {(byte) 0xE2, (byte) 0x80, (byte) 0x99}; + ByteBuffer b2 = ByteBuffer.wrap(rightSingleQuoteInUtf8); + utf8decoder.decode(b2, eventConsumer); + assertEquals(1, eventConsumer.events.size()); + utf8decoder.flush(b2, eventConsumer); + assertEquals(1, eventConsumer.events.size()); + String fromUtf8 = (String) eventConsumer.events.get(0).get(Plain.MESSAGE_FIELD); + assertEquals(fromCp1252, fromUtf8); + } + + private void testDecode(String charset, String inputString, Integer expectedPreflushEvents, String[] expectedMessages) { + Plain plain = getPlainCodec(charset); + + byte[] inputBytes = null; + try { + inputBytes = inputString.getBytes("UTF-8"); + } catch (UnsupportedEncodingException ex) { + Assert.fail(); + } + TestEventConsumer eventConsumer = new TestEventConsumer(); + ByteBuffer inputBuffer = ByteBuffer.wrap(inputBytes, 0, inputBytes.length); + plain.decode(inputBuffer, eventConsumer); + if (expectedPreflushEvents != null) { + assertEquals(expectedPreflushEvents.intValue(), eventConsumer.events.size()); + } + + inputBuffer.compact(); + inputBuffer.flip(); + + // flushing the plain codec should never produce events + TestEventConsumer flushConsumer = new TestEventConsumer(); + plain.flush(inputBuffer, flushConsumer); + assertEquals(0, flushConsumer.events.size()); + + compareMessages(expectedMessages, eventConsumer.events, flushConsumer.events); + } + + private static Plain getPlainCodec(String charset) { + Map config = new HashMap<>(); + if (charset != null) { + config.put("charset", charset); + } + return new Plain(new ConfigurationImpl(config), new TestContext()); + } + + @Test + public void testEncodeWithUtf8() throws IOException { + ByteArrayOutputStream outputStream = new ByteArrayOutputStream(); + String message = new String("München 安装中文输入法".getBytes(), Charset.forName("UTF-8")); + Map config = new HashMap<>(); + config.put("format", "%{message}"); + Plain codec = new Plain(new ConfigurationImpl(config), new TestContext()); + Event e1 = new Event(Collections.singletonMap("message", message)); + codec.encode(e1, outputStream); + Assert.assertEquals(message, new String(outputStream.toByteArray(), Charset.forName("UTF-8"))); + } + + @Test + public void testEncodeWithCharset() throws IOException { + ByteArrayOutputStream outputStream = new ByteArrayOutputStream(); + byte[] rightSingleQuoteInUtf8 = {(byte) 0xE2, (byte) 0x80, (byte) 0x99}; + String rightSingleQuote = new String(rightSingleQuoteInUtf8, Charset.forName("UTF-8")); + + // encode with cp-1252 + Map config = new HashMap<>(); + config.put("charset", "cp1252"); + config.put("format", "%{message}"); + config.put("delimiter", ""); + Event e1 = new Event(Collections.singletonMap("message", rightSingleQuote)); + Plain cp1252encoder = new Plain(new ConfigurationImpl(config), new TestContext()); + byte[] rightSingleQuoteInCp1252 = {(byte) 0x92}; + + cp1252encoder.encode(e1, outputStream); + byte[] resultBytes = outputStream.toByteArray(); + Assert.assertArrayEquals(rightSingleQuoteInCp1252, resultBytes); + } + + @Test + public void testEncodeWithFormat() throws IOException { + ByteArrayOutputStream outputStream = new ByteArrayOutputStream(); + Plain encoder = new Plain(new ConfigurationImpl(Collections.singletonMap("format", "%{host}-%{message}")), null); + String message = "Hello world"; + String host = "test"; + String expectedOutput = host + "-" + message; + Event e = new Event(); + e.setField("message", message); + e.setField("host", host); + + encoder.encode(e, outputStream); + + String resultingString = outputStream.toString(); + assertEquals(expectedOutput, resultingString); + } + + @Test + public void testClone() throws IOException { + ByteArrayOutputStream outputStream = new ByteArrayOutputStream(); + String charset = "cp1252"; + byte[] rightSingleQuoteInUtf8 = {(byte) 0xE2, (byte) 0x80, (byte) 0x99}; + String rightSingleQuote = new String(rightSingleQuoteInUtf8, Charset.forName("UTF-8")); + + // encode with cp-1252 + Map config = new HashMap<>(); + config.put("charset", charset); + config.put("format", "%{message}"); + Event e1 = new Event(Collections.singletonMap("message", rightSingleQuote)); + Plain codec = new Plain(new ConfigurationImpl(config), new TestContext()); + + // clone codec + Codec clone = codec.cloneCodec(); + Assert.assertEquals(codec.getClass(), clone.getClass()); + Plain plain2 = (Plain)clone; + + // verify charset and delimiter + byte[] rightSingleQuoteInCp1252 = {(byte) 0x92}; + plain2.encode(e1, outputStream); + Assert.assertArrayEquals(rightSingleQuoteInCp1252, outputStream.toByteArray()); + } + +} diff --git a/logstash-core/src/test/java/org/logstash/plugins/codecs/TestEventConsumer.java b/logstash-core/src/test/java/org/logstash/plugins/codecs/TestEventConsumer.java new file mode 100644 index 000000000..6e6aae1d3 --- /dev/null +++ b/logstash-core/src/test/java/org/logstash/plugins/codecs/TestEventConsumer.java @@ -0,0 +1,17 @@ +package org.logstash.plugins.codecs; + +import java.util.ArrayList; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import java.util.function.Consumer; + +public class TestEventConsumer implements Consumer> { + + List> events = new ArrayList<>(); + + @Override + public void accept(Map stringObjectMap) { + events.add(new HashMap<>(stringObjectMap)); + } +} From 58dbda45f35c59344609e615c08f0820bd0ffe0f Mon Sep 17 00:00:00 2001 From: Florian Kelbert Date: Thu, 30 May 2019 12:21:37 +0100 Subject: [PATCH 0147/1126] Value of start_timestamp must to be quoted Fixes #10836 --- docs/static/dead-letter-queues.asciidoc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/static/dead-letter-queues.asciidoc b/docs/static/dead-letter-queues.asciidoc index 9bb3b7936..4d1c283c7 100644 --- a/docs/static/dead-letter-queues.asciidoc +++ b/docs/static/dead-letter-queues.asciidoc @@ -144,7 +144,7 @@ processing events based on the timestamp of when they entered the queue: input { dead_letter_queue { path => "/path/to/data/dead_letter_queue" - start_timestamp => 2017-06-06T23:40:37 + start_timestamp => "2017-06-06T23:40:37" pipeline_id => "main" } } From 9f30ea281f498ff01b9dd1502bb0efdf1d2cb274 Mon Sep 17 00:00:00 2001 From: Karen Metts Date: Mon, 15 Apr 2019 17:10:27 -0400 Subject: [PATCH 0148/1126] Remove note about j11 Fixes #10689 --- docs/static/getting-started-with-logstash.asciidoc | 3 --- 1 file changed, 3 deletions(-) diff --git a/docs/static/getting-started-with-logstash.asciidoc b/docs/static/getting-started-with-logstash.asciidoc index c70b85b27..0354ad260 100644 --- a/docs/static/getting-started-with-logstash.asciidoc +++ b/docs/static/getting-started-with-logstash.asciidoc @@ -41,9 +41,6 @@ automatically detect your environment and install the correct startup method JAVA_HOME environment variable during package installation time, you may get an error message, and Logstash will be unable to start properly. -IMPORTANT: Users have reported issues with Debian or RPM install packages and Java 11. -We are investigating and tracking in https://github.com/elastic/logstash/issues/10593[Issue #10593]. - [float] [[installing-binary]] === Installing from a Downloaded Binary From b76ea1989ed03a1c6c479f8ba4c37bc870dbb1e0 Mon Sep 17 00:00:00 2001 From: Ry Biesemeyer Date: Fri, 31 May 2019 17:18:32 +0000 Subject: [PATCH 0149/1126] field_refefence: handle illegal field references in converted maps When using the Jruby event API, re-cast java exceptions produced by illegal field references to ruby `RuntimeError`s, which can be caught by the ruby-based plugins. This is similar to what we already do in the Jruby event API when directly handling field references, but catches a case where the `Valuifier` encounters an illegal reference when creating a `ConvertedMap`. Fixes #10839 --- .../logstash/ext/JrubyEventExtLibrary.java | 18 ++++++++- .../ext/JrubyEventExtLibraryTest.java | 37 +++++++++++++++++++ 2 files changed, 54 insertions(+), 1 deletion(-) diff --git a/logstash-core/src/main/java/org/logstash/ext/JrubyEventExtLibrary.java b/logstash-core/src/main/java/org/logstash/ext/JrubyEventExtLibrary.java index a7a44c77b..369ea3fd0 100644 --- a/logstash-core/src/main/java/org/logstash/ext/JrubyEventExtLibrary.java +++ b/logstash-core/src/main/java/org/logstash/ext/JrubyEventExtLibrary.java @@ -96,7 +96,7 @@ public final class JrubyEventExtLibrary { } this.event.setTimestamp(((JrubyTimestampExtLibrary.RubyTimestamp)value).getTimestamp()); } else { - this.event.setField(r, Valuefier.convert(value)); + this.event.setField(r, safeValueifierConvert(value)); } return value; } @@ -322,6 +322,22 @@ public final class JrubyEventExtLibrary { } } + /** + * Shared logic to wrap {@link FieldReference.IllegalSyntaxException}s that are raised by + * {@link Valuefier#convert(Object)} when encountering illegal syntax in a ruby-exception + * that can be easily handled within the ruby plugins + * + * @param value a {@link Object} to be passed to {@link Valuefier#convert(Object)} + * @return the resulting {@link Object} (see: {@link Valuefier#convert(Object)}) + */ + private static Object safeValueifierConvert(final Object value) { + try { + return Valuefier.convert(value); + } catch (FieldReference.IllegalSyntaxException ise) { + throw RubyUtil.RUBY.newRuntimeError(ise.getMessage()); + } + } + private void setEvent(Event event) { this.event = event; diff --git a/logstash-core/src/test/java/org/logstash/ext/JrubyEventExtLibraryTest.java b/logstash-core/src/test/java/org/logstash/ext/JrubyEventExtLibraryTest.java index 8cd1e5327..0fbd60663 100644 --- a/logstash-core/src/test/java/org/logstash/ext/JrubyEventExtLibraryTest.java +++ b/logstash-core/src/test/java/org/logstash/ext/JrubyEventExtLibraryTest.java @@ -2,13 +2,18 @@ package org.logstash.ext; import java.io.IOException; import java.util.Arrays; +import java.util.Collections; import java.util.HashMap; import java.util.Map; import org.assertj.core.api.Assertions; +import org.hamcrest.CoreMatchers; +import org.jruby.RubyHash; import org.jruby.RubyString; +import org.jruby.exceptions.RuntimeError; import org.jruby.javasupport.JavaUtil; import org.jruby.runtime.ThreadContext; import org.jruby.runtime.builtin.IRubyObject; +import org.junit.Assert; import org.junit.Test; import org.logstash.ObjectMappers; import org.logstash.RubyUtil; @@ -55,6 +60,38 @@ public final class JrubyEventExtLibraryTest { .contains("\"テストフィールド\":\"someValue\""); } + @Test + public void correctlyRaiseRubyRuntimeErrorWhenGivenInvalidFieldReferences() { + final ThreadContext context = RubyUtil.RUBY.getCurrentContext(); + final JrubyEventExtLibrary.RubyEvent event = + JrubyEventExtLibrary.RubyEvent.newRubyEvent(context.runtime); + final RubyString key = rubyString("il[[]]]legal"); + final RubyString value = rubyString("foo"); + try { + event.ruby_set_field(context, key, value); + } catch (RuntimeError rubyRuntimeError) { + Assert.assertThat(rubyRuntimeError.getLocalizedMessage(), CoreMatchers.containsString("Invalid FieldReference")); + return; + } + Assert.fail("expected ruby RuntimeError was not thrown."); + } + + @Test + public void correctlyRaiseRubyRuntimeErrorWhenGivenInvalidFieldReferencesInMap() { + final ThreadContext context = RubyUtil.RUBY.getCurrentContext(); + final JrubyEventExtLibrary.RubyEvent event = + JrubyEventExtLibrary.RubyEvent.newRubyEvent(context.runtime); + final RubyString key = rubyString("foo"); + final RubyHash value = RubyHash.newHash(context.runtime, Collections.singletonMap(rubyString("il[[]]]legal"), rubyString("okay")), context.nil); + try { + event.ruby_set_field(context, key, value); + } catch (RuntimeError rubyRuntimeError) { + Assert.assertThat(rubyRuntimeError.getLocalizedMessage(), CoreMatchers.containsString("Invalid FieldReference")); + return; + } + Assert.fail("expected ruby RuntimeError was not thrown."); + } + private static RubyString rubyString(final String java) { return RubyUtil.RUBY.newString(java); } From b519dc1e1e88c79fa610d4d43b30960318779720 Mon Sep 17 00:00:00 2001 From: Dan Hermann Date: Fri, 7 Jun 2019 10:01:19 -0500 Subject: [PATCH 0150/1126] fix parsing of boolean options provided to Java plugins Fixes #10848 --- .../logstash/plugins/ConfigurationImpl.java | 2 ++ .../plugins/ConfigurationImplTest.java | 22 +++++++++++++++++++ 2 files changed, 24 insertions(+) diff --git a/logstash-core/src/main/java/org/logstash/plugins/ConfigurationImpl.java b/logstash-core/src/main/java/org/logstash/plugins/ConfigurationImpl.java index 7215a4a24..57e95302c 100644 --- a/logstash-core/src/main/java/org/logstash/plugins/ConfigurationImpl.java +++ b/logstash-core/src/main/java/org/logstash/plugins/ConfigurationImpl.java @@ -44,6 +44,8 @@ public final class ConfigurationImpl implements Configuration { return (T) o; } else if (configSpec.type() == Double.class && o.getClass() == Long.class) { return configSpec.type().cast(((Long)o).doubleValue()); + } else if (configSpec.type() == Boolean.class && o instanceof String) { + return configSpec.type().cast(Boolean.parseBoolean((String) o)); } else if (configSpec.type() == Codec.class && o instanceof String && pluginFactory != null) { Codec codec = pluginFactory.buildDefaultCodec((String) o); return configSpec.type().cast(codec); diff --git a/logstash-core/src/test/java/org/logstash/plugins/ConfigurationImplTest.java b/logstash-core/src/test/java/org/logstash/plugins/ConfigurationImplTest.java index 6d30bdda2..02d543583 100644 --- a/logstash-core/src/test/java/org/logstash/plugins/ConfigurationImplTest.java +++ b/logstash-core/src/test/java/org/logstash/plugins/ConfigurationImplTest.java @@ -188,4 +188,26 @@ public class ConfigurationImplTest { Assert.assertEquals("", p.toString()); } + @Test + public void testBooleanValues() { + PluginConfigSpec booleanConfig = PluginConfigSpec.booleanSetting(booleanKey, false, false, false); + Configuration config = new ConfigurationImpl(Collections.singletonMap(booleanKey, "tRuE")); + boolean value = config.get(booleanConfig); + Assert.assertTrue(value); + + config = new ConfigurationImpl(Collections.singletonMap(booleanKey, "false")); + value = config.get(booleanConfig); + Assert.assertFalse(value); + + booleanConfig = PluginConfigSpec.booleanSetting(booleanKey, false, false, false); + config = new ConfigurationImpl(Collections.emptyMap()); + value = config.get(booleanConfig); + Assert.assertFalse(value); + + booleanConfig = PluginConfigSpec.booleanSetting(booleanKey, true, false, false); + config = new ConfigurationImpl(Collections.emptyMap()); + value = config.get(booleanConfig); + Assert.assertTrue(value); + } + } From a1e806d2c50e7834e4f01aabbcc4a7b790a01cb6 Mon Sep 17 00:00:00 2001 From: Jeff Date: Tue, 11 Jun 2019 09:44:37 -0400 Subject: [PATCH 0151/1126] Add details about Elastic Search dependency No Elastic Search dependency is mentioned in the guide for Logstash up to this point. This would be good for those who are getting started to Log Stash without knowing much about Elastic Search and unaware that it isn't already packages along with the install of Logstash. Fixes #10852 --- docs/static/configuration.asciidoc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/static/configuration.asciidoc b/docs/static/configuration.asciidoc index 07d8e0c46..e3519aecd 100644 --- a/docs/static/configuration.asciidoc +++ b/docs/static/configuration.asciidoc @@ -23,7 +23,7 @@ Then, run logstash and specify the configuration file with the `-f` flag. bin/logstash -f logstash-simple.conf ---------------------------------- -Et voilà! Logstash reads the specified configuration file and outputs to both Elasticsearch and stdout. Before we +Et voilà! Logstash reads the specified configuration file and outputs to both Elasticsearch and stdout. Note that if you see a message in stdout that reads "Elasticsearch Unreachable" that you will need to make sure Elasticsearch is installed and up and reachable on port 9200. Before we move on to some <>, let's take a closer look at what's in a config file. [[configuration-file-structure]] From f18992c647a907f166748185fca0a50adc974501 Mon Sep 17 00:00:00 2001 From: Joao Duarte Date: Fri, 14 Jun 2019 17:49:25 +0100 Subject: [PATCH 0152/1126] avoid clashes between Environment class methods Fixes #10860 --- lib/bootstrap/environment.rb | 2 +- lib/pluginmanager/pack.rb | 4 ++-- lib/pluginmanager/unpack.rb | 4 ++-- logstash-core/lib/logstash/environment.rb | 8 ++++++-- logstash-core/spec/logstash/environment_spec.rb | 8 ++++---- 5 files changed, 15 insertions(+), 11 deletions(-) diff --git a/lib/bootstrap/environment.rb b/lib/bootstrap/environment.rb index 71d99b8ad..513ef7711 100644 --- a/lib/bootstrap/environment.rb +++ b/lib/bootstrap/environment.rb @@ -42,7 +42,7 @@ module LogStash !File.exists?(File.join(LogStash::Environment::LOGSTASH_HOME, "x-pack")) end - def windows? + def win_platform? ::Gem.win_platform? end diff --git a/lib/pluginmanager/pack.rb b/lib/pluginmanager/pack.rb index 2f0072819..925216a36 100644 --- a/lib/pluginmanager/pack.rb +++ b/lib/pluginmanager/pack.rb @@ -2,8 +2,8 @@ require_relative "pack_command" class LogStash::PluginManager::Pack < LogStash::PluginManager::PackCommand - option "--tgz", :flag, "compress package as a tar.gz file", :default => !LogStash::Environment.windows? - option "--zip", :flag, "compress package as a zip file", :default => LogStash::Environment.windows? + option "--tgz", :flag, "compress package as a tar.gz file", :default => !LogStash::Environment.win_platform? + option "--zip", :flag, "compress package as a zip file", :default => LogStash::Environment.win_platform? option "--[no-]clean", :flag, "clean up the generated dump of plugins", :default => true option "--overwrite", :flag, "Overwrite a previously generated package file", :default => false diff --git a/lib/pluginmanager/unpack.rb b/lib/pluginmanager/unpack.rb index f1f7221e1..c42f1ba25 100644 --- a/lib/pluginmanager/unpack.rb +++ b/lib/pluginmanager/unpack.rb @@ -2,8 +2,8 @@ require_relative "pack_command" class LogStash::PluginManager::Unpack < LogStash::PluginManager::PackCommand - option "--tgz", :flag, "unpack a packaged tar.gz file", :default => !LogStash::Environment.windows? - option "--zip", :flag, "unpack a packaged zip file", :default => LogStash::Environment.windows? + option "--tgz", :flag, "unpack a packaged tar.gz file", :default => !LogStash::Environment.win_platform? + option "--zip", :flag, "unpack a packaged zip file", :default => LogStash::Environment.win_platform? parameter "file", "the package file name", :attribute_name => :package_file, :required => true diff --git a/logstash-core/lib/logstash/environment.rb b/logstash-core/lib/logstash/environment.rb index 31df098fa..8e8dd22ec 100644 --- a/logstash-core/lib/logstash/environment.rb +++ b/logstash-core/lib/logstash/environment.rb @@ -164,11 +164,15 @@ module LogStash end def windows? - RbConfig::CONFIG['host_os'] =~ WINDOW_OS_RE + host_os =~ WINDOW_OS_RE end def linux? - RbConfig::CONFIG['host_os'] =~ LINUX_OS_RE + host_os =~ LINUX_OS_RE + end + + def host_os + RbConfig::CONFIG['host_os'] end def locales_path(path) diff --git a/logstash-core/spec/logstash/environment_spec.rb b/logstash-core/spec/logstash/environment_spec.rb index d64ed3941..79d05fbea 100644 --- a/logstash-core/spec/logstash/environment_spec.rb +++ b/logstash-core/spec/logstash/environment_spec.rb @@ -57,14 +57,14 @@ describe LogStash::Environment do context "windows" do windows_host_os.each do |host| it "#{host} returns true" do - expect(RbConfig::CONFIG).to receive(:[]).with("host_os").and_return(host) + allow(LogStash::Environment).to receive(:host_os).and_return(host) expect(LogStash::Environment.windows?).to be_truthy end end linux_host_os.each do |host| it "#{host} returns false" do - expect(RbConfig::CONFIG).to receive(:[]).with("host_os").and_return(host) + allow(LogStash::Environment).to receive(:host_os).and_return(host) expect(LogStash::Environment.windows?).to be_falsey end end @@ -73,14 +73,14 @@ describe LogStash::Environment do context "Linux" do windows_host_os.each do |host| it "#{host} returns true" do - expect(RbConfig::CONFIG).to receive(:[]).with("host_os").and_return(host) + allow(LogStash::Environment).to receive(:host_os).and_return(host) expect(LogStash::Environment.linux?).to be_falsey end end linux_host_os.each do |host| it "#{host} returns false" do - expect(RbConfig::CONFIG).to receive(:[]).with("host_os").and_return(host) + allow(LogStash::Environment).to receive(:host_os).and_return(host) expect(LogStash::Environment.linux?).to be_truthy end end From 48c581b6fd617bf19e47b096fef5554ba5baaa7a Mon Sep 17 00:00:00 2001 From: Rob Bavey Date: Mon, 17 Jun 2019 11:23:41 -0400 Subject: [PATCH 0153/1126] Add Logstash JMS input to the list of default plugins Fixes #10865 --- rakelib/plugins-metadata.json | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/rakelib/plugins-metadata.json b/rakelib/plugins-metadata.json index 5181640ca..94d5c05ab 100644 --- a/rakelib/plugins-metadata.json +++ b/rakelib/plugins-metadata.json @@ -308,6 +308,10 @@ "default-plugins": true, "skip-list": false }, + "logstash-input-jms": { + "default-plugins": true, + "skip-list": false + }, "logstash-input-journald": { "default-plugins": false, "skip-list": true From 369f8e80d477312beb4b1c521a945f107df0825d Mon Sep 17 00:00:00 2001 From: Karen Metts Date: Mon, 17 Jun 2019 16:50:55 -0400 Subject: [PATCH 0154/1126] Add homebrew as installation option Fixes #10874 --- .../getting-started-with-logstash.asciidoc | 54 ++++++++++++++++++- 1 file changed, 52 insertions(+), 2 deletions(-) diff --git a/docs/static/getting-started-with-logstash.asciidoc b/docs/static/getting-started-with-logstash.asciidoc index 0354ad260..b1b6959c6 100644 --- a/docs/static/getting-started-with-logstash.asciidoc +++ b/docs/static/getting-started-with-logstash.asciidoc @@ -45,8 +45,13 @@ error message, and Logstash will be unable to start properly. [[installing-binary]] === Installing from a Downloaded Binary -Download the https://www.elastic.co/downloads/logstash[Logstash installation file] that matches your host environment. -Unpack the file. Do not install Logstash into a directory path that contains colon (:) characters. +The {ls} binaries are available from +https://www.elastic.co/downloads/logstash[https://www.elastic.co/downloads]. +Download the Logstash installation file for your host environment--TARG.GZ, DEB, +ZIP, or RPM. + +Unpack the file. Do not install Logstash into a directory path that +contains colon (:) characters. [NOTE] -- @@ -230,6 +235,51 @@ See the {logstash-ref}/running-logstash.html[Running Logstash] document for mana endif::[] +[float] +[[brew]] +=== Installing {ls} on macOS with Homebrew + +Elastic publishes Homebrew formulae so you can install {ls} with the +https://brew.sh/[Homebrew] package manager. + +To install with Homebrew, you first need to tap the Elastic Homebrew repository: + +[source,sh] +------------------------- +brew tap elastic/tap +------------------------- + +After you've tapped the Elastic Homebrew repo, you can use `brew install` to +install the default distribution of {ls}: + +[source,sh] +------------------------- +brew install elastic/tap/logstash-full +------------------------- + +This installs the most recently released default distribution of {ls}. +To install the OSS distribution, specify `elastic/tap/logstash-oss`. + + +[float] +[[brew-start]] +==== Starting {ls} with Homebrew + +To have launchd start elastic/tap/logstash-full now and restart at login, run: + +[source,sh] +----- +brew services start elastic/tap/logstash-full +----- + +To run {ls}, in the foreground, run: + +[source,sh] +----- +logstash +----- + + ==== Docker Images are available for running Logstash as a Docker container. They are From 5e970fe578dc5a4a367171a9ace7a47b7715a97f Mon Sep 17 00:00:00 2001 From: Dan Hermann Date: Tue, 25 Jun 2019 10:49:23 -0500 Subject: [PATCH 0155/1126] remove the beta designation from the docs for Java plugins Fixes #10891 --- docs/static/contributing-java-plugin.asciidoc | 2 -- 1 file changed, 2 deletions(-) diff --git a/docs/static/contributing-java-plugin.asciidoc b/docs/static/contributing-java-plugin.asciidoc index e509eaaf6..45cb134b9 100644 --- a/docs/static/contributing-java-plugin.asciidoc +++ b/docs/static/contributing-java-plugin.asciidoc @@ -1,8 +1,6 @@ [[contributing-java-plugin]] == Contributing a Java Plugin -beta[] - Now you can write your own Java plugin for use with {ls}. We have provided instructions and GitHub examples to give you a head start. From 8a048ccc27a5eb2de64e6134cdf3d8ef2c489a92 Mon Sep 17 00:00:00 2001 From: Dan Hermann Date: Wed, 19 Jun 2019 12:26:28 -0500 Subject: [PATCH 0156/1126] Do not shut down API webserver until after pipelines have been shut down Fixes #10880 --- logstash-core/lib/logstash/agent.rb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/logstash-core/lib/logstash/agent.rb b/logstash-core/lib/logstash/agent.rb index d8ffa82bb..94f3cabfb 100644 --- a/logstash-core/lib/logstash/agent.rb +++ b/logstash-core/lib/logstash/agent.rb @@ -186,9 +186,9 @@ class LogStash::Agent pipeline_bus.setBlockOnUnlisten(true) stop_collecting_metrics - stop_webserver transition_to_stopped converge_result = shutdown_pipelines + stop_webserver converge_result end From d03c0f14a439e8674ec7d47ee9ca539d64e055b0 Mon Sep 17 00:00:00 2001 From: Dan Hermann Date: Mon, 6 May 2019 16:52:12 -0500 Subject: [PATCH 0157/1126] Remove debug code for p2p plus formatting Fixes #10840 --- .../plugins/builtin/pipeline/input.rb | 5 +- .../plugins/pipeline/AddressState.java | 15 ++--- .../plugins/pipeline/PipelineBus.java | 57 ++++++++++--------- .../plugins/pipeline/PipelineInput.java | 5 +- .../plugins/pipeline/PipelineOutput.java | 5 -- 5 files changed, 40 insertions(+), 47 deletions(-) diff --git a/logstash-core/lib/logstash/plugins/builtin/pipeline/input.rb b/logstash-core/lib/logstash/plugins/builtin/pipeline/input.rb index 340bd1ef5..e08b8a85e 100644 --- a/logstash-core/lib/logstash/plugins/builtin/pipeline/input.rb +++ b/logstash-core/lib/logstash/plugins/builtin/pipeline/input.rb @@ -44,10 +44,7 @@ module ::LogStash; module Plugins; module Builtin; module Pipeline; class Input @queue << event end - return true - rescue => e - require 'pry'; binding.pry - return true + true end def stop diff --git a/logstash-core/src/main/java/org/logstash/plugins/pipeline/AddressState.java b/logstash-core/src/main/java/org/logstash/plugins/pipeline/AddressState.java index 2b90453d8..0266e59d5 100644 --- a/logstash-core/src/main/java/org/logstash/plugins/pipeline/AddressState.java +++ b/logstash-core/src/main/java/org/logstash/plugins/pipeline/AddressState.java @@ -4,16 +4,14 @@ import java.util.Set; import java.util.concurrent.ConcurrentHashMap; /** - * Class for representing the state of an internal address. + * Represents the state of an internal address. */ public class AddressState { - private final String address; + private final Set outputs = ConcurrentHashMap.newKeySet(); private volatile PipelineInput input = null; - AddressState(String address) { - this.address = address; - } + AddressState(String address) {} /** * Add the given output and ensure associated input's receivers are updated @@ -38,14 +36,13 @@ public class AddressState { * @return true if successful, false if another input is listening */ public synchronized boolean assignInputIfMissing(PipelineInput newInput) { + // We aren't changing anything if (input == null) { input = newInput; return true; - } else if (input == newInput) { - return true; // We aren't changing anything + } else { + return input == newInput; } - - return false; } /** diff --git a/logstash-core/src/main/java/org/logstash/plugins/pipeline/PipelineBus.java b/logstash-core/src/main/java/org/logstash/plugins/pipeline/PipelineBus.java index 1d5f92f00..11886569a 100644 --- a/logstash-core/src/main/java/org/logstash/plugins/pipeline/PipelineBus.java +++ b/logstash-core/src/main/java/org/logstash/plugins/pipeline/PipelineBus.java @@ -5,37 +5,35 @@ import org.apache.logging.log4j.Logger; import org.logstash.RubyUtil; import org.logstash.ext.JrubyEventExtLibrary; -import java.util.*; +import java.util.Collection; import java.util.concurrent.ConcurrentHashMap; -import java.util.concurrent.atomic.AtomicBoolean; import java.util.stream.Stream; /** * This class is essentially the communication bus / central state for the `pipeline` inputs/outputs to talk to each - * other. - * - * This class is threadsafe. + * other. This class is threadsafe. */ public class PipelineBus { final ConcurrentHashMap addressStates = new ConcurrentHashMap<>(); final ConcurrentHashMap> outputsToAddressStates = new ConcurrentHashMap<>(); volatile boolean blockOnUnlisten = false; - private static final Logger logger = LogManager.getLogger(PipelineBus.class); + private static final Logger logger = LogManager.getLogger(PipelineBus.class); /** * Sends events from the provided output. - * @param sender The output sending the events. - * @param events A collection of JRuby events + * + * @param sender The output sending the events. + * @param events A collection of JRuby events * @param ensureDelivery set to true if you want this to retry indefinitely in the event an event send fails */ public void sendEvents(final PipelineOutput sender, - final Collection events, - final boolean ensureDelivery) { + final Collection events, + final boolean ensureDelivery) { if (events.isEmpty()) return; // This can happen on pipeline shutdown or in some other situations final ConcurrentHashMap addressesToInputs = outputsToAddressStates.get(sender); - addressesToInputs.forEach( (address, addressState) -> { + addressesToInputs.forEach((address, addressState) -> { final Stream clones = events.stream().map(e -> e.rubyClone(RubyUtil.RUBY)); PipelineInput input = addressState.getInput(); // Save on calls to getInput since it's volatile @@ -61,16 +59,17 @@ public class PipelineBus { /** * Should be called by an output on register - * @param output output to be registered + * + * @param output output to be registered * @param addresses collection of addresses on which to register this sender */ public void registerSender(final PipelineOutput output, final Iterable addresses) { addresses.forEach((String address) -> { addressStates.compute(address, (k, value) -> { - final AddressState state = value != null ? value : new AddressState(address); - state.addOutput(output); + final AddressState state = value != null ? value : new AddressState(address); + state.addOutput(output); - return state; + return state; }); }); @@ -79,7 +78,8 @@ public class PipelineBus { /** * Should be called by an output on close - * @param output output that will be unregistered + * + * @param output output that will be unregistered * @param addresses collection of addresses this sender was registered with */ public void unregisterSender(final PipelineOutput output, final Iterable addresses) { @@ -99,13 +99,14 @@ public class PipelineBus { /** * Updates the internal state for this output to reflect the fact that there may be a change * in the inputs receiving events from it. + * * @param output output to update */ private void updateOutputReceivers(final PipelineOutput output) { outputsToAddressStates.compute(output, (k, value) -> { ConcurrentHashMap outputAddressToInputMapping = value != null ? value : new ConcurrentHashMap<>(); - addressStates.forEach( (address, state) -> { + addressStates.forEach((address, state) -> { if (state.hasOutput(output)) outputAddressToInputMapping.put(address, state); }); @@ -116,7 +117,8 @@ public class PipelineBus { /** * Listens to a given address with the provided listener * Only one listener can listen on an address at a time - * @param input Input to register as listener + * + * @param input Input to register as listener * @param address Address on which to listen * @return true if the listener successfully subscribed */ @@ -124,7 +126,7 @@ public class PipelineBus { final boolean[] result = new boolean[1]; addressStates.compute(address, (k, value) -> { - AddressState state = value != null ? value : new AddressState(address); + AddressState state = value != null ? value : new AddressState(address); if (state.assignInputIfMissing(input)) { state.getOutputs().forEach(this::updateOutputReceivers); @@ -143,7 +145,8 @@ public class PipelineBus { * Stop listening on the given address with the given listener * Will change behavior depending on whether {@link #isBlockOnUnlisten()} is true or not. * Will call a blocking method if it is, a non-blocking one if it isn't - * @param input Input that should stop listening + * + * @param input Input that should stop listening * @param address Address on which the input should stop listening * @throws InterruptedException if interrupted while attempting to stop listening */ @@ -157,7 +160,8 @@ public class PipelineBus { /** * Stop listening on the given address with the given listener - * @param input Input that should stop listening + * + * @param input Input that should stop listening * @param address Address on which to stop listening * @throws InterruptedException if interrupted while attempting to stop listening */ @@ -185,7 +189,7 @@ public class PipelineBus { return state; }); - if (waiting[0] == false) { + if (!waiting[0]) { break; } else { Thread.sleep(100); @@ -195,14 +199,15 @@ public class PipelineBus { /** * Unlisten to use during reloads. This lets upstream outputs block while this input is missing - * @param input Input that should stop listening + * + * @param input Input that should stop listening * @param address Address on which to stop listening */ public void unlistenNonblock(final PipelineInput input, final String address) { addressStates.computeIfPresent(address, (k, state) -> { - state.unassignInput(input); - state.getOutputs().forEach(this::updateOutputReceivers); - return state.isEmpty() ? null : state; + state.unassignInput(input); + state.getOutputs().forEach(this::updateOutputReceivers); + return state.isEmpty() ? null : state; }); } diff --git a/logstash-core/src/main/java/org/logstash/plugins/pipeline/PipelineInput.java b/logstash-core/src/main/java/org/logstash/plugins/pipeline/PipelineInput.java index 0e63864a4..204958a8e 100644 --- a/logstash-core/src/main/java/org/logstash/plugins/pipeline/PipelineInput.java +++ b/logstash-core/src/main/java/org/logstash/plugins/pipeline/PipelineInput.java @@ -6,15 +6,14 @@ import java.util.stream.Stream; public interface PipelineInput { /** - * Accepts an event - * It might be rejected if the input is stopping + * Accepts an event. It might be rejected if the input is stopping. + * * @param events a collection of events * @return true if the event was successfully received */ boolean internalReceive(Stream events); /** - * * @return true if the input is running */ boolean isRunning(); diff --git a/logstash-core/src/main/java/org/logstash/plugins/pipeline/PipelineOutput.java b/logstash-core/src/main/java/org/logstash/plugins/pipeline/PipelineOutput.java index d80609496..0a110f379 100644 --- a/logstash-core/src/main/java/org/logstash/plugins/pipeline/PipelineOutput.java +++ b/logstash-core/src/main/java/org/logstash/plugins/pipeline/PipelineOutput.java @@ -1,9 +1,4 @@ package org.logstash.plugins.pipeline; -import org.logstash.ext.JrubyEventExtLibrary; - -import java.util.Map; -import java.util.function.Function; - public interface PipelineOutput { } From 9a5faf24bf1ea98c676ca7a1bcd4a2434b78471b Mon Sep 17 00:00:00 2001 From: Mike Place Date: Wed, 26 Jun 2019 22:58:20 +0200 Subject: [PATCH 0158/1126] Enhance GET _node/stats/pipelines API for Metricbeat monitoring (#10576) (#10909) * parent 8c5697c7485eeabb85ab00e972660d6190e6dae7 author Guy Boertje 1556806171 +0100 committer Mike Place 1557234770 +0200 Bump JrJackson to 0.4.8 Fixes #10748 LIR serializer refactor Remove commented code Remove more commented code Remove license and add encoding Style change to make code more vertical. eid and hash Use pipelines_info to construct the stats Add tests for new fields Add queue stats * bad merge resolution * bad merge resolution * Don't merge if nil * Better merge strategy * add vertex gate * Guard against nil * Use extended queue stats in pipeline report * Add cluster uuids to Elasticsearch outputters in pipeline output * move uuid * remove old uuid lookup * Only populate cluster_uuids when present * remove print * cluster_uuids -> cluster_uuid * Update logstash-core/lib/logstash/api/commands/stats.rb Co-Authored-By: Ry Biesemeyer * Update logstash-core/lib/logstash/api/commands/stats.rb Co-Authored-By: Ry Biesemeyer * Update logstash-core/lib/logstash/api/commands/stats.rb Co-Authored-By: Ry Biesemeyer * Make var singular * Match singular var name * Remove unnecessary nil check * Pass in the matching pipeline for the report * Remove old way of inserting cluster_uuids * Update logstash-core/lib/logstash/api/commands/stats.rb I like this much better and in testing it seems to work correctly. Co-Authored-By: Ry Biesemeyer * Remove unreferenced code that was part of debugging * Remove events var which was unused * Don't try to remove before insert * Update logstash-core/lib/logstash/api/commands/stats.rb Co-Authored-By: Ry Biesemeyer * Make pipeline extended stats generation more efficient * Implement suggestion to improve readability * Cleaner merging per review recommendation * Only generate extended_stats once * remove unneeded comments * Add cluster_uuid to node vertex * remove top-level cluster_uuids * Update logstash-core/lib/logstash/api/commands/stats.rb Co-Authored-By: Ry Biesemeyer * Implement change to make logic more simple suggested in review * Rely on options gate to insert graph Resolves concern here: https://github.com/elastic/logstash/pull/10576#issuecomment-501774635 * Update logstash-core/lib/logstash/api/commands/stats.rb Co-Authored-By: Ry Biesemeyer * Move UUID lookup to API layer * Move private method to bottom per review recommandation --- .../lib/logstash/api/commands/node.rb | 1 - .../lib/logstash/api/commands/stats.rb | 69 ++++++++++++++++--- .../lib/logstash/api/modules/node.rb | 6 +- .../lib/logstash/api/modules/node_stats.rb | 11 ++- .../lib/logstash/config/lir_serializer.rb | 1 + .../lib/logstash/config}/pipelines_info.rb | 19 +++-- .../inputs/metrics/state_event_factory.rb | 1 + .../inputs/metrics/stats_event_factory.rb | 4 +- 8 files changed, 90 insertions(+), 22 deletions(-) rename {x-pack/lib/monitoring/inputs/metrics/stats_event => logstash-core/lib/logstash/config}/pipelines_info.rb (92%) diff --git a/logstash-core/lib/logstash/api/commands/node.rb b/logstash-core/lib/logstash/api/commands/node.rb index e5b278f6f..00f5ecd7d 100644 --- a/logstash-core/lib/logstash/api/commands/node.rb +++ b/logstash-core/lib/logstash/api/commands/node.rb @@ -36,7 +36,6 @@ module LogStash :config_reload_interval, :dead_letter_queue_enabled, :dead_letter_queue_path, - :cluster_uuids ).reject{|_, v|v.nil?} if options.fetch(:graph, false) metrics.merge!(extract_metrics([:stats, :pipelines, pipeline_id.to_sym, :config], :graph)) diff --git a/logstash-core/lib/logstash/api/commands/stats.rb b/logstash-core/lib/logstash/api/commands/stats.rb index 3e43501a4..5f2871941 100644 --- a/logstash-core/lib/logstash/api/commands/stats.rb +++ b/logstash-core/lib/logstash/api/commands/stats.rb @@ -1,6 +1,7 @@ # encoding: utf-8 require "logstash/api/commands/base" require 'logstash/util/thread_dump' +require 'logstash/config/pipelines_info' require_relative "hot_threads_reporter" java_import java.nio.file.Files @@ -10,6 +11,20 @@ module LogStash module Api module Commands class Stats < Commands::Base + def queue + pipeline_ids = service.get_shallow(:stats, :pipelines).keys + total_queued_events = 0 + pipeline_ids.each do |pipeline_id| + p_stats = service.get_shallow(:stats, :pipelines, pipeline_id.to_sym) + type = p_stats[:queue] && p_stats[:queue][:type].value + pipeline = service.agent.get_pipeline(pipeline_id) + next if pipeline.nil? || pipeline.system? || type != 'persisted' + total_queued_events += p_stats[:queue][:events].value + end + + {:events_count => total_queued_events} + end + def jvm { :threads => extract_metrics( @@ -45,14 +60,24 @@ module LogStash ) end - def pipeline(pipeline_id = nil) + def pipeline(pipeline_id = nil, opts={}) + extended_stats = LogStash::Config::PipelinesInfo.format_pipelines_info( + service.agent, + service.snapshot.metric_store, + true).each_with_object({}) do |pipeline_stats, memo| + pipeline_id = pipeline_stats["id"].to_s + memo[pipeline_id] = pipeline_stats + end + if pipeline_id.nil? pipeline_ids = service.get_shallow(:stats, :pipelines).keys pipeline_ids.each_with_object({}) do |pipeline_id, result| - result[pipeline_id] = plugins_stats_report(pipeline_id) + extended_pipeline = extended_stats[pipeline_id.to_s] + result[pipeline_id] = plugins_stats_report(pipeline_id, extended_pipeline, opts) end else - { pipeline_id => plugins_stats_report(pipeline_id) } + extended_pipeline = extended_stats[pipeline_id.to_s] + { pipeline_id => plugins_stats_report(pipeline_id, extended_pipeline, opts) } end rescue # failed to find pipeline {} @@ -92,9 +117,9 @@ module LogStash end private - def plugins_stats_report(pipeline_id) + def plugins_stats_report(pipeline_id, extended_pipeline, opts={}) stats = service.get_shallow(:stats, :pipelines, pipeline_id.to_sym) - PluginsStats.report(stats) + PluginsStats.report(stats, extended_pipeline, opts) end module PluginsStats @@ -110,8 +135,8 @@ module LogStash end end - def report(stats) - { + def report(stats, extended_stats=nil, opts={}) + ret = { :events => stats[:events], :plugins => { :inputs => plugin_stats(stats, :inputs), @@ -121,8 +146,36 @@ module LogStash }, :reloads => stats[:reloads], :queue => stats[:queue] - }.merge(stats[:dlq] ? {:dead_letter_queue => stats[:dlq]} : {}) + } + ret[:dead_letter_queue] = stats[:dlq] if stats.include?(:dlq) + + # if extended_stats were provided, enrich the return value + if extended_stats + ret[:queue] = extended_stats["queue"] if extended_stats.include?("queue") + if opts[:vertices] && extended_stats.include?("vertices") + ret[:vertices] = extended_stats["vertices"].map { |vertex| decorate_vertex(vertex) } + end end + + ret + end + + ## + # Returns a vertex, decorated with additional metadata if available. + # Does not mutate the passed `vertex` object. + # @api private + # @param vertex [Hash{String=>Object}] + # @return [Hash{String=>Object}] + def decorate_vertex(vertex) + plugin_id = vertex["id"]&.to_s + return vertex unless plugin_id && LogStash::PluginMetadata.exists?(plugin_id) + + plugin_metadata = LogStash::PluginMetadata.for_plugin(plugin_id) + cluster_uuid = plugin_metadata&.get(:cluster_uuid) + vertex = vertex.merge("cluster_uuid" => cluster_uuid) unless cluster_uuid.nil? + + vertex + end end # module PluginsStats end end diff --git a/logstash-core/lib/logstash/api/modules/node.rb b/logstash-core/lib/logstash/api/modules/node.rb index d0553fe01..1846df5d4 100644 --- a/logstash-core/lib/logstash/api/modules/node.rb +++ b/logstash-core/lib/logstash/api/modules/node.rb @@ -29,14 +29,16 @@ module LogStash get "/pipelines/:id" do pipeline_id = params["id"] - opts = {:graph => as_boolean(params.fetch("graph", false))} + opts = {:graph => as_boolean(params.fetch("graph", false)), + :vertices => as_boolean(params.fetch("vertices", false))} payload = node.pipeline(pipeline_id, opts) halt(404) if payload.empty? respond_with(:pipelines => { pipeline_id => payload } ) end get "/pipelines" do - opts = {:graph => as_boolean(params.fetch("graph", false))} + opts = {:graph => as_boolean(params.fetch("graph", false)), + :vertices => as_boolean(params.fetch("vertices", false))} payload = node.pipelines(opts) halt(404) if payload.empty? respond_with(:pipelines => payload ) diff --git a/logstash-core/lib/logstash/api/modules/node_stats.rb b/logstash-core/lib/logstash/api/modules/node_stats.rb index 2a58fc7ae..42b02690c 100644 --- a/logstash-core/lib/logstash/api/modules/node_stats.rb +++ b/logstash-core/lib/logstash/api/modules/node_stats.rb @@ -21,11 +21,17 @@ module LogStash :events => events_payload, :pipelines => pipeline_payload, :reloads => reloads_payload, - :os => os_payload + :os => os_payload, + :queue => queue } respond_with(payload, {:filter => params["filter"]}) end + private + def queue + @stats.queue + end + private def os_payload @stats.os @@ -52,7 +58,8 @@ module LogStash end def pipeline_payload(val = nil) - @stats.pipeline(val) + opts = {:vertices => as_boolean(params.fetch("vertices", false))} + @stats.pipeline(val, opts) end end end diff --git a/logstash-core/lib/logstash/config/lir_serializer.rb b/logstash-core/lib/logstash/config/lir_serializer.rb index 82b1ce2ff..025055113 100644 --- a/logstash-core/lib/logstash/config/lir_serializer.rb +++ b/logstash-core/lib/logstash/config/lir_serializer.rb @@ -124,3 +124,4 @@ module LogStash; end end end + diff --git a/x-pack/lib/monitoring/inputs/metrics/stats_event/pipelines_info.rb b/logstash-core/lib/logstash/config/pipelines_info.rb similarity index 92% rename from x-pack/lib/monitoring/inputs/metrics/stats_event/pipelines_info.rb rename to logstash-core/lib/logstash/config/pipelines_info.rb index 9abd227b4..65faf2db6 100644 --- a/x-pack/lib/monitoring/inputs/metrics/stats_event/pipelines_info.rb +++ b/logstash-core/lib/logstash/config/pipelines_info.rb @@ -2,7 +2,7 @@ # or more contributor license agreements. Licensed under the Elastic License; # you may not use this file except in compliance with the Elastic License. # -module LogStash; module Inputs; class Metrics; module StatsEvent; +module LogStash; module Config; class PipelinesInfo def self.format_pipelines_info(agent, metric_store, extended_performance_collection) # It is important that we iterate via the agent's pipelines vs. the @@ -24,11 +24,9 @@ module LogStash; module Inputs; class Metrics; module StatsEvent; "failures" => p_stats[:reloads][:failures].value } } - if extended_performance_collection res["vertices"] = format_pipeline_vertex_stats(p_stats[:plugins], pipeline) end - res end.compact end @@ -93,11 +91,18 @@ module LogStash; module Inputs; class Metrics; module StatsEvent; acc end - - acc << { + segment = { :id => plugin_id, :pipeline_ephemeral_id => pipeline.ephemeral_id - }.merge(segmented) + } + + if LogStash::PluginMetadata.exists?(plugin_id.to_s) + plugin_metadata = LogStash::PluginMetadata.for_plugin(plugin_id.to_s) + cluster_uuid = plugin_metadata&.get(:cluster_uuid) + segment[:cluster_uuid] = cluster_uuid unless cluster_uuid.nil? + end + + acc << segment.merge(segmented) acc end end @@ -144,4 +149,4 @@ module LogStash; module Inputs; class Metrics; module StatsEvent; } end end -end; end; end; end +end; end; diff --git a/x-pack/lib/monitoring/inputs/metrics/state_event_factory.rb b/x-pack/lib/monitoring/inputs/metrics/state_event_factory.rb index 5d31d1c6c..175557b77 100644 --- a/x-pack/lib/monitoring/inputs/metrics/state_event_factory.rb +++ b/x-pack/lib/monitoring/inputs/metrics/state_event_factory.rb @@ -38,3 +38,4 @@ module LogStash; module Inputs; class Metrics; end end end; end; end + diff --git a/x-pack/lib/monitoring/inputs/metrics/stats_event_factory.rb b/x-pack/lib/monitoring/inputs/metrics/stats_event_factory.rb index ae55808da..a8d9a24b3 100644 --- a/x-pack/lib/monitoring/inputs/metrics/stats_event_factory.rb +++ b/x-pack/lib/monitoring/inputs/metrics/stats_event_factory.rb @@ -5,7 +5,7 @@ module LogStash; module Inputs; class Metrics; class StatsEventFactory include ::LogStash::Util::Loggable - require 'monitoring/inputs/metrics/stats_event/pipelines_info' + require 'logstash/config/pipelines_info' def initialize(global_stats, snapshot) @global_stats = global_stats @@ -19,7 +19,7 @@ module LogStash; module Inputs; class Metrics; "logstash" => fetch_node_stats(agent, @metric_store), "events" => format_global_event_count(@metric_store), "process" => format_process_stats(@metric_store), - "pipelines" => StatsEvent::PipelinesInfo.format_pipelines_info(agent, @metric_store, extended_performance_collection), + "pipelines" => LogStash::Config::PipelinesInfo.format_pipelines_info(agent, @metric_store, extended_performance_collection), "reloads" => format_reloads(@metric_store), "jvm" => format_jvm_stats(@metric_store), "os" => format_os_stats(@metric_store), From c9180826173a5396a1ade73d0978b3a9b3524106 Mon Sep 17 00:00:00 2001 From: Mike Place Date: Wed, 26 Jun 2019 23:05:33 +0200 Subject: [PATCH 0159/1126] Restore UUID lookup to node (#10884) (#10911) * Restore UUID lookup to node * Fix incorrect merge * Move private method to bottom * Change method name per review suggestion * Update method description --- .../lib/logstash/api/commands/node.rb | 23 ++++++++++++++++++- 1 file changed, 22 insertions(+), 1 deletion(-) diff --git a/logstash-core/lib/logstash/api/commands/node.rb b/logstash-core/lib/logstash/api/commands/node.rb index 00f5ecd7d..e76b41675 100644 --- a/logstash-core/lib/logstash/api/commands/node.rb +++ b/logstash-core/lib/logstash/api/commands/node.rb @@ -38,7 +38,10 @@ module LogStash :dead_letter_queue_path, ).reject{|_, v|v.nil?} if options.fetch(:graph, false) - metrics.merge!(extract_metrics([:stats, :pipelines, pipeline_id.to_sym, :config], :graph)) + extended_stats = extract_metrics([:stats, :pipelines, pipeline_id.to_sym, :config], :graph) + decorated_vertices = extended_stats[:graph]["graph"]["vertices"].map { |vertex| decorate_with_cluster_uuids(vertex) } + extended_stats[:graph]["graph"]["vertices"] = decorated_vertices + metrics.merge!(extended_stats) end metrics rescue @@ -77,6 +80,24 @@ module LogStash def hot_threads(options={}) HotThreadsReport.new(self, options) end + + private + ## + # Returns a vertex, decorated with the cluster UUID metadata retrieved from ES + # Does not mutate the passed `vertex` object. + # @api private + # @param vertex [Hash{String=>Object}] + # @return [Hash{String=>Object}] + def decorate_with_cluster_uuids(vertex) + plugin_id = vertex["id"]&.to_s + return vertex unless plugin_id && LogStash::PluginMetadata.exists?(plugin_id) + + plugin_metadata = LogStash::PluginMetadata.for_plugin(plugin_id) + cluster_uuid = plugin_metadata&.get(:cluster_uuid) + vertex = vertex.merge("cluster_uuid" => cluster_uuid) unless cluster_uuid.nil? + + vertex + end end end end From 20fc46551026cbac6af8431692e2d1ccd10770f6 Mon Sep 17 00:00:00 2001 From: Mike Place Date: Wed, 26 Jun 2019 23:14:14 +0200 Subject: [PATCH 0160/1126] Add workers and batch_size to root request (#10853) (#10910) * Add workers and batch_size to root request * Add batch delay per review recommendation --- logstash-core/lib/logstash/api/commands/default_metadata.rb | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/logstash-core/lib/logstash/api/commands/default_metadata.rb b/logstash-core/lib/logstash/api/commands/default_metadata.rb index 25a83ffc8..4dbea76c5 100644 --- a/logstash-core/lib/logstash/api/commands/default_metadata.rb +++ b/logstash-core/lib/logstash/api/commands/default_metadata.rb @@ -15,6 +15,11 @@ module LogStash :ephemeral_id => service.agent.ephemeral_id, :status => "green", # This is hard-coded to mirror x-pack behavior :snapshot => ::BUILD_INFO["build_snapshot"], + :pipeline => { + :workers => LogStash::SETTINGS.get("pipeline.workers"), + :batch_size => LogStash::SETTINGS.get("pipeline.batch.size"), + :batch_delay => LogStash::SETTINGS.get("pipeline.batch.delay"), + } } end From ed57c5dc5386f774b6daca3830e37506f0f103f2 Mon Sep 17 00:00:00 2001 From: Mike Place Date: Mon, 24 Jun 2019 13:08:42 +0200 Subject: [PATCH 0161/1126] Inject hash and ephemeral_id into stats Fixes #10885 --- logstash-core/lib/logstash/api/commands/stats.rb | 2 ++ 1 file changed, 2 insertions(+) diff --git a/logstash-core/lib/logstash/api/commands/stats.rb b/logstash-core/lib/logstash/api/commands/stats.rb index 5f2871941..461644b7a 100644 --- a/logstash-core/lib/logstash/api/commands/stats.rb +++ b/logstash-core/lib/logstash/api/commands/stats.rb @@ -152,6 +152,8 @@ module LogStash # if extended_stats were provided, enrich the return value if extended_stats ret[:queue] = extended_stats["queue"] if extended_stats.include?("queue") + ret[:hash] = extended_stats["hash"] + ret[:ephemeral_id] = extended_stats["ephemeral_id"] if opts[:vertices] && extended_stats.include?("vertices") ret[:vertices] = extended_stats["vertices"].map { |vertex| decorate_vertex(vertex) } end From beb0a337f96bcf8955ecaf657d326c26e17a9f61 Mon Sep 17 00:00:00 2001 From: Joao Duarte Date: Thu, 27 Jun 2019 10:58:03 +0100 Subject: [PATCH 0162/1126] remove gcs output from skip list Fixes #10919 --- rakelib/plugins-metadata.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/rakelib/plugins-metadata.json b/rakelib/plugins-metadata.json index 94d5c05ab..7f50b98ec 100644 --- a/rakelib/plugins-metadata.json +++ b/rakelib/plugins-metadata.json @@ -422,7 +422,7 @@ }, "logstash-output-google_cloud_storage": { "default-plugins": false, - "skip-list": true + "skip-list": false }, "logstash-output-graphite": { "default-plugins": true, From 357ce1339db24df175f93c0757c620879c935172 Mon Sep 17 00:00:00 2001 From: Mike Place Date: Fri, 28 Jun 2019 10:19:50 +0200 Subject: [PATCH 0163/1126] Inject hash and ephemeral_id into stats (#10885) (#10918) From 25b291e54e5b71d8d071eb0febeaf20ee9dc5c07 Mon Sep 17 00:00:00 2001 From: Dan Hermann Date: Wed, 12 Jun 2019 19:27:46 -0500 Subject: [PATCH 0164/1126] docs for Java plain codec Fixes #10870 --- .../core-plugins/codecs/java-plain.asciidoc | 54 +++++++++++++++++++ 1 file changed, 54 insertions(+) create mode 100644 docs/static/core-plugins/codecs/java-plain.asciidoc diff --git a/docs/static/core-plugins/codecs/java-plain.asciidoc b/docs/static/core-plugins/codecs/java-plain.asciidoc new file mode 100644 index 000000000..b2d819a97 --- /dev/null +++ b/docs/static/core-plugins/codecs/java-plain.asciidoc @@ -0,0 +1,54 @@ +:plugin: java_plain +:type: codec + +/////////////////////////////////////////// +START - GENERATED VARIABLES, DO NOT EDIT! +/////////////////////////////////////////// +:version: %VERSION% +:release_date: %RELEASE_DATE% +:changelog_url: %CHANGELOG_URL% +:include_path: ../../../../logstash/docs/include +/////////////////////////////////////////// +END - GENERATED VARIABLES, DO NOT EDIT! +/////////////////////////////////////////// + +[id="plugins-{type}s-{plugin}"] + +=== Java plain codec plugin + +include::{include_path}/plugin_header.asciidoc[] + +==== Description + +The `java_plain` codec is for text data with no delimiters between events. It is useful mainly for inputs and outputs that +already have a defined framing in their transport protocol such as ZeroMQ, RabbitMQ, Redis, etc. + +[id="plugins-{type}s-{plugin}-options"] +==== Plain Codec Configuration Options + +[cols="<,<,<",options="header",] +|======================================================================= +|Setting |Input type|Required +| <> |<>, one of `["ASCII-8BIT", "UTF-8", "US-ASCII", "Big5", "Big5-HKSCS", "Big5-UAO", "CP949", "Emacs-Mule", "EUC-JP", "EUC-KR", "EUC-TW", "GB2312", "GB18030", "GBK", "ISO-8859-1", "ISO-8859-2", "ISO-8859-3", "ISO-8859-4", "ISO-8859-5", "ISO-8859-6", "ISO-8859-7", "ISO-8859-8", "ISO-8859-9", "ISO-8859-10", "ISO-8859-11", "ISO-8859-13", "ISO-8859-14", "ISO-8859-15", "ISO-8859-16", "KOI8-R", "KOI8-U", "Shift_JIS", "UTF-16BE", "UTF-16LE", "UTF-32BE", "UTF-32LE", "Windows-31J", "Windows-1250", "Windows-1251", "Windows-1252", "IBM437", "IBM737", "IBM775", "CP850", "IBM852", "CP852", "IBM855", "CP855", "IBM857", "IBM860", "IBM861", "IBM862", "IBM863", "IBM864", "IBM865", "IBM866", "IBM869", "Windows-1258", "GB1988", "macCentEuro", "macCroatian", "macCyrillic", "macGreek", "macIceland", "macRoman", "macRomania", "macThai", "macTurkish", "macUkraine", "CP950", "CP951", "IBM037", "stateless-ISO-2022-JP", "eucJP-ms", "CP51932", "EUC-JIS-2004", "GB12345", "ISO-2022-JP", "ISO-2022-JP-2", "CP50220", "CP50221", "Windows-1256", "Windows-1253", "Windows-1255", "Windows-1254", "TIS-620", "Windows-874", "Windows-1257", "MacJapanese", "UTF-7", "UTF8-MAC", "UTF-16", "UTF-32", "UTF8-DoCoMo", "SJIS-DoCoMo", "UTF8-KDDI", "SJIS-KDDI", "ISO-2022-JP-KDDI", "stateless-ISO-2022-JP-KDDI", "UTF8-SoftBank", "SJIS-SoftBank", "BINARY", "CP437", "CP737", "CP775", "IBM850", "CP857", "CP860", "CP861", "CP862", "CP863", "CP864", "CP865", "CP866", "CP869", "CP1258", "Big5-HKSCS:2008", "ebcdic-cp-us", "eucJP", "euc-jp-ms", "EUC-JISX0213", "eucKR", "eucTW", "EUC-CN", "eucCN", "CP936", "ISO2022-JP", "ISO2022-JP2", "ISO8859-1", "ISO8859-2", "ISO8859-3", "ISO8859-4", "ISO8859-5", "ISO8859-6", "CP1256", "ISO8859-7", "CP1253", "ISO8859-8", "CP1255", "ISO8859-9", "CP1254", "ISO8859-10", "ISO8859-11", "CP874", "ISO8859-13", "CP1257", "ISO8859-14", "ISO8859-15", "ISO8859-16", "CP878", "MacJapan", "ASCII", "ANSI_X3.4-1968", "646", "CP65000", "CP65001", "UTF-8-MAC", "UTF-8-HFS", "UCS-2BE", "UCS-4BE", "UCS-4LE", "CP932", "csWindows31J", "SJIS", "PCK", "CP1250", "CP1251", "CP1252", "external", "locale"]`|No +| <> |<>|No +|======================================================================= + +  + +[id="plugins-{type}s-{plugin}-charset"] +===== `charset` + + * Value can be any of: `ASCII-8BIT`, `UTF-8`, `US-ASCII`, `Big5`, `Big5-HKSCS`, `Big5-UAO`, `CP949`, `Emacs-Mule`, `EUC-JP`, `EUC-KR`, `EUC-TW`, `GB2312`, `GB18030`, `GBK`, `ISO-8859-1`, `ISO-8859-2`, `ISO-8859-3`, `ISO-8859-4`, `ISO-8859-5`, `ISO-8859-6`, `ISO-8859-7`, `ISO-8859-8`, `ISO-8859-9`, `ISO-8859-10`, `ISO-8859-11`, `ISO-8859-13`, `ISO-8859-14`, `ISO-8859-15`, `ISO-8859-16`, `KOI8-R`, `KOI8-U`, `Shift_JIS`, `UTF-16BE`, `UTF-16LE`, `UTF-32BE`, `UTF-32LE`, `Windows-31J`, `Windows-1250`, `Windows-1251`, `Windows-1252`, `IBM437`, `IBM737`, `IBM775`, `CP850`, `IBM852`, `CP852`, `IBM855`, `CP855`, `IBM857`, `IBM860`, `IBM861`, `IBM862`, `IBM863`, `IBM864`, `IBM865`, `IBM866`, `IBM869`, `Windows-1258`, `GB1988`, `macCentEuro`, `macCroatian`, `macCyrillic`, `macGreek`, `macIceland`, `macRoman`, `macRomania`, `macThai`, `macTurkish`, `macUkraine`, `CP950`, `CP951`, `IBM037`, `stateless-ISO-2022-JP`, `eucJP-ms`, `CP51932`, `EUC-JIS-2004`, `GB12345`, `ISO-2022-JP`, `ISO-2022-JP-2`, `CP50220`, `CP50221`, `Windows-1256`, `Windows-1253`, `Windows-1255`, `Windows-1254`, `TIS-620`, `Windows-874`, `Windows-1257`, `MacJapanese`, `UTF-7`, `UTF8-MAC`, `UTF-16`, `UTF-32`, `UTF8-DoCoMo`, `SJIS-DoCoMo`, `UTF8-KDDI`, `SJIS-KDDI`, `ISO-2022-JP-KDDI`, `stateless-ISO-2022-JP-KDDI`, `UTF8-SoftBank`, `SJIS-SoftBank`, `BINARY`, `CP437`, `CP737`, `CP775`, `IBM850`, `CP857`, `CP860`, `CP861`, `CP862`, `CP863`, `CP864`, `CP865`, `CP866`, `CP869`, `CP1258`, `Big5-HKSCS:2008`, `ebcdic-cp-us`, `eucJP`, `euc-jp-ms`, `EUC-JISX0213`, `eucKR`, `eucTW`, `EUC-CN`, `eucCN`, `CP936`, `ISO2022-JP`, `ISO2022-JP2`, `ISO8859-1`, `ISO8859-2`, `ISO8859-3`, `ISO8859-4`, `ISO8859-5`, `ISO8859-6`, `CP1256`, `ISO8859-7`, `CP1253`, `ISO8859-8`, `CP1255`, `ISO8859-9`, `CP1254`, `ISO8859-10`, `ISO8859-11`, `CP874`, `ISO8859-13`, `CP1257`, `ISO8859-14`, `ISO8859-15`, `ISO8859-16`, `CP878`, `MacJapan`, `ASCII`, `ANSI_X3.4-1968`, `646`, `CP65000`, `CP65001`, `UTF-8-MAC`, `UTF-8-HFS`, `UCS-2BE`, `UCS-4BE`, `UCS-4LE`, `CP932`, `csWindows31J`, `SJIS`, `PCK`, `CP1250`, `CP1251`, `CP1252`, `external`, `locale` + * Default value is `"UTF-8"` + +The character encoding used in this input. Examples include `UTF-8` and `cp1252`. This setting is useful if your data +is in a character set other than `UTF-8`. + +[id="plugins-{type}s-{plugin}-format"] +===== `format` + + * Value type is <> + * There is no default value for this setting. + +Set the desired text format for encoding in +https://www.elastic.co/guide/en/logstash/current/event-dependent-configuration.html#sprintf[`sprintf`] format. From df7c7d07deb5178f12edc4c24240c06dcaa867d5 Mon Sep 17 00:00:00 2001 From: Dan Hermann Date: Wed, 12 Jun 2019 19:20:06 -0500 Subject: [PATCH 0165/1126] docs for Java line codec Fixes #10869 --- .../core-plugins/codecs/java-line.asciidoc | 66 +++++++++++++++++++ 1 file changed, 66 insertions(+) create mode 100644 docs/static/core-plugins/codecs/java-line.asciidoc diff --git a/docs/static/core-plugins/codecs/java-line.asciidoc b/docs/static/core-plugins/codecs/java-line.asciidoc new file mode 100644 index 000000000..d769b1b6a --- /dev/null +++ b/docs/static/core-plugins/codecs/java-line.asciidoc @@ -0,0 +1,66 @@ +:plugin: java_line +:type: codec + +/////////////////////////////////////////// +START - GENERATED VARIABLES, DO NOT EDIT! +/////////////////////////////////////////// +:version: %VERSION% +:release_date: %RELEASE_DATE% +:changelog_url: %CHANGELOG_URL% +:include_path: ../../../../logstash/docs/include +/////////////////////////////////////////// +END - GENERATED VARIABLES, DO NOT EDIT! +/////////////////////////////////////////// + +[id="plugins-{type}s-{plugin}"] + +=== Java line codec plugin + +include::{include_path}/plugin_header.asciidoc[] + +==== Description + +Encodes and decodes line-oriented text data. + +Decoding behavior: All text data between specified delimiters will be decoded as distinct events. + +Encoding behavior: Each event will be emitted with the specified trailing delimiter. + +[id="plugins-{type}s-{plugin}-options"] +==== Line Codec Configuration Options + +[cols="<,<,<",options="header",] +|======================================================================= +|Setting |Input type|Required +| <> |<>, one of `["ASCII-8BIT", "UTF-8", "US-ASCII", "Big5", "Big5-HKSCS", "Big5-UAO", "CP949", "Emacs-Mule", "EUC-JP", "EUC-KR", "EUC-TW", "GB2312", "GB18030", "GBK", "ISO-8859-1", "ISO-8859-2", "ISO-8859-3", "ISO-8859-4", "ISO-8859-5", "ISO-8859-6", "ISO-8859-7", "ISO-8859-8", "ISO-8859-9", "ISO-8859-10", "ISO-8859-11", "ISO-8859-13", "ISO-8859-14", "ISO-8859-15", "ISO-8859-16", "KOI8-R", "KOI8-U", "Shift_JIS", "UTF-16BE", "UTF-16LE", "UTF-32BE", "UTF-32LE", "Windows-31J", "Windows-1250", "Windows-1251", "Windows-1252", "IBM437", "IBM737", "IBM775", "CP850", "IBM852", "CP852", "IBM855", "CP855", "IBM857", "IBM860", "IBM861", "IBM862", "IBM863", "IBM864", "IBM865", "IBM866", "IBM869", "Windows-1258", "GB1988", "macCentEuro", "macCroatian", "macCyrillic", "macGreek", "macIceland", "macRoman", "macRomania", "macThai", "macTurkish", "macUkraine", "CP950", "CP951", "IBM037", "stateless-ISO-2022-JP", "eucJP-ms", "CP51932", "EUC-JIS-2004", "GB12345", "ISO-2022-JP", "ISO-2022-JP-2", "CP50220", "CP50221", "Windows-1256", "Windows-1253", "Windows-1255", "Windows-1254", "TIS-620", "Windows-874", "Windows-1257", "MacJapanese", "UTF-7", "UTF8-MAC", "UTF-16", "UTF-32", "UTF8-DoCoMo", "SJIS-DoCoMo", "UTF8-KDDI", "SJIS-KDDI", "ISO-2022-JP-KDDI", "stateless-ISO-2022-JP-KDDI", "UTF8-SoftBank", "SJIS-SoftBank", "BINARY", "CP437", "CP737", "CP775", "IBM850", "CP857", "CP860", "CP861", "CP862", "CP863", "CP864", "CP865", "CP866", "CP869", "CP1258", "Big5-HKSCS:2008", "ebcdic-cp-us", "eucJP", "euc-jp-ms", "EUC-JISX0213", "eucKR", "eucTW", "EUC-CN", "eucCN", "CP936", "ISO2022-JP", "ISO2022-JP2", "ISO8859-1", "ISO8859-2", "ISO8859-3", "ISO8859-4", "ISO8859-5", "ISO8859-6", "CP1256", "ISO8859-7", "CP1253", "ISO8859-8", "CP1255", "ISO8859-9", "CP1254", "ISO8859-10", "ISO8859-11", "CP874", "ISO8859-13", "CP1257", "ISO8859-14", "ISO8859-15", "ISO8859-16", "CP878", "MacJapan", "ASCII", "ANSI_X3.4-1968", "646", "CP65000", "CP65001", "UTF-8-MAC", "UTF-8-HFS", "UCS-2BE", "UCS-4BE", "UCS-4LE", "CP932", "csWindows31J", "SJIS", "PCK", "CP1250", "CP1251", "CP1252", "external", "locale"]`|No +| <> |<>|No +| <> |<>|No +|======================================================================= + +  + +[id="plugins-{type}s-{plugin}-charset"] +===== `charset` + + * Value can be any of: `ASCII-8BIT`, `UTF-8`, `US-ASCII`, `Big5`, `Big5-HKSCS`, `Big5-UAO`, `CP949`, `Emacs-Mule`, `EUC-JP`, `EUC-KR`, `EUC-TW`, `GB2312`, `GB18030`, `GBK`, `ISO-8859-1`, `ISO-8859-2`, `ISO-8859-3`, `ISO-8859-4`, `ISO-8859-5`, `ISO-8859-6`, `ISO-8859-7`, `ISO-8859-8`, `ISO-8859-9`, `ISO-8859-10`, `ISO-8859-11`, `ISO-8859-13`, `ISO-8859-14`, `ISO-8859-15`, `ISO-8859-16`, `KOI8-R`, `KOI8-U`, `Shift_JIS`, `UTF-16BE`, `UTF-16LE`, `UTF-32BE`, `UTF-32LE`, `Windows-31J`, `Windows-1250`, `Windows-1251`, `Windows-1252`, `IBM437`, `IBM737`, `IBM775`, `CP850`, `IBM852`, `CP852`, `IBM855`, `CP855`, `IBM857`, `IBM860`, `IBM861`, `IBM862`, `IBM863`, `IBM864`, `IBM865`, `IBM866`, `IBM869`, `Windows-1258`, `GB1988`, `macCentEuro`, `macCroatian`, `macCyrillic`, `macGreek`, `macIceland`, `macRoman`, `macRomania`, `macThai`, `macTurkish`, `macUkraine`, `CP950`, `CP951`, `IBM037`, `stateless-ISO-2022-JP`, `eucJP-ms`, `CP51932`, `EUC-JIS-2004`, `GB12345`, `ISO-2022-JP`, `ISO-2022-JP-2`, `CP50220`, `CP50221`, `Windows-1256`, `Windows-1253`, `Windows-1255`, `Windows-1254`, `TIS-620`, `Windows-874`, `Windows-1257`, `MacJapanese`, `UTF-7`, `UTF8-MAC`, `UTF-16`, `UTF-32`, `UTF8-DoCoMo`, `SJIS-DoCoMo`, `UTF8-KDDI`, `SJIS-KDDI`, `ISO-2022-JP-KDDI`, `stateless-ISO-2022-JP-KDDI`, `UTF8-SoftBank`, `SJIS-SoftBank`, `BINARY`, `CP437`, `CP737`, `CP775`, `IBM850`, `CP857`, `CP860`, `CP861`, `CP862`, `CP863`, `CP864`, `CP865`, `CP866`, `CP869`, `CP1258`, `Big5-HKSCS:2008`, `ebcdic-cp-us`, `eucJP`, `euc-jp-ms`, `EUC-JISX0213`, `eucKR`, `eucTW`, `EUC-CN`, `eucCN`, `CP936`, `ISO2022-JP`, `ISO2022-JP2`, `ISO8859-1`, `ISO8859-2`, `ISO8859-3`, `ISO8859-4`, `ISO8859-5`, `ISO8859-6`, `CP1256`, `ISO8859-7`, `CP1253`, `ISO8859-8`, `CP1255`, `ISO8859-9`, `CP1254`, `ISO8859-10`, `ISO8859-11`, `CP874`, `ISO8859-13`, `CP1257`, `ISO8859-14`, `ISO8859-15`, `ISO8859-16`, `CP878`, `MacJapan`, `ASCII`, `ANSI_X3.4-1968`, `646`, `CP65000`, `CP65001`, `UTF-8-MAC`, `UTF-8-HFS`, `UCS-2BE`, `UCS-4BE`, `UCS-4LE`, `CP932`, `csWindows31J`, `SJIS`, `PCK`, `CP1250`, `CP1251`, `CP1252`, `external`, `locale` + * Default value is `"UTF-8"` + +The character encoding used by this input. Examples include `UTF-8` and `cp1252`. This setting is useful if your +inputs are in `Latin-1` (aka `cp1252`) or other character sets than `UTF-8`. + +[id="plugins-{type}s-{plugin}-delimiter"] +===== `delimiter` + + * Value type is <> + * Default value is the system-dependent line separator ("\n" for UNIX systems; "\r\n" for Microsoft Windows) + +Specifies the delimiter that indicates end-of-line. + +[id="plugins-{type}s-{plugin}-format"] +===== `format` + + * Value type is <> + * There is no default value for this setting. + +Set the desired text format for encoding in +https://www.elastic.co/guide/en/logstash/current/event-dependent-configuration.html#sprintf[`sprintf`] format. From df4ffd58904a37bc7f56bd669e475494819f531b Mon Sep 17 00:00:00 2001 From: Dan Hermann Date: Wed, 12 Jun 2019 19:05:14 -0500 Subject: [PATCH 0166/1126] docs for java dots codec Fixes #10868 --- .../core-plugins/codecs/java-dots.asciidoc | 27 +++++++++++++++++++ 1 file changed, 27 insertions(+) create mode 100644 docs/static/core-plugins/codecs/java-dots.asciidoc diff --git a/docs/static/core-plugins/codecs/java-dots.asciidoc b/docs/static/core-plugins/codecs/java-dots.asciidoc new file mode 100644 index 000000000..6e9b04f7d --- /dev/null +++ b/docs/static/core-plugins/codecs/java-dots.asciidoc @@ -0,0 +1,27 @@ +:plugin: jdots +:type: codec + +/////////////////////////////////////////// +START - GENERATED VARIABLES, DO NOT EDIT! +/////////////////////////////////////////// +:version: %VERSION% +:release_date: %RELEASE_DATE% +:changelog_url: %CHANGELOG_URL% +:include_path: ../../../../logstash/docs/include +/////////////////////////////////////////// +END - GENERATED VARIABLES, DO NOT EDIT! +/////////////////////////////////////////// + +[id="plugins-{type}s-{plugin}"] + +=== Java dots codec plugin + +include::{include_path}/plugin_header.asciidoc[] + +==== Description + +This codec renders each processed event as a dot (`.`). It is typically used with the `java_stdout` output to provide +approximate event throughput. It is especially useful when combined with `pv` and `wc -c` as follows: + +[source,bash] + bin/logstash -f /path/to/config/with/jdots/codec | pv | wc -c From f280f48f898fe759db97c17a8aef8eb43c625cfc Mon Sep 17 00:00:00 2001 From: Dan Hermann Date: Wed, 12 Jun 2019 18:54:14 -0500 Subject: [PATCH 0167/1126] docs for Java sink output Fixes #10867 --- .../core-plugins/outputs/java-sink.asciidoc | 36 +++++++++++++++++++ 1 file changed, 36 insertions(+) create mode 100644 docs/static/core-plugins/outputs/java-sink.asciidoc diff --git a/docs/static/core-plugins/outputs/java-sink.asciidoc b/docs/static/core-plugins/outputs/java-sink.asciidoc new file mode 100644 index 000000000..e52b2e8ed --- /dev/null +++ b/docs/static/core-plugins/outputs/java-sink.asciidoc @@ -0,0 +1,36 @@ +:plugin: sink +:type: output +:default_codec!: + +/////////////////////////////////////////// +START - GENERATED VARIABLES, DO NOT EDIT! +/////////////////////////////////////////// +:version: %VERSION% +:release_date: %RELEASE_DATE% +:changelog_url: %CHANGELOG_URL% +:include_path: ../../../../logstash/docs/include +/////////////////////////////////////////// +END - GENERATED VARIABLES, DO NOT EDIT! +/////////////////////////////////////////// + +[id="plugins-{type}s-{plugin}"] + +=== Sink output plugin + +include::{include_path}/plugin_header.asciidoc[] + +==== Description + +An event sink that discards any events received. Generally useful for testing the performance of inputs +and filters. + +[id="plugins-{type}s-{plugin}-options"] +==== Sink Output Configuration Options + +There are no special configuration options for this plugin, +but it does support the <>. + +[id="plugins-{type}s-{plugin}-common-options"] +include::{include_path}/{type}.asciidoc[] + +:default_codec!: \ No newline at end of file From 82f3b3cb78d6047d7b00000ae67e6e10ea7924b3 Mon Sep 17 00:00:00 2001 From: Dan Hermann Date: Wed, 12 Jun 2019 18:44:44 -0500 Subject: [PATCH 0168/1126] docs for java stdout output Fixes #10866 --- .../core-plugins/outputs/java-stdout.asciidoc | 53 +++++++++++++++++++ 1 file changed, 53 insertions(+) create mode 100644 docs/static/core-plugins/outputs/java-stdout.asciidoc diff --git a/docs/static/core-plugins/outputs/java-stdout.asciidoc b/docs/static/core-plugins/outputs/java-stdout.asciidoc new file mode 100644 index 000000000..c040c3451 --- /dev/null +++ b/docs/static/core-plugins/outputs/java-stdout.asciidoc @@ -0,0 +1,53 @@ +:plugin: java_stdout +:type: output +:default_codec: java_line + +/////////////////////////////////////////// +START - GENERATED VARIABLES, DO NOT EDIT! +/////////////////////////////////////////// +:version: %VERSION% +:release_date: %RELEASE_DATE% +:changelog_url: %CHANGELOG_URL% +:include_path: ../../../../logstash/docs/include +/////////////////////////////////////////// +END - GENERATED VARIABLES, DO NOT EDIT! +/////////////////////////////////////////// + +[id="plugins-{type}s-{plugin}"] + +=== Java stdout output plugin + +include::{include_path}/plugin_header.asciidoc[] + +==== Description + +Prints events to the STDOUT of the shell running Logstash. This output is convenient for debugging +plugin configurations by providing instant access to event data after it has passed through the inputs and filters. + +For example, the following output configuration in conjunction with the Logstash `-e` command-line flag, will +allow you to see the results of your event pipeline for quick iteration. +[source,ruby] + output { + java_stdout {} + } + +Useful codecs include: + +`java_line`: outputs event data in JSON format followed by an end-of-line character. This is the default codec for +java_stdout. + +[source,ruby] + output { + stdout { } + } + +[id="plugins-{type}s-{plugin}-options"] +==== Stdout Output Configuration Options + +There are no special configuration options for this plugin, +but it does support the <>. + +[id="plugins-{type}s-{plugin}-common-options"] +include::{include_path}/{type}.asciidoc[] + +:default_codec!: \ No newline at end of file From 6669e2bd19848a9080f9e8f4f1ed8d7608fe12df Mon Sep 17 00:00:00 2001 From: Dan Hermann Date: Wed, 12 Jun 2019 18:31:35 -0500 Subject: [PATCH 0169/1126] docs for java stdin input Fixes #10858 --- .../core-plugins/inputs/java-stdin.asciidoc | 38 +++++++++++++++++++ 1 file changed, 38 insertions(+) create mode 100644 docs/static/core-plugins/inputs/java-stdin.asciidoc diff --git a/docs/static/core-plugins/inputs/java-stdin.asciidoc b/docs/static/core-plugins/inputs/java-stdin.asciidoc new file mode 100644 index 000000000..e103cc094 --- /dev/null +++ b/docs/static/core-plugins/inputs/java-stdin.asciidoc @@ -0,0 +1,38 @@ +:plugin: java_stdin +:type: input +:default_codec: java_line + +/////////////////////////////////////////// +START - GENERATED VARIABLES, DO NOT EDIT! +/////////////////////////////////////////// +:version: %VERSION% +:release_date: %RELEASE_DATE% +:changelog_url: %CHANGELOG_URL% +:include_path: ../../../../logstash/docs/include +/////////////////////////////////////////// +END - GENERATED VARIABLES, DO NOT EDIT! +/////////////////////////////////////////// + +[id="plugins-{type}s-{plugin}"] + +=== Java stdin input plugin + +include::{include_path}/plugin_header.asciidoc[] + +==== Description + +Read events from standard input. + +By default, each event is assumed to be terminated by end-of-line. If you want events delimited in a different +method, you'll need to use a codec with support for that encoding. + +[id="plugins-{type}s-{plugin}-options"] +==== Stdin Input Configuration Options + +There are no special configuration options for this plugin, +but it does support the <>. + +[id="plugins-{type}s-{plugin}-common-options"] +include::{include_path}/{type}.asciidoc[] + +:default_codec!: \ No newline at end of file From 241d8b68b1fdd51aaa9b431f0df1a380e83dbf20 Mon Sep 17 00:00:00 2001 From: Dan Hermann Date: Wed, 12 Jun 2019 17:57:02 -0500 Subject: [PATCH 0170/1126] docs for java_generator input Fixes #10857 --- .../inputs/java-generator.asciidoc | 120 ++++++++++++++++++ 1 file changed, 120 insertions(+) create mode 100644 docs/static/core-plugins/inputs/java-generator.asciidoc diff --git a/docs/static/core-plugins/inputs/java-generator.asciidoc b/docs/static/core-plugins/inputs/java-generator.asciidoc new file mode 100644 index 000000000..d3b9b422e --- /dev/null +++ b/docs/static/core-plugins/inputs/java-generator.asciidoc @@ -0,0 +1,120 @@ +:plugin: java_generator +:type: input +:default_codec: plain + +/////////////////////////////////////////// +START - GENERATED VARIABLES, DO NOT EDIT! +/////////////////////////////////////////// +:version: %VERSION% +:release_date: %RELEASE_DATE% +:changelog_url: %CHANGELOG_URL% +:include_path: ../../../../logstash/docs/include +/////////////////////////////////////////// +END - GENERATED VARIABLES, DO NOT EDIT! +/////////////////////////////////////////// + +[id="plugins-{type}s-{plugin}"] + +=== Java generator input plugin + +include::{include_path}/plugin_header.asciidoc[] + +==== Description + +Generate synthethic log events. + +This plugin generates a stream of synthetic events that can be used to test the correctness or performance of a +Logstash pipeline. + + +[id="plugins-{type}s-{plugin}-options"] +==== Generator Input Configuration Options + +This plugin supports the following configuration options plus the <> described later. + +[cols="<,<,<",options="header",] +|======================================================================= +|Setting |Input type|Required +| <> |<>|No +| <> |<>|No +| <> |<>|No +| <> |<>|No +| <> |<>|No +|======================================================================= + +Also see <> for a list of options supported by all +input plugins. + +  + +[id="plugins-{type}s-{plugin}-count"] +===== `count` + + * Value type is <> + * Default value is `0` + +Sets the number of events that should be generated. + +The default, `0`, means generate an unlimited number of events. + +[id="plugins-{type}s-{plugin}-eps"] +===== `eps` + + * Value type is <> + * Default value is `0` + +Sets the rate at which events should be generated. Fractional values may be specified. For +example, a rate of `0.25` means that one event will be generated every four seconds. + +The default, `0`, means generate events as fast as possible. + +[id="plugins-{type}s-{plugin}-lines"] +===== `lines` + + * Value type is <> + * There is no default value for this setting. + +The lines to emit, in order. This option overrides the 'message' setting if it has also been specified. + +Example: +[source,ruby] + input { + java_generator { + lines => [ + "line 1", + "line 2", + "line 3" + ] + # Emit all lines 2 times. + count => 2 + } + } + +The above will emit a series of three events `line 1` then `line 2` then `line 3` two times for a total of 6 events. + +[id="plugins-{type}s-{plugin}-message"] +===== `message` + + * Value type is <> + * Default value is `"Hello world!"` + +The message string to use in the event. + +[id="plugins-{type}s-{plugin}-threads"] +===== `threads` + + * Value type is <> + * Default value is `1` + +Increasing the number of generator threads up to about the number of CPU cores generally increases overall event +throughput. The `count`, `eps`, and `lines` settings all apply on a per-thread basis. In other words, each thread +will emit the number of events specified in the `count` setting for a total of `threads * count` events. Each thread +will emit events at the `eps` rate for a total rate of `threads * eps`, and each thread will emit each line specified +in the `lines` option. + + + +[id="plugins-{type}s-{plugin}-common-options"] +include::{include_path}/{type}.asciidoc[] + +:default_codec!: \ No newline at end of file From 2e3254d8322de748d1e7495f3b3b3020e3b002d8 Mon Sep 17 00:00:00 2001 From: Dan Hermann Date: Wed, 12 Jun 2019 18:39:11 -0500 Subject: [PATCH 0171/1126] docs for the Java UUID filter Fixes #10859 --- .../filters/java-uuid-filter.asciidoc | 93 +++++++++++++++++++ 1 file changed, 93 insertions(+) create mode 100644 docs/static/core-plugins/filters/java-uuid-filter.asciidoc diff --git a/docs/static/core-plugins/filters/java-uuid-filter.asciidoc b/docs/static/core-plugins/filters/java-uuid-filter.asciidoc new file mode 100644 index 000000000..9df103917 --- /dev/null +++ b/docs/static/core-plugins/filters/java-uuid-filter.asciidoc @@ -0,0 +1,93 @@ +:plugin: java_uuid +:type: filter + +/////////////////////////////////////////// +START - GENERATED VARIABLES, DO NOT EDIT! +/////////////////////////////////////////// +:version: %VERSION% +:release_date: %RELEASE_DATE% +:changelog_url: %CHANGELOG_URL% +:include_path: ../../../../logstash/docs/include +/////////////////////////////////////////// +END - GENERATED VARIABLES, DO NOT EDIT! +/////////////////////////////////////////// + +[id="plugins-{type}s-{plugin}"] + +=== Java UUID filter plugin + +include::{include_path}/plugin_header.asciidoc[] + +==== Description + +The uuid filter allows you to generate a +https://en.wikipedia.org/wiki/Universally_unique_identifier[UUID] +and add it as a field to each processed event. + +This is useful if you need to generate a string that's unique for every +event even if the same input is processed multiple times. If you want +to generate strings that are identical each time an event with the same +content is processed (i.e., a hash), you should use the +{logstash-ref}/plugins-filters-fingerprint.html[fingerprint filter] instead. + +The generated UUIDs follow the version 4 definition in +https://tools.ietf.org/html/rfc4122[RFC 4122] and will be +represented in standard hexadecimal string format, e.g. +"e08806fe-02af-406c-bbde-8a5ae4475e57". + +[id="plugins-{type}s-{plugin}-options"] +==== Uuid Filter Configuration Options + +This plugin supports the following configuration options plus the <> described later. + +[cols="<,<,<",options="header",] +|======================================================================= +|Setting |Input type|Required +| <> |<>|No +| <> |<>|Yes +|======================================================================= + +Also see <> for a list of options supported by all +filter plugins. + +  + +[id="plugins-{type}s-{plugin}-overwrite"] +===== `overwrite` + + * Value type is <> + * Default value is `false` + +Determines if an existing value in the field specified by the `target` option should +be overwritten by the filter. + +Example: +[source,ruby] + filter { + java_uuid { + target => "uuid" + overwrite => true + } + } + +[id="plugins-{type}s-{plugin}-target"] +===== `target` + + * This is a required setting. + * Value type is <> + * There is no default value for this setting. + +Specifies the name of the field in which the generated UUID should be stored. + +Example: +[source,ruby] + filter { + java_uuid { + target => "uuid" + } + } + + + +[id="plugins-{type}s-{plugin}-common-options"] +include::{include_path}/{type}.asciidoc[] \ No newline at end of file From ec07b43a53c0e13c1336d9be9e412b5c8e7bc4dc Mon Sep 17 00:00:00 2001 From: Karen Metts Date: Fri, 28 Jun 2019 12:04:17 -0400 Subject: [PATCH 0172/1126] Add java example plugins to skiplist Fixes #10921 --- rakelib/plugins-metadata.json | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) diff --git a/rakelib/plugins-metadata.json b/rakelib/plugins-metadata.json index 7f50b98ec..c6bd39451 100644 --- a/rakelib/plugins-metadata.json +++ b/rakelib/plugins-metadata.json @@ -39,6 +39,10 @@ "default-plugins": true, "skip-list": false }, + "logstash-codec-java_codec_example": { + "default-plugins": false, + "skip-list": true + }, "logstash-codec-json": { "default-plugins": true, "skip-list": false @@ -139,6 +143,10 @@ "default-plugins": true, "skip-list": false }, + "logstash-filter-java_filter_example": { + "default-plugins": false, + "skip-list": true + }, "logstash-filter-jdbc_static": { "default-plugins": true, "skip-list": false @@ -304,6 +312,10 @@ "default-plugins": true, "skip-list": false }, + "logstash-input-java_input_example": { + "default-plugins": false, + "skip-list": true + }, "logstash-input-jdbc": { "default-plugins": true, "skip-list": false @@ -432,6 +444,10 @@ "default-plugins": true, "skip-list": false }, + "logstash-output-java_output_example": { + "default-plugins": false, + "skip-list": true + }, "logstash-output-kafka": { "default-plugins": true, "skip-list": false From 7d206b78d139c1a5c133fc27154f4cac86ccc47a Mon Sep 17 00:00:00 2001 From: Dan Hermann Date: Mon, 10 Jun 2019 13:20:36 -0500 Subject: [PATCH 0173/1126] Fix pipeline shutdown ordering Fixes #10872 --- .../plugins/builtin/pipeline/input.rb | 5 +++-- .../builtin/pipeline_input_output_spec.rb | 21 +++++++++++++++++++ .../plugins/pipeline/PipelineBus.java | 11 ++++++---- 3 files changed, 31 insertions(+), 6 deletions(-) diff --git a/logstash-core/lib/logstash/plugins/builtin/pipeline/input.rb b/logstash-core/lib/logstash/plugins/builtin/pipeline/input.rb index e08b8a85e..3e6e01cdb 100644 --- a/logstash-core/lib/logstash/plugins/builtin/pipeline/input.rb +++ b/logstash-core/lib/logstash/plugins/builtin/pipeline/input.rb @@ -48,9 +48,10 @@ module ::LogStash; module Plugins; module Builtin; module Pipeline; class Input end def stop - # We stop receiving events before we unlisten to prevent races - @running.set(false) if @running # If register wasn't yet called, no @running! pipeline_bus.unlisten(self, address) + # We stop receiving events _after_ we unlisten to pick up any events sent by upstream outputs that + # have not yet stopped + @running.set(false) if @running # If register wasn't yet called, no @running! end def isRunning diff --git a/logstash-core/spec/logstash/plugins/builtin/pipeline_input_output_spec.rb b/logstash-core/spec/logstash/plugins/builtin/pipeline_input_output_spec.rb index b3d0234c8..0da63471c 100644 --- a/logstash-core/spec/logstash/plugins/builtin/pipeline_input_output_spec.rb +++ b/logstash-core/spec/logstash/plugins/builtin/pipeline_input_output_spec.rb @@ -101,6 +101,27 @@ describe ::LogStash::Plugins::Builtin::Pipeline do output.do_close end end + + it "stopped input should process events until upstream outputs stop" do + start_input + output.register + pipeline_bus.setBlockOnUnlisten(true) + + output.multi_receive([event]) + expect(queue.pop(true).to_hash_with_metadata).to match(event.to_hash_with_metadata) + + @thread = Thread.new do + begin + input.do_stop + end + end + + sleep 1 + output.multi_receive([event]) + expect(queue.pop(true).to_hash_with_metadata).to match(event.to_hash_with_metadata) + + output.do_close + end end describe "one output to multiple inputs" do diff --git a/logstash-core/src/main/java/org/logstash/plugins/pipeline/PipelineBus.java b/logstash-core/src/main/java/org/logstash/plugins/pipeline/PipelineBus.java index 11886569a..7ab2f3bb9 100644 --- a/logstash-core/src/main/java/org/logstash/plugins/pipeline/PipelineBus.java +++ b/logstash-core/src/main/java/org/logstash/plugins/pipeline/PipelineBus.java @@ -10,10 +10,12 @@ import java.util.concurrent.ConcurrentHashMap; import java.util.stream.Stream; /** - * This class is essentially the communication bus / central state for the `pipeline` inputs/outputs to talk to each - * other. This class is threadsafe. + * This class is the communication bus for the `pipeline` inputs and outputs to talk to each other. + * + * This class is threadsafe. */ public class PipelineBus { + final ConcurrentHashMap addressStates = new ConcurrentHashMap<>(); final ConcurrentHashMap> outputsToAddressStates = new ConcurrentHashMap<>(); volatile boolean blockOnUnlisten = false; @@ -159,9 +161,10 @@ public class PipelineBus { } /** - * Stop listening on the given address with the given listener + * Stop listening on the given address with the given listener. Blocks until upstream outputs have + * stopped. * - * @param input Input that should stop listening + * @param input Input that should stop listening * @param address Address on which to stop listening * @throws InterruptedException if interrupted while attempting to stop listening */ From d1e92862c33274e96108fe5a388a781920225144 Mon Sep 17 00:00:00 2001 From: Dan Hermann Date: Thu, 27 Jun 2019 11:09:02 -0500 Subject: [PATCH 0174/1126] serialize access to PipelineBus methods on a per-plugin basis, code cleanup in AddressState Fixes #10872 --- .../plugins/pipeline/AddressState.java | 2 - .../plugins/pipeline/PipelineBus.java | 119 ++++++++++-------- 2 files changed, 66 insertions(+), 55 deletions(-) diff --git a/logstash-core/src/main/java/org/logstash/plugins/pipeline/AddressState.java b/logstash-core/src/main/java/org/logstash/plugins/pipeline/AddressState.java index 0266e59d5..48d05c889 100644 --- a/logstash-core/src/main/java/org/logstash/plugins/pipeline/AddressState.java +++ b/logstash-core/src/main/java/org/logstash/plugins/pipeline/AddressState.java @@ -11,8 +11,6 @@ public class AddressState { private final Set outputs = ConcurrentHashMap.newKeySet(); private volatile PipelineInput input = null; - AddressState(String address) {} - /** * Add the given output and ensure associated input's receivers are updated * @param output output to be added diff --git a/logstash-core/src/main/java/org/logstash/plugins/pipeline/PipelineBus.java b/logstash-core/src/main/java/org/logstash/plugins/pipeline/PipelineBus.java index 7ab2f3bb9..bae5b6f8c 100644 --- a/logstash-core/src/main/java/org/logstash/plugins/pipeline/PipelineBus.java +++ b/logstash-core/src/main/java/org/logstash/plugins/pipeline/PipelineBus.java @@ -1,5 +1,6 @@ package org.logstash.plugins.pipeline; +import com.google.common.annotations.VisibleForTesting; import org.apache.logging.log4j.LogManager; import org.apache.logging.log4j.Logger; import org.logstash.RubyUtil; @@ -33,30 +34,32 @@ public class PipelineBus { final boolean ensureDelivery) { if (events.isEmpty()) return; // This can happen on pipeline shutdown or in some other situations - final ConcurrentHashMap addressesToInputs = outputsToAddressStates.get(sender); + synchronized (sender) { + final ConcurrentHashMap addressesToInputs = outputsToAddressStates.get(sender); - addressesToInputs.forEach((address, addressState) -> { - final Stream clones = events.stream().map(e -> e.rubyClone(RubyUtil.RUBY)); + addressesToInputs.forEach((address, addressState) -> { + final Stream clones = events.stream().map(e -> e.rubyClone(RubyUtil.RUBY)); - PipelineInput input = addressState.getInput(); // Save on calls to getInput since it's volatile - boolean sendWasSuccess = input != null && input.internalReceive(clones); + PipelineInput input = addressState.getInput(); // Save on calls to getInput since it's volatile + boolean sendWasSuccess = input != null && input.internalReceive(clones); - // Retry send if the initial one failed - while (ensureDelivery && !sendWasSuccess) { - // We need to refresh the input in case the mapping has updated between loops - String message = String.format("Attempted to send event to '%s' but that address was unavailable. " + - "Maybe the destination pipeline is down or stopping? Will Retry.", address); - logger.warn(message); - input = addressState.getInput(); - sendWasSuccess = input != null && input.internalReceive(clones); - try { - Thread.sleep(1000); - } catch (InterruptedException e) { - Thread.currentThread().interrupt(); - logger.error("Sleep unexpectedly interrupted in bus retry loop", e); + // Retry send if the initial one failed + while (ensureDelivery && !sendWasSuccess) { + // We need to refresh the input in case the mapping has updated between loops + String message = String.format("Attempted to send event to '%s' but that address was unavailable. " + + "Maybe the destination pipeline is down or stopping? Will Retry.", address); + logger.warn(message); + input = addressState.getInput(); + sendWasSuccess = input != null && input.internalReceive(clones); + try { + Thread.sleep(1000); + } catch (InterruptedException e) { + Thread.currentThread().interrupt(); + logger.error("Sleep unexpectedly interrupted in bus retry loop", e); + } } - } - }); + }); + } } /** @@ -66,16 +69,18 @@ public class PipelineBus { * @param addresses collection of addresses on which to register this sender */ public void registerSender(final PipelineOutput output, final Iterable addresses) { - addresses.forEach((String address) -> { - addressStates.compute(address, (k, value) -> { - final AddressState state = value != null ? value : new AddressState(address); - state.addOutput(output); + synchronized (output) { + addresses.forEach((String address) -> { + addressStates.compute(address, (k, value) -> { + final AddressState state = value != null ? value : new AddressState(); + state.addOutput(output); - return state; + return state; + }); }); - }); - updateOutputReceivers(output); + updateOutputReceivers(output); + } } /** @@ -85,17 +90,19 @@ public class PipelineBus { * @param addresses collection of addresses this sender was registered with */ public void unregisterSender(final PipelineOutput output, final Iterable addresses) { - addresses.forEach(address -> { - addressStates.computeIfPresent(address, (k, state) -> { - state.removeOutput(output); + synchronized (output) { + addresses.forEach(address -> { + addressStates.computeIfPresent(address, (k, state) -> { + state.removeOutput(output); - if (state.isEmpty()) return null; + if (state.isEmpty()) return null; - return state; + return state; + }); }); - }); - outputsToAddressStates.remove(output); + outputsToAddressStates.remove(output); + } } /** @@ -125,22 +132,24 @@ public class PipelineBus { * @return true if the listener successfully subscribed */ public boolean listen(final PipelineInput input, final String address) { - final boolean[] result = new boolean[1]; + synchronized (input) { + final boolean[] result = new boolean[1]; - addressStates.compute(address, (k, value) -> { - AddressState state = value != null ? value : new AddressState(address); + addressStates.compute(address, (k, value) -> { + AddressState state = value != null ? value : new AddressState(); - if (state.assignInputIfMissing(input)) { - state.getOutputs().forEach(this::updateOutputReceivers); - result[0] = true; - } else { - result[0] = false; - } + if (state.assignInputIfMissing(input)) { + state.getOutputs().forEach(this::updateOutputReceivers); + result[0] = true; + } else { + result[0] = false; + } - return state; - }); + return state; + }); - return result[0]; + return result[0]; + } } /** @@ -153,10 +162,12 @@ public class PipelineBus { * @throws InterruptedException if interrupted while attempting to stop listening */ public void unlisten(final PipelineInput input, final String address) throws InterruptedException { - if (isBlockOnUnlisten()) { - unlistenBlock(input, address); - } else { - unlistenNonblock(input, address); + synchronized (input) { + if (isBlockOnUnlisten()) { + unlistenBlock(input, address); + } else { + unlistenNonblock(input, address); + } } } @@ -168,7 +179,7 @@ public class PipelineBus { * @param address Address on which to stop listening * @throws InterruptedException if interrupted while attempting to stop listening */ - public void unlistenBlock(final PipelineInput input, final String address) throws InterruptedException { + private void unlistenBlock(final PipelineInput input, final String address) throws InterruptedException { final boolean[] waiting = {true}; // Block until all senders are done @@ -206,7 +217,8 @@ public class PipelineBus { * @param input Input that should stop listening * @param address Address on which to stop listening */ - public void unlistenNonblock(final PipelineInput input, final String address) { + @VisibleForTesting + void unlistenNonblock(final PipelineInput input, final String address) { addressStates.computeIfPresent(address, (k, state) -> { state.unassignInput(input); state.getOutputs().forEach(this::updateOutputReceivers); @@ -214,7 +226,8 @@ public class PipelineBus { }); } - public boolean isBlockOnUnlisten() { + @VisibleForTesting + boolean isBlockOnUnlisten() { return blockOnUnlisten; } From 0ff6d11344da9b367a42081c2fb3aee6cf712390 Mon Sep 17 00:00:00 2001 From: Dan Hermann Date: Thu, 27 Jun 2019 17:54:35 -0500 Subject: [PATCH 0175/1126] don't perform long-running pipeline actions inside calls to ConcurrentHashMap.compute to avoid deadlocks Fixes #10872 --- .../lib/logstash/pipelines_registry.rb | 51 ++++++++++++++----- 1 file changed, 37 insertions(+), 14 deletions(-) diff --git a/logstash-core/lib/logstash/pipelines_registry.rb b/logstash-core/lib/logstash/pipelines_registry.rb index 15358db92..a0e7649df 100644 --- a/logstash-core/lib/logstash/pipelines_registry.rb +++ b/logstash-core/lib/logstash/pipelines_registry.rb @@ -35,6 +35,7 @@ module LogStash # will block until the other compute finishes so no mutex is necessary # for synchronizing compute calls @states = java.util.concurrent.ConcurrentHashMap.new + @locks = java.util.concurrent.ConcurrentHashMap.new end # Execute the passed creation logic block and create a new state upon success @@ -46,9 +47,13 @@ module LogStash # # @return [Boolean] new pipeline creation success def create_pipeline(pipeline_id, pipeline, &create_block) - success = false + lock = get_lock(pipeline_id) + begin + lock.lock - @states.compute(pipeline_id) do |_, state| + success = false + + state = @states.get(pipeline_id) if state if state.terminated? success = yield @@ -56,14 +61,16 @@ module LogStash else logger.error("Attempted to create a pipeline that already exists", :pipeline_id => pipeline_id) end - state + @states.put(pipeline_id, state) else success = yield - success ? PipelineState.new(pipeline_id, pipeline) : nil + @states.put(pipeline_id, success ? PipelineState.new(pipeline_id, pipeline) : nil) end - end - success + success + ensure + lock.unlock + end end # Execute the passed termination logic block @@ -72,14 +79,20 @@ module LogStash # # @yieldparam [Pipeline] the pipeline to terminate def terminate_pipeline(pipeline_id, &stop_block) - @states.compute(pipeline_id) do |_, state| + lock = get_lock(pipeline_id) + begin + lock.lock + + state = @states.get(pipeline_id) if state.nil? logger.error("Attempted to terminate a pipeline that does not exists", :pipeline_id => pipeline_id) - nil + @states.put(pipeline_id, nil) else yield(state.pipeline) - state + @states.put(pipeline_id, state) end + ensure + lock.unlock end end @@ -91,12 +104,14 @@ module LogStash # # @return [Boolean] new pipeline creation success def reload_pipeline(pipeline_id, &reload_block) - success = false + lock = get_lock(pipeline_id) + begin + success = false - @states.compute(pipeline_id) do |_, state| + state = @states.get(pipeline_id) if state.nil? logger.error("Attempted to reload a pipeline that does not exists", :pipeline_id => pipeline_id) - nil + @states.put(pipeline_id, nil) else state.set_reloading(true) begin @@ -105,11 +120,13 @@ module LogStash ensure state.set_reloading(false) end - state + @states.put(pipeline_id, state) end - end success + ensure + lock.unlock + end end # @param pipeline_id [String, Symbol] the pipeline id @@ -162,5 +179,11 @@ module LogStash end end end + + def get_lock(pipeline_id) + @locks.compute_if_absent(pipeline_id) do |k| + java.util.concurrent.locks.ReentrantLock.new + end + end end end From f48da1e4614937749f347ae2923da6b83f4b2cd1 Mon Sep 17 00:00:00 2001 From: Dan Hermann Date: Thu, 27 Jun 2019 18:40:06 -0500 Subject: [PATCH 0176/1126] add missing lock statement Fixes #10872 --- logstash-core/lib/logstash/pipelines_registry.rb | 1 + 1 file changed, 1 insertion(+) diff --git a/logstash-core/lib/logstash/pipelines_registry.rb b/logstash-core/lib/logstash/pipelines_registry.rb index a0e7649df..c53ad5df0 100644 --- a/logstash-core/lib/logstash/pipelines_registry.rb +++ b/logstash-core/lib/logstash/pipelines_registry.rb @@ -106,6 +106,7 @@ module LogStash def reload_pipeline(pipeline_id, &reload_block) lock = get_lock(pipeline_id) begin + lock.lock success = false state = @states.get(pipeline_id) From e925b4c48d17675059c64b0d7a78219edd12117b Mon Sep 17 00:00:00 2001 From: Dan Hermann Date: Thu, 27 Jun 2019 19:16:07 -0500 Subject: [PATCH 0177/1126] don't put nulls in the map Fixes #10872 --- logstash-core/lib/logstash/pipelines_registry.rb | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/logstash-core/lib/logstash/pipelines_registry.rb b/logstash-core/lib/logstash/pipelines_registry.rb index c53ad5df0..86ed1eacb 100644 --- a/logstash-core/lib/logstash/pipelines_registry.rb +++ b/logstash-core/lib/logstash/pipelines_registry.rb @@ -64,7 +64,7 @@ module LogStash @states.put(pipeline_id, state) else success = yield - @states.put(pipeline_id, success ? PipelineState.new(pipeline_id, pipeline) : nil) + @states.put(pipeline_id, PipelineState.new(pipeline_id, pipeline)) if success end success @@ -86,7 +86,7 @@ module LogStash state = @states.get(pipeline_id) if state.nil? logger.error("Attempted to terminate a pipeline that does not exists", :pipeline_id => pipeline_id) - @states.put(pipeline_id, nil) + @states.remote(pipeline_id) else yield(state.pipeline) @states.put(pipeline_id, state) @@ -112,7 +112,7 @@ module LogStash state = @states.get(pipeline_id) if state.nil? logger.error("Attempted to reload a pipeline that does not exists", :pipeline_id => pipeline_id) - @states.put(pipeline_id, nil) + @states.remove(pipeline_id) else state.set_reloading(true) begin From 1802869d80c11d1bb8b49455f983d1d30fcd16ab Mon Sep 17 00:00:00 2001 From: Dan Hermann Date: Thu, 27 Jun 2019 20:00:00 -0500 Subject: [PATCH 0178/1126] remote != remove Fixes #10872 --- logstash-core/lib/logstash/pipelines_registry.rb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/logstash-core/lib/logstash/pipelines_registry.rb b/logstash-core/lib/logstash/pipelines_registry.rb index 86ed1eacb..51ec9b944 100644 --- a/logstash-core/lib/logstash/pipelines_registry.rb +++ b/logstash-core/lib/logstash/pipelines_registry.rb @@ -86,7 +86,7 @@ module LogStash state = @states.get(pipeline_id) if state.nil? logger.error("Attempted to terminate a pipeline that does not exists", :pipeline_id => pipeline_id) - @states.remote(pipeline_id) + @states.remove(pipeline_id) else yield(state.pipeline) @states.put(pipeline_id, state) From 46c1611dff02a5adb80c9d8f28e18d393f47c22e Mon Sep 17 00:00:00 2001 From: Dan Hermann Date: Fri, 28 Jun 2019 07:12:15 -0500 Subject: [PATCH 0179/1126] use method-level ensure blocks Fixes #10872 --- .../lib/logstash/pipelines_registry.rb | 94 +++++++++---------- 1 file changed, 44 insertions(+), 50 deletions(-) diff --git a/logstash-core/lib/logstash/pipelines_registry.rb b/logstash-core/lib/logstash/pipelines_registry.rb index 51ec9b944..6ba13679f 100644 --- a/logstash-core/lib/logstash/pipelines_registry.rb +++ b/logstash-core/lib/logstash/pipelines_registry.rb @@ -48,29 +48,27 @@ module LogStash # @return [Boolean] new pipeline creation success def create_pipeline(pipeline_id, pipeline, &create_block) lock = get_lock(pipeline_id) - begin - lock.lock + lock.lock - success = false + success = false - state = @states.get(pipeline_id) - if state - if state.terminated? - success = yield - state.set_pipeline(pipeline) - else - logger.error("Attempted to create a pipeline that already exists", :pipeline_id => pipeline_id) - end - @states.put(pipeline_id, state) - else + state = @states.get(pipeline_id) + if state + if state.terminated? success = yield - @states.put(pipeline_id, PipelineState.new(pipeline_id, pipeline)) if success + state.set_pipeline(pipeline) + else + logger.error("Attempted to create a pipeline that already exists", :pipeline_id => pipeline_id) end - - success - ensure - lock.unlock + @states.put(pipeline_id, state) + else + success = yield + @states.put(pipeline_id, PipelineState.new(pipeline_id, pipeline)) if success end + + success + ensure + lock.unlock end # Execute the passed termination logic block @@ -80,20 +78,18 @@ module LogStash # @yieldparam [Pipeline] the pipeline to terminate def terminate_pipeline(pipeline_id, &stop_block) lock = get_lock(pipeline_id) - begin - lock.lock + lock.lock - state = @states.get(pipeline_id) - if state.nil? - logger.error("Attempted to terminate a pipeline that does not exists", :pipeline_id => pipeline_id) - @states.remove(pipeline_id) - else - yield(state.pipeline) - @states.put(pipeline_id, state) - end - ensure - lock.unlock + state = @states.get(pipeline_id) + if state.nil? + logger.error("Attempted to terminate a pipeline that does not exists", :pipeline_id => pipeline_id) + @states.remove(pipeline_id) + else + yield(state.pipeline) + @states.put(pipeline_id, state) end + ensure + lock.unlock end # Execute the passed reloading logic block in the context of the reloading state and set new pipeline in state @@ -105,29 +101,27 @@ module LogStash # @return [Boolean] new pipeline creation success def reload_pipeline(pipeline_id, &reload_block) lock = get_lock(pipeline_id) - begin - lock.lock - success = false + lock.lock + success = false - state = @states.get(pipeline_id) - if state.nil? - logger.error("Attempted to reload a pipeline that does not exists", :pipeline_id => pipeline_id) - @states.remove(pipeline_id) - else - state.set_reloading(true) - begin - success, new_pipeline = yield - state.set_pipeline(new_pipeline) - ensure - state.set_reloading(false) - end - @states.put(pipeline_id, state) + state = @states.get(pipeline_id) + if state.nil? + logger.error("Attempted to reload a pipeline that does not exists", :pipeline_id => pipeline_id) + @states.remove(pipeline_id) + else + state.set_reloading(true) + begin + success, new_pipeline = yield + state.set_pipeline(new_pipeline) + ensure + state.set_reloading(false) end - - success - ensure - lock.unlock + @states.put(pipeline_id, state) end + + success + ensure + lock.unlock end # @param pipeline_id [String, Symbol] the pipeline id From 5e8a694d598eeeb05b640a253da4c2b3ff15e93a Mon Sep 17 00:00:00 2001 From: Dan Hermann Date: Fri, 28 Jun 2019 07:16:15 -0500 Subject: [PATCH 0180/1126] simplify unit test Fixes #10872 --- .../logstash/plugins/builtin/pipeline_input_output_spec.rb | 6 +----- 1 file changed, 1 insertion(+), 5 deletions(-) diff --git a/logstash-core/spec/logstash/plugins/builtin/pipeline_input_output_spec.rb b/logstash-core/spec/logstash/plugins/builtin/pipeline_input_output_spec.rb index 0da63471c..d8bcebe8d 100644 --- a/logstash-core/spec/logstash/plugins/builtin/pipeline_input_output_spec.rb +++ b/logstash-core/spec/logstash/plugins/builtin/pipeline_input_output_spec.rb @@ -110,11 +110,7 @@ describe ::LogStash::Plugins::Builtin::Pipeline do output.multi_receive([event]) expect(queue.pop(true).to_hash_with_metadata).to match(event.to_hash_with_metadata) - @thread = Thread.new do - begin - input.do_stop - end - end + Thread.new { input.do_stop } sleep 1 output.multi_receive([event]) From 67bddcee12a08fb731783ad9e141edd8c84b73ce Mon Sep 17 00:00:00 2001 From: Joao Duarte Date: Tue, 2 Jul 2019 16:41:04 +0100 Subject: [PATCH 0181/1126] disable testInvalidInputPlugin Test has been failing on windows for many weeks. See https://github.com/elastic/logstash/issues/10926 Fixes #10927 --- .../src/test/java/org/logstash/plugins/PluginValidatorTest.java | 2 ++ 1 file changed, 2 insertions(+) diff --git a/logstash-core/src/test/java/org/logstash/plugins/PluginValidatorTest.java b/logstash-core/src/test/java/org/logstash/plugins/PluginValidatorTest.java index 68e22563e..c3c756ce1 100644 --- a/logstash-core/src/test/java/org/logstash/plugins/PluginValidatorTest.java +++ b/logstash-core/src/test/java/org/logstash/plugins/PluginValidatorTest.java @@ -1,6 +1,7 @@ package org.logstash.plugins; import org.junit.Assert; +import org.junit.Ignore; import org.junit.Test; import org.logstash.plugins.codecs.Line; import org.logstash.plugins.filters.Uuid; @@ -43,6 +44,7 @@ public class PluginValidatorTest { Assert.assertTrue(PluginValidator.validatePlugin(PluginLookup.PluginType.OUTPUT, Stdout.class)); } + @Ignore("Test failing on windows for many weeks. See https://github.com/elastic/logstash/issues/10926") @Test public void testInvalidInputPlugin() throws IOException { Path tempJar = null; From ae409ca44959c7b0392059043c56892f617fe939 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jo=C3=A3o=20Duarte?= Date: Wed, 3 Jul 2019 19:06:57 +0100 Subject: [PATCH 0182/1126] bump 7.x to 7.4.0 (#10932) --- README.md | 16 ++++++++-------- docs/index.asciidoc | 6 +++--- versions.yml | 4 ++-- 3 files changed, 13 insertions(+), 13 deletions(-) diff --git a/README.md b/README.md index 791a5fb60..a3215db75 100644 --- a/README.md +++ b/README.md @@ -28,14 +28,14 @@ These builds are created nightly and have undergone no formal QA, so they should | [deb-complete][] | [deb-oss][] | | [rpm-complete][] | [rpm-oss][] | -[tar-complete]: https://snapshots.elastic.co/downloads/logstash/logstash-7.3.0-SNAPSHOT.tar.gz -[zip-complete]: https://snapshots.elastic.co/downloads/logstash/logstash-7.3.0-SNAPSHOT.zip -[deb-complete]: https://snapshots.elastic.co/downloads/logstash/logstash-7.3.0-SNAPSHOT.deb -[rpm-complete]: https://snapshots.elastic.co/downloads/logstash/logstash-7.3.0-SNAPSHOT.rpm -[tar-oss]: https://snapshots.elastic.co/downloads/logstash/logstash-oss-7.3.0-SNAPSHOT.tar.gz -[zip-oss]: https://snapshots.elastic.co/downloads/logstash/logstash-oss-7.3.0-SNAPSHOT.zip -[deb-oss]: https://snapshots.elastic.co/downloads/logstash/logstash-oss-7.3.0-SNAPSHOT.deb -[rpm-oss]: https://snapshots.elastic.co/downloads/logstash/logstash-oss-7.3.0-SNAPSHOT.rpm +[tar-complete]: https://snapshots.elastic.co/downloads/logstash/logstash-7.4.0-SNAPSHOT.tar.gz +[zip-complete]: https://snapshots.elastic.co/downloads/logstash/logstash-7.4.0-SNAPSHOT.zip +[deb-complete]: https://snapshots.elastic.co/downloads/logstash/logstash-7.4.0-SNAPSHOT.deb +[rpm-complete]: https://snapshots.elastic.co/downloads/logstash/logstash-7.4.0-SNAPSHOT.rpm +[tar-oss]: https://snapshots.elastic.co/downloads/logstash/logstash-oss-7.4.0-SNAPSHOT.tar.gz +[zip-oss]: https://snapshots.elastic.co/downloads/logstash/logstash-oss-7.4.0-SNAPSHOT.zip +[deb-oss]: https://snapshots.elastic.co/downloads/logstash/logstash-oss-7.4.0-SNAPSHOT.deb +[rpm-oss]: https://snapshots.elastic.co/downloads/logstash/logstash-oss-7.4.0-SNAPSHOT.rpm ## Need Help? diff --git a/docs/index.asciidoc b/docs/index.asciidoc index cee564700..6f54df27a 100644 --- a/docs/index.asciidoc +++ b/docs/index.asciidoc @@ -8,9 +8,9 @@ :plugins-repo-dir: {docdir}/../../logstash-docs/docs :branch: 7.x :major-version: 7.x -:logstash_version: 7.3.0 -:elasticsearch_version: 7.3.0 -:kibana_version: 7.3.0 +:logstash_version: 7.4.0 +:elasticsearch_version: 7.4.0 +:kibana_version: 7.4.0 :docker-repo: docker.elastic.co/logstash/logstash :docker-image: {docker-repo}:{logstash_version} diff --git a/versions.yml b/versions.yml index 2db949025..3d88867c0 100644 --- a/versions.yml +++ b/versions.yml @@ -1,7 +1,7 @@ --- # alpha and beta qualifiers are now added via VERSION_QUALIFIER environment var -logstash: 7.3.0 -logstash-core: 7.3.0 +logstash: 7.4.0 +logstash-core: 7.4.0 logstash-core-plugin-api: 2.1.16 # jruby must reference a *released* version of jruby which can be downloaded from the official download url From 534c2676228acb663eabdef1da0b57bfb20fe1e9 Mon Sep 17 00:00:00 2001 From: Joao Duarte Date: Wed, 10 Jul 2019 16:35:11 +0100 Subject: [PATCH 0183/1126] Cleanup gradle tasks and dependency installation - have `bootstrap` task do as little as possible: install gems in Gemfile.template that don't belong to groups - have test tasks depend on the `installTestGems` task instead of `bootstrap` - logstash es output is now a dependency because of license checking - fix out of memory problem in SharedHelpers.trap Also use release lockfile during installDefaultGems The release lockfile is only copied to Gemfile.lock if it doesn't exist. During the `installDefaultGems` task other plugin installation tasks already occurred, generating a lock file. This commit removes it before running the plugin installation. Fixes #10942 --- Gemfile.template | 1 + build.gradle | 55 ++++++++------------- rakelib/plugin.rake | 14 ++++++ rakelib/plugins_docs_dependencies.rake | 66 +++++++++++++++++++++----- 4 files changed, 90 insertions(+), 46 deletions(-) diff --git a/Gemfile.template b/Gemfile.template index 8ad97c8c2..deee7206b 100644 --- a/Gemfile.template +++ b/Gemfile.template @@ -11,6 +11,7 @@ gem "paquet", "~> 0.2" gem "pleaserun", "~>0.0.28" gem "rake", "~> 12" gem "ruby-progressbar", "~> 1" +gem "logstash-output-elasticsearch" gem "childprocess", "~> 0.9", :group => :build gem "fpm", "~> 1.3.3", :group => :build gem "gems", "~> 1", :group => :build diff --git a/build.gradle b/build.gradle index 5b2275e6c..21bbd3209 100644 --- a/build.gradle +++ b/build.gradle @@ -119,28 +119,9 @@ clean { delete "${projectDir}/build/rubyDependencies.csv" } -task bootstrap {} - -project(":logstash-core") { - ["rubyTests", "test"].each { tsk -> - tasks.getByPath(":logstash-core:" + tsk).configure { - dependsOn bootstrap - } - } -} - -task installDefaultGems(dependsOn: downloadAndInstallJRuby) { - inputs.files file("${projectDir}/Gemfile.template") - inputs.files fileTree("${projectDir}/rakelib") - inputs.files file("${projectDir}/versions.yml") - outputs.file("${projectDir}/Gemfile") - outputs.file("${projectDir}/Gemfile.lock") - outputs.dir("${projectDir}/logstash-core/lib/jars") - outputs.dir("${projectDir}/vendor/bundle/jruby/2.5.0") +task bootstrap { doLast { - gem(projectDir, buildDir, "rake", "12.3.1", "${projectDir}/vendor/bundle/jruby/2.5.0") - gem(projectDir, buildDir, "json", "1.8.6", "${projectDir}/vendor/bundle/jruby/2.5.0") - rake(projectDir, buildDir, 'plugin:install-default') + rake(projectDir, buildDir, 'plugin:install-base') } } @@ -148,17 +129,14 @@ def assemblyDeps = [downloadAndInstallJRuby, assemble] + subprojects.collect { it.tasks.findByName("assemble") } -task installTestGems(dependsOn: assemblyDeps) { - inputs.files file("${projectDir}/Gemfile.template") - inputs.files fileTree("${projectDir}/rakelib") - inputs.files file("${projectDir}/versions.yml") - outputs.file("${projectDir}/Gemfile") - outputs.file("${projectDir}/Gemfile.lock") - outputs.dir("${projectDir}/logstash-core/lib/jars") - outputs.dir("${projectDir}/vendor/bundle/jruby/2.5.0") +task installDefaultGems(dependsOn: assemblyDeps) { + doLast { + rake(projectDir, buildDir, 'plugin:install-default') + } +} + +task installTestGems(dependsOn: assemblyDeps) { doLast { - gem(projectDir, buildDir, "rake", "12.3.1", "${projectDir}/vendor/bundle/jruby/2.5.0") - gem(projectDir, buildDir, "json", "1.8.6", "${projectDir}/vendor/bundle/jruby/2.5.0") rake(projectDir, buildDir, 'plugin:install-development-dependencies') } } @@ -175,7 +153,6 @@ task assembleTarDistribution(dependsOn: assemblyDeps) { inputs.files fileTree("${projectDir}/x-pack") outputs.files file("${buildDir}/logstash-${project.version}-SNAPSHOT.tar.gz") doLast { - gem(projectDir, buildDir, "rake", "12.3.1", "${projectDir}/vendor/bundle/jruby/2.5.0") rake(projectDir, buildDir, 'artifact:tar') } } @@ -226,6 +203,14 @@ task assembleOssZipDistribution(dependsOn: assemblyDeps) { } } +project(":logstash-core") { + ["rubyTests", "test"].each { tsk -> + tasks.getByPath(":logstash-core:" + tsk).configure { + dependsOn installTestGems + } + } +} + def logstashBuildDir = "${buildDir}/logstash-${project.version}-SNAPSHOT" task unpackTarDistribution(dependsOn: assembleTarDistribution, type: Copy) { @@ -318,13 +303,13 @@ task generateLicenseReportInputs() { } } -task generatePluginsVersion(dependsOn: bootstrap) { +task generatePluginsVersion(dependsOn: installDefaultGems) { doLast { rake(projectDir, buildDir, 'generate_plugins_version') } } -bootstrap.dependsOn installTestGems +bootstrap.dependsOn assemblyDeps runIntegrationTests.shouldRunAfter tasks.getByPath(":logstash-core:test") check.dependsOn runIntegrationTests @@ -421,7 +406,7 @@ if (!oss) { project(":logstash-xpack") { ["rubyTests", "rubyIntegrationTests", "test"].each { tsk -> tasks.getByPath(":logstash-xpack:" + tsk).configure { - dependsOn bootstrap + dependsOn installTestGems } } tasks.getByPath(":logstash-xpack:rubyIntegrationTests").configure { diff --git a/rakelib/plugin.rake b/rakelib/plugin.rake index 21559e94a..e50994631 100644 --- a/rakelib/plugin.rake +++ b/rakelib/plugin.rake @@ -8,6 +8,18 @@ namespace "plugin" do LogStash::PluginManager::Main.run("bin/logstash-plugin", ["install"] + args) end + task "install-base" => "bootstrap" do + puts("[plugin:install-base] Installing base dependencies") + install_plugins("--development", "--preserve") + task.reenable # Allow this task to be run again + end + + def remove_lockfile + if ::File.exist?(LogStash::Environment::LOCKFILE) + ::File.delete(LogStash::Environment::LOCKFILE) + end + end + task "install-development-dependencies" => "bootstrap" do puts("[plugin:install-development-dependencies] Installing development dependencies") install_plugins("--development", "--preserve") @@ -26,6 +38,8 @@ namespace "plugin" do task "install-default" => "bootstrap" do puts("[plugin:install-default] Installing default plugins") + + remove_lockfile # because we want to use the release lockfile install_plugins("--no-verify", "--preserve", *LogStash::RakeLib::DEFAULT_PLUGINS) task.reenable # Allow this task to be run again diff --git a/rakelib/plugins_docs_dependencies.rake b/rakelib/plugins_docs_dependencies.rake index dda853eb0..a3aaf34b8 100644 --- a/rakelib/plugins_docs_dependencies.rake +++ b/rakelib/plugins_docs_dependencies.rake @@ -83,15 +83,7 @@ class PluginVersionWorking plugins_to_install.each do |plugin| begin - builder = Bundler::Dsl.new - gemfile = LogStash::Gemfile.new(File.new(LogStash::Environment::GEMFILE_PATH, "r+")).load - gemfile.update(plugin) - - builder.eval_gemfile("bundler file", gemfile.generate()) - definition = builder.to_definition(LogStash::Environment::LOCKFILE, {}) - definition.resolve_remotely! - from = PLUGIN_METADATA.fetch(plugin, {}).fetch("default-plugins", false) ? :default : :missing - extract_versions(definition, successful_dependencies, from) + try_plugin(plugin, successful_dependencies) puts "Successfully installed: #{plugin}" rescue => e puts "Failed to install: #{plugin}" @@ -107,13 +99,25 @@ class PluginVersionWorking puts "Failures: #{failures.size}/#{total}" end + def try_plugin(plugin, successful_dependencies) + builder = Bundler::Dsl.new + gemfile = LogStash::Gemfile.new(File.new(LogStash::Environment::GEMFILE_PATH, "r+")).load + gemfile.update(plugin) + + builder.eval_gemfile("bundler file", gemfile.generate()) + definition = builder.to_definition(LogStash::Environment::LOCKFILE, {}) + definition.resolve_remotely! + from = PLUGIN_METADATA.fetch(plugin, {}).fetch("default-plugins", false) ? :default : :missing + extract_versions(definition, successful_dependencies, from) + end + def extract_versions(definition, dependencies, from) #definition.specs.select { |spec| spec.metadata && spec.metadata["logstash_plugin"] == "true" }.each do |spec| # # Bundler doesn't seem to provide us with `spec.metadata` for remotely # discovered plugins (via rubygems.org api), so we have to choose by # a name pattern instead of by checking spec.metadata["logstash_plugin"] - definition.specs.select { |spec| spec.name =~ /^logstash-(input|filter|output|codec)-/ }.each do |spec| + definition.resolve.select { |spec| spec.name =~ /^logstash-(input|filter|output|codec)-/ }.each do |spec| dependencies[spec.name] ||= [] dependencies[spec.name] << VersionDependencies.new(spec.version, from) end @@ -135,5 +139,45 @@ task :generate_plugins_version do require "pluginmanager/gemfile" require "bootstrap/environment" + # This patch comes after an investigation of `generate_plugins_version` + # causing OOM during `./gradlew generatePluginsVersion`. + # Why does this patch fix the issue? Hang on, this is going to be wild ride: + # In this rake task we compute a manifest that tells us, for each logstash plugin, + # what is the latest version that can be installed. + # We do this by (again for each plugin): + # * adding the plugin to the current Gemfile + # * instantiate a `Bundler::Dsl` instance with said Gemfile + # * retrieve a Bundler::Definition by passing in the Gemfile.lock + # * call `definition.resolve_remotely! + # + # Now, these repeated calls to `resolve_remotely!` on new instances of Definitions + # cause the out of memory. Resolving remote dependencies uses Bundler::Worker instances + # who trap the SIGINT signal in their `initializer` [1]. This shared helper method creates a closure that is + # passed to `Signal.trap`, and capture the return [2], which is the previous proc (signal handler). + # Since the variable that stores the return from `Signal.trap` is present in the binding, multiple calls + # to this helper cause each new closures to reference the previous one. The size of each binding + # accumulates and OOM occurs after 70-100 iterations. + # This is easy to replicate by looping over `Bundler::SharedHelpers.trap("INT") { 1 }`. + # + # This workaround removes the capture of the previous binding. Not calling all the previous handlers + # may cause some threads to not be cleaned up, but this rake task has a short life so everything + # ends up being cleaned up on exit anyway. + # We're confining this patch to this task only as this is the only place where we need to resolve + # dependencies many many times. + # + # You're still here? You're awesome :) Thanks for reading! + # + # [1] https://github.com/bundler/bundler/blob/d9d75807196b91f454de48d5afd0c43b395243a3/lib/bundler/worker.rb#L29 + # [2] https://github.com/bundler/bundler/blob/d9d75807196b91f454de48d5afd0c43b395243a3/lib/bundler/shared_helpers.rb#L173 + module ::Bundler + module SharedHelpers + def trap(signal, override = false, &block) + Signal.trap(signal) do + block.call + end + end + end + end + PluginVersionWorking.new.generate -end \ No newline at end of file +end From 072d33690ccbc6587853a2a4635824195d35ad73 Mon Sep 17 00:00:00 2001 From: Joao Duarte Date: Fri, 12 Jul 2019 09:58:30 +0100 Subject: [PATCH 0184/1126] fix plugin version bump rake task By removing the default plugins from the Gemfile.template the current task that modified the template was not working correctly. This commit either replaces the dependency entry if it exists or otherwise creates it. Fixes #10947 --- tools/release/bump_plugin_versions.rb | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/tools/release/bump_plugin_versions.rb b/tools/release/bump_plugin_versions.rb index 71cdfd7c7..0506dcdeb 100755 --- a/tools/release/bump_plugin_versions.rb +++ b/tools/release/bump_plugin_versions.rb @@ -53,7 +53,9 @@ puts "Generating new Gemfile.template file with computed dependencies" gemfile = IO.read("Gemfile.template") base_plugin_versions.each do |plugin, version| dependency = compute_dependecy(version, allow_bump_for) - gemfile.gsub!(/"#{plugin}".*$/, "\"#{plugin}\", \"#{dependency}\"") + if gemfile.gsub!(/"#{plugin}".*$/, "\"#{plugin}\", \"#{dependency}\"").nil? + gemfile << "gem \"#{plugin}\", \"#{dependency}\"\n" + end end IO.write("Gemfile.template", gemfile) From fe4b6ee308a194625d1aeb142586ab606c8f799e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Rodrigo=20L=C3=B3pez=20Dato?= Date: Thu, 2 May 2019 16:35:56 +0100 Subject: [PATCH 0185/1126] Allow LogStash::Event to be instantiated with a Java Event Allows inputs such as dead_letter_queue to create Ruby events that include both data and metadata from deserialised Java events Fixes #10749 --- .../src/main/java/org/logstash/ext/JrubyEventExtLibrary.java | 2 ++ 1 file changed, 2 insertions(+) diff --git a/logstash-core/src/main/java/org/logstash/ext/JrubyEventExtLibrary.java b/logstash-core/src/main/java/org/logstash/ext/JrubyEventExtLibrary.java index 369ea3fd0..dcd1b6b0e 100644 --- a/logstash-core/src/main/java/org/logstash/ext/JrubyEventExtLibrary.java +++ b/logstash-core/src/main/java/org/logstash/ext/JrubyEventExtLibrary.java @@ -71,6 +71,8 @@ public final class JrubyEventExtLibrary { this.event = new Event( ConvertedMap.newFromRubyHash(context, (RubyHash) data) ); + } else if (data != null && data.getJavaClass().equals(Event.class)) { + this.event = data.toJava(Event.class); } else { initializeFallback(context, data); } From b4f01e88fc56a9c174759b02a9f7028a1f17c997 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Rodrigo=20L=C3=B3pez=20Dato?= Date: Thu, 2 May 2019 16:38:27 +0100 Subject: [PATCH 0186/1126] Expose DLQ writers to all types of plugins, not just Ruby outputs Fixes #10749 --- .../logstash/plugins/PluginFactoryExt.java | 19 +++++++++---------- 1 file changed, 9 insertions(+), 10 deletions(-) diff --git a/logstash-core/src/main/java/org/logstash/plugins/PluginFactoryExt.java b/logstash-core/src/main/java/org/logstash/plugins/PluginFactoryExt.java index 71132da87..f570fe0d6 100644 --- a/logstash-core/src/main/java/org/logstash/plugins/PluginFactoryExt.java +++ b/logstash-core/src/main/java/org/logstash/plugins/PluginFactoryExt.java @@ -398,18 +398,17 @@ public final class PluginFactoryExt { public Context toContext(PluginLookup.PluginType pluginType, AbstractNamespacedMetricExt metric) { DeadLetterQueueWriter dlq = NullDeadLetterQueueWriter.getInstance(); - if (pluginType == PluginLookup.PluginType.OUTPUT) { - if (dlqWriter instanceof AbstractDeadLetterQueueWriterExt.PluginDeadLetterQueueWriterExt) { - IRubyObject innerWriter = - ((AbstractDeadLetterQueueWriterExt.PluginDeadLetterQueueWriterExt) dlqWriter) - .innerWriter(RubyUtil.RUBY.getCurrentContext()); - - if (innerWriter != null) { - if (org.logstash.common.io.DeadLetterQueueWriter.class.isAssignableFrom(innerWriter.getJavaClass())) { - dlq = new DLQWriterAdapter(innerWriter.toJava(org.logstash.common.io.DeadLetterQueueWriter.class)); - } + if (dlqWriter instanceof AbstractDeadLetterQueueWriterExt.PluginDeadLetterQueueWriterExt) { + IRubyObject innerWriter = + ((AbstractDeadLetterQueueWriterExt.PluginDeadLetterQueueWriterExt) dlqWriter) + .innerWriter(RubyUtil.RUBY.getCurrentContext()); + if (innerWriter != null) { + if (org.logstash.common.io.DeadLetterQueueWriter.class.isAssignableFrom(innerWriter.getJavaClass())) { + dlq = new DLQWriterAdapter(innerWriter.toJava(org.logstash.common.io.DeadLetterQueueWriter.class)); } } + } else if (dlqWriter.getJavaClass().equals(DeadLetterQueueWriter.class)) { + dlq = dlqWriter.toJava(DeadLetterQueueWriter.class); } return new ContextImpl(dlq, new NamespacedMetricImpl(RubyUtil.RUBY.getCurrentContext(), metric)); From 2f8be2caeafd02afaaa1520004dde53f3b48519c Mon Sep 17 00:00:00 2001 From: Colin Surprenant Date: Fri, 12 Jul 2019 16:52:16 -0400 Subject: [PATCH 0187/1126] [7.x clean backport of #10934] logstash-input-twitter as a default plugin (#10953) --- rakelib/plugins-metadata.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/rakelib/plugins-metadata.json b/rakelib/plugins-metadata.json index c6bd39451..f073fd749 100644 --- a/rakelib/plugins-metadata.json +++ b/rakelib/plugins-metadata.json @@ -391,7 +391,7 @@ "skip-list": false }, "logstash-input-twitter": { - "default-plugins": false, + "default-plugins": true, "skip-list": false }, "logstash-input-udp": { From e4538fd69251eb8ed611d8285be997047ec2693a Mon Sep 17 00:00:00 2001 From: Rob Waight <43173714+rwaight@users.noreply.github.com> Date: Thu, 11 Jul 2019 08:59:13 -0500 Subject: [PATCH 0188/1126] Document running Logstash on Windows (#10805) * Create running-logstash-windows.asciidoc Initial commit for #4005 * Update running-logstash-windows 1. Added section to validate JVM pre-requisites and shell sections for nssm, task scheduler, and PowerShell 2. Updated options to run Logstash on Windows, update section headers 3. Clarified JVM pre-requisites and included example to add environmental variables using SETX 4. Added example Logstash configuration, added steps for running Logstash manually with PowerShell 5. Removed `WIP` from the PowerShell section; updated the example to include output to Elasticsearch; Added notes for running Logstash as a service with NSSM 6. Removed `WIP` from the NSSM section; Added notes for running Logstash as a Scheduled Task; Added notes to stopping Logstash for each section; Removed `WIP` from the Scheduled Task section; Removed `WIP` from the page header 7. Updated initial section; moved the running manually section as the first configuration; added notes to the NSSM and Schedule Task sections. 8. Push headings down one level 9. Clarify this document contains examples for running Logstash on Windows. Updated which NSSM file should be extracted for use. 10. Updated formatting for the example Logstash configuration 11. Update formatting for the command examples 12. Update the instructions in the Task Scheduler section 13. Update the instructions in the run Logstash manually section, the NSSM section, and update formatting 14. Update formatting 15. Add note regarding support for running multiple pipelines 16. Clarify use of command line options. Re-state what is mentioned in the `Running Logstash from the Command Line` doc that: "Specifying command line options is useful when you are testing Logstash. However, in a production environment, we recommend that you use [logstash-settings-file] to control Logstash execution." 17. Clarify steps to accessing the Windows Environmental Variables window (i.e., link to Microsoft docs). 18. Remove unnecessary plus signs 19. Updated source types for examples, updated documents for specific Logstash versions with `{logstash_version}` * Update running-logstash-command-line 1. Add note for running Logstash on Windows with `bin\logstash.bat` 2. Update formatting for running Logstash from the Windows command line Fixes #10946 --- .../running-logstash-command-line.asciidoc | 7 + docs/static/running-logstash-windows.asciidoc | 152 +++++++++++++++++- 2 files changed, 158 insertions(+), 1 deletion(-) diff --git a/docs/static/running-logstash-command-line.asciidoc b/docs/static/running-logstash-command-line.asciidoc index b5cd5219a..a177ddab1 100644 --- a/docs/static/running-logstash-command-line.asciidoc +++ b/docs/static/running-logstash-command-line.asciidoc @@ -8,6 +8,13 @@ To run Logstash from the command line, use the following command: bin/logstash [options] ---- +To run Logstash from the Windows command line, use the following command: + +[source,shell] +---- +bin/logstash.bat [options] +---- + Where `options` are <> flags that you can specify to control Logstash execution. The location of the `bin` directory varies by platform. See <> to find the location of `bin\logstash` on diff --git a/docs/static/running-logstash-windows.asciidoc b/docs/static/running-logstash-windows.asciidoc index 443d22c0a..79ecc4222 100644 --- a/docs/static/running-logstash-windows.asciidoc +++ b/docs/static/running-logstash-windows.asciidoc @@ -1,3 +1,153 @@ [[running-logstash-windows]] === Running Logstash on Windows -Coming soon! +Before reading this section, see <> to get started. You also need to be familiar with <> as command line options are used to test running Logstash on Windows. + +IMPORTANT: Specifying command line options is useful when you are testing Logstash. However, in a production environment, we recommend that you use <> to control Logstash execution. Using the settings file makes it easier for you to specify multiple options, and it provides you with a single, versionable file that you can use to start up Logstash consistently for each run. + +Logstash is not started automatically after installation. How to start and stop Logstash on Windows depends on whether you want to run it manually, as a service (with https://nssm.cc/[NSSM]), or run it as a scheduled task. This guide provides an example of some of the ways Logstash can run on Windows. + +NOTE: It is recommended to validate your configuration works by running Logstash manually before running Logstash as a service or a scheduled task. + +[[running-logstash-windows-validation]] +==== Validating JVM Pre-Requisites on Windows +After installing a https://www.elastic.co/support/matrix#matrix_jvm[supported JVM], open a https://docs.microsoft.com/en-us/powershell/[PowerShell] session and run the following commands to verify `JAVA_HOME` is set and the Java version: + +===== `Write-Host $env:JAVA_HOME` +** The output should be pointed to where the JVM software is located, for example: ++ +[source,sh] +----- +PS C:\> Write-Host $env:JAVA_HOME +C:\Program Files\Java\jdk-11.0.3 +----- + +** If `JAVA_HOME` is not set, perform one of the following: +*** Set using the GUI: +**** Navigate to the Windows https://docs.microsoft.com/en-us/windows/win32/procthread/environment-variables[Environmental Variables] window +**** In the Environmental Variables window, edit JAVA_HOME to point to where the JDK software is located, for example: `C:\Program Files\Java\jdk-11.0.3` +*** Set using PowerShell: +**** In an Administrative PowerShell session, execute the following `https://docs.microsoft.com/en-us/windows-server/administration/windows-commands/setx[SETX]` commands: ++ +[source,sh] +----- +PS C:\Windows\system32> SETX /m JAVA_HOME "C:\Program Files\Java\jdk-11.0.3" +PS C:\Windows\system32> SETX /m PATH "$env:PATH;C:\Program Files\Java\jdk-11.0.3\bin;" +----- +**** Exit PowerShell, then open a new PowerShell session and run `Write-Host $env:JAVA_HOME` to verify + +===== `Java -version` +** This command produces output similar to the following: ++ +[source,sh] +----- +PS C:\> Java -version +java version "11.0.3" 2019-04-16 LTS +Java(TM) SE Runtime Environment 18.9 (build 11.0.3+12-LTS) +Java HotSpot(TM) 64-Bit Server VM 18.9 (build 11.0.3+12-LTS, mixed mode) +----- + +NOTE: As of the publication of this document, please review this https://github.com/elastic/logstash/issues/10496[known issue that impacts Java 11] before proceeding. + +Once you have <> and validated JVM pre-requisites, you may proceed. + +NOTE: For the examples listed below, we are running Windows Server 2016, Java 11.0.3, have extracted the https://www.elastic.co/downloads/logstash[Logstash ZIP package] to `C:\logstash-{logstash_version}\`, and using the example `syslog.conf` file shown below (stored in `C:\logstash-{logstash_version}\config\`). + +[[running-logstash-windows-manual]] +==== Running Logstash manually +Logstash can be run manually using https://docs.microsoft.com/en-us/powershell/[PowerShell]. Open an Administrative https://docs.microsoft.com/en-us/powershell/[PowerShell] session, then run the following commands: + +["source","sh",subs="attributes"] +----- +PS C:\Windows\system32> cd C:\logstash-{logstash_version}\ +PS C:\logstash-{logstash_version}> .\bin\logstash.bat -f .\config\syslog.conf +----- + +NOTE: In a production environment, we recommend that you use <> to control Logstash execution. + +Wait for the following messages to appear, to confirm Logstash has started successfully: + +["source","sh",subs="attributes"] +----- +[logstash.runner ] Starting Logstash {"logstash.version"=>"{logstash_version}"} +[logstash.inputs.udp ] Starting UDP listener {:address=>"0.0.0.0:514"} +[logstash.agent ] Successfully started Logstash API endpoint {:port=>9600} +----- + +[[running-logstash-windows-nssm]] +==== Running Logstash as a service with NSSM +NOTE: It is recommended to validate your configuration works by running Logstash manually before you proceed. + +Download https://nssm.cc/[NSSM], then extract `nssm.exe` from `nssm-\win64\nssm.exe` to `C:\logstash-{logstash_version}\bin\`. Then open an Administrative https://docs.microsoft.com/en-us/powershell/[PowerShell] session, then run the following commands: + +["source","sh",subs="attributes"] +----- +PS C:\Windows\system32> cd C:\logstash-{logstash_version}\ +PS C:\logstash-{logstash_version}> .\bin\nssm.exe install logstash +----- + +Once the `NSSM service installer` window appears, specify the following parameters in the `Application` tab: + +** In the `Application` tab: +*** Path: Path to `logstash.bat`: `C:\logstash-{logstash_version}\bin\logstash.bat` +*** Startup Directory: Path to the `bin` directory: `C:\logstash-{logstash_version}\bin` +*** Arguments: For this example to start Logstash: `-f C:\logstash-{logstash_version}\config\syslog.conf` ++ +NOTE: In a production environment, we recommend that you use <> to control Logstash execution. + +** Review and make any changes necessary in the `Details` tab: +*** Ensure `Startup Type` is set appropriately +*** Set the `Display name` and `Description` fields to something relevant + +** Review any other required settings (for the example we aren't making any other changes) +*** Be sure to determine if you need to set the `Log on` user +** Validate the `Service name` is set appropriately +*** For this example, we will set ours to `logstash-syslog` + +** Click `Install Service` +*** Click 'OK' when the `Service "logstash-syslog" installed successfully!` window appears + +Once the service has been installed with NSSM, validate and start the service following the https://docs.microsoft.com/en-us/powershell/scripting/samples/managing-services[PowerShell Managing Services] documentation. + +[[running-logstash-windows-scheduledtask]] +==== Running Logstash with Task Scheduler +NOTE: It is recommended to validate your configuration works by running Logstash manually before you proceed. + +Open the Windows https://docs.microsoft.com/en-us/windows/desktop/taskschd/task-scheduler-start-page[Task Scheduler], then click `Create Task` in the Actions window. Specify the following parameters in the `Actions` tab: + +** In the `Actions` tab: +*** Click `New`, then specify the following: +*** Action: `Start a program` +*** Program/script: `C:\logstash-{logstash_version}\bin\logstash.bat` +*** Add arguments: `-f C:\logstash-{logstash_version}\config\syslog.conf` ++ +NOTE: In a production environment, we recommend that you use <> to control Logstash execution. +*** Start in: C:\logstash-{logstash_version}\bin\ + +** Review and make any changes necessary in the `General`, `Triggers`, `Conditions`, and `Settings` tabs. + +** Click `OK` to finish creating the scheduled task. + +** Once the new task has been created, either wait for it to run on the schedule or select the service then click `Run` to start the task. + +NOTE: Logstash can be stopped by selecting the service, then clicking `End` in the Task Scheduler window. + +[[running-logstash-windows-example]] +==== Example Logstash Configuration +We will configure Logstash to listen for syslog messages over port 514 with this configuration (file name is `syslog.conf`): +[source,yaml] +----- +# Sample Logstash configuration for receiving +# UDP syslog messages over port 514 + +input { + udp { + port => 514 + type => "syslog" + } +} + +output { + elasticsearch { hosts => ["localhost:9200"] } + stdout { codec => rubydebug } +} +----- From 859b37fa6202bdb64b9c0204b6c772425f7350b8 Mon Sep 17 00:00:00 2001 From: Karen Metts Date: Fri, 12 Jul 2019 07:41:01 -0400 Subject: [PATCH 0189/1126] Fix formatting for nested version attributes Fixes #10949 --- docs/static/running-logstash-windows.asciidoc | 34 ++++++++++++------- 1 file changed, 21 insertions(+), 13 deletions(-) diff --git a/docs/static/running-logstash-windows.asciidoc b/docs/static/running-logstash-windows.asciidoc index 79ecc4222..12c64811e 100644 --- a/docs/static/running-logstash-windows.asciidoc +++ b/docs/static/running-logstash-windows.asciidoc @@ -26,7 +26,7 @@ C:\Program Files\Java\jdk-11.0.3 **** Navigate to the Windows https://docs.microsoft.com/en-us/windows/win32/procthread/environment-variables[Environmental Variables] window **** In the Environmental Variables window, edit JAVA_HOME to point to where the JDK software is located, for example: `C:\Program Files\Java\jdk-11.0.3` *** Set using PowerShell: -**** In an Administrative PowerShell session, execute the following `https://docs.microsoft.com/en-us/windows-server/administration/windows-commands/setx[SETX]` commands: +**** In an Administrative PowerShell session, execute the following https://docs.microsoft.com/en-us/windows-server/administration/windows-commands/setx[SETX] commands: + [source,sh] ----- @@ -50,7 +50,11 @@ NOTE: As of the publication of this document, please review this https://github. Once you have <> and validated JVM pre-requisites, you may proceed. -NOTE: For the examples listed below, we are running Windows Server 2016, Java 11.0.3, have extracted the https://www.elastic.co/downloads/logstash[Logstash ZIP package] to `C:\logstash-{logstash_version}\`, and using the example `syslog.conf` file shown below (stored in `C:\logstash-{logstash_version}\config\`). +NOTE: For the examples listed below, we are running Windows Server 2016, Java 11.0.3, +have extracted the https://www.elastic.co/downloads/logstash[Logstash ZIP +package] to +C:{backslash}logstash-{logstash_version}{backslash}+, and using the example +`syslog.conf` file shown below (stored in ++C:{backslash}logstash-{logstash_version}{backslash}config{backslash}+). [[running-logstash-windows-manual]] ==== Running Logstash manually @@ -58,8 +62,8 @@ Logstash can be run manually using https://docs.microsoft.com/en-us/powershell/[ ["source","sh",subs="attributes"] ----- -PS C:\Windows\system32> cd C:\logstash-{logstash_version}\ -PS C:\logstash-{logstash_version}> .\bin\logstash.bat -f .\config\syslog.conf +PS C:{backslash}Windows{backslash}system32> cd C:{backslash}logstash-{logstash_version}{backslash} +PS C:{backslash}logstash-{logstash_version}> .{backslash}bin{backslash}logstash.bat -f .{backslash}config{backslash}syslog.conf ----- NOTE: In a production environment, we recommend that you use <> to control Logstash execution. @@ -77,20 +81,24 @@ Wait for the following messages to appear, to confirm Logstash has started succe ==== Running Logstash as a service with NSSM NOTE: It is recommended to validate your configuration works by running Logstash manually before you proceed. -Download https://nssm.cc/[NSSM], then extract `nssm.exe` from `nssm-\win64\nssm.exe` to `C:\logstash-{logstash_version}\bin\`. Then open an Administrative https://docs.microsoft.com/en-us/powershell/[PowerShell] session, then run the following commands: +Download https://nssm.cc/[NSSM], then extract `nssm.exe` from +`nssm-\win64\nssm.exe` to +C:{backslash}logstash-{logstash_version}{backslash}bin{backslash}+. +Then open an Administrative +https://docs.microsoft.com/en-us/powershell/[PowerShell] session, then run the +following commands: ["source","sh",subs="attributes"] ----- -PS C:\Windows\system32> cd C:\logstash-{logstash_version}\ -PS C:\logstash-{logstash_version}> .\bin\nssm.exe install logstash +PS C:\Windows\system32> cd C:{backslash}logstash-{logstash_version}{backslash} +PS C:{backslash}logstash-{logstash_version}> .\bin\nssm.exe install logstash ----- Once the `NSSM service installer` window appears, specify the following parameters in the `Application` tab: ** In the `Application` tab: -*** Path: Path to `logstash.bat`: `C:\logstash-{logstash_version}\bin\logstash.bat` -*** Startup Directory: Path to the `bin` directory: `C:\logstash-{logstash_version}\bin` -*** Arguments: For this example to start Logstash: `-f C:\logstash-{logstash_version}\config\syslog.conf` +*** Path: Path to `logstash.bat`: +C:{backslash}logstash-{logstash_version}{backslash}bin{backslash}logstash.bat+ +*** Startup Directory: Path to the `bin` directory: +C:{backslash}logstash-{logstash_version}{backslash}bin+ +*** Arguments: For this example to start Logstash: +-f C:{backslash}logstash-{logstash_version}{backslash}config{backslash}syslog.conf+ + NOTE: In a production environment, we recommend that you use <> to control Logstash execution. @@ -117,11 +125,11 @@ Open the Windows https://docs.microsoft.com/en-us/windows/desktop/taskschd/task- ** In the `Actions` tab: *** Click `New`, then specify the following: *** Action: `Start a program` -*** Program/script: `C:\logstash-{logstash_version}\bin\logstash.bat` -*** Add arguments: `-f C:\logstash-{logstash_version}\config\syslog.conf` +*** Program/script: +C:{backslash}logstash-{logstash_version}{backslash}bin{backslash}logstash.bat+ +*** Add arguments: +-f C:\logstash-{logstash_version}{backslash}config{backslash}syslog.conf+ +*** Start in: +C:{backslash}logstash-{logstash_version}{backslash}bin{backslash}+ + NOTE: In a production environment, we recommend that you use <> to control Logstash execution. -*** Start in: C:\logstash-{logstash_version}\bin\ ** Review and make any changes necessary in the `General`, `Triggers`, `Conditions`, and `Settings` tabs. From 3d00f3e648f3d9b06fee370c102f475485afe3db Mon Sep 17 00:00:00 2001 From: DeDe Morton Date: Tue, 16 Jul 2019 14:13:15 -0700 Subject: [PATCH 0190/1126] Fix include path Fixes #10969 --- docs/static/core-plugins/filters/java-uuid-filter.asciidoc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/static/core-plugins/filters/java-uuid-filter.asciidoc b/docs/static/core-plugins/filters/java-uuid-filter.asciidoc index 9df103917..603704431 100644 --- a/docs/static/core-plugins/filters/java-uuid-filter.asciidoc +++ b/docs/static/core-plugins/filters/java-uuid-filter.asciidoc @@ -7,7 +7,7 @@ START - GENERATED VARIABLES, DO NOT EDIT! :version: %VERSION% :release_date: %RELEASE_DATE% :changelog_url: %CHANGELOG_URL% -:include_path: ../../../../logstash/docs/include +:include_path: ../../../../../logstash/docs/include /////////////////////////////////////////// END - GENERATED VARIABLES, DO NOT EDIT! /////////////////////////////////////////// From bd5f84ab0cd252a56e65d4f45a05683b9c207da8 Mon Sep 17 00:00:00 2001 From: Karen Metts Date: Thu, 18 Jul 2019 16:20:45 -0400 Subject: [PATCH 0191/1126] Prepare core plugin docs for inclusion in LS ref Fixes #10977 --- docs/include/plugin_header-core.asciidoc | 14 ++++++++++++++ .../{java-dots.asciidoc => java_dots.asciidoc} | 15 ++++++--------- .../{java-line.asciidoc => java_line.asciidoc} | 15 ++++++--------- ...{java-plain.asciidoc => java_plain.asciidoc} | 15 ++++++--------- ...-uuid-filter.asciidoc => java_uuid.asciidoc} | 14 ++++++-------- ...nerator.asciidoc => java_generator.asciidoc} | 17 +++++++---------- ...{java-stdin.asciidoc => java_stdin.asciidoc} | 15 ++++++--------- .../{java-sink.asciidoc => java_sink.asciidoc} | 17 +++++++---------- ...ava-stdout.asciidoc => java_stdout.asciidoc} | 15 ++++++--------- 9 files changed, 64 insertions(+), 73 deletions(-) create mode 100644 docs/include/plugin_header-core.asciidoc rename docs/static/core-plugins/codecs/{java-dots.asciidoc => java_dots.asciidoc} (64%) rename docs/static/core-plugins/codecs/{java-line.asciidoc => java_line.asciidoc} (94%) rename docs/static/core-plugins/codecs/{java-plain.asciidoc => java_plain.asciidoc} (94%) rename docs/static/core-plugins/filters/{java-uuid-filter.asciidoc => java_uuid.asciidoc} (89%) rename docs/static/core-plugins/inputs/{java-generator.asciidoc => java_generator.asciidoc} (89%) rename docs/static/core-plugins/inputs/{java-stdin.asciidoc => java_stdin.asciidoc} (70%) rename docs/static/core-plugins/outputs/{java-sink.asciidoc => java_sink.asciidoc} (66%) rename docs/static/core-plugins/outputs/{java-stdout.asciidoc => java_stdout.asciidoc} (78%) diff --git a/docs/include/plugin_header-core.asciidoc b/docs/include/plugin_header-core.asciidoc new file mode 100644 index 000000000..64717a25d --- /dev/null +++ b/docs/include/plugin_header-core.asciidoc @@ -0,0 +1,14 @@ +[subs="attributes"] +++++ +{plugin} +++++ + +*{ls} Core Plugin.* The {plugin} {type} plugin cannot be +installed or uninstalled independently of {ls}. + +==== Getting Help + +For questions about the plugin, open a topic in the +http://discuss.elastic.co[Discuss] forums. For bugs or feature requests, open an +issue in https://github.com/logstash[Github]. + diff --git a/docs/static/core-plugins/codecs/java-dots.asciidoc b/docs/static/core-plugins/codecs/java_dots.asciidoc similarity index 64% rename from docs/static/core-plugins/codecs/java-dots.asciidoc rename to docs/static/core-plugins/codecs/java_dots.asciidoc index 6e9b04f7d..486ea30c9 100644 --- a/docs/static/core-plugins/codecs/java-dots.asciidoc +++ b/docs/static/core-plugins/codecs/java_dots.asciidoc @@ -1,22 +1,19 @@ -:plugin: jdots +:plugin: java_dots :type: codec /////////////////////////////////////////// -START - GENERATED VARIABLES, DO NOT EDIT! +REPLACES GENERATED VARIABLES /////////////////////////////////////////// -:version: %VERSION% -:release_date: %RELEASE_DATE% -:changelog_url: %CHANGELOG_URL% -:include_path: ../../../../logstash/docs/include +:include_path: ../../../../../logstash/docs/include /////////////////////////////////////////// -END - GENERATED VARIABLES, DO NOT EDIT! +END - REPLACES GENERATED VARIABLES /////////////////////////////////////////// [id="plugins-{type}s-{plugin}"] -=== Java dots codec plugin +=== Java_dots codec plugin -include::{include_path}/plugin_header.asciidoc[] +include::{include_path}/plugin_header-core.asciidoc[] ==== Description diff --git a/docs/static/core-plugins/codecs/java-line.asciidoc b/docs/static/core-plugins/codecs/java_line.asciidoc similarity index 94% rename from docs/static/core-plugins/codecs/java-line.asciidoc rename to docs/static/core-plugins/codecs/java_line.asciidoc index d769b1b6a..6b0f64d4f 100644 --- a/docs/static/core-plugins/codecs/java-line.asciidoc +++ b/docs/static/core-plugins/codecs/java_line.asciidoc @@ -2,21 +2,18 @@ :type: codec /////////////////////////////////////////// -START - GENERATED VARIABLES, DO NOT EDIT! +REPLACES GENERATED VARIABLES /////////////////////////////////////////// -:version: %VERSION% -:release_date: %RELEASE_DATE% -:changelog_url: %CHANGELOG_URL% -:include_path: ../../../../logstash/docs/include +:include_path: ../../../../../logstash/docs/include /////////////////////////////////////////// -END - GENERATED VARIABLES, DO NOT EDIT! +END - REPLACES GENERATED VARIABLES /////////////////////////////////////////// [id="plugins-{type}s-{plugin}"] -=== Java line codec plugin +=== Java_line codec plugin -include::{include_path}/plugin_header.asciidoc[] +include::{include_path}/plugin_header-core.asciidoc[] ==== Description @@ -27,7 +24,7 @@ Decoding behavior: All text data between specified delimiters will be decoded as Encoding behavior: Each event will be emitted with the specified trailing delimiter. [id="plugins-{type}s-{plugin}-options"] -==== Line Codec Configuration Options +==== Java_line Codec Configuration Options [cols="<,<,<",options="header",] |======================================================================= diff --git a/docs/static/core-plugins/codecs/java-plain.asciidoc b/docs/static/core-plugins/codecs/java_plain.asciidoc similarity index 94% rename from docs/static/core-plugins/codecs/java-plain.asciidoc rename to docs/static/core-plugins/codecs/java_plain.asciidoc index b2d819a97..97685739d 100644 --- a/docs/static/core-plugins/codecs/java-plain.asciidoc +++ b/docs/static/core-plugins/codecs/java_plain.asciidoc @@ -2,21 +2,18 @@ :type: codec /////////////////////////////////////////// -START - GENERATED VARIABLES, DO NOT EDIT! +REPLACES GENERATED VARIABLES /////////////////////////////////////////// -:version: %VERSION% -:release_date: %RELEASE_DATE% -:changelog_url: %CHANGELOG_URL% -:include_path: ../../../../logstash/docs/include +:include_path: ../../../../../logstash/docs/include /////////////////////////////////////////// -END - GENERATED VARIABLES, DO NOT EDIT! +END - REPLACES GENERATED VARIABLES /////////////////////////////////////////// [id="plugins-{type}s-{plugin}"] -=== Java plain codec plugin +=== Java_plain codec plugin -include::{include_path}/plugin_header.asciidoc[] +include::{include_path}/plugin_header-core.asciidoc[] ==== Description @@ -24,7 +21,7 @@ The `java_plain` codec is for text data with no delimiters between events. It is already have a defined framing in their transport protocol such as ZeroMQ, RabbitMQ, Redis, etc. [id="plugins-{type}s-{plugin}-options"] -==== Plain Codec Configuration Options +==== Java_plain Codec Configuration Options [cols="<,<,<",options="header",] |======================================================================= diff --git a/docs/static/core-plugins/filters/java-uuid-filter.asciidoc b/docs/static/core-plugins/filters/java_uuid.asciidoc similarity index 89% rename from docs/static/core-plugins/filters/java-uuid-filter.asciidoc rename to docs/static/core-plugins/filters/java_uuid.asciidoc index 603704431..bfa66aaa0 100644 --- a/docs/static/core-plugins/filters/java-uuid-filter.asciidoc +++ b/docs/static/core-plugins/filters/java_uuid.asciidoc @@ -2,21 +2,19 @@ :type: filter /////////////////////////////////////////// -START - GENERATED VARIABLES, DO NOT EDIT! +REPLACES GENERATED VARIABLES /////////////////////////////////////////// -:version: %VERSION% -:release_date: %RELEASE_DATE% -:changelog_url: %CHANGELOG_URL% :include_path: ../../../../../logstash/docs/include /////////////////////////////////////////// -END - GENERATED VARIABLES, DO NOT EDIT! +END - REPLACES GENERATED VARIABLES /////////////////////////////////////////// + [id="plugins-{type}s-{plugin}"] -=== Java UUID filter plugin +=== Java_uuid filter plugin -include::{include_path}/plugin_header.asciidoc[] +include::{include_path}/plugin_header-core.asciidoc[] ==== Description @@ -36,7 +34,7 @@ represented in standard hexadecimal string format, e.g. "e08806fe-02af-406c-bbde-8a5ae4475e57". [id="plugins-{type}s-{plugin}-options"] -==== Uuid Filter Configuration Options +==== Java_uuid Filter Configuration Options This plugin supports the following configuration options plus the <> described later. diff --git a/docs/static/core-plugins/inputs/java-generator.asciidoc b/docs/static/core-plugins/inputs/java_generator.asciidoc similarity index 89% rename from docs/static/core-plugins/inputs/java-generator.asciidoc rename to docs/static/core-plugins/inputs/java_generator.asciidoc index d3b9b422e..b888a8fa7 100644 --- a/docs/static/core-plugins/inputs/java-generator.asciidoc +++ b/docs/static/core-plugins/inputs/java_generator.asciidoc @@ -3,32 +3,29 @@ :default_codec: plain /////////////////////////////////////////// -START - GENERATED VARIABLES, DO NOT EDIT! +REPLACES GENERATED VARIABLES /////////////////////////////////////////// -:version: %VERSION% -:release_date: %RELEASE_DATE% -:changelog_url: %CHANGELOG_URL% -:include_path: ../../../../logstash/docs/include +:include_path: ../../../../../logstash/docs/include /////////////////////////////////////////// -END - GENERATED VARIABLES, DO NOT EDIT! +END - REPLACES GENERATED VARIABLES /////////////////////////////////////////// [id="plugins-{type}s-{plugin}"] -=== Java generator input plugin +=== Java_generator input plugin -include::{include_path}/plugin_header.asciidoc[] +include::{include_path}/plugin_header-core.asciidoc[] ==== Description -Generate synthethic log events. +Generate synthetic log events. This plugin generates a stream of synthetic events that can be used to test the correctness or performance of a Logstash pipeline. [id="plugins-{type}s-{plugin}-options"] -==== Generator Input Configuration Options +==== Java_generator Input Configuration Options This plugin supports the following configuration options plus the <> described later. diff --git a/docs/static/core-plugins/inputs/java-stdin.asciidoc b/docs/static/core-plugins/inputs/java_stdin.asciidoc similarity index 70% rename from docs/static/core-plugins/inputs/java-stdin.asciidoc rename to docs/static/core-plugins/inputs/java_stdin.asciidoc index e103cc094..d7137540e 100644 --- a/docs/static/core-plugins/inputs/java-stdin.asciidoc +++ b/docs/static/core-plugins/inputs/java_stdin.asciidoc @@ -3,21 +3,18 @@ :default_codec: java_line /////////////////////////////////////////// -START - GENERATED VARIABLES, DO NOT EDIT! +REPLACES GENERATED VARIABLES /////////////////////////////////////////// -:version: %VERSION% -:release_date: %RELEASE_DATE% -:changelog_url: %CHANGELOG_URL% -:include_path: ../../../../logstash/docs/include +:include_path: ../../../../../logstash/docs/include /////////////////////////////////////////// -END - GENERATED VARIABLES, DO NOT EDIT! +END - REPLACES GENERATED VARIABLES /////////////////////////////////////////// [id="plugins-{type}s-{plugin}"] -=== Java stdin input plugin +=== Java_stdin input plugin -include::{include_path}/plugin_header.asciidoc[] +include::{include_path}/plugin_header-core.asciidoc[] ==== Description @@ -27,7 +24,7 @@ By default, each event is assumed to be terminated by end-of-line. If you want e method, you'll need to use a codec with support for that encoding. [id="plugins-{type}s-{plugin}-options"] -==== Stdin Input Configuration Options +==== Java_stdin Input Configuration Options There are no special configuration options for this plugin, but it does support the <>. diff --git a/docs/static/core-plugins/outputs/java-sink.asciidoc b/docs/static/core-plugins/outputs/java_sink.asciidoc similarity index 66% rename from docs/static/core-plugins/outputs/java-sink.asciidoc rename to docs/static/core-plugins/outputs/java_sink.asciidoc index e52b2e8ed..cfec6dbb9 100644 --- a/docs/static/core-plugins/outputs/java-sink.asciidoc +++ b/docs/static/core-plugins/outputs/java_sink.asciidoc @@ -1,23 +1,20 @@ -:plugin: sink +:plugin: java_sink :type: output :default_codec!: /////////////////////////////////////////// -START - GENERATED VARIABLES, DO NOT EDIT! +REPLACES GENERATED VARIABLES /////////////////////////////////////////// -:version: %VERSION% -:release_date: %RELEASE_DATE% -:changelog_url: %CHANGELOG_URL% -:include_path: ../../../../logstash/docs/include +:include_path: ../../../../../logstash/docs/include /////////////////////////////////////////// -END - GENERATED VARIABLES, DO NOT EDIT! +END - REPLACES GENERATED VARIABLES /////////////////////////////////////////// [id="plugins-{type}s-{plugin}"] -=== Sink output plugin +=== Java_sink output plugin -include::{include_path}/plugin_header.asciidoc[] +include::{include_path}/plugin_header-core.asciidoc[] ==== Description @@ -25,7 +22,7 @@ An event sink that discards any events received. Generally useful for testing th and filters. [id="plugins-{type}s-{plugin}-options"] -==== Sink Output Configuration Options +==== Java_sink Output Configuration Options There are no special configuration options for this plugin, but it does support the <>. diff --git a/docs/static/core-plugins/outputs/java-stdout.asciidoc b/docs/static/core-plugins/outputs/java_stdout.asciidoc similarity index 78% rename from docs/static/core-plugins/outputs/java-stdout.asciidoc rename to docs/static/core-plugins/outputs/java_stdout.asciidoc index c040c3451..315a109b8 100644 --- a/docs/static/core-plugins/outputs/java-stdout.asciidoc +++ b/docs/static/core-plugins/outputs/java_stdout.asciidoc @@ -3,21 +3,18 @@ :default_codec: java_line /////////////////////////////////////////// -START - GENERATED VARIABLES, DO NOT EDIT! +REPLACES GENERATED VARIABLES /////////////////////////////////////////// -:version: %VERSION% -:release_date: %RELEASE_DATE% -:changelog_url: %CHANGELOG_URL% -:include_path: ../../../../logstash/docs/include +:include_path: ../../../../../logstash/docs/include /////////////////////////////////////////// -END - GENERATED VARIABLES, DO NOT EDIT! +END - REPLACES GENERATED VARIABLES /////////////////////////////////////////// [id="plugins-{type}s-{plugin}"] -=== Java stdout output plugin +=== Java_stdout output plugin -include::{include_path}/plugin_header.asciidoc[] +include::{include_path}/plugin_header-core.asciidoc[] ==== Description @@ -42,7 +39,7 @@ java_stdout. } [id="plugins-{type}s-{plugin}-options"] -==== Stdout Output Configuration Options +==== Java_stdout Output Configuration Options There are no special configuration options for this plugin, but it does support the <>. From f474ecb9a9ccb56f59c05a652beb72d9b74efe11 Mon Sep 17 00:00:00 2001 From: Karen Metts Date: Mon, 22 Jul 2019 08:39:32 -0400 Subject: [PATCH 0192/1126] Incorporate review comments Fixes #10977 --- docs/static/core-plugins/codecs/java_dots.asciidoc | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/docs/static/core-plugins/codecs/java_dots.asciidoc b/docs/static/core-plugins/codecs/java_dots.asciidoc index 486ea30c9..3337668f3 100644 --- a/docs/static/core-plugins/codecs/java_dots.asciidoc +++ b/docs/static/core-plugins/codecs/java_dots.asciidoc @@ -1,4 +1,4 @@ -:plugin: java_dots +:plugin: jdots :type: codec /////////////////////////////////////////// @@ -11,7 +11,7 @@ END - REPLACES GENERATED VARIABLES [id="plugins-{type}s-{plugin}"] -=== Java_dots codec plugin +=== Jdots codec plugin include::{include_path}/plugin_header-core.asciidoc[] From 524dd452024cf9c7032a313221370b1f8ca4a87d Mon Sep 17 00:00:00 2001 From: Colin Surprenant Date: Fri, 19 Jul 2019 14:49:03 -0400 Subject: [PATCH 0193/1126] make sure joni regexp interruptability is enabled Fixes #10978 --- config/jvm.options | 2 ++ 1 file changed, 2 insertions(+) diff --git a/config/jvm.options b/config/jvm.options index 401f7154b..ac27467d0 100644 --- a/config/jvm.options +++ b/config/jvm.options @@ -49,6 +49,8 @@ -Djruby.compile.invokedynamic=true # Force Compilation -Djruby.jit.threshold=0 +# Make sure joni regexp interruptability is enabled +-Djruby.regexp.interruptible=true ## heap dumps From 6810c1952503ea7f625e7798c34cd4588995a1f0 Mon Sep 17 00:00:00 2001 From: Ry Biesemeyer Date: Mon, 22 Jul 2019 23:40:00 +0000 Subject: [PATCH 0194/1126] update Jinja2 docker dependency Fixes #10986 --- docker/requirements.txt | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/docker/requirements.txt b/docker/requirements.txt index b75870b5b..8fffe2d3b 100644 --- a/docker/requirements.txt +++ b/docker/requirements.txt @@ -1,6 +1,6 @@ flake8==3.4.1 -jinja2-cli[yaml]==0.6.0 -jinja2==2.9.5 +jinja2-cli[yaml]==0.7.0 +jinja2==2.10.1 retrying==1.3.3 testinfra==1.6.0 pyfiglet From 3293c22d2d8d34208f0ed811b64e35328fdce265 Mon Sep 17 00:00:00 2001 From: Nik Everett Date: Wed, 24 Jul 2019 15:02:46 -0400 Subject: [PATCH 0195/1126] Docs: Add more missing subs for asciidoctor (#10991) Adds a few missing `[attributes="subs"]` clauses for asciidoctor. --- docs/static/monitoring/configuring-logstash.asciidoc | 1 + docs/static/security/logstash.asciidoc | 1 + docs/static/setup/configuring-xls.asciidoc | 1 + 3 files changed, 3 insertions(+) diff --git a/docs/static/monitoring/configuring-logstash.asciidoc b/docs/static/monitoring/configuring-logstash.asciidoc index d1a69cd1d..62fe025e5 100644 --- a/docs/static/monitoring/configuring-logstash.asciidoc +++ b/docs/static/monitoring/configuring-logstash.asciidoc @@ -1,6 +1,7 @@ [role="xpack"] [[configuring-logstash]] === Configuring Monitoring for Logstash Nodes +[subs="attributes"] ++++ {monitoring} ++++ diff --git a/docs/static/security/logstash.asciidoc b/docs/static/security/logstash.asciidoc index c54910894..3a95fc426 100644 --- a/docs/static/security/logstash.asciidoc +++ b/docs/static/security/logstash.asciidoc @@ -1,6 +1,7 @@ [role="xpack"] [[ls-security]] === Configuring Security in Logstash +[subs="attributes"] ++++ {security} ++++ diff --git a/docs/static/setup/configuring-xls.asciidoc b/docs/static/setup/configuring-xls.asciidoc index 9017c24d7..a4702e36e 100644 --- a/docs/static/setup/configuring-xls.asciidoc +++ b/docs/static/setup/configuring-xls.asciidoc @@ -1,6 +1,7 @@ [role="xpack"] [[settings-xpack]] === {xpack} Settings in Logstash +[subs="attributes"] ++++ {xpack} Settings ++++ From 120b6a7d041692b30d1fb6a72fd6f38d8c8bc87d Mon Sep 17 00:00:00 2001 From: Dan Hermann Date: Mon, 5 Aug 2019 10:38:13 -0500 Subject: [PATCH 0196/1126] add regex support for constant conditionals Fixes #11017 --- .../config/ir/compiler/EventCondition.java | 33 +++++++++++++++- .../config/ir/CompiledPipelineTest.java | 38 +++++++++++++++++++ 2 files changed, 69 insertions(+), 2 deletions(-) diff --git a/logstash-core/src/main/java/org/logstash/config/ir/compiler/EventCondition.java b/logstash-core/src/main/java/org/logstash/config/ir/compiler/EventCondition.java index f76b6eb35..329951bc8 100644 --- a/logstash-core/src/main/java/org/logstash/config/ir/compiler/EventCondition.java +++ b/logstash-core/src/main/java/org/logstash/config/ir/compiler/EventCondition.java @@ -19,6 +19,7 @@ import org.logstash.config.ir.expression.BinaryBooleanExpression; import org.logstash.config.ir.expression.BooleanExpression; import org.logstash.config.ir.expression.EventValueExpression; import org.logstash.config.ir.expression.Expression; +import org.logstash.config.ir.expression.RegexValueExpression; import org.logstash.config.ir.expression.ValueExpression; import org.logstash.config.ir.expression.binary.And; import org.logstash.config.ir.expression.binary.Eq; @@ -184,6 +185,11 @@ public interface EventCondition { expression.getRight() instanceof EventValueExpression; } + private static boolean vAndR(final BinaryBooleanExpression expression) { + return expression.getLeft() instanceof ValueExpression && + expression.getRight() instanceof RegexValueExpression; + } + private static EventCondition truthy(final Truthy truthy) { final EventCondition condition; final Expression inner = truthy.getExpression(); @@ -201,8 +207,13 @@ public interface EventCondition { final Expression uright = regex.getRight(); if (eAndV(regex)) { condition = new EventCondition.Compiler.FieldMatches( - ((EventValueExpression) uleft).getFieldName(), - ((ValueExpression) uright).get().toString() + ((EventValueExpression) uleft).getFieldName(), + ((ValueExpression) uright).get().toString() + ); + } else if (vAndR(regex)) { + condition = new EventCondition.Compiler.ConstantMatches( + ((ValueExpression) uleft).get(), + ((RegexValueExpression) uright).get().toString() ); } else { throw new EventCondition.Compiler.UnexpectedTypeException(uleft, uright); @@ -463,6 +474,24 @@ public interface EventCondition { } } + private static final class ConstantMatches implements EventCondition { + + private final boolean matches; + + private ConstantMatches(final Object constant, final String regex) { + this.matches = constant instanceof String && + !(RubyUtil.RUBY.newString((String) constant).match( + WorkerLoop.THREAD_CONTEXT.get(), + RubyUtil.RUBY.newString(regex)).isNil()); + } + + @Override + public boolean fulfilled(final JrubyEventExtLibrary.RubyEvent event) { + return matches; + } + + } + private static final class ConstantStringInField implements EventCondition { private final FieldReference field; diff --git a/logstash-core/src/test/java/org/logstash/config/ir/CompiledPipelineTest.java b/logstash-core/src/test/java/org/logstash/config/ir/CompiledPipelineTest.java index 4017509b8..9c1b17b6e 100644 --- a/logstash-core/src/test/java/org/logstash/config/ir/CompiledPipelineTest.java +++ b/logstash-core/src/test/java/org/logstash/config/ir/CompiledPipelineTest.java @@ -249,6 +249,43 @@ public final class CompiledPipelineTest extends RubyEnvTestCase { assertCorrectFieldToFieldComparison(gte, 7, 8, false); } + @Test + public void correctlyCompilesRegexMatchesWithConstant() throws IncompleteSourceWithMetadataException { + verifyRegex("=~", 1); + } + + @Test + public void correctlyCompilesRegexNoMatchesWithConstant() throws IncompleteSourceWithMetadataException { + verifyRegex("!~", 0); + } + + private void verifyRegex(String operator, int expectedEvents) + throws IncompleteSourceWithMetadataException { + final Event event = new Event(); + + final JrubyEventExtLibrary.RubyEvent testEvent = + JrubyEventExtLibrary.RubyEvent.newRubyEvent(RubyUtil.RUBY, event); + + new CompiledPipeline( + ConfigCompiler.configToPipelineIR( + "input {mockinput{}} output { " + + String.format("if \"z\" %s /z/ { ", operator) + + " mockoutput{} } }", + false + ), + new CompiledPipelineTest.MockPluginFactory( + Collections.singletonMap("mockinput", () -> null), + Collections.singletonMap("mockaddfilter", () -> null), + Collections.singletonMap("mockoutput", mockOutputSupplier()) + ) + ).buildExecution() + .compute(RubyUtil.RUBY.newArray(testEvent), false, false); + final Collection outputEvents = EVENT_SINKS.get(runId); + MatcherAssert.assertThat(outputEvents.size(), CoreMatchers.is(expectedEvents)); + MatcherAssert.assertThat(outputEvents.contains(testEvent), CoreMatchers.is(expectedEvents >= 1)); + outputEvents.clear(); + } + @Test public void equalityCheckOnCompositeField() throws Exception { final PipelineIR pipelineIR = ConfigCompiler.configToPipelineIR( @@ -386,6 +423,7 @@ public final class CompiledPipelineTest extends RubyEnvTestCase { final Event event) throws IncompleteSourceWithMetadataException { final JrubyEventExtLibrary.RubyEvent testEvent = JrubyEventExtLibrary.RubyEvent.newRubyEvent(RubyUtil.RUBY, event); + new CompiledPipeline( ConfigCompiler.configToPipelineIR( "input {mockinput{}} filter { " + From 4b5dc343ae10b95e67967f1d55db14f28189494e Mon Sep 17 00:00:00 2001 From: Dan Hermann Date: Wed, 7 Aug 2019 07:07:53 -0500 Subject: [PATCH 0197/1126] fix compilation of [field] in [field] event conditions Fixes #11026 --- logstash-core/build.gradle | 2 + .../config/ir/compiler/EventCondition.java | 6 +- .../config/ir/CompiledPipelineTest.java | 6 +- .../config/ir/EventConditionTest.java | 127 ++++++++++++++++++ 4 files changed, 135 insertions(+), 6 deletions(-) create mode 100644 logstash-core/src/test/java/org/logstash/config/ir/EventConditionTest.java diff --git a/logstash-core/build.gradle b/logstash-core/build.gradle index 13ddb05ff..6a6b1ed5a 100644 --- a/logstash-core/build.gradle +++ b/logstash-core/build.gradle @@ -68,6 +68,7 @@ task javaTests(type: Test) { exclude '/org/logstash/RSpecTests.class' exclude '/org/logstash/config/ir/ConfigCompilerTest.class' exclude '/org/logstash/config/ir/CompiledPipelineTest.class' + exclude '/org/logstash/config/ir/EventConditionTest.class' exclude '/org/logstash/config/ir/compiler/OutputDelegatorTest.class' exclude '/org/logstash/config/ir/compiler/JavaCodecDelegatorTest.class' exclude '/org/logstash/plugins/NamespacedMetricImplTest.class' @@ -81,6 +82,7 @@ task rubyTests(type: Test) { include '/org/logstash/RSpecTests.class' include '/org/logstash/config/ir/ConfigCompilerTest.class' include '/org/logstash/config/ir/CompiledPipelineTest.class' + include '/org/logstash/config/ir/EventConditionTest.class' include '/org/logstash/config/ir/compiler/OutputDelegatorTest.class' include '/org/logstash/config/ir/compiler/JavaCodecDelegatorTest.class' include '/org/logstash/plugins/NamespacedMetricImplTest.class' diff --git a/logstash-core/src/main/java/org/logstash/config/ir/compiler/EventCondition.java b/logstash-core/src/main/java/org/logstash/config/ir/compiler/EventCondition.java index 329951bc8..c8e29c32b 100644 --- a/logstash-core/src/main/java/org/logstash/config/ir/compiler/EventCondition.java +++ b/logstash-core/src/main/java/org/logstash/config/ir/compiler/EventCondition.java @@ -287,7 +287,7 @@ public interface EventCondition { (EventValueExpression) left, (List) ((ValueExpression) right).get() ); } else if (eAndE(in)) { - condition = in((EventValueExpression) right, (EventValueExpression) left); + condition = in((EventValueExpression) left, (EventValueExpression) right); } else if (vAndV(in)) { condition = in((ValueExpression) left, (ValueExpression) right); } else { @@ -571,8 +571,8 @@ public interface EventCondition { if (lfound instanceof ConvertedList || lfound instanceof ConvertedMap) { return false; } else if (lfound instanceof RubyString && rfound instanceof RubyString) { - return ((RubyString) lfound).getByteList() - .indexOf(((RubyString) rfound).getByteList()) > -1; + return ((RubyString) rfound).getByteList() + .indexOf(((RubyString) lfound).getByteList()) > -1; } else if (rfound instanceof ConvertedList) { return contains((ConvertedList) rfound, lfound); } else { diff --git a/logstash-core/src/test/java/org/logstash/config/ir/CompiledPipelineTest.java b/logstash-core/src/test/java/org/logstash/config/ir/CompiledPipelineTest.java index 9c1b17b6e..70642c106 100644 --- a/logstash-core/src/test/java/org/logstash/config/ir/CompiledPipelineTest.java +++ b/logstash-core/src/test/java/org/logstash/config/ir/CompiledPipelineTest.java @@ -50,7 +50,7 @@ public final class CompiledPipelineTest extends RubyEnvTestCase { /** * Mock filter that does not modify the batch. */ - private static final IRubyObject IDENTITY_FILTER = RubyUtil.RUBY.evalScriptlet( + static final IRubyObject IDENTITY_FILTER = RubyUtil.RUBY.evalScriptlet( String.join( "\n", "output = Object.new", @@ -64,7 +64,7 @@ public final class CompiledPipelineTest extends RubyEnvTestCase { /** * Mock filter that adds the value 'bar' to the field 'foo' for every event in the batch. */ - private static final IRubyObject ADD_FIELD_FILTER = RubyUtil.RUBY.evalScriptlet( + static final IRubyObject ADD_FIELD_FILTER = RubyUtil.RUBY.evalScriptlet( String.join( "\n", "output = Object.new", @@ -458,7 +458,7 @@ public final class CompiledPipelineTest extends RubyEnvTestCase { /** * Configurable Mock {@link PluginFactory} */ - private static final class MockPluginFactory implements PluginFactory { + static final class MockPluginFactory implements PluginFactory { private final Map> inputs; diff --git a/logstash-core/src/test/java/org/logstash/config/ir/EventConditionTest.java b/logstash-core/src/test/java/org/logstash/config/ir/EventConditionTest.java new file mode 100644 index 000000000..29a234596 --- /dev/null +++ b/logstash-core/src/test/java/org/logstash/config/ir/EventConditionTest.java @@ -0,0 +1,127 @@ +package org.logstash.config.ir; + +import org.hamcrest.CoreMatchers; +import org.hamcrest.MatcherAssert; +import org.jruby.RubyArray; +import org.junit.After; +import org.junit.Before; +import org.junit.Test; +import org.logstash.RubyUtil; +import org.logstash.ext.JrubyEventExtLibrary; + +import java.util.Arrays; +import java.util.Collection; +import java.util.Collections; +import java.util.List; +import java.util.Map; +import java.util.concurrent.ConcurrentHashMap; +import java.util.concurrent.LinkedTransferQueue; +import java.util.concurrent.atomic.AtomicLong; +import java.util.function.Consumer; +import java.util.function.Supplier; + +import static org.logstash.config.ir.CompiledPipelineTest.IDENTITY_FILTER; +import static org.logstash.ext.JrubyEventExtLibrary.RubyEvent; + +public final class EventConditionTest extends RubyEnvTestCase { + + /** + * Globally accessible map of test run id to a queue of {@link JrubyEventExtLibrary.RubyEvent} + * that can be used by Ruby outputs. + */ + private static final Map> EVENT_SINKS = + new ConcurrentHashMap<>(); + + private static final AtomicLong TEST_RUN = new AtomicLong(); + + /** + * Unique identifier for this test run so that mock test outputs can correctly identify + * their event sink in {@link #EVENT_SINKS}. + */ + private long runId; + + @Before + public void beforeEach() { + runId = TEST_RUN.incrementAndGet(); + EVENT_SINKS.put(runId, new LinkedTransferQueue<>()); + } + + @After + public void afterEach() { + EVENT_SINKS.remove(runId); + } + + @Test + @SuppressWarnings("rawtypes") + public void testInclusionWithFieldInField() throws Exception { + final PipelineIR pipelineIR = ConfigCompiler.configToPipelineIR( + "input {mockinput{}} filter { " + + "mockfilter {} } " + + "output { " + + " if [left] in [right] { " + + " mockoutput{}" + + " } }", + false + ); + + // left list values never match + RubyEvent leftIsList = RubyEvent.newRubyEvent(RubyUtil.RUBY); + List listValues = Arrays.asList("foo", "bar", "baz"); + leftIsList.getEvent().setField("left", listValues); + leftIsList.getEvent().setField("right", listValues); + + // left map values never match + RubyEvent leftIsMap = RubyEvent.newRubyEvent(RubyUtil.RUBY); + Map mapValues = Collections.singletonMap("foo", "bar"); + leftIsMap.getEvent().setField("left", mapValues); + leftIsMap.getEvent().setField("right", mapValues); + + // left and right string values match when right.contains(left) + RubyEvent leftIsString1 = RubyEvent.newRubyEvent(RubyUtil.RUBY); + leftIsString1.getEvent().setField("left", "foo"); + leftIsString1.getEvent().setField("right", "zfooz"); + RubyEvent leftIsString2 = RubyEvent.newRubyEvent(RubyUtil.RUBY); + leftIsString2.getEvent().setField("left", "foo"); + leftIsString2.getEvent().setField("right", "zzz"); + + // right list value matches when right.contains(left) + RubyEvent rightIsList1 = RubyEvent.newRubyEvent(RubyUtil.RUBY); + rightIsList1.getEvent().setField("left", "bar"); + rightIsList1.getEvent().setField("right", listValues); + RubyEvent rightIsList2 = RubyEvent.newRubyEvent(RubyUtil.RUBY); + rightIsList2.getEvent().setField("left", "zzz"); + rightIsList2.getEvent().setField("right", listValues); + + // non-string values match when left == right + RubyEvent nonStringValue1 = RubyEvent.newRubyEvent(RubyUtil.RUBY); + nonStringValue1.getEvent().setField("left", 42L); + nonStringValue1.getEvent().setField("right", 42L); + RubyEvent nonStringValue2 = RubyEvent.newRubyEvent(RubyUtil.RUBY); + nonStringValue2.getEvent().setField("left", 42L); + nonStringValue2.getEvent().setField("right", 43L); + + RubyArray inputBatch = RubyUtil.RUBY.newArray(leftIsList, leftIsMap, leftIsString1, leftIsString2, + rightIsList1, rightIsList2, nonStringValue1, nonStringValue2); + + new CompiledPipeline( + pipelineIR, + new CompiledPipelineTest.MockPluginFactory( + Collections.singletonMap("mockinput", () -> null), + Collections.singletonMap("mockfilter", () -> IDENTITY_FILTER), + Collections.singletonMap("mockoutput", mockOutputSupplier()) + ) + ).buildExecution().compute(inputBatch, false, false); + final RubyEvent[] outputEvents = EVENT_SINKS.get(runId).toArray(new RubyEvent[0]); + + MatcherAssert.assertThat(outputEvents.length, CoreMatchers.is(3)); + MatcherAssert.assertThat(outputEvents[0], CoreMatchers.is(leftIsString1)); + MatcherAssert.assertThat(outputEvents[1], CoreMatchers.is(rightIsList1)); + MatcherAssert.assertThat(outputEvents[2], CoreMatchers.is(nonStringValue1)); + } + + private Supplier>> mockOutputSupplier() { + return () -> events -> events.forEach( + event -> EVENT_SINKS.get(runId).add(event) + ); + } +} From d64e5a7853f12ce048695bed6d5c3347b066d14b Mon Sep 17 00:00:00 2001 From: Dan Hermann Date: Thu, 8 Aug 2019 14:08:34 -0500 Subject: [PATCH 0198/1126] support truthy eval of constants Fixes #11032 --- .../config/ir/compiler/EventCondition.java | 18 ++++--- .../config/ir/EventConditionTest.java | 52 ++++++++++++++++--- 2 files changed, 58 insertions(+), 12 deletions(-) diff --git a/logstash-core/src/main/java/org/logstash/config/ir/compiler/EventCondition.java b/logstash-core/src/main/java/org/logstash/config/ir/compiler/EventCondition.java index c8e29c32b..2ce320f2a 100644 --- a/logstash-core/src/main/java/org/logstash/config/ir/compiler/EventCondition.java +++ b/logstash-core/src/main/java/org/logstash/config/ir/compiler/EventCondition.java @@ -195,6 +195,8 @@ public interface EventCondition { final Expression inner = truthy.getExpression(); if (inner instanceof EventValueExpression) { condition = truthy((EventValueExpression) inner); + } else if (inner instanceof ValueExpression) { + condition = constant(valueIsTruthy(((ValueExpression) inner).get())); } else { throw new EventCondition.Compiler.UnexpectedTypeException(inner); } @@ -455,6 +457,15 @@ public interface EventCondition { return value ? event -> true : event -> false; } + private static boolean valueIsTruthy(Object object) { + if (object == null) { + return false; + } + final String other = object.toString(); + return other != null && !other.isEmpty() && + !Boolean.toString(false).equals(other); + } + private static final class FieldMatches implements EventCondition { private final FieldReference field; @@ -611,12 +622,7 @@ public interface EventCondition { @Override public boolean fulfilled(final JrubyEventExtLibrary.RubyEvent event) { final Object object = event.getEvent().getUnconvertedField(field); - if (object == null) { - return false; - } - final String other = object.toString(); - return other != null && !other.isEmpty() && - !Boolean.toString(false).equals(other); + return valueIsTruthy(object); } } diff --git a/logstash-core/src/test/java/org/logstash/config/ir/EventConditionTest.java b/logstash-core/src/test/java/org/logstash/config/ir/EventConditionTest.java index 29a234596..0d47a4a1d 100644 --- a/logstash-core/src/test/java/org/logstash/config/ir/EventConditionTest.java +++ b/logstash-core/src/test/java/org/logstash/config/ir/EventConditionTest.java @@ -1,7 +1,5 @@ package org.logstash.config.ir; -import org.hamcrest.CoreMatchers; -import org.hamcrest.MatcherAssert; import org.jruby.RubyArray; import org.junit.After; import org.junit.Before; @@ -22,6 +20,8 @@ import java.util.function.Supplier; import static org.logstash.config.ir.CompiledPipelineTest.IDENTITY_FILTER; import static org.logstash.ext.JrubyEventExtLibrary.RubyEvent; +import static org.hamcrest.CoreMatchers.is; +import static org.hamcrest.MatcherAssert.assertThat; public final class EventConditionTest extends RubyEnvTestCase { @@ -113,10 +113,50 @@ public final class EventConditionTest extends RubyEnvTestCase { ).buildExecution().compute(inputBatch, false, false); final RubyEvent[] outputEvents = EVENT_SINKS.get(runId).toArray(new RubyEvent[0]); - MatcherAssert.assertThat(outputEvents.length, CoreMatchers.is(3)); - MatcherAssert.assertThat(outputEvents[0], CoreMatchers.is(leftIsString1)); - MatcherAssert.assertThat(outputEvents[1], CoreMatchers.is(rightIsList1)); - MatcherAssert.assertThat(outputEvents[2], CoreMatchers.is(nonStringValue1)); + assertThat(outputEvents.length, is(3)); + assertThat(outputEvents[0], is(leftIsString1)); + assertThat(outputEvents[1], is(rightIsList1)); + assertThat(outputEvents[2], is(nonStringValue1)); + } + + @Test + public void testConditionWithConstantValue() throws Exception { + testConditionWithConstantValue("\"[abc]\"", 1); + } + + @Test + public void testConditionWithConstantFalseLiteralValue() throws Exception { + testConditionWithConstantValue("\"false\"", 0); + } + + @Test + public void testConditionWithConstantEmptyStringValue() throws Exception { + testConditionWithConstantValue("\"\"", 0); + } + + private void testConditionWithConstantValue(String condition, int expectedMatches) throws Exception { + final PipelineIR pipelineIR = ConfigCompiler.configToPipelineIR( + "input {mockinput{}} filter { " + + "mockfilter {} } " + + "output { " + + " if " + condition + " { " + + " mockoutput{}" + + " } }", + false + ); + + new CompiledPipeline( + pipelineIR, + new CompiledPipelineTest.MockPluginFactory( + Collections.singletonMap("mockinput", () -> null), + Collections.singletonMap("mockfilter", () -> IDENTITY_FILTER), + Collections.singletonMap("mockoutput", mockOutputSupplier()) + )) + .buildExecution() + .compute(RubyUtil.RUBY.newArray(RubyEvent.newRubyEvent(RubyUtil.RUBY)), false, false); + + final Collection outputEvents = EVENT_SINKS.get(runId); + assertThat(outputEvents.size(), is(expectedMatches)); } private Supplier>> mockOutputSupplier() { From b2e8b0b6c48b935eaf6dc3af5b10e34203f5b5ac Mon Sep 17 00:00:00 2001 From: Rob Bavey Date: Mon, 12 Aug 2019 12:07:18 -0400 Subject: [PATCH 0199/1126] Update jrjackson, jackson versions Also splits out jackson and jackson databind versions to allow separate revisions for databind. Fixes #11040 --- logstash-core/build.gradle | 3 ++- versions.yml | 5 +++-- 2 files changed, 5 insertions(+), 3 deletions(-) diff --git a/logstash-core/build.gradle b/logstash-core/build.gradle index 6a6b1ed5a..146547f67 100644 --- a/logstash-core/build.gradle +++ b/logstash-core/build.gradle @@ -9,6 +9,7 @@ description = """Logstash Core Java""" version = versionMap['logstash-core'] String jrubyVersion = versionMap['jruby']['version'] String jacksonVersion = versionMap['jackson'] +String jacksonDatabindVersion = versionMap['jackson-databind'] repositories { mavenCentral() @@ -132,7 +133,7 @@ dependencies { compile 'commons-codec:commons-codec:1.11' // Jackson version moved to versions.yml in the project root (the JrJackson version is there too) compile "com.fasterxml.jackson.core:jackson-core:${jacksonVersion}" - compile "com.fasterxml.jackson.core:jackson-databind:${jacksonVersion}" + compile "com.fasterxml.jackson.core:jackson-databind:${jacksonDatabindVersion}" compile "com.fasterxml.jackson.core:jackson-annotations:${jacksonVersion}" compile 'org.codehaus.janino:janino:3.0.11' compile "com.fasterxml.jackson.dataformat:jackson-dataformat-cbor:${jacksonVersion}" diff --git a/versions.yml b/versions.yml index 3d88867c0..f1aa2c278 100644 --- a/versions.yml +++ b/versions.yml @@ -21,5 +21,6 @@ jruby: # Note: this file is copied to the root of logstash-core because its gemspec needs it when # bundler evaluates the gemspec via bin/logstash # Ensure Jackson version here is kept in sync with version used by jrjackson gem -jrjackson: 0.4.8 -jackson: 2.9.8 +jrjackson: 0.4.9 +jackson: 2.9.9 +jackson-databind: 2.9.9.3 \ No newline at end of file From 085d93650e2697d661388ba063d5548239d0e8ea Mon Sep 17 00:00:00 2001 From: Joao Duarte Date: Mon, 12 Aug 2019 21:20:17 +0100 Subject: [PATCH 0200/1126] update jruby to 9.2.8.0 Fixes #11041 --- logstash-core/spec/logstash/jruby_version_spec.rb | 2 +- rubyUtils.gradle | 2 +- versions.yml | 4 ++-- 3 files changed, 4 insertions(+), 4 deletions(-) diff --git a/logstash-core/spec/logstash/jruby_version_spec.rb b/logstash-core/spec/logstash/jruby_version_spec.rb index c8d8d2066..69424fd10 100644 --- a/logstash-core/spec/logstash/jruby_version_spec.rb +++ b/logstash-core/spec/logstash/jruby_version_spec.rb @@ -9,7 +9,7 @@ describe "JRuby Version" do # ref: # https://github.com/logstash-plugins/logstash-filter-dns/issues/51 # https://github.com/jruby/jruby/pull/5722 - expect(JRUBY_VERSION).to eq("9.2.7.0") + expect(JRUBY_VERSION).to eq("9.2.8.0") end end diff --git a/rubyUtils.gradle b/rubyUtils.gradle index 6f0eec45e..e286d703e 100644 --- a/rubyUtils.gradle +++ b/rubyUtils.gradle @@ -6,7 +6,7 @@ buildscript { dependencies { classpath 'org.yaml:snakeyaml:1.23' classpath "de.undercouch:gradle-download-task:3.2.0" - classpath "org.jruby:jruby-complete:9.2.7.0" + classpath "org.jruby:jruby-complete:9.2.8.0" } } diff --git a/versions.yml b/versions.yml index f1aa2c278..fd4f7d151 100644 --- a/versions.yml +++ b/versions.yml @@ -7,8 +7,8 @@ logstash-core-plugin-api: 2.1.16 # jruby must reference a *released* version of jruby which can be downloaded from the official download url # *and* for which jars artifacts are published for compile-time jruby: - version: 9.2.7.0 - sha1: dc35f9bb991f526f058bf6b9591c460f98cffe9e + version: 9.2.8.0 + sha1: 5b0b73b3d696afaeac92e6f8879dedcc63ac39d8 # jruby-runtime-override, if specified, will override the jruby version installed in vendor/jruby for logstash runtime only, # not for the compile-time jars From 2375ae1b171370f77363d709def66e8cbe6d5ec5 Mon Sep 17 00:00:00 2001 From: Dan Hermann Date: Thu, 1 Aug 2019 16:58:03 -0500 Subject: [PATCH 0201/1126] Expand config variables for Java plugins Fixes #11043 --- .../common/EnvironmentVariableProvider.java | 10 ++ .../logstash/config/ir/CompiledPipeline.java | 75 ++++++++++--- .../execution/AbstractPipelineExt.java | 18 +++ .../execution/JavaBasePipelineExt.java | 3 +- .../plugins/ConfigVariableExpander.java | 83 ++++++++++++++ .../common/ConfigVariableExpanderTest.java | 106 ++++++++++++++++++ .../secret/store/SecretStoreFactoryTest.java | 5 +- qa/integration/specs/secret_store_spec.rb | 13 --- 8 files changed, 281 insertions(+), 32 deletions(-) create mode 100644 logstash-core/src/main/java/org/logstash/common/EnvironmentVariableProvider.java create mode 100644 logstash-core/src/main/java/org/logstash/plugins/ConfigVariableExpander.java create mode 100644 logstash-core/src/test/java/org/logstash/common/ConfigVariableExpanderTest.java diff --git a/logstash-core/src/main/java/org/logstash/common/EnvironmentVariableProvider.java b/logstash-core/src/main/java/org/logstash/common/EnvironmentVariableProvider.java new file mode 100644 index 000000000..b576cdf3e --- /dev/null +++ b/logstash-core/src/main/java/org/logstash/common/EnvironmentVariableProvider.java @@ -0,0 +1,10 @@ +package org.logstash.common; + +public interface EnvironmentVariableProvider { + + String get(String key); + + static EnvironmentVariableProvider defaultProvider() { + return System::getenv; + } +} diff --git a/logstash-core/src/main/java/org/logstash/config/ir/CompiledPipeline.java b/logstash-core/src/main/java/org/logstash/config/ir/CompiledPipeline.java index 9cc2546ab..612865c8f 100644 --- a/logstash-core/src/main/java/org/logstash/config/ir/CompiledPipeline.java +++ b/logstash-core/src/main/java/org/logstash/config/ir/CompiledPipeline.java @@ -8,6 +8,7 @@ import org.jruby.javasupport.JavaUtil; import org.jruby.runtime.builtin.IRubyObject; import org.logstash.RubyUtil; import org.logstash.Rubyfier; +import org.logstash.common.EnvironmentVariableProvider; import org.logstash.common.SourceWithMetadata; import org.logstash.config.ir.compiler.AbstractFilterDelegatorExt; import org.logstash.config.ir.compiler.AbstractOutputDelegatorExt; @@ -22,11 +23,15 @@ import org.logstash.config.ir.graph.PluginVertex; import org.logstash.config.ir.graph.Vertex; import org.logstash.config.ir.imperative.PluginStatement; import org.logstash.ext.JrubyEventExtLibrary; +import org.logstash.plugins.ConfigVariableExpander; +import org.logstash.secret.store.SecretStore; +import java.util.ArrayList; import java.util.Collection; import java.util.Collections; import java.util.HashMap; import java.util.HashSet; +import java.util.List; import java.util.Map; import java.util.Objects; import java.util.stream.Collectors; @@ -73,13 +78,27 @@ public final class CompiledPipeline { */ private final RubyIntegration.PluginFactory pluginFactory; - public CompiledPipeline(final PipelineIR pipelineIR, - final RubyIntegration.PluginFactory pluginFactory) { + public CompiledPipeline( + final PipelineIR pipelineIR, + final RubyIntegration.PluginFactory pluginFactory) { + this(pipelineIR, pluginFactory, null); + } + + public CompiledPipeline( + final PipelineIR pipelineIR, + final RubyIntegration.PluginFactory pluginFactory, + final SecretStore secretStore) { this.pipelineIR = pipelineIR; this.pluginFactory = pluginFactory; - inputs = setupInputs(); - filters = setupFilters(); - outputs = setupOutputs(); + try (ConfigVariableExpander cve = new ConfigVariableExpander( + secretStore, + EnvironmentVariableProvider.defaultProvider())) { + inputs = setupInputs(cve); + filters = setupFilters(cve); + outputs = setupOutputs(cve); + } catch (Exception e) { + throw new IllegalStateException("Unable to configure plugins: " + e.getMessage()); + } } public Collection outputs() { @@ -106,7 +125,7 @@ public final class CompiledPipeline { /** * Sets up all outputs learned from {@link PipelineIR}. */ - private Map setupOutputs() { + private Map setupOutputs(ConfigVariableExpander cve) { final Collection outs = pipelineIR.getOutputPluginVertices(); final Map res = new HashMap<>(outs.size()); outs.forEach(v -> { @@ -114,7 +133,7 @@ public final class CompiledPipeline { final SourceWithMetadata source = v.getSourceWithMetadata(); res.put(v.getId(), pluginFactory.buildOutput( RubyUtil.RUBY.newString(def.getName()), RubyUtil.RUBY.newFixnum(source.getLine()), - RubyUtil.RUBY.newFixnum(source.getColumn()), convertArgs(def), convertJavaArgs(def) + RubyUtil.RUBY.newFixnum(source.getColumn()), convertArgs(def), convertJavaArgs(def, cve) )); }); return res; @@ -123,7 +142,7 @@ public final class CompiledPipeline { /** * Sets up all Ruby filters learnt from {@link PipelineIR}. */ - private Map setupFilters() { + private Map setupFilters(ConfigVariableExpander cve) { final Collection filterPlugins = pipelineIR.getFilterPluginVertices(); final Map res = new HashMap<>(filterPlugins.size(), 1.0F); @@ -132,7 +151,7 @@ public final class CompiledPipeline { final SourceWithMetadata source = vertex.getSourceWithMetadata(); res.put(vertex.getId(), pluginFactory.buildFilter( RubyUtil.RUBY.newString(def.getName()), RubyUtil.RUBY.newFixnum(source.getLine()), - RubyUtil.RUBY.newFixnum(source.getColumn()), convertArgs(def), convertJavaArgs(def) + RubyUtil.RUBY.newFixnum(source.getColumn()), convertArgs(def), convertJavaArgs(def, cve) )); } return res; @@ -141,7 +160,7 @@ public final class CompiledPipeline { /** * Sets up all Ruby inputs learnt from {@link PipelineIR}. */ - private Collection setupInputs() { + private Collection setupInputs(ConfigVariableExpander cve) { final Collection vertices = pipelineIR.getInputPluginVertices(); final Collection nodes = new HashSet<>(vertices.size()); vertices.forEach(v -> { @@ -149,7 +168,7 @@ public final class CompiledPipeline { final SourceWithMetadata source = v.getSourceWithMetadata(); IRubyObject o = pluginFactory.buildInput( RubyUtil.RUBY.newString(def.getName()), RubyUtil.RUBY.newFixnum(source.getLine()), - RubyUtil.RUBY.newFixnum(source.getColumn()), convertArgs(def), convertJavaArgs(def)); + RubyUtil.RUBY.newFixnum(source.getColumn()), convertArgs(def), convertJavaArgs(def, cve)); nodes.add(o); }); return nodes; @@ -190,23 +209,47 @@ public final class CompiledPipeline { * @return Map of plugin arguments as understood by the {@link RubyIntegration.PluginFactory} * methods that create Java plugins */ - private Map convertJavaArgs(final PluginDefinition def) { - for (final Map.Entry entry : def.getArguments().entrySet()) { + private Map convertJavaArgs(final PluginDefinition def, ConfigVariableExpander cve) { + Map args = expandConfigVariables(cve, def.getArguments()); + for (final Map.Entry entry : args.entrySet()) { final Object value = entry.getValue(); final String key = entry.getKey(); final IRubyObject toput; if (value instanceof PluginStatement) { final PluginDefinition codec = ((PluginStatement) value).getPluginDefinition(); + Map codecArgs = expandConfigVariables(cve, codec.getArguments()); toput = pluginFactory.buildCodec( RubyUtil.RUBY.newString(codec.getName()), Rubyfier.deep(RubyUtil.RUBY, codec.getArguments()), - codec.getArguments() + codecArgs ); Codec javaCodec = (Codec)JavaUtil.unwrapJavaValue(toput); - def.getArguments().put(key, javaCodec); + args.put(key, javaCodec); } } - return def.getArguments(); + return args; + } + + @SuppressWarnings({"rawtypes", "unchecked"}) + private Map expandConfigVariables(ConfigVariableExpander cve, Map configArgs) { + Map expandedConfig = new HashMap<>(); + for (Map.Entry e : configArgs.entrySet()) { + if (e.getValue() instanceof List) { + List list = (List) e.getValue(); + List expandedObjects = new ArrayList<>(); + for (Object o : list) { + expandedObjects.add(cve.expand(o)); + } + expandedConfig.put(e.getKey(), expandedObjects); + } else if (e.getValue() instanceof Map) { + expandedConfig.put(e.getKey(), expandConfigVariables(cve, (Map) e.getValue())); + } else if (e.getValue() instanceof String) { + expandedConfig.put(e.getKey(), cve.expand(e.getValue())); + } else { + expandedConfig.put(e.getKey(), e.getValue()); + } + } + return expandedConfig; } /** diff --git a/logstash-core/src/main/java/org/logstash/execution/AbstractPipelineExt.java b/logstash-core/src/main/java/org/logstash/execution/AbstractPipelineExt.java index e96f0396d..2c6cd93f6 100644 --- a/logstash-core/src/main/java/org/logstash/execution/AbstractPipelineExt.java +++ b/logstash-core/src/main/java/org/logstash/execution/AbstractPipelineExt.java @@ -37,6 +37,8 @@ import org.logstash.instrument.metrics.AbstractMetricExt; import org.logstash.instrument.metrics.AbstractNamespacedMetricExt; import org.logstash.instrument.metrics.MetricKeys; import org.logstash.instrument.metrics.NullMetricExt; +import org.logstash.secret.store.SecretStore; +import org.logstash.secret.store.SecretStoreExt; @JRubyClass(name = "AbstractPipeline") public class AbstractPipelineExt extends RubyBasicObject { @@ -366,6 +368,22 @@ public class AbstractPipelineExt extends RubyBasicObject { return settings.callMethod(context, "get_value", context.runtime.newString(name)); } + protected final boolean hasSetting(final ThreadContext context, final String name) { + return settings.callMethod(context, "registered?", context.runtime.newString(name)) == context.tru; + } + + protected SecretStore getSecretStore(final ThreadContext context) { + String keystoreFile = hasSetting(context, "keystore.file") + ? getSetting(context, "keystore.file").asJavaString() + : null; + String keystoreClassname = hasSetting(context, "keystore.classname") + ? getSetting(context, "keystore.classname").asJavaString() + : null; + return (keystoreFile != null && keystoreClassname != null) + ? SecretStoreExt.getIfExists(keystoreFile, keystoreClassname) + : null; + } + private AbstractNamespacedMetricExt getDlqMetric(final ThreadContext context) { if (dlqMetric == null) { dlqMetric = metric.namespace( diff --git a/logstash-core/src/main/java/org/logstash/execution/JavaBasePipelineExt.java b/logstash-core/src/main/java/org/logstash/execution/JavaBasePipelineExt.java index f8ac46672..16e576dd0 100644 --- a/logstash-core/src/main/java/org/logstash/execution/JavaBasePipelineExt.java +++ b/logstash-core/src/main/java/org/logstash/execution/JavaBasePipelineExt.java @@ -56,7 +56,8 @@ public final class JavaBasePipelineExt extends AbstractPipelineExt { context.runtime, RubyUtil.EXECUTION_CONTEXT_FACTORY_CLASS ).initialize(context, args[3], this, dlqWriter(context)), RubyUtil.FILTER_DELEGATOR_CLASS - ) + ), + getSecretStore(context) ); inputs = RubyArray.newArray(context.runtime, lirExecution.inputs()); filters = RubyArray.newArray(context.runtime, lirExecution.filters()); diff --git a/logstash-core/src/main/java/org/logstash/plugins/ConfigVariableExpander.java b/logstash-core/src/main/java/org/logstash/plugins/ConfigVariableExpander.java new file mode 100644 index 000000000..c143baccd --- /dev/null +++ b/logstash-core/src/main/java/org/logstash/plugins/ConfigVariableExpander.java @@ -0,0 +1,83 @@ +package org.logstash.plugins; + +import org.logstash.common.EnvironmentVariableProvider; +import org.logstash.secret.SecretIdentifier; +import org.logstash.secret.store.SecretStore; + +import java.nio.charset.StandardCharsets; +import java.util.regex.Matcher; +import java.util.regex.Pattern; + +public class ConfigVariableExpander implements AutoCloseable { + + private static String SUBSTITUTION_PLACEHOLDER_REGEX = "\\$\\{(?[a-zA-Z_.][a-zA-Z0-9_.]*)(:(?[^}]*))?}"; + + private Pattern substitutionPattern = Pattern.compile(SUBSTITUTION_PLACEHOLDER_REGEX); + private SecretStore secretStore; + private EnvironmentVariableProvider envVarProvider; + + public ConfigVariableExpander(SecretStore secretStore, EnvironmentVariableProvider envVarProvider) { + this.secretStore = secretStore; + this.envVarProvider = envVarProvider; + } + + /** + * Replace all substitution variable references in @variable and returns the substituted value, or the + * original value if a substitution cannot be made. + * + * Process following patterns : ${VAR}, ${VAR:defaultValue} + * + * If value matches the pattern, the following precedence applies: + * Secret store value + * Environment entry value + * Default value if provided in the pattern + * Exception raised + * + * If the value does not match the pattern, the 'value' param returns as-is + */ + public Object expand(Object value) { + String variable; + if (value instanceof String) { + variable = (String) value; + } else { + return value; + } + + Matcher m = substitutionPattern.matcher(variable); + if (m.matches()) { + String variableName = m.group("name"); + + if (secretStore != null) { + byte[] ssValue = secretStore.retrieveSecret(new SecretIdentifier(variableName)); + if (ssValue != null) { + return new String(ssValue, StandardCharsets.UTF_8); + } + } + + if (envVarProvider != null) { + String evValue = envVarProvider.get(variableName); + if (evValue != null) { + return evValue; + } + } + + String defaultValue = m.group("default"); + if (defaultValue != null) { + return defaultValue; + } + + throw new IllegalStateException(String.format( + "Cannot evaluate `%s`. Replacement variable `%s` is not defined in a Logstash " + + "secret store or an environment entry and there is no default value given.", + variable, variableName)); + } else { + return variable; + } + } + + @Override + public void close() { + // most keystore implementations will have close() methods + + } +} diff --git a/logstash-core/src/test/java/org/logstash/common/ConfigVariableExpanderTest.java b/logstash-core/src/test/java/org/logstash/common/ConfigVariableExpanderTest.java new file mode 100644 index 000000000..d6b261373 --- /dev/null +++ b/logstash-core/src/test/java/org/logstash/common/ConfigVariableExpanderTest.java @@ -0,0 +1,106 @@ +package org.logstash.common; + +import org.junit.Assert; +import org.junit.Test; +import org.logstash.plugins.ConfigVariableExpander; +import org.logstash.secret.SecretIdentifier; + +import java.nio.charset.StandardCharsets; +import java.util.Collections; +import java.util.Map; + +import static org.logstash.secret.store.SecretStoreFactoryTest.MemoryStore; + +public class ConfigVariableExpanderTest { + + @Test + public void testNonStringValueReturnsUnchanged() { + long nonStringValue = 42L; + ConfigVariableExpander cve = getFakeCve(Collections.emptyMap(), Collections.emptyMap()); + Object expandedValue = cve.expand(nonStringValue); + Assert.assertEquals(nonStringValue, expandedValue); + } + + @Test + public void testExpansionWithoutVariable() throws Exception { + String key = "foo"; + ConfigVariableExpander cve = getFakeCve(Collections.emptyMap(), Collections.emptyMap()); + String expandedValue = (String) cve.expand(key); + Assert.assertEquals(key, expandedValue); + } + + @Test + public void testSimpleExpansion() throws Exception { + String key = "foo"; + String val = "bar"; + ConfigVariableExpander cve = getFakeCve(Collections.emptyMap(), Collections.singletonMap(key, val)); + + String expandedValue = (String) cve.expand("${" + key + "}"); + Assert.assertEquals(val, expandedValue); + } + + @Test + public void testExpansionWithDefaultValue() throws Exception { + String key = "foo"; + String val = "bar"; + String defaultValue = "baz"; + ConfigVariableExpander cve = getFakeCve(Collections.emptyMap(), Collections.emptyMap()); + + String expandedValue = (String) cve.expand("${" + key + ":" + defaultValue + "}"); + Assert.assertEquals(defaultValue, expandedValue); + } + + @Test + public void testExpansionWithoutValueThrows() throws Exception { + String key = "foo"; + ConfigVariableExpander cve = getFakeCve(Collections.emptyMap(), Collections.emptyMap()); + + try { + String expandedValue = (String) cve.expand("${" + key + "}"); + Assert.fail("Exception should have been thrown"); + } catch (IllegalStateException ise) { + Assert.assertTrue(ise.getMessage().startsWith("Cannot evaluate")); + } + } + + @Test + public void testPrecedenceOfSecretStoreValue() throws Exception { + String key = "foo"; + String ssVal = "ssbar"; + String evVal = "evbar"; + String defaultValue = "defaultbar"; + ConfigVariableExpander cve = getFakeCve( + Collections.singletonMap(key, ssVal), + Collections.singletonMap(key, evVal)); + + String expandedValue = (String) cve.expand("${" + key + ":" + defaultValue + "}"); + Assert.assertEquals(ssVal, expandedValue); + } + + @Test + public void testPrecedenceOfEnvironmentVariableValue() throws Exception { + String key = "foo"; + String evVal = "evbar"; + String defaultValue = "defaultbar"; + ConfigVariableExpander cve = getFakeCve( + Collections.emptyMap(), + Collections.singletonMap(key, evVal)); + + String expandedValue = (String) cve.expand("${" + key + ":" + defaultValue + "}"); + Assert.assertEquals(evVal, expandedValue); + } + + private static ConfigVariableExpander getFakeCve( + final Map ssValues, final Map envVarValues) { + + MemoryStore ms = new MemoryStore(); + for (Map.Entry e : ssValues.entrySet()) { + if (e.getValue() instanceof String) { + ms.persistSecret(new SecretIdentifier(e.getKey()), + ((String) e.getValue()).getBytes(StandardCharsets.UTF_8)); + } + } + return new ConfigVariableExpander(ms, envVarValues::get); + } + +} diff --git a/logstash-core/src/test/java/org/logstash/secret/store/SecretStoreFactoryTest.java b/logstash-core/src/test/java/org/logstash/secret/store/SecretStoreFactoryTest.java index c753da617..b391757cf 100644 --- a/logstash-core/src/test/java/org/logstash/secret/store/SecretStoreFactoryTest.java +++ b/logstash-core/src/test/java/org/logstash/secret/store/SecretStoreFactoryTest.java @@ -133,7 +133,7 @@ public class SecretStoreFactoryTest { /** * Valid alternate implementation */ - static class MemoryStore implements SecretStore { + public static class MemoryStore implements SecretStore { Map secrets = new HashMap(1); @@ -178,7 +178,8 @@ public class SecretStoreFactoryTest { @Override public byte[] retrieveSecret(SecretIdentifier id) { - return secrets.get(id).array(); + ByteBuffer bb = secrets.get(id); + return bb != null ? bb.array() : null; } } diff --git a/qa/integration/specs/secret_store_spec.rb b/qa/integration/specs/secret_store_spec.rb index 5f2d154c5..111e6c687 100644 --- a/qa/integration/specs/secret_store_spec.rb +++ b/qa/integration/specs/secret_store_spec.rb @@ -74,19 +74,6 @@ describe "Test that Logstash" do end end - context "will start" do - let(:settings) {{"pipeline.id" => "main"}} - it "with the wrong password and variables are NOT in settings" do - test_env["LOGSTASH_KEYSTORE_PASS"] = "WRONG_PASSWRD" - @logstash.env_variables = test_env - @logstash.spawn_logstash("-e", "input {generator { count => 1 }} output { }", "--path.settings", settings_dir) - try(num_retries) do - expect(@logstash.exited?).to be(true) - end - expect(@logstash.exit_code).to be(0) - end - end - context "won't start " do let(:settings) {{"pipeline.id" => "${missing}"}} it "with correct password, but invalid variable " do From 8f78612e937b6bc516c17c300304bcc26094267b Mon Sep 17 00:00:00 2001 From: Dan Hermann Date: Tue, 13 Aug 2019 15:43:06 -0500 Subject: [PATCH 0202/1126] fix javadoc warning Fixes #11046 --- .../logstash/plugins/ConfigVariableExpander.java | 13 ++++++++----- 1 file changed, 8 insertions(+), 5 deletions(-) diff --git a/logstash-core/src/main/java/org/logstash/plugins/ConfigVariableExpander.java b/logstash-core/src/main/java/org/logstash/plugins/ConfigVariableExpander.java index c143baccd..e5732b500 100644 --- a/logstash-core/src/main/java/org/logstash/plugins/ConfigVariableExpander.java +++ b/logstash-core/src/main/java/org/logstash/plugins/ConfigVariableExpander.java @@ -22,18 +22,21 @@ public class ConfigVariableExpander implements AutoCloseable { } /** - * Replace all substitution variable references in @variable and returns the substituted value, or the - * original value if a substitution cannot be made. + * Replace all substitution variable references and returns the substituted value or the original value + * if a substitution cannot be made. * - * Process following patterns : ${VAR}, ${VAR:defaultValue} + * Substitution variables have the patterns: ${VAR} or ${VAR:defaultValue} * - * If value matches the pattern, the following precedence applies: + * If a substitution variable is found, the following precedence applies: * Secret store value * Environment entry value * Default value if provided in the pattern * Exception raised * - * If the value does not match the pattern, the 'value' param returns as-is + * If a substitution variable is not found, the value is return unchanged + * + * @param value Config value in which substitution variables, if any, should be replaced. + * @return Config value with any substitution variables replaced */ public Object expand(Object value) { String variable; From c2391b1849fd98e4f6247650383810c0ecf6d4ed Mon Sep 17 00:00:00 2001 From: "amitav.mohanty" Date: Mon, 12 Aug 2019 19:49:30 +0530 Subject: [PATCH 0203/1126] Improved logging of version mismatch in DLQ file reader (RecordIOReader) Fixes #11039 --- .../logstash/common/io/RecordIOReader.java | 8 +++++-- .../common/io/RecordIOReaderTest.java | 22 +++++++++++++++++++ 2 files changed, 28 insertions(+), 2 deletions(-) diff --git a/logstash-core/src/main/java/org/logstash/common/io/RecordIOReader.java b/logstash-core/src/main/java/org/logstash/common/io/RecordIOReader.java index 5e74d3de8..1a2094853 100644 --- a/logstash-core/src/main/java/org/logstash/common/io/RecordIOReader.java +++ b/logstash-core/src/main/java/org/logstash/common/io/RecordIOReader.java @@ -55,8 +55,12 @@ public final class RecordIOReader implements Closeable { ByteBuffer versionBuffer = ByteBuffer.allocate(1); this.channel.read(versionBuffer); versionBuffer.rewind(); - if (versionBuffer.get() != VERSION) { - throw new RuntimeException("Invalid file. check version"); + byte versionInFile = versionBuffer.get(); + if (versionInFile != VERSION) { + this.channel.close(); + throw new RuntimeException(String.format( + "Invalid version on PQ data file %s. Expected version: %c. Version found on file: %c", + path, VERSION, versionInFile)); } this.channelPosition = this.channel.position(); } diff --git a/logstash-core/src/test/java/org/logstash/common/io/RecordIOReaderTest.java b/logstash-core/src/test/java/org/logstash/common/io/RecordIOReaderTest.java index 58d8aba68..e8e46d50a 100644 --- a/logstash-core/src/test/java/org/logstash/common/io/RecordIOReaderTest.java +++ b/logstash-core/src/test/java/org/logstash/common/io/RecordIOReaderTest.java @@ -8,7 +8,9 @@ import org.logstash.ackedqueue.StringElement; import java.io.IOException; import java.nio.ByteBuffer; +import java.nio.channels.FileChannel; import java.nio.file.Path; +import java.nio.file.StandardOpenOption; import java.util.Arrays; import java.util.Comparator; import java.util.function.Function; @@ -20,6 +22,7 @@ import static org.hamcrest.CoreMatchers.nullValue; import static org.hamcrest.MatcherAssert.assertThat; import static org.logstash.common.io.RecordIOWriter.BLOCK_SIZE; import static org.logstash.common.io.RecordIOWriter.RECORD_HEADER_SIZE; +import static org.logstash.common.io.RecordIOWriter.VERSION; public class RecordIOReaderTest { private Path file; @@ -172,6 +175,25 @@ public class RecordIOReaderTest { } } + @Test + public void testVersion() throws IOException { + RecordIOWriter writer = new RecordIOWriter(file); + FileChannel channel = FileChannel.open(file, StandardOpenOption.READ); + ByteBuffer versionBuffer = ByteBuffer.allocate(1); + channel.read(versionBuffer); + versionBuffer.rewind(); + channel.close(); + assertThat(versionBuffer.get() == VERSION, equalTo(true)); + } + + @Test(expected = RuntimeException.class) + public void testVersionMismatch() throws IOException { + FileChannel channel = FileChannel.open(file, StandardOpenOption.WRITE); + channel.write(ByteBuffer.wrap(new byte[] { '2' })); + channel.close(); + RecordIOReader reader = new RecordIOReader(file); + } + private char[] fillArray(final int fillSize) { char[] blockSize= new char[fillSize]; Arrays.fill(blockSize, 'e'); From accc636126614b494dea189596eab10904ea955e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jo=C3=A3o=20Duarte?= Date: Tue, 20 Aug 2019 15:47:52 +0100 Subject: [PATCH 0204/1126] avoid variable collision in pipeline stats api (#11059) Fixes #11062 --- .../lib/logstash/api/commands/stats.rb | 4 +- .../spec/logstash/api/commands/stats_spec.rb | 37 +++++++++++++++++++ logstash-core/spec/support/shared_contexts.rb | 5 ++- 3 files changed, 43 insertions(+), 3 deletions(-) diff --git a/logstash-core/lib/logstash/api/commands/stats.rb b/logstash-core/lib/logstash/api/commands/stats.rb index 461644b7a..a473d5ed0 100644 --- a/logstash-core/lib/logstash/api/commands/stats.rb +++ b/logstash-core/lib/logstash/api/commands/stats.rb @@ -65,8 +65,8 @@ module LogStash service.agent, service.snapshot.metric_store, true).each_with_object({}) do |pipeline_stats, memo| - pipeline_id = pipeline_stats["id"].to_s - memo[pipeline_id] = pipeline_stats + p_id = pipeline_stats["id"].to_s + memo[p_id] = pipeline_stats end if pipeline_id.nil? diff --git a/logstash-core/spec/logstash/api/commands/stats_spec.rb b/logstash-core/spec/logstash/api/commands/stats_spec.rb index 62335fb1e..c52b844ba 100644 --- a/logstash-core/spec/logstash/api/commands/stats_spec.rb +++ b/logstash-core/spec/logstash/api/commands/stats_spec.rb @@ -49,4 +49,41 @@ describe LogStash::Api::Commands::Stats do end end + + describe "pipeline stats" do + let(:report_method) { :pipeline } + it "returns information on existing pipeline" do + expect(report.keys).to include(:main) + end + context "for each pipeline" do + it "returns information on pipeline" do + expect(report[:main].keys).to include( + :events, + :plugins, + :reloads, + :queue, + ) + end + it "returns event information" do + expect(report[:main][:events].keys).to include( + :in, + :filtered, + :duration_in_millis, + :out, + :queue_push_duration_in_millis + ) + end + end + context "when using multiple pipelines" do + before(:each) do + expect(LogStash::Config::PipelinesInfo).to receive(:format_pipelines_info).and_return([ + {"id" => :main}, + {"id" => :secondary}, + ]) + end + it "contains metrics for all pipelines" do + expect(report.keys).to include(:main, :secondary) + end + end + end end diff --git a/logstash-core/spec/support/shared_contexts.rb b/logstash-core/spec/support/shared_contexts.rb index 55ddfd7e9..b2ac83f90 100644 --- a/logstash-core/spec/support/shared_contexts.rb +++ b/logstash-core/spec/support/shared_contexts.rb @@ -24,9 +24,12 @@ shared_context "api setup" do settings.set("config.reload.automatic", false) @agent = make_test_agent(settings) @agent.execute + @pipelines_registry = LogStash::PipelinesRegistry.new pipeline_config = mock_pipeline_config(:main, "input { generator { id => '123' } } output { null {} }") pipeline_creator = LogStash::PipelineAction::Create.new(pipeline_config, @agent.metric) - @pipelines_registry = LogStash::PipelinesRegistry.new + expect(pipeline_creator.execute(@agent, @pipelines_registry)).to be_truthy + pipeline_config = mock_pipeline_config(:secondary, "input { generator { id => '123' } } output { null {} }") + pipeline_creator = LogStash::PipelineAction::Create.new(pipeline_config, @agent.metric) expect(pipeline_creator.execute(@agent, @pipelines_registry)).to be_truthy end From fe6783b3cb045a78e6e40600b2842a015a977f9c Mon Sep 17 00:00:00 2001 From: Aaron Mildenstein Date: Fri, 2 Aug 2019 14:34:26 -0700 Subject: [PATCH 0205/1126] Add missing "create" privilege to documentation Users following our documentation are frustrated to discover that they get 403 errors from Logstash, even when following the instructions to the letter. The problem is that the `create` privilege is missing. With this in place, it works as designed. These changes may need to be back ported to previous branches, too. Fixes #11013 --- docs/static/security/logstash.asciidoc | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/docs/static/security/logstash.asciidoc b/docs/static/security/logstash.asciidoc index 3a95fc426..42c499196 100644 --- a/docs/static/security/logstash.asciidoc +++ b/docs/static/security/logstash.asciidoc @@ -37,7 +37,7 @@ To set up authentication credentials for Logstash: . Use the the **Management > Roles** UI in {kib} or the `role` API to create a `logstash_writer` role. For *cluster* privileges, add `manage_index_templates` and `monitor`. -For *indices* privileges, add `write`, `delete`, and `create_index`. +For *indices* privileges, add `write`, `create`, `delete`, and `create_index`. + If you plan to use {ref}/getting-started-index-lifecycle-management.html[index lifecycle management], also add `manage_ilm` for cluster and `manage` and `manage_ilm` for indices. @@ -50,7 +50,7 @@ POST _xpack/security/role/logstash_writer "indices": [ { "names": [ "logstash-*" ], <2> - "privileges": ["write","delete","create_index","manage","manage_ilm"] <3> + "privileges": ["write","create","delete","create_index","manage","manage_ilm"] <3> } ] } From 0f25107cde6e47bd8c1dc0bef13dffe7dbba7a1a Mon Sep 17 00:00:00 2001 From: Rob Bavey Date: Tue, 20 Aug 2019 10:57:10 -0400 Subject: [PATCH 0206/1126] Fix misleading log message Fix DLQ error log message incorrectly referring to PQ. Fixes #11063 --- .../src/main/java/org/logstash/common/io/RecordIOReader.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/logstash-core/src/main/java/org/logstash/common/io/RecordIOReader.java b/logstash-core/src/main/java/org/logstash/common/io/RecordIOReader.java index 1a2094853..390f93a09 100644 --- a/logstash-core/src/main/java/org/logstash/common/io/RecordIOReader.java +++ b/logstash-core/src/main/java/org/logstash/common/io/RecordIOReader.java @@ -59,7 +59,7 @@ public final class RecordIOReader implements Closeable { if (versionInFile != VERSION) { this.channel.close(); throw new RuntimeException(String.format( - "Invalid version on PQ data file %s. Expected version: %c. Version found on file: %c", + "Invalid version on DLQ data file %s. Expected version: %c. Version found on file: %c", path, VERSION, versionInFile)); } this.channelPosition = this.channel.position(); From 334b874beb558da6d5a2f000c58a73c75d63d280 Mon Sep 17 00:00:00 2001 From: Dan Hermann Date: Mon, 12 Aug 2019 09:26:49 -0500 Subject: [PATCH 0207/1126] Integration test for Java plugins Fixes #11054 --- qa/integration/fixtures/java_api_spec.yml | 20 +++++++++ qa/integration/specs/java_api_spec.rb | 51 +++++++++++++++++++++++ 2 files changed, 71 insertions(+) create mode 100644 qa/integration/fixtures/java_api_spec.yml create mode 100644 qa/integration/specs/java_api_spec.rb diff --git a/qa/integration/fixtures/java_api_spec.yml b/qa/integration/fixtures/java_api_spec.yml new file mode 100644 index 000000000..72a2ce9d3 --- /dev/null +++ b/qa/integration/fixtures/java_api_spec.yml @@ -0,0 +1,20 @@ +--- +services: +- logstash +config: |- + input { + java_generator { + count => 1 + } + } + filter { + java_uuid { + target => "uuid" + } + sleep { + time => 10 + } + } + output { + java_stdout { } + } diff --git a/qa/integration/specs/java_api_spec.rb b/qa/integration/specs/java_api_spec.rb new file mode 100644 index 000000000..c27803043 --- /dev/null +++ b/qa/integration/specs/java_api_spec.rb @@ -0,0 +1,51 @@ +require_relative '../framework/fixture' +require_relative '../framework/settings' +require_relative '../framework/helpers' +require "stud/temporary" +require "stud/try" +require "rspec/wait" +require "yaml" +require "fileutils" + +describe "Java plugin API" do + before(:all) do + @fixture = Fixture.new(__FILE__) + end + + before(:each) { + @logstash = @fixture.get_service("logstash") + } + + after(:all) { + @fixture.teardown + } + + after(:each) { + @logstash.teardown + } + + let(:max_retry) { 120 } + let!(:settings_dir) { Stud::Temporary.directory } + + it "successfully sends events through Java plugins" do + + @logstash.start_background_with_config_settings(config_to_temp_file(@fixture.config), settings_dir) + + # wait for Logstash to start + started = false + while !started + begin + sleep(1) + result = @logstash.monitoring_api.event_stats + started = !result.nil? + rescue + retry + end + end + + Stud.try(max_retry.times, RSpec::Expectations::ExpectationNotMetError) do + result = @logstash.monitoring_api.event_stats + expect(result["in"]).to eq(1) + end + end +end From 0e90733c84e072ededbca7854d3d08dfbfee97f6 Mon Sep 17 00:00:00 2001 From: Nik Everett Date: Wed, 21 Aug 2019 09:07:12 -0400 Subject: [PATCH 0208/1126] Docs: Fix backticks in how to docs (#11018) In the "methods" sections of the how to develop a plugin docs Asciidoctor as incorrectly passing backticks into the output when it should have marked the words surrounded by backticks as code. I'm not 100% sure why it did that. The fix is to force macro evaluation immediately on attribute assignment. --- docs/static/codec.asciidoc | 2 +- docs/static/filter.asciidoc | 2 +- docs/static/input.asciidoc | 2 +- docs/static/output.asciidoc | 2 +- 4 files changed, 4 insertions(+), 4 deletions(-) diff --git a/docs/static/codec.asciidoc b/docs/static/codec.asciidoc index 6b0fd558a..f3ed7fd7e 100644 --- a/docs/static/codec.asciidoc +++ b/docs/static/codec.asciidoc @@ -10,6 +10,6 @@ :getstarted: Let's step through creating a {plugintype} plugin using the https://github.com/logstash-plugins/logstash-codec-example/[example {plugintype} plugin]. -:methodheader: Logstash codecs must implement the `register` method, and the `decode` method or the `encode` method (or both). +:methodheader: pass:m[Logstash codecs must implement the `register` method, and the `decode` method or the `encode` method (or both).] include::include/pluginbody.asciidoc[] diff --git a/docs/static/filter.asciidoc b/docs/static/filter.asciidoc index ba20f5856..e12712c8b 100644 --- a/docs/static/filter.asciidoc +++ b/docs/static/filter.asciidoc @@ -9,6 +9,6 @@ :getstarted: Let's step through creating a {plugintype} plugin using the https://github.com/logstash-plugins/logstash-filter-example/[example {plugintype} plugin]. -:methodheader: Logstash filters must implement the `register` and `filter` methods. +:methodheader: pass:m[Logstash filters must implement the `register` and `filter` methods.] include::include/pluginbody.asciidoc[] diff --git a/docs/static/input.asciidoc b/docs/static/input.asciidoc index d84275b51..7c3f720e7 100644 --- a/docs/static/input.asciidoc +++ b/docs/static/input.asciidoc @@ -7,6 +7,6 @@ :getstarted: Let's step through creating an {plugintype} plugin using the https://github.com/logstash-plugins/logstash-input-example/[example {plugintype} plugin]. -:methodheader: Logstash inputs must implement two main methods: `register` and `run`. +:methodheader: pass:m[Logstash inputs must implement two main methods: `register` and `run`.] include::include/pluginbody.asciidoc[] diff --git a/docs/static/output.asciidoc b/docs/static/output.asciidoc index 0f9b1b1c0..d42536d6b 100644 --- a/docs/static/output.asciidoc +++ b/docs/static/output.asciidoc @@ -9,6 +9,6 @@ :getstarted: Let's step through creating an {plugintype} plugin using the https://github.com/logstash-plugins/logstash-output-example/[example {plugintype} plugin]. -:methodheader: Logstash outputs must implement the `register` and `multi_receive` methods. +:methodheader: pass:m[Logstash outputs must implement the `register` and `multi_receive` methods.] include::include/pluginbody.asciidoc[] From c75ef874aea611129291f789960eb8ac29e08a5a Mon Sep 17 00:00:00 2001 From: Dan Hermann Date: Wed, 14 Aug 2019 10:46:06 -0500 Subject: [PATCH 0209/1126] Use correct execution engine for test-and-exit mode Fixes #11067 --- logstash-core/lib/logstash/runner.rb | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/logstash-core/lib/logstash/runner.rb b/logstash-core/lib/logstash/runner.rb index 45e7fb231..e89b2a9d5 100644 --- a/logstash-core/lib/logstash/runner.rb +++ b/logstash-core/lib/logstash/runner.rb @@ -336,7 +336,8 @@ class LogStash::Runner < Clamp::StrictCommand # TODO(ph): make it better for multiple pipeline if results.success? results.response.each do |pipeline_config| - LogStash::BasePipeline.new(pipeline_config) + pipeline_class = pipeline_config.settings.get_value("pipeline.java_execution") ? LogStash::JavaPipeline : LogStash::BasePipeline + pipeline_class.new(pipeline_config) end puts "Configuration OK" logger.info "Using config.test_and_exit mode. Config Validation Result: OK. Exiting Logstash" From ea101cea00b1eec2290a7a4758d5571f5606c232 Mon Sep 17 00:00:00 2001 From: Nik Everett Date: Thu, 22 Aug 2019 15:18:29 -0400 Subject: [PATCH 0210/1126] Docs: Fix formatting in table (#11016) Fixes formatting in a table cell in `logstash-monitoring-overview.html`. A `+` which was required by AsciiDoc was leaking into the output when the doc is built with Asciidoctor. --- docs/static/monitoring/collectors.asciidoc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/static/monitoring/collectors.asciidoc b/docs/static/monitoring/collectors.asciidoc index 323c4d55b..dbe94defd 100644 --- a/docs/static/monitoring/collectors.asciidoc +++ b/docs/static/monitoring/collectors.asciidoc @@ -16,7 +16,7 @@ collectors: one for node stats and one for pipeline stats. | Node Stats | `logstash_stats` | Gathers details about the running node, such as memory utilization and CPU usage (for example, `GET /_stats`). -+ + This runs on every Logstash node with {monitoring} enabled. One common failure is that Logstash directories are copied with their `path.data` directory included (`./data` by default), which copies the persistent UUID of the Logstash From 44f08e20c754295f69ef7358616d9a2f57e36881 Mon Sep 17 00:00:00 2001 From: Peter Dyson Date: Mon, 26 Aug 2019 09:00:57 +1000 Subject: [PATCH 0211/1126] hint plugins need to be installed before bundle Fixes #11080 --- lib/pluginmanager/offline_plugin_packager.rb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/pluginmanager/offline_plugin_packager.rb b/lib/pluginmanager/offline_plugin_packager.rb index c4cd6cf24..568f21d3e 100644 --- a/lib/pluginmanager/offline_plugin_packager.rb +++ b/lib/pluginmanager/offline_plugin_packager.rb @@ -66,7 +66,7 @@ module LogStash module PluginManager if specs.size > 0 specs else - raise LogStash::PluginManager::PluginNotFoundError, "Cannot find plugins matching: `#{plugin_pattern}`" + raise LogStash::PluginManager::PluginNotFoundError, "Cannot find plugins matching: `#{plugin_pattern}`. Please install these before creating the offline pack" end end.flatten end From 5125e0729e95c60d8d3f726d9ebd0af933efda8d Mon Sep 17 00:00:00 2001 From: Dan Hermann Date: Tue, 13 Aug 2019 14:36:09 -0500 Subject: [PATCH 0212/1126] Write generated Java files to disk only if debug flag is set Fixes #11082 --- .../ir/compiler/ComputeStepSyntaxElement.java | 20 ++++++++++--------- 1 file changed, 11 insertions(+), 9 deletions(-) diff --git a/logstash-core/src/main/java/org/logstash/config/ir/compiler/ComputeStepSyntaxElement.java b/logstash-core/src/main/java/org/logstash/config/ir/compiler/ComputeStepSyntaxElement.java index 2cf86c284..bfd3bf56a 100644 --- a/logstash-core/src/main/java/org/logstash/config/ir/compiler/ComputeStepSyntaxElement.java +++ b/logstash-core/src/main/java/org/logstash/config/ir/compiler/ComputeStepSyntaxElement.java @@ -74,9 +74,13 @@ public final class ComputeStepSyntaxElement { } else { final String name = String.format("CompiledDataset%d", CLASS_CACHE.size()); final String code = generateCode(name); - final Path sourceFile = SOURCE_DIR.resolve(String.format("%s.java", name)); - Files.write(sourceFile, code.getBytes(StandardCharsets.UTF_8)); - COMPILER.cookFile(sourceFile.toFile()); + if (SOURCE_DIR != null) { + final Path sourceFile = SOURCE_DIR.resolve(String.format("%s.java", name)); + Files.write(sourceFile, code.getBytes(StandardCharsets.UTF_8)); + COMPILER.cookFile(sourceFile.toFile()); + } else { + COMPILER.cook(code); + } COMPILER.setParentClassLoader(COMPILER.getClassLoader()); clazz = (Class) COMPILER.getClassLoader().loadClass( String.format("org.logstash.generated.%s", name) @@ -125,17 +129,15 @@ public final class ComputeStepSyntaxElement { } private static Path debugDir() { - final Path sourceDir; + Path sourceDir = null; try { final Path parentDir; final String dir = System.getProperty(ICookable.SYSTEM_PROPERTY_SOURCE_DEBUGGING_DIR); - if (dir == null) { - parentDir = Files.createTempDirectory("logstash"); - } else { + if (dir != null) { parentDir = Paths.get(dir); + sourceDir = parentDir.resolve("org").resolve("logstash").resolve("generated"); + Files.createDirectories(sourceDir); } - sourceDir = parentDir.resolve("org").resolve("logstash").resolve("generated"); - Files.createDirectories(sourceDir); } catch (final IOException ex) { throw new IllegalStateException(ex); } From 3e99e1f203c6f8ab85d4d92fe815c6a85a887bf0 Mon Sep 17 00:00:00 2001 From: Dan Hermann Date: Fri, 12 Jul 2019 12:09:14 -0500 Subject: [PATCH 0213/1126] Update Reflections library Fixes #10951 --- logstash-core/build.gradle | 3 + .../plugins/discovery/AbstractScanner.java | 84 --- .../plugins/discovery/ClasspathHelper.java | 200 ------ .../plugins/discovery/Configuration.java | 41 -- .../discovery/ConfigurationBuilder.java | 245 ------- .../plugins/discovery/FilterBuilder.java | 137 ---- .../discovery/JavaReflectionAdapter.java | 67 -- .../plugins/discovery/JavassistAdapter.java | 76 --- .../plugins/discovery/MetadataAdapter.java | 23 - .../plugins/discovery/PluginRegistry.java | 3 +- .../plugins/discovery/ReflectionUtils.java | 120 ---- .../plugins/discovery/Reflections.java | 155 ----- .../discovery/ReflectionsException.java | 16 - .../logstash/plugins/discovery/Scanner.java | 24 - .../org/logstash/plugins/discovery/Store.java | 126 ---- .../plugins/discovery/SubTypesScanner.java | 36 - .../discovery/TypeAnnotationsScanner.java | 26 - .../org/logstash/plugins/discovery/Utils.java | 83 --- .../org/logstash/plugins/discovery/Vfs.java | 634 ------------------ qa/integration/specs/monitoring_api_spec.rb | 2 +- 20 files changed, 6 insertions(+), 2095 deletions(-) delete mode 100644 logstash-core/src/main/java/org/logstash/plugins/discovery/AbstractScanner.java delete mode 100644 logstash-core/src/main/java/org/logstash/plugins/discovery/ClasspathHelper.java delete mode 100644 logstash-core/src/main/java/org/logstash/plugins/discovery/Configuration.java delete mode 100644 logstash-core/src/main/java/org/logstash/plugins/discovery/ConfigurationBuilder.java delete mode 100644 logstash-core/src/main/java/org/logstash/plugins/discovery/FilterBuilder.java delete mode 100644 logstash-core/src/main/java/org/logstash/plugins/discovery/JavaReflectionAdapter.java delete mode 100644 logstash-core/src/main/java/org/logstash/plugins/discovery/JavassistAdapter.java delete mode 100644 logstash-core/src/main/java/org/logstash/plugins/discovery/MetadataAdapter.java delete mode 100644 logstash-core/src/main/java/org/logstash/plugins/discovery/ReflectionUtils.java delete mode 100644 logstash-core/src/main/java/org/logstash/plugins/discovery/Reflections.java delete mode 100644 logstash-core/src/main/java/org/logstash/plugins/discovery/ReflectionsException.java delete mode 100644 logstash-core/src/main/java/org/logstash/plugins/discovery/Scanner.java delete mode 100644 logstash-core/src/main/java/org/logstash/plugins/discovery/Store.java delete mode 100644 logstash-core/src/main/java/org/logstash/plugins/discovery/SubTypesScanner.java delete mode 100644 logstash-core/src/main/java/org/logstash/plugins/discovery/TypeAnnotationsScanner.java delete mode 100644 logstash-core/src/main/java/org/logstash/plugins/discovery/Utils.java delete mode 100644 logstash-core/src/main/java/org/logstash/plugins/discovery/Vfs.java diff --git a/logstash-core/build.gradle b/logstash-core/build.gradle index 146547f67..5a5d5f51b 100644 --- a/logstash-core/build.gradle +++ b/logstash-core/build.gradle @@ -130,6 +130,9 @@ dependencies { compile 'org.apache.logging.log4j:log4j-api:2.11.1' compile 'org.apache.logging.log4j:log4j-core:2.11.1' runtime 'org.apache.logging.log4j:log4j-slf4j-impl:2.11.1' + compile('org.reflections:reflections:0.9.11') { + exclude group: 'com.google.guava', module: 'guava' + } compile 'commons-codec:commons-codec:1.11' // Jackson version moved to versions.yml in the project root (the JrJackson version is there too) compile "com.fasterxml.jackson.core:jackson-core:${jacksonVersion}" diff --git a/logstash-core/src/main/java/org/logstash/plugins/discovery/AbstractScanner.java b/logstash-core/src/main/java/org/logstash/plugins/discovery/AbstractScanner.java deleted file mode 100644 index 088e86700..000000000 --- a/logstash-core/src/main/java/org/logstash/plugins/discovery/AbstractScanner.java +++ /dev/null @@ -1,84 +0,0 @@ -package org.logstash.plugins.discovery; - -import com.google.common.base.Predicate; -import com.google.common.base.Predicates; -import com.google.common.collect.Multimap; - -/** - * - */ -@SuppressWarnings({"RawUseOfParameterizedType", "unchecked"}) -public abstract class AbstractScanner implements Scanner { - - private Configuration configuration; - private Multimap store; - private Predicate resultFilter = Predicates.alwaysTrue(); //accept all by default - - public boolean acceptsInput(String file) { - return getMetadataAdapter().acceptsInput(file); - } - - public Object scan(Vfs.File file, Object classObject) { - if (classObject == null) { - try { - classObject = configuration.getMetadataAdapter().getOfCreateClassObject(file); - } catch (Exception e) { - throw new ReflectionsException("could not create class object from file " + file.getRelativePath(), e); - } - } - scan(classObject); - return classObject; - } - - public abstract void scan(Object cls); - - // - public Configuration getConfiguration() { - return configuration; - } - - public void setConfiguration(final Configuration configuration) { - this.configuration = configuration; - } - - public Multimap getStore() { - return store; - } - - public void setStore(final Multimap store) { - this.store = store; - } - - public Predicate getResultFilter() { - return resultFilter; - } - - public void setResultFilter(Predicate resultFilter) { - this.resultFilter = resultFilter; - } - - @Override - public Scanner filterResultsBy(Predicate filter) { - this.setResultFilter(filter); - return this; - } - - public boolean acceptResult(final String fqn) { - return fqn != null && resultFilter.apply(fqn); - } - - @SuppressWarnings("rawtypes") - protected MetadataAdapter getMetadataAdapter() { - return configuration.getMetadataAdapter(); - } - - @Override - public boolean equals(Object o) { - return this == o || o != null && getClass() == o.getClass(); - } - - @Override - public int hashCode() { - return getClass().hashCode(); - } -} diff --git a/logstash-core/src/main/java/org/logstash/plugins/discovery/ClasspathHelper.java b/logstash-core/src/main/java/org/logstash/plugins/discovery/ClasspathHelper.java deleted file mode 100644 index 8d73d5e43..000000000 --- a/logstash-core/src/main/java/org/logstash/plugins/discovery/ClasspathHelper.java +++ /dev/null @@ -1,200 +0,0 @@ -package org.logstash.plugins.discovery; - - -import java.util.ArrayList; -import java.util.Arrays; -import java.util.Collection; -import java.util.Enumeration; -import java.util.LinkedHashMap; -import java.util.List; -import java.util.Map; - -import java.io.IOException; -import java.net.MalformedURLException; -import java.net.URL; -import java.net.URLClassLoader; - -/** - * Helper methods for working with the classpath. - */ -public abstract class ClasspathHelper { - - /** - * Gets the current thread context class loader. - * {@code Thread.currentThread().getContextClassLoader()}. - * - * @return the context class loader, may be null - */ - public static ClassLoader contextClassLoader() { - return Thread.currentThread().getContextClassLoader(); - } - - /** - * Gets the class loader of this library. - * {@code Reflections.class.getClassLoader()}. - * - * @return the static library class loader, may be null - */ - public static ClassLoader staticClassLoader() { - return Reflections.class.getClassLoader(); - } - - /** - * Returns an array of class Loaders initialized from the specified array. - *

- * If the input is null or empty, it defaults to both {@link #contextClassLoader()} and {@link #staticClassLoader()} - * - * @param classLoaders provided ClassLoaders - * @return the array of class loaders, not null - */ - public static ClassLoader[] classLoaders(ClassLoader... classLoaders) { - if (classLoaders != null && classLoaders.length != 0) { - return classLoaders; - } else { - ClassLoader contextClassLoader = contextClassLoader(), staticClassLoader = staticClassLoader(); - return contextClassLoader != null ? - staticClassLoader != null && contextClassLoader != staticClassLoader ? - new ClassLoader[]{contextClassLoader, staticClassLoader} : - new ClassLoader[]{contextClassLoader} : - new ClassLoader[] {}; - - } - } - - public static Collection forPackage(String name, ClassLoader... classLoaders) { - return forResource(resourceName(name), classLoaders); - } - - /** - * Returns a distinct collection of URLs based on a resource. - *

- * This searches for the resource name, using {@link ClassLoader#getResources(String)}. - * For example, {@code forResource(test.properties)} effectively returns URLs from the - * classpath containing files of that name. - *

- * If the optional {@link ClassLoader}s are not specified, then both {@link #contextClassLoader()} - * and {@link #staticClassLoader()} are used for {@link ClassLoader#getResources(String)}. - *

- * The returned URLs retains the order of the given {@code classLoaders}. - * - * @param resourceName resource name on which to search - * @param classLoaders optional ClassLoaders to search - * @return the collection of URLs, not null - */ - public static Collection forResource(String resourceName, ClassLoader... classLoaders) { - final List result = new ArrayList<>(); - final ClassLoader[] loaders = classLoaders(classLoaders); - for (ClassLoader classLoader : loaders) { - try { - final Enumeration urls = classLoader.getResources(resourceName); - while (urls.hasMoreElements()) { - final URL url = urls.nextElement(); - int index = url.toExternalForm().lastIndexOf(resourceName); - if (index != -1) { - // Add old url as contextUrl to support exotic url handlers - result.add(new URL(url, url.toExternalForm().substring(0, index))); - } else { - result.add(url); - } - } - } catch (IOException e) { - } - } - return distinctUrls(result); - } - - /** - * Returns the URL that contains a {@code Class}. - *

- * This searches for the class using {@link ClassLoader#getResource(String)}. - *

- * If the optional {@link ClassLoader}s are not specified, then both {@link #contextClassLoader()} - * and {@link #staticClassLoader()} are used for {@link ClassLoader#getResources(String)}. - * - * @param aClass class for which to search - * @param classLoaders optional ClassLoaders to search - * @return the URL containing the class, null if not found - */ - public static URL forClass(Class aClass, ClassLoader... classLoaders) { - final ClassLoader[] loaders = classLoaders(classLoaders); - final String resourceName = aClass.getName().replace(".", "/") + ".class"; - for (ClassLoader classLoader : loaders) { - try { - final URL url = classLoader.getResource(resourceName); - if (url != null) { - final String normalizedUrl = url.toExternalForm().substring(0, url.toExternalForm().lastIndexOf(aClass.getPackage().getName().replace(".", "/"))); - return new URL(normalizedUrl); - } - } catch (MalformedURLException e) { - } - } - return null; - } - - /** - * Returns a distinct collection of URLs based on URLs derived from class loaders. - *

- * This finds the URLs using {@link URLClassLoader#getURLs()} using both - * {@link #contextClassLoader()} and {@link #staticClassLoader()}. - *

- * The returned URLs retains the order of the given {@code classLoaders}. - * - * @return the collection of URLs, not null - */ - public static Collection forClassLoader() { - return forClassLoader(classLoaders()); - } - - /** - * Returns a distinct collection of URLs based on URLs derived from class loaders. - *

- * This finds the URLs using {@link URLClassLoader#getURLs()} using the specified - * class loader, searching up the parent hierarchy. - *

- * If the optional {@link ClassLoader}s are not specified, then both {@link #contextClassLoader()} - * and {@link #staticClassLoader()} are used for {@link ClassLoader#getResources(String)}. - *

- * The returned URLs retains the order of the given {@code classLoaders}. - * - * @param classLoaders optional ClassLoaders to search - * @return the collection of URLs, not null - */ - public static Collection forClassLoader(ClassLoader... classLoaders) { - final Collection result = new ArrayList<>(); - final ClassLoader[] loaders = classLoaders(classLoaders); - for (ClassLoader classLoader : loaders) { - while (classLoader != null) { - if (classLoader instanceof URLClassLoader) { - URL[] urls = ((URLClassLoader) classLoader).getURLs(); - if (urls != null) { - result.addAll(Arrays.asList(urls)); - } - } - classLoader = classLoader.getParent(); - } - } - return distinctUrls(result); - } - - private static String resourceName(String name) { - if (name != null) { - String resourceName = name.replace(".", "/"); - resourceName = resourceName.replace("\\", "/"); - if (resourceName.startsWith("/")) { - resourceName = resourceName.substring(1); - } - return resourceName; - } - return null; - } - - //http://michaelscharf.blogspot.co.il/2006/11/javaneturlequals-and-hashcode-make.html - private static Collection distinctUrls(Collection urls) { - Map distinct = new LinkedHashMap<>(urls.size()); - for (URL url : urls) { - distinct.put(url.toExternalForm(), url); - } - return distinct.values(); - } -} - diff --git a/logstash-core/src/main/java/org/logstash/plugins/discovery/Configuration.java b/logstash-core/src/main/java/org/logstash/plugins/discovery/Configuration.java deleted file mode 100644 index 225e10272..000000000 --- a/logstash-core/src/main/java/org/logstash/plugins/discovery/Configuration.java +++ /dev/null @@ -1,41 +0,0 @@ -package org.logstash.plugins.discovery; - -import com.google.common.base.Predicate; -import java.net.URL; -import java.util.Set; -import java.util.concurrent.ExecutorService; - -public interface Configuration { - /** - * @return the scanner instances used for scanning different metadata - */ - Set getScanners(); - - /** - * @return the urls to be scanned - */ - Set getUrls(); - - /** - * @return the metadata adapter used to fetch metadata from classes - */ - @SuppressWarnings("rawtypes") - MetadataAdapter getMetadataAdapter(); - - /** - * @return the fully qualified name filter used to filter types to be scanned - */ - Predicate getInputsFilter(); - - /** - * @return executor service used to scan files. if null, scanning is done in a simple for loop - */ - ExecutorService getExecutorService(); - - /** - * @return class loaders, might be used for resolving methods/fields - */ - ClassLoader[] getClassLoaders(); - - boolean shouldExpandSuperTypes(); -} diff --git a/logstash-core/src/main/java/org/logstash/plugins/discovery/ConfigurationBuilder.java b/logstash-core/src/main/java/org/logstash/plugins/discovery/ConfigurationBuilder.java deleted file mode 100644 index a23aa7eb4..000000000 --- a/logstash-core/src/main/java/org/logstash/plugins/discovery/ConfigurationBuilder.java +++ /dev/null @@ -1,245 +0,0 @@ -package org.logstash.plugins.discovery; - -import com.google.common.base.Predicate; -import com.google.common.collect.Lists; -import com.google.common.collect.ObjectArrays; -import com.google.common.collect.Sets; -import java.net.URL; -import java.util.Collection; -import java.util.List; -import java.util.Set; -import java.util.concurrent.ExecutorService; - -public final class ConfigurationBuilder implements Configuration { - - private final Set scanners; - - private Set urls; - @SuppressWarnings("rawtypes") protected MetadataAdapter metadataAdapter; - - private Predicate inputsFilter; - - private ExecutorService executorService; - - private ClassLoader[] classLoaders; - private boolean expandSuperTypes = true; - - public ConfigurationBuilder() { - scanners = Sets.newHashSet(new TypeAnnotationsScanner(), new SubTypesScanner()); - urls = Sets.newHashSet(); - } - - @SuppressWarnings({"unchecked","rawtypes"}) - public static ConfigurationBuilder build(final Object... params) { - ConfigurationBuilder builder = new ConfigurationBuilder(); - - //flatten - List parameters = Lists.newArrayList(); - if (params != null) { - for (Object param : params) { - if (param != null) { - if (param.getClass().isArray()) { - for (Object p : (Object[]) param) - if (p != null) { - parameters.add(p); - } - } else if (param instanceof Iterable) { - for (Object p : (Iterable) param) - if (p != null) { - parameters.add(p); - } - } else { - parameters.add(param); - } - } - } - } - - List loaders = Lists.newArrayList(); - for (Object param : parameters) - if (param instanceof ClassLoader) { - loaders.add((ClassLoader) param); - } - - ClassLoader[] classLoaders = loaders.isEmpty() ? null : loaders.toArray(new ClassLoader[loaders.size()]); - FilterBuilder filter = new FilterBuilder(); - List scanners = Lists.newArrayList(); - - for (Object param : parameters) { - if (param instanceof String) { - builder.addUrls(ClasspathHelper.forPackage((String) param, classLoaders)); - filter.includePackage((String) param); - } else if (param instanceof Class) { - if (Scanner.class.isAssignableFrom((Class) param)) { - try { - builder.addScanners((Scanner) ((Class) param).getConstructor().newInstance()); - } catch (Exception e) { /*fallback*/ } - } - builder.addUrls(ClasspathHelper.forClass((Class) param, classLoaders)); - filter.includePackage((Class) param); - } else if (param instanceof Scanner) { - scanners.add((Scanner) param); - } else if (param instanceof URL) { - builder.addUrls((URL) param); - } else if (param instanceof ClassLoader) { /* already taken care */ } else if (param instanceof Predicate) { - filter.add((Predicate) param); - } else if (param instanceof ExecutorService) { - builder.setExecutorService((ExecutorService) param); - } - } - - if (builder.getUrls().isEmpty()) { - if (classLoaders != null) { - builder.addUrls(ClasspathHelper.forClassLoader(classLoaders)); //default urls getResources("") - } else { - builder.addUrls(ClasspathHelper.forClassLoader()); //default urls getResources("") - } - } - - builder.filterInputsBy(filter); - if (!scanners.isEmpty()) { - builder.setScanners(scanners.toArray(new Scanner[scanners.size()])); - } - if (!loaders.isEmpty()) { - builder.addClassLoaders(loaders); - } - - return builder; - } - - @Override - - public Set getScanners() { - return scanners; - } - - /** - * set the scanners instances for scanning different metadata - * @param scanners provided scanners - * @return updated {@link ConfigurationBuilder} instance - */ - public ConfigurationBuilder setScanners(final Scanner... scanners) { - this.scanners.clear(); - return addScanners(scanners); - } - - /** - * set the scanners instances for scanning different metadata - * @param scanners provided scanners - * @return updated {@link ConfigurationBuilder} instance - */ - public ConfigurationBuilder addScanners(final Scanner... scanners) { - this.scanners.addAll(Sets.newHashSet(scanners)); - return this; - } - - @Override - - public Set getUrls() { - return urls; - } - - /** - * add urls to be scanned - *

use {@link ClasspathHelper} convenient methods to get the relevant urls - * @param urls provided URLs - * @return updated {@link ConfigurationBuilder} instance - */ - public ConfigurationBuilder addUrls(final Collection urls) { - this.urls.addAll(urls); - return this; - } - - /** - * add urls to be scanned - *

use {@link ClasspathHelper} convenient methods to get the relevant urls - * @param urls provided URLs - * @return updated {@link ConfigurationBuilder} instance - */ - public ConfigurationBuilder addUrls(final URL... urls) { - this.urls.addAll(Sets.newHashSet(urls)); - return this; - } - - /** - * @return the metadata adapter. - * if javassist library exists in the classpath, this method returns {@link JavassistAdapter} otherwise defaults to {@link JavaReflectionAdapter}. - *

the {@link JavassistAdapter} is preferred in terms of performance and class loading. - */ - @SuppressWarnings("rawtypes") - @Override - public MetadataAdapter getMetadataAdapter() { - if (metadataAdapter != null) { - return metadataAdapter; - } else { - try { - return metadataAdapter = new JavassistAdapter(); - } catch (Throwable e) { - return metadataAdapter = new JavaReflectionAdapter(); - } - } - } - - @Override - public Predicate getInputsFilter() { - return inputsFilter; - } - - /** - * sets the input filter for all resources to be scanned. - *

supply a {@link Predicate} or use the {@link FilterBuilder} - * @param inputsFilter provided inputs filter - * @return updated {@link ConfigurationBuilder} instance - */ - public ConfigurationBuilder filterInputsBy(Predicate inputsFilter) { - this.inputsFilter = inputsFilter; - return this; - } - - @Override - public ExecutorService getExecutorService() { - return executorService; - } - - /** - * sets the executor service used for scanning. - * @param executorService provided executor service - * @return updated {@link ConfigurationBuilder} instance - */ - public ConfigurationBuilder setExecutorService(ExecutorService executorService) { - this.executorService = executorService; - return this; - } - - /** - * @return class loader, might be used for scanning or resolving methods/fields - */ - @Override - public ClassLoader[] getClassLoaders() { - return classLoaders; - } - - @Override - public boolean shouldExpandSuperTypes() { - return expandSuperTypes; - } - - /** - * add class loader, might be used for resolving methods/fields - * @param classLoaders provided class loaders - * @return updated {@link ConfigurationBuilder} instance - */ - public ConfigurationBuilder addClassLoaders(ClassLoader... classLoaders) { - this.classLoaders = this.classLoaders == null ? classLoaders : ObjectArrays.concat(this.classLoaders, classLoaders, ClassLoader.class); - return this; - } - - /** - * add class loader, might be used for resolving methods/fields - * @param classLoaders provided class loaders - * @return updated {@link ConfigurationBuilder} instance - */ - public ConfigurationBuilder addClassLoaders(Collection classLoaders) { - return addClassLoaders(classLoaders.toArray(new ClassLoader[classLoaders.size()])); - } -} diff --git a/logstash-core/src/main/java/org/logstash/plugins/discovery/FilterBuilder.java b/logstash-core/src/main/java/org/logstash/plugins/discovery/FilterBuilder.java deleted file mode 100644 index 1f981fae6..000000000 --- a/logstash-core/src/main/java/org/logstash/plugins/discovery/FilterBuilder.java +++ /dev/null @@ -1,137 +0,0 @@ -package org.logstash.plugins.discovery; - -import com.google.common.base.Joiner; -import com.google.common.base.Predicate; -import com.google.common.collect.Lists; -import java.util.List; -import java.util.regex.Pattern; - -public class FilterBuilder implements Predicate { - private final List> chain; - - public FilterBuilder() { - chain = Lists.newArrayList(); - } - - /** - * exclude a regular expression - * @param regex regex to exclude - * @return updated {@link FilterBuilder} instance - */ - public FilterBuilder exclude(final String regex) { - add(new FilterBuilder.Exclude(regex)); - return this; - } - - /** - * add a Predicate to the chain of predicates - * @param filter predicate to add - * @return updated {@link FilterBuilder} instance - */ - public FilterBuilder add(Predicate filter) { - chain.add(filter); - return this; - } - - /** - * include a package of a given class - * @param aClass provided class - * @return updated {@link FilterBuilder} instance - */ - public FilterBuilder includePackage(final Class aClass) { - return add(new FilterBuilder.Include(packageNameRegex(aClass))); - } - - /** - * include packages of given prefixes - * @param prefixes package prefixes - * @return updated {@link FilterBuilder} instance - */ - public FilterBuilder includePackage(final String... prefixes) { - for (String prefix : prefixes) { - add(new FilterBuilder.Include(prefix(prefix))); - } - return this; - } - - private static String packageNameRegex(Class aClass) { - return prefix(aClass.getPackage().getName() + "."); - } - - public static String prefix(String qualifiedName) { - return qualifiedName.replace(".", "\\.") + ".*"; - } - - @Override - public String toString() { - return Joiner.on(", ").join(chain); - } - - public boolean apply(String regex) { - boolean accept = chain == null || chain.isEmpty() || chain.get(0) instanceof FilterBuilder.Exclude; - - if (chain != null) { - for (Predicate filter : chain) { - if (accept && filter instanceof FilterBuilder.Include) { - continue; - } //skip if this filter won't change - if (!accept && filter instanceof FilterBuilder.Exclude) { - continue; - } - accept = filter.apply(regex); - if (!accept && filter instanceof FilterBuilder.Exclude) { - break; - } //break on first exclusion - } - } - return accept; - } - - public abstract static class Matcher implements Predicate { - final Pattern pattern; - - public Matcher(final String regex) { - pattern = Pattern.compile(regex); - } - - public abstract boolean apply(String regex); - - @Override - public String toString() { - return pattern.pattern(); - } - } - - public static class Include extends FilterBuilder.Matcher { - public Include(final String patternString) { - super(patternString); - } - - @Override - public boolean apply(final String regex) { - return pattern.matcher(regex).matches(); - } - - @Override - public String toString() { - return "+" + super.toString(); - } - } - - public static class Exclude extends FilterBuilder.Matcher { - public Exclude(final String patternString) { - super(patternString); - } - - @Override - public boolean apply(final String regex) { - return !pattern.matcher(regex).matches(); - } - - @Override - public String toString() { - return "-" + super.toString(); - } - } - -} diff --git a/logstash-core/src/main/java/org/logstash/plugins/discovery/JavaReflectionAdapter.java b/logstash-core/src/main/java/org/logstash/plugins/discovery/JavaReflectionAdapter.java deleted file mode 100644 index 8edc965b9..000000000 --- a/logstash-core/src/main/java/org/logstash/plugins/discovery/JavaReflectionAdapter.java +++ /dev/null @@ -1,67 +0,0 @@ -package org.logstash.plugins.discovery; - -import java.lang.annotation.Annotation; -import java.util.ArrayList; -import java.util.List; - -@SuppressWarnings("rawtypes") -public final class JavaReflectionAdapter implements MetadataAdapter { - - public List getClassAnnotationNames(Class aClass) { - return getAnnotationNames(aClass.getDeclaredAnnotations()); - } - - public Class getOfCreateClassObject(Vfs.File file) { return getOfCreateClassObject(file, new ClassLoader[]{}); } - - public Class getOfCreateClassObject(Vfs.File file, ClassLoader... loaders) { - String name = file.getRelativePath().replace("/", ".").replace(".class", ""); - return ReflectionUtils.forName(name, loaders); - } - - public String getClassName(Class cls) { - return cls.getName(); - } - - public String getSuperclassName(Class cls) { - Class superclass = cls.getSuperclass(); - return superclass != null ? superclass.getName() : ""; - } - - public List getInterfacesNames(Class cls) { - Class[] classes = cls.getInterfaces(); - List names = new ArrayList<>(classes != null ? classes.length : 0); - if (classes != null) { - for (Class cls1 : classes) names.add(cls1.getName()); - } - return names; - } - - public boolean acceptsInput(String file) { - return file.endsWith(".class"); - } - - private List getAnnotationNames(Annotation[] annotations) { - List names = new ArrayList<>(annotations.length); - for (Annotation annotation : annotations) { - names.add(annotation.annotationType().getName()); - } - return names; - } - - public static String getName(Class type) { - if (type.isArray()) { - try { - Class cl = type; - int dim = 0; - while (cl.isArray()) { - dim++; - cl = cl.getComponentType(); - } - return cl.getName() + Utils.repeat("[]", dim); - } catch (Throwable e) { - // do nothing - } - } - return type.getName(); - } -} diff --git a/logstash-core/src/main/java/org/logstash/plugins/discovery/JavassistAdapter.java b/logstash-core/src/main/java/org/logstash/plugins/discovery/JavassistAdapter.java deleted file mode 100644 index 570473699..000000000 --- a/logstash-core/src/main/java/org/logstash/plugins/discovery/JavassistAdapter.java +++ /dev/null @@ -1,76 +0,0 @@ -package org.logstash.plugins.discovery; - -import com.google.common.collect.Lists; -import java.io.BufferedInputStream; -import java.io.DataInputStream; -import java.io.IOException; -import java.io.InputStream; -import java.util.Arrays; -import java.util.List; -import javassist.bytecode.AnnotationsAttribute; -import javassist.bytecode.ClassFile; -import javassist.bytecode.annotation.Annotation; - -/** - * - */ -public class JavassistAdapter implements MetadataAdapter { - - /** - * setting this to false will result in returning only visible annotations from the relevant methods here (only {@link java.lang.annotation.RetentionPolicy#RUNTIME}) - */ - public static boolean includeInvisibleTag = true; - - public List getClassAnnotationNames(final ClassFile aClass) { - return getAnnotationNames((AnnotationsAttribute) aClass.getAttribute(AnnotationsAttribute.visibleTag), - includeInvisibleTag ? (AnnotationsAttribute) aClass.getAttribute(AnnotationsAttribute.invisibleTag) : null); - } - - public ClassFile getOfCreateClassObject(final Vfs.File file) { - InputStream inputStream = null; - try { - inputStream = file.openInputStream(); - DataInputStream dis = new DataInputStream(new BufferedInputStream(inputStream)); - return new ClassFile(dis); - } catch (IOException e) { - throw new ReflectionsException("could not create class file from " + file.getName(), e); - } finally { - Utils.close(inputStream); - } - } - - // - public String getClassName(final ClassFile cls) { - return cls.getName(); - } - - public String getSuperclassName(final ClassFile cls) { - return cls.getSuperclass(); - } - - public List getInterfacesNames(final ClassFile cls) { - return Arrays.asList(cls.getInterfaces()); - } - - public boolean acceptsInput(String file) { - return file.endsWith(".class"); - } - - // - private List getAnnotationNames(final AnnotationsAttribute... annotationsAttributes) { - List result = Lists.newArrayList(); - - if (annotationsAttributes != null) { - for (AnnotationsAttribute annotationsAttribute : annotationsAttributes) { - if (annotationsAttribute != null) { - for (Annotation annotation : annotationsAttribute.getAnnotations()) { - result.add(annotation.getTypeName()); - } - } - } - } - - return result; - } - -} diff --git a/logstash-core/src/main/java/org/logstash/plugins/discovery/MetadataAdapter.java b/logstash-core/src/main/java/org/logstash/plugins/discovery/MetadataAdapter.java deleted file mode 100644 index 23b7e018c..000000000 --- a/logstash-core/src/main/java/org/logstash/plugins/discovery/MetadataAdapter.java +++ /dev/null @@ -1,23 +0,0 @@ -package org.logstash.plugins.discovery; - -import java.util.List; - -/** - * - */ -public interface MetadataAdapter { - - // - String getClassName(final C cls); - - String getSuperclassName(final C cls); - - List getInterfacesNames(final C cls); - - List getClassAnnotationNames(final C aClass); - - C getOfCreateClassObject(Vfs.File file) throws Exception; - - boolean acceptsInput(String file); - -} diff --git a/logstash-core/src/main/java/org/logstash/plugins/discovery/PluginRegistry.java b/logstash-core/src/main/java/org/logstash/plugins/discovery/PluginRegistry.java index 8a1f232d7..f779a317f 100644 --- a/logstash-core/src/main/java/org/logstash/plugins/discovery/PluginRegistry.java +++ b/logstash-core/src/main/java/org/logstash/plugins/discovery/PluginRegistry.java @@ -8,6 +8,7 @@ import co.elastic.logstash.api.Filter; import co.elastic.logstash.api.Input; import co.elastic.logstash.api.LogstashPlugin; import co.elastic.logstash.api.Output; +import org.reflections.Reflections; import java.lang.annotation.Annotation; import java.lang.reflect.Constructor; @@ -33,7 +34,7 @@ public final class PluginRegistry { @SuppressWarnings("unchecked") private static void discoverPlugins() { - Reflections reflections = new Reflections(""); + Reflections reflections = new Reflections("org.logstash.plugins"); Set> annotated = reflections.getTypesAnnotatedWith(LogstashPlugin.class); for (final Class cls : annotated) { for (final Annotation annotation : cls.getAnnotations()) { diff --git a/logstash-core/src/main/java/org/logstash/plugins/discovery/ReflectionUtils.java b/logstash-core/src/main/java/org/logstash/plugins/discovery/ReflectionUtils.java deleted file mode 100644 index 8bc2a6c53..000000000 --- a/logstash-core/src/main/java/org/logstash/plugins/discovery/ReflectionUtils.java +++ /dev/null @@ -1,120 +0,0 @@ -package org.logstash.plugins.discovery; - -import com.google.common.collect.Lists; -import java.util.ArrayList; -import java.util.Arrays; -import java.util.LinkedHashSet; -import java.util.List; -import java.util.Set; - -@SuppressWarnings("unchecked") -public abstract class ReflectionUtils { - - - public static boolean includeObject; - - /** - * @param type type to query - * @return immediate supertype and interfaces of the given {@code type} - */ - public static Set> getSuperTypes(Class type) { - Set> result = new LinkedHashSet<>(); - Class superclass = type.getSuperclass(); - Class[] interfaces = type.getInterfaces(); - if (superclass != null && (includeObject || !superclass.equals(Object.class))) { - result.add(superclass); - } - if (interfaces != null && interfaces.length > 0) { - result.addAll(Arrays.asList(interfaces)); - } - return result; - } - - //predicates - - public static Class forName(String typeName, ClassLoader... classLoaders) { - if (getPrimitiveNames().contains(typeName)) { - return getPrimitiveTypes().get(getPrimitiveNames().indexOf(typeName)); - } else { - String type; - if (typeName.contains("[")) { - int i = typeName.indexOf("["); - type = typeName.substring(0, i); - String array = typeName.substring(i).replace("]", ""); - - if (getPrimitiveNames().contains(type)) { - type = getPrimitiveDescriptors().get(getPrimitiveNames().indexOf(type)); - } else { - type = "L" + type + ";"; - } - - type = array + type; - } else { - type = typeName; - } - - List reflectionsExceptions = Lists.newArrayList(); - for (ClassLoader classLoader : ClasspathHelper.classLoaders(classLoaders)) { - if (type.contains("[")) { - try { - return Class.forName(type, false, classLoader); - } catch (Throwable e) { - reflectionsExceptions.add(new ReflectionsException("could not get type for name " + typeName, e)); - } - } - try { - return classLoader.loadClass(type); - } catch (Throwable e) { - reflectionsExceptions.add(new ReflectionsException("could not get type for name " + typeName, e)); - } - } - return null; - } - } - - /** - * @param Search will include subclasses of this type - * @param classes list of names of Java types - * @param classLoaders class loaders to search - * @return list of Java types given string representations of their names - */ - public static List> forNames(final Iterable classes, ClassLoader... classLoaders) { - List> result = new ArrayList<>(); - for (String className : classes) { - Class type = forName(className, classLoaders); - if (type != null) { - result.add((Class) type); - } - } - return result; - } - - private static List primitiveNames; - @SuppressWarnings("rawtypes") private static List primitiveTypes; - private static List primitiveDescriptors; - - private static void initPrimitives() { - if (primitiveNames == null) { - primitiveNames = Lists.newArrayList("boolean", "char", "byte", "short", "int", "long", "float", "double", "void"); - primitiveTypes = Lists.newArrayList(boolean.class, char.class, byte.class, short.class, int.class, long.class, float.class, double.class, void.class); - primitiveDescriptors = Lists.newArrayList("Z", "C", "B", "S", "I", "J", "F", "D", "V"); - } - } - - private static List getPrimitiveNames() { - initPrimitives(); - return primitiveNames; - } - - @SuppressWarnings("rawtypes") - private static List getPrimitiveTypes() { - initPrimitives(); - return primitiveTypes; - } - - private static List getPrimitiveDescriptors() { - initPrimitives(); - return primitiveDescriptors; - } - -} diff --git a/logstash-core/src/main/java/org/logstash/plugins/discovery/Reflections.java b/logstash-core/src/main/java/org/logstash/plugins/discovery/Reflections.java deleted file mode 100644 index 61e20356f..000000000 --- a/logstash-core/src/main/java/org/logstash/plugins/discovery/Reflections.java +++ /dev/null @@ -1,155 +0,0 @@ -package org.logstash.plugins.discovery; - -import com.google.common.base.Predicate; -import com.google.common.collect.HashMultimap; -import com.google.common.collect.Iterables; -import com.google.common.collect.Lists; -import com.google.common.collect.Multimap; -import com.google.common.collect.Sets; -import java.lang.annotation.Annotation; -import java.lang.annotation.Inherited; -import java.net.URL; -import java.util.List; -import java.util.Set; -import java.util.concurrent.ExecutorService; -import java.util.concurrent.Future; - -public class Reflections { - - protected final Configuration configuration; - protected Store store; - - public Reflections(final Configuration configuration) { - this.configuration = configuration; - store = new Store(configuration); - - if (configuration.getScanners() != null && !configuration.getScanners().isEmpty()) { - //inject to scanners - for (Scanner scanner : configuration.getScanners()) { - scanner.setConfiguration(configuration); - scanner.setStore(store.getOrCreate(scanner.getClass().getSimpleName())); - } - - scan(); - - if (configuration.shouldExpandSuperTypes()) { - expandSuperTypes(); - } - } - } - - public Reflections(final String prefix, final Scanner... scanners) { - this((Object) prefix, scanners); - } - - public Reflections(final Object... params) { - this(ConfigurationBuilder.build(params)); - } - - @SuppressWarnings("rawtypes") - protected void scan() { - if (configuration.getUrls() == null || configuration.getUrls().isEmpty()) { - return; - } - ExecutorService executorService = configuration.getExecutorService(); - List> futures = Lists.newArrayList(); - - for (final URL url : configuration.getUrls()) { - try { - if (executorService != null) { - futures.add(executorService.submit(() -> scan(url))); - } else { - scan(url); - } - } catch (ReflectionsException e) { - } - } - - if (executorService != null) { - for (Future future : futures) { - try { - future.get(); - } catch (Exception e) { - throw new RuntimeException(e); - } - } - } - - if (executorService != null) { - executorService.shutdown(); - } - } - - protected void scan(URL url) { - Vfs.Dir dir = Vfs.fromURL(url); - - try { - for (final Vfs.File file : dir.getFiles()) { - // scan if inputs filter accepts file relative path or fqn - Predicate inputsFilter = configuration.getInputsFilter(); - String path = file.getRelativePath(); - String fqn = path.replace('/', '.'); - if (inputsFilter == null || inputsFilter.apply(path) || inputsFilter.apply(fqn)) { - Object classObject = null; - for (Scanner scanner : configuration.getScanners()) { - try { - if (scanner.acceptsInput(path) || scanner.acceptResult(fqn)) { - classObject = scanner.scan(file, classObject); - } - } catch (Exception e) { - } - } - } - } - } finally { - dir.close(); - } - } - - public void expandSuperTypes() { - if (store.keySet().contains(index(SubTypesScanner.class))) { - Multimap mmap = store.get(index(SubTypesScanner.class)); - Sets.SetView keys = Sets.difference(mmap.keySet(), Sets.newHashSet(mmap.values())); - Multimap expand = HashMultimap.create(); - for (String key : keys) { - final Class type = ReflectionUtils.forName(key); - if (type != null) { - expandSupertypes(expand, key, type); - } - } - mmap.putAll(expand); - } - } - - private void expandSupertypes(Multimap mmap, String key, Class type) { - for (Class supertype : ReflectionUtils.getSuperTypes(type)) { - if (mmap.put(supertype.getName(), key)) { - expandSupertypes(mmap, supertype.getName(), supertype); - } - } - } - - public Set> getTypesAnnotatedWith(final Class annotation) { - return getTypesAnnotatedWith(annotation, false); - } - - public Set> getTypesAnnotatedWith(final Class annotation, boolean honorInherited) { - Iterable annotated = store.get(index(TypeAnnotationsScanner.class), annotation.getName()); - Iterable classes = getAllAnnotated(annotated, annotation.isAnnotationPresent(Inherited.class), honorInherited); - return Sets.newHashSet(Iterables.concat(ReflectionUtils.forNames(annotated, loaders()), ReflectionUtils.forNames(classes, loaders()))); - } - - protected Iterable getAllAnnotated(Iterable annotated, boolean inherited, boolean honorInherited) { - Iterable subTypes = Iterables.concat(annotated, store.getAll(index(TypeAnnotationsScanner.class), annotated)); - return Iterables.concat(subTypes, store.getAll(index(SubTypesScanner.class), subTypes)); - } - - private static String index(Class scannerClass) { - return scannerClass.getSimpleName(); - } - - private ClassLoader[] loaders() { - return configuration.getClassLoaders(); - } - -} diff --git a/logstash-core/src/main/java/org/logstash/plugins/discovery/ReflectionsException.java b/logstash-core/src/main/java/org/logstash/plugins/discovery/ReflectionsException.java deleted file mode 100644 index dcde5c576..000000000 --- a/logstash-core/src/main/java/org/logstash/plugins/discovery/ReflectionsException.java +++ /dev/null @@ -1,16 +0,0 @@ -package org.logstash.plugins.discovery; - -public class ReflectionsException extends RuntimeException { - - private static final long serialVersionUID = 1L; - - public ReflectionsException(String message) { - super(message); - } - - public ReflectionsException(String message, Throwable cause) { - super(message, cause); - } - -} - diff --git a/logstash-core/src/main/java/org/logstash/plugins/discovery/Scanner.java b/logstash-core/src/main/java/org/logstash/plugins/discovery/Scanner.java deleted file mode 100644 index ef7fd62b2..000000000 --- a/logstash-core/src/main/java/org/logstash/plugins/discovery/Scanner.java +++ /dev/null @@ -1,24 +0,0 @@ -package org.logstash.plugins.discovery; - -import com.google.common.base.Predicate; -import com.google.common.collect.Multimap; - -/** - * - */ -public interface Scanner { - - void setConfiguration(Configuration configuration); - - Multimap getStore(); - - void setStore(Multimap store); - - Scanner filterResultsBy(Predicate filter); - - boolean acceptsInput(String file); - - Object scan(Vfs.File file, Object classObject); - - boolean acceptResult(String fqn); -} diff --git a/logstash-core/src/main/java/org/logstash/plugins/discovery/Store.java b/logstash-core/src/main/java/org/logstash/plugins/discovery/Store.java deleted file mode 100644 index 609f3151e..000000000 --- a/logstash-core/src/main/java/org/logstash/plugins/discovery/Store.java +++ /dev/null @@ -1,126 +0,0 @@ -package org.logstash.plugins.discovery; - -import com.google.common.collect.Iterables; -import com.google.common.collect.Lists; -import com.google.common.collect.Multimap; -import com.google.common.collect.Multimaps; -import com.google.common.collect.SetMultimap; -import com.google.common.collect.Sets; -import java.util.Arrays; -import java.util.Collections; -import java.util.HashMap; -import java.util.Iterator; -import java.util.List; -import java.util.Map; -import java.util.Set; -import java.util.concurrent.ConcurrentHashMap; - -public final class Store { - - private transient boolean concurrent; - private final Map> storeMap; - - //used via reflection - @SuppressWarnings("UnusedDeclaration") - protected Store() { - storeMap = new HashMap<>(); - concurrent = false; - } - - public Store(Configuration configuration) { - storeMap = new HashMap<>(); - concurrent = configuration.getExecutorService() != null; - } - - /** - * @return all indices - */ - public Set keySet() { - return storeMap.keySet(); - } - - /** - * @param index specified index - * @return existing or newly-created multimap object for the given {@code index} - */ - public Multimap getOrCreate(String index) { - Multimap mmap = storeMap.get(index); - if (mmap == null) { - SetMultimap multimap = - Multimaps.newSetMultimap(new HashMap<>(), - () -> Collections.newSetFromMap(new ConcurrentHashMap<>())); - mmap = concurrent ? Multimaps.synchronizedSetMultimap(multimap) : multimap; - storeMap.put(index, mmap); - } - return mmap; - } - - public Multimap get(String index) { - Multimap mmap = storeMap.get(index); - if (mmap == null) { - throw new ReflectionsException("Scanner " + index + " was not configured"); - } - return mmap; - } - - /** - * @param index specified index - * @param keys specified keys - * @return values stored for the given {@code index} and {@code keys} - */ - public Iterable get(String index, String... keys) { - return get(index, Arrays.asList(keys)); - } - - /** - * @param index specified index - * @param keys specified keys - * @return values stored for the given {@code index} and {@code keys} - */ - public Iterable get(String index, Iterable keys) { - Multimap mmap = get(index); - IterableChain result = new IterableChain<>(); - for (String key : keys) { - result.addAll(mmap.get(key)); - } - return result; - } - - /** - * @param index specified index - * @param keys specified keys - * @param result accumulates intermediate results - * @return values stored for the given {@code index} and {@code keys}, including keys - */ - private Iterable getAllIncluding(String index, Iterable keys, IterableChain result) { - result.addAll(keys); - for (String key : keys) { - Iterable values = get(index, key); - if (values.iterator().hasNext()) { - getAllIncluding(index, values, result); - } - } - return result; - } - - /** - * @param index specified index - * @param keys specified keys - * @return values stored for the given {@code index} and {@code keys}, not including keys - */ - public Iterable getAll(String index, Iterable keys) { - return getAllIncluding(index, get(index, keys), new IterableChain<>()); - } - - private static class IterableChain implements Iterable { - private final List> chain = Lists.newArrayList(); - - private void addAll(Iterable iterable) { - chain.add(iterable); - } - - public Iterator iterator() { - return Iterables.concat(chain).iterator(); - } - } -} diff --git a/logstash-core/src/main/java/org/logstash/plugins/discovery/SubTypesScanner.java b/logstash-core/src/main/java/org/logstash/plugins/discovery/SubTypesScanner.java deleted file mode 100644 index 820565998..000000000 --- a/logstash-core/src/main/java/org/logstash/plugins/discovery/SubTypesScanner.java +++ /dev/null @@ -1,36 +0,0 @@ -package org.logstash.plugins.discovery; - -import java.util.List; - -/** scans for superclass and interfaces of a class, allowing a reverse lookup for subtypes */ -public class SubTypesScanner extends AbstractScanner { - - /** created new SubTypesScanner. will exclude direct Object subtypes */ - public SubTypesScanner() { - this(true); //exclude direct Object subtypes by default - } - - /** created new SubTypesScanner. - * @param excludeObjectClass if false, include direct {@link Object} subtypes in results. */ - public SubTypesScanner(boolean excludeObjectClass) { - if (excludeObjectClass) { - filterResultsBy(new FilterBuilder().exclude(Object.class.getName())); //exclude direct Object subtypes - } - } - - @SuppressWarnings({"unchecked"}) - public void scan(final Object cls) { - String className = getMetadataAdapter().getClassName(cls); - String superclass = getMetadataAdapter().getSuperclassName(cls); - - if (acceptResult(superclass)) { - getStore().put(superclass, className); - } - - for (String anInterface : (List) getMetadataAdapter().getInterfacesNames(cls)) { - if (acceptResult(anInterface)) { - getStore().put(anInterface, className); - } - } - } -} diff --git a/logstash-core/src/main/java/org/logstash/plugins/discovery/TypeAnnotationsScanner.java b/logstash-core/src/main/java/org/logstash/plugins/discovery/TypeAnnotationsScanner.java deleted file mode 100644 index 3b31cc6ad..000000000 --- a/logstash-core/src/main/java/org/logstash/plugins/discovery/TypeAnnotationsScanner.java +++ /dev/null @@ -1,26 +0,0 @@ -package org.logstash.plugins.discovery; - -import java.lang.annotation.Inherited; -import java.util.List; - -/** - * scans for class's annotations, where @Retention(RetentionPolicy.RUNTIME) - */ -@SuppressWarnings("unchecked") -public class TypeAnnotationsScanner extends AbstractScanner { - - @Override - public void scan(final Object cls) { - final String className = getMetadataAdapter().getClassName(cls); - - for (String annotationType : (List) getMetadataAdapter().getClassAnnotationNames(cls)) { - - if (acceptResult(annotationType) || - annotationType.equals(Inherited.class.getName())) { //as an exception, accept Inherited as well - getStore().put(annotationType, className); - } - } - } - -} - diff --git a/logstash-core/src/main/java/org/logstash/plugins/discovery/Utils.java b/logstash-core/src/main/java/org/logstash/plugins/discovery/Utils.java deleted file mode 100644 index bdb3046a7..000000000 --- a/logstash-core/src/main/java/org/logstash/plugins/discovery/Utils.java +++ /dev/null @@ -1,83 +0,0 @@ -package org.logstash.plugins.discovery; - -import com.google.common.base.Joiner; -import java.io.IOException; -import java.io.InputStream; -import java.lang.reflect.Constructor; -import java.lang.reflect.Field; -import java.lang.reflect.Method; -import java.util.ArrayList; -import java.util.Arrays; -import java.util.List; - -/** - * Convenient methods for plugin discovery. - */ -public abstract class Utils { - - public static String repeat(String string, int times) { - StringBuilder sb = new StringBuilder(); - - for (int i = 0; i < times; i++) { - sb.append(string); - } - - return sb.toString(); - } - - /** - * @param s string to test - * @return Java5-compatible isEmpty result - */ - public static boolean isEmpty(String s) { - return s == null || s.length() == 0; - } - - public static boolean isEmpty(Object[] objects) { - return objects == null || objects.length == 0; - } - - public static void close(InputStream closeable) { - try { - if (closeable != null) { - closeable.close(); - } - } catch (IOException e) { - } - } - - public static String name(@SuppressWarnings("rawtypes") Class type) { - if (!type.isArray()) { - return type.getName(); - } else { - int dim = 0; - while (type.isArray()) { - dim++; - type = type.getComponentType(); - } - return type.getName() + repeat("[]", dim); - } - } - - public static List names(Iterable> types) { - List result = new ArrayList<>(); - for (Class type : types) result.add(name(type)); - return result; - } - - public static List names(Class... types) { - return names(Arrays.asList(types)); - } - - public static String name(@SuppressWarnings("rawtypes") Constructor constructor) { - return constructor.getName() + "." + "" + "(" + Joiner.on(", ").join(names(constructor.getParameterTypes())) + ")"; - } - - public static String name(Method method) { - return method.getDeclaringClass().getName() + "." + method.getName() + "(" + Joiner.on(", ").join(names(method.getParameterTypes())) + ")"; - } - - public static String name(Field field) { - return field.getDeclaringClass().getName() + "." + field.getName(); - } -} diff --git a/logstash-core/src/main/java/org/logstash/plugins/discovery/Vfs.java b/logstash-core/src/main/java/org/logstash/plugins/discovery/Vfs.java deleted file mode 100644 index 5de32413f..000000000 --- a/logstash-core/src/main/java/org/logstash/plugins/discovery/Vfs.java +++ /dev/null @@ -1,634 +0,0 @@ -package org.logstash.plugins.discovery; - -import com.google.common.base.Predicate; -import com.google.common.collect.AbstractIterator; -import com.google.common.collect.Lists; -import java.io.FileInputStream; -import java.io.FileNotFoundException; -import java.io.IOException; -import java.io.InputStream; -import java.io.UnsupportedEncodingException; -import java.net.JarURLConnection; -import java.net.MalformedURLException; -import java.net.URISyntaxException; -import java.net.URL; -import java.net.URLConnection; -import java.net.URLDecoder; -import java.util.Collections; -import java.util.Enumeration; -import java.util.List; -import java.util.Stack; -import java.util.jar.JarFile; -import java.util.jar.JarInputStream; -import java.util.regex.Matcher; -import java.util.regex.Pattern; -import java.util.zip.ZipEntry; - -public abstract class Vfs { - private static List defaultUrlTypes = Lists.newArrayList(Vfs.DefaultUrlTypes.values()); - - /** - * an abstract vfs dir - */ - public interface Dir { - String getPath(); - - Iterable getFiles(); - - void close(); - } - - /** - * an abstract vfs file - */ - public interface File { - String getName(); - - String getRelativePath(); - - InputStream openInputStream() throws IOException; - } - - /** - * a matcher and factory for a url - */ - public interface UrlType { - boolean matches(URL url) throws Exception; - - Vfs.Dir createDir(URL url) throws Exception; - } - - /** - * @param url URL from which to create a Dir - * @return Dir created from the given url, using the defaultUrlTypes - */ - public static Vfs.Dir fromURL(final URL url) { - return fromURL(url, defaultUrlTypes); - } - - /** - * @param url URL from which to create a Dir - * @param urlTypes given URL types - * @return Dir created from the given url, using the given urlTypes - */ - public static Vfs.Dir fromURL(final URL url, final List urlTypes) { - for (final Vfs.UrlType type : urlTypes) { - try { - if (type.matches(url)) { - final Vfs.Dir dir = type.createDir(url); - if (dir != null) { - return dir; - } - } - } catch (final Throwable e) { - } - } - - throw new ReflectionsException("could not create Vfs.Dir from url, no matching UrlType was found [" + url.toExternalForm() + "]\n" + - "either use fromURL(final URL url, final List urlTypes) or " + - "use the static setDefaultURLTypes(final List urlTypes) or addDefaultURLTypes(UrlType urlType) " + - "with your specialized UrlType."); - } - - /** - * @param url provided URL - * @return {@link Vfs.File} from provided URL - */ - public static java.io.File getFile(final URL url) { - java.io.File file; - String path; - - try { - path = url.toURI().getSchemeSpecificPart(); - if ((file = new java.io.File(path)).exists()) { - return file; - } - } catch (final URISyntaxException e) { - } - - try { - path = URLDecoder.decode(url.getPath(), "UTF-8"); - if (path.contains(".jar!")) { - path = path.substring(0, path.lastIndexOf(".jar!") + ".jar".length()); - } - if ((file = new java.io.File(path)).exists()) { - return file; - } - - } catch (final UnsupportedEncodingException e) { - } - - try { - path = url.toExternalForm(); - if (path.startsWith("jar:")) { - path = path.substring("jar:".length()); - } - if (path.startsWith("wsjar:")) { - path = path.substring("wsjar:".length()); - } - if (path.startsWith("file:")) { - path = path.substring("file:".length()); - } - if (path.contains(".jar!")) { - path = path.substring(0, path.indexOf(".jar!") + ".jar".length()); - } - if ((file = new java.io.File(path)).exists()) { - return file; - } - - path = path.replace("%20", " "); - if ((file = new java.io.File(path)).exists()) { - return file; - } - - } catch (final Exception e) { - } - - return null; - } - - private static boolean hasJarFileInPath(final URL url) { - return url.toExternalForm().matches(".*\\.jar(\\!.*|$)"); - } - - public enum DefaultUrlTypes implements Vfs.UrlType { - jarFile { - @Override - public boolean matches(final URL url) { - return url.getProtocol().equals("file") && hasJarFileInPath(url); - } - - @Override - public Vfs.Dir createDir(final URL url) throws Exception { - return new Vfs.ZipDir(new JarFile(getFile(url))); - } - }, - - jarUrl { - @Override - public boolean matches(final URL url) { - return "jar".equals(url.getProtocol()) || "zip".equals(url.getProtocol()) || "wsjar".equals(url.getProtocol()); - } - - @Override - public Vfs.Dir createDir(final URL url) throws Exception { - try { - final URLConnection urlConnection = url.openConnection(); - if (urlConnection instanceof JarURLConnection) { - return new Vfs.ZipDir(((JarURLConnection) urlConnection).getJarFile()); - } - } catch (final Throwable e) { /*fallback*/ } - final java.io.File file = getFile(url); - if (file != null) { - return new Vfs.ZipDir(new JarFile(file)); - } - return null; - } - }, - - directory { - @Override - public boolean matches(final URL url) { - if (url.getProtocol().equals("file") && !hasJarFileInPath(url)) { - final java.io.File file = getFile(url); - return file != null && file.isDirectory(); - } else { - return false; - } - } - - @Override - public Vfs.Dir createDir(final URL url) { - return new Vfs.SystemDir(getFile(url)); - } - }, - - jboss_vfs { - @Override - public boolean matches(final URL url) { - return url.getProtocol().equals("vfs"); - } - - @Override - public Vfs.Dir createDir(final URL url) throws Exception { - final Object content = url.openConnection().getContent(); - final Class virtualFile = ClasspathHelper.contextClassLoader().loadClass("org.jboss.vfs.VirtualFile"); - final java.io.File physicalFile = (java.io.File) virtualFile.getMethod("getPhysicalFile").invoke(content); - final String name = (String) virtualFile.getMethod("getName").invoke(content); - java.io.File file = new java.io.File(physicalFile.getParentFile(), name); - if (!file.exists() || !file.canRead()) { - file = physicalFile; - } - return file.isDirectory() ? new Vfs.SystemDir(file) : new Vfs.ZipDir(new JarFile(file)); - } - }, - - jboss_vfsfile { - @Override - public boolean matches(final URL url) { - return "vfszip".equals(url.getProtocol()) || "vfsfile".equals(url.getProtocol()); - } - - @Override - public Vfs.Dir createDir(final URL url) { - return new Vfs.UrlTypeVFS().createDir(url); - } - }, - - bundle { - @Override - public boolean matches(final URL url) { - return url.getProtocol().startsWith("bundle"); - } - - @Override - public Vfs.Dir createDir(final URL url) throws Exception { - return fromURL((URL) ClasspathHelper.contextClassLoader(). - loadClass("org.eclipse.core.runtime.FileLocator").getMethod("resolve", URL.class).invoke(null, url)); - } - }, - - jarInputStream { - @Override - public boolean matches(final URL url) { - return url.toExternalForm().contains(".jar"); - } - - @Override - public Vfs.Dir createDir(final URL url) { - return new Vfs.JarInputDir(url); - } - } - } - - private static final class JarInputDir implements Vfs.Dir { - private final URL url; - JarInputStream jarInputStream; - long cursor; - long nextCursor; - - public JarInputDir(final URL url) { - this.url = url; - } - - @Override - public String getPath() { - return url.getPath(); - } - - @Override - public Iterable getFiles() { - return () -> new AbstractIterator() { - - { - try { - jarInputStream = new JarInputStream(url.openConnection().getInputStream()); - } catch (final Exception e) { - throw new ReflectionsException("Could not open url connection", e); - } - } - - @Override - protected Vfs.File computeNext() { - while (true) { - try { - final ZipEntry entry = jarInputStream.getNextJarEntry(); - if (entry == null) { - return endOfData(); - } - - long size = entry.getSize(); - if (size < 0) { - size = 0xffffffffl + size; //JDK-6916399 - } - nextCursor += size; - if (!entry.isDirectory()) { - return new Vfs.JarInputFile(entry, Vfs.JarInputDir.this, cursor, nextCursor); - } - } catch (final IOException e) { - throw new ReflectionsException("could not get next zip entry", e); - } - } - } - }; - } - - @Override - public void close() { - Utils.close(jarInputStream); - } - } - - public static class JarInputFile implements Vfs.File { - private final ZipEntry entry; - private final Vfs.JarInputDir jarInputDir; - private final long fromIndex; - private final long endIndex; - - public JarInputFile(final ZipEntry entry, final Vfs.JarInputDir jarInputDir, final long cursor, final long nextCursor) { - this.entry = entry; - this.jarInputDir = jarInputDir; - fromIndex = cursor; - endIndex = nextCursor; - } - - @Override - public String getName() { - final String name = entry.getName(); - return name.substring(name.lastIndexOf("/") + 1); - } - - @Override - public String getRelativePath() { - return entry.getName(); - } - - @Override - public InputStream openInputStream() { - return new InputStream() { - @Override - public int read() throws IOException { - if (jarInputDir.cursor >= fromIndex && jarInputDir.cursor <= endIndex) { - final int read = jarInputDir.jarInputStream.read(); - jarInputDir.cursor++; - return read; - } else { - return -1; - } - } - }; - } - } - - public static final class ZipDir implements Vfs.Dir { - final java.util.zip.ZipFile jarFile; - - public ZipDir(final JarFile jarFile) { - this.jarFile = jarFile; - } - - @Override - public String getPath() { - return jarFile.getName(); - } - - @Override - public Iterable getFiles() { - return () -> new AbstractIterator() { - final Enumeration entries = jarFile.entries(); - - @Override - protected Vfs.File computeNext() { - while (entries.hasMoreElements()) { - final ZipEntry entry = entries.nextElement(); - if (!entry.isDirectory()) { - return new Vfs.ZipFile(Vfs.ZipDir.this, entry); - } - } - - return endOfData(); - } - }; - } - - @Override - public void close() { - try { - jarFile.close(); - } catch (final IOException e) { - } - } - - @Override - public String toString() { - return jarFile.getName(); - } - } - - public static final class ZipFile implements Vfs.File { - private final Vfs.ZipDir root; - private final ZipEntry entry; - - public ZipFile(final Vfs.ZipDir root, final ZipEntry entry) { - this.root = root; - this.entry = entry; - } - - @Override - public String getName() { - final String name = entry.getName(); - return name.substring(name.lastIndexOf("/") + 1); - } - - @Override - public String getRelativePath() { - return entry.getName(); - } - - @Override - public InputStream openInputStream() throws IOException { - return root.jarFile.getInputStream(entry); - } - - @Override - public String toString() { - return root.getPath() + "!" + java.io.File.separatorChar + entry.toString(); - } - } - - public static final class SystemDir implements Vfs.Dir { - private final java.io.File file; - - public SystemDir(final java.io.File file) { - if (file != null && (!file.isDirectory() || !file.canRead())) { - throw new RuntimeException("cannot use dir " + file); - } - - this.file = file; - } - - @Override - public String getPath() { - if (file == null) { - return "/NO-SUCH-DIRECTORY/"; - } - return file.getPath().replace("\\", "/"); - } - - @Override - public Iterable getFiles() { - if (file == null || !file.exists()) { - return Collections.emptyList(); - } - return () -> new AbstractIterator() { - final Stack stack = new Stack<>(); - - { - stack.addAll(listFiles(file)); - } - - @Override - protected Vfs.File computeNext() { - while (!stack.isEmpty()) { - final java.io.File file = stack.pop(); - if (file.isDirectory()) { - stack.addAll(listFiles(file)); - } else { - return new Vfs.SystemFile(Vfs.SystemDir.this, file); - } - } - - return endOfData(); - } - }; - } - - private static List listFiles(final java.io.File file) { - final java.io.File[] files = file.listFiles(); - - if (files != null) { - return Lists.newArrayList(files); - } else { - return Lists.newArrayList(); - } - } - - @Override - public void close() { - } - - @Override - public String toString() { - return getPath(); - } - } - - private static final class UrlTypeVFS implements Vfs.UrlType { - public static final String[] REPLACE_EXTENSION = {".ear/", ".jar/", ".war/", ".sar/", ".har/", ".par/"}; - - final String VFSZIP = "vfszip"; - final String VFSFILE = "vfsfile"; - - @Override - public boolean matches(final URL url) { - return VFSZIP.equals(url.getProtocol()) || VFSFILE.equals(url.getProtocol()); - } - - @Override - public Vfs.Dir createDir(final URL url) { - try { - final URL adaptedUrl = adaptURL(url); - return new Vfs.ZipDir(new JarFile(adaptedUrl.getFile())); - } catch (final Exception e) { - try { - return new Vfs.ZipDir(new JarFile(url.getFile())); - } catch (final IOException e1) { - } - } - return null; - } - - public URL adaptURL(final URL url) throws MalformedURLException { - if (VFSZIP.equals(url.getProtocol())) { - return replaceZipSeparators(url.getPath(), realFile); - } else if (VFSFILE.equals(url.getProtocol())) { - return new URL(url.toString().replace(VFSFILE, "file")); - } else { - return url; - } - } - - URL replaceZipSeparators(final String path, final Predicate acceptFile) - throws MalformedURLException { - int pos = 0; - while (pos != -1) { - pos = findFirstMatchOfDeployableExtention(path, pos); - - if (pos > 0) { - final java.io.File file = new java.io.File(path.substring(0, pos - 1)); - if (acceptFile.apply(file)) { - return replaceZipSeparatorStartingFrom(path, pos); - } - } - } - - throw new ReflectionsException("Unable to identify the real zip file in path '" + path + "'."); - } - - int findFirstMatchOfDeployableExtention(final String path, final int pos) { - final Pattern p = Pattern.compile("\\.[ejprw]ar/"); - final Matcher m = p.matcher(path); - if (m.find(pos)) { - return m.end(); - } else { - return -1; - } - } - - Predicate realFile = file -> file.exists() && file.isFile(); - - URL replaceZipSeparatorStartingFrom(final String path, final int pos) - throws MalformedURLException { - final String zipFile = path.substring(0, pos - 1); - String zipPath = path.substring(pos); - - int numSubs = 1; - for (final String ext : REPLACE_EXTENSION) { - while (zipPath.contains(ext)) { - zipPath = zipPath.replace(ext, ext.substring(0, 4) + "!"); - numSubs++; - } - } - - String prefix = ""; - for (int i = 0; i < numSubs; i++) { - prefix += "zip:"; - } - - if (zipPath.trim().length() == 0) { - return new URL(prefix + "/" + zipFile); - } else { - return new URL(prefix + "/" + zipFile + "!" + zipPath); - } - } - } - - private static final class SystemFile implements Vfs.File { - private final Vfs.SystemDir root; - private final java.io.File file; - - public SystemFile(final Vfs.SystemDir root, final java.io.File file) { - this.root = root; - this.file = file; - } - - @Override - public String getName() { - return file.getName(); - } - - @Override - public String getRelativePath() { - final String filepath = file.getPath().replace("\\", "/"); - if (filepath.startsWith(root.getPath())) { - return filepath.substring(root.getPath().length() + 1); - } - - return null; //should not get here - } - - @Override - public InputStream openInputStream() { - try { - return new FileInputStream(file); - } catch (final FileNotFoundException e) { - throw new RuntimeException(e); - } - } - - @Override - public String toString() { - return file.toString(); - } - } -} diff --git a/qa/integration/specs/monitoring_api_spec.rb b/qa/integration/specs/monitoring_api_spec.rb index a82af0520..c40e5302b 100644 --- a/qa/integration/specs/monitoring_api_spec.rb +++ b/qa/integration/specs/monitoring_api_spec.rb @@ -129,7 +129,7 @@ describe "Test Monitoring API" do result = logstash_service.monitoring_api.logging_get result["loggers"].each do | k, v | #since we explicitly set the logstash.agent logger above, the logger.logstash parent logger will not take precedence - if k.eql?("logstash.agent") || k.start_with?("org.logstash") + if k.eql?("logstash.agent") || k.start_with?("org.logstash") || k.eql?("org.reflections.Reflections") expect(v).to eq("INFO") else expect(v).to eq("ERROR") From 18ba98aa9186e316365995cda3ea263f0024a67d Mon Sep 17 00:00:00 2001 From: Mike Place Date: Mon, 12 Aug 2019 12:05:28 +0000 Subject: [PATCH 0214/1126] Enhanced API testing (#10972) * Starting to audit tests * Additional field checking in stats * Add epehemeral id * More tests * Test new structure of pipeline report * Add default_metadata testing * Add node command tests * add jvm * test no mutate * Add check for graph flag * Break apart test per review suggestion * Remove test that doesn't test much --- .../api/commands/default_metadata_spec.rb | 37 +++++ .../spec/logstash/api/commands/node_spec.rb | 126 ++++++++++++++++++ .../spec/logstash/api/commands/stats_spec.rb | 90 +++++++++++-- .../spec/logstash/api/modules/node_spec.rb | 1 + .../logstash/api/modules/node_stats_spec.rb | 12 +- 5 files changed, 255 insertions(+), 11 deletions(-) create mode 100644 logstash-core/spec/logstash/api/commands/default_metadata_spec.rb create mode 100644 logstash-core/spec/logstash/api/commands/node_spec.rb diff --git a/logstash-core/spec/logstash/api/commands/default_metadata_spec.rb b/logstash-core/spec/logstash/api/commands/default_metadata_spec.rb new file mode 100644 index 000000000..ee5157ffb --- /dev/null +++ b/logstash-core/spec/logstash/api/commands/default_metadata_spec.rb @@ -0,0 +1,37 @@ +# encoding: utf-8 +require "spec_helper" + +describe LogStash::Api::Commands::DefaultMetadata do + include_context "api setup" + + let(:report_method) { :all } + subject(:report) do + factory = ::LogStash::Api::CommandFactory.new(LogStash::Api::Service.new(@agent)) + factory.build(:default_metadata).send(report_method) + end + + let(:report_class) { described_class } + + describe "#plugins_stats_report" do + let(:report_method) { :all } + # Enforce just the structure + it "check keys" do + expect(report.keys).to include( + :host, + :version, + :http_address, + :id, + :name, + :ephemeral_id, + :status, + :snapshot, + :pipeline + ) + expect(report[:pipeline].keys).to include( + :workers, + :batch_size, + :batch_delay, + ) + end + end +end diff --git a/logstash-core/spec/logstash/api/commands/node_spec.rb b/logstash-core/spec/logstash/api/commands/node_spec.rb new file mode 100644 index 000000000..0077519bc --- /dev/null +++ b/logstash-core/spec/logstash/api/commands/node_spec.rb @@ -0,0 +1,126 @@ +# encoding: utf-8 +require "spec_helper" + +describe LogStash::Api::Commands::Node do + include_context "api setup" + + let(:report_method) { :all } + let(:pipeline_id) { nil } + let(:opts) { {} } + let(:mocked_vertex) {{:config_name=>"elasticsearch", + :plugin_type=>"output", + :meta=>{ + :source=>{ + :protocol=>"str", + :id=>"pipeline", + :line=>1, + :column=>64 + } + }, + :id=>"2d2270426a2e8d7976b972b6a5318624331fa0d39fa3f903d2f3490e58a7d25a", + :explicit_id=>false, + :type=>"plugin"} + } + subject(:report) do + factory = ::LogStash::Api::CommandFactory.new(LogStash::Api::Service.new(@agent)) + if report_method == :pipelines + factory.build(:node).send(report_method, opts) + elsif report_method == :pipeline + factory.build(:node).send(report_method, pipeline_id, opts) + elsif report_method == :decorate_with_cluster_uuids + factory.build(:node).send(report_method, mocked_vertex) + else + factory.build(:node).send(report_method) + end + end + + let(:report_class) { described_class } + + describe "#all" do + let(:report_method) { :all } + # Enforce just the structure + it "check keys" do + expect(report.keys).to include( + :pipelines, + :os, + :jvm + ) + end + end + + + describe "#pipeline" do + let(:report_method) { :pipeline } + let(:pipeline_id) { "main" } + # Enforce just the structure + it "check keys" do + expect(report.keys).to include( + :ephemeral_id, + :hash, + :workers, + :batch_size, + :batch_delay, + :config_reload_automatic, + :config_reload_interval, + :dead_letter_queue_enabled, + # :dead_letter_queue_path is nil in tests + # so it is ignored + ) + end + end + + describe "#pipeline?opts" do + let(:report_method) { :pipeline } + let(:pipeline_id) { "main" } + let(:opts) { { :graph=>true } } + # Enforce just the structure + it "check keys" do + expect(report.keys).to include( + :ephemeral_id, + :hash, + :workers, + :batch_size, + :batch_delay, + :config_reload_automatic, + :config_reload_interval, + :dead_letter_queue_enabled, + # Be sure we display a graph when we set the option to + :graph + ) + end + end + + describe "#os" do + let(:report_method) { :os } + it "check_keys" do + expect(report.keys).to include( + :name, + :arch, + :version, + :available_processors + ) + end + end + + describe "#jvm" do + let(:report_method) { :jvm } + it "check_keys" do + expect(report.keys).to include( + :pid, + :version, + :vm_version, + :vm_vendor, + :vm_name, + :start_time_in_millis, + :mem, + :gc_collectors + ) + expect(report[:mem].keys).to include( + :heap_init_in_bytes, + :heap_max_in_bytes, + :non_heap_init_in_bytes, + :non_heap_max_in_bytes + ) + end + end +end diff --git a/logstash-core/spec/logstash/api/commands/stats_spec.rb b/logstash-core/spec/logstash/api/commands/stats_spec.rb index c52b844ba..792a1d6df 100644 --- a/logstash-core/spec/logstash/api/commands/stats_spec.rb +++ b/logstash-core/spec/logstash/api/commands/stats_spec.rb @@ -5,25 +5,63 @@ describe LogStash::Api::Commands::Stats do include_context "api setup" let(:report_method) { :run } + let(:extended_pipeline) { nil } + let(:opts) { {} } subject(:report) do factory = ::LogStash::Api::CommandFactory.new(LogStash::Api::Service.new(@agent)) - - factory.build(:stats).send(report_method) + if extended_pipeline + factory.build(:stats).send(report_method, "main", extended_pipeline, opts) + else + factory.build(:stats).send(report_method) + end end let(:report_class) { described_class } + describe "#plugins_stats_report" do + let(:report_method) { :plugins_stats_report } + # Enforce just the structure + let(:extended_pipeline) { + { + :queue => "fake_queue", + :hash => "fake_hash", + :ephemeral_id => "fake_epehemeral_id", + :vertices => "fake_vertices" + } + } + # TODO pass in a real sample vertex +# let(:opts) { +# { +# :vertices => "fake vertices" +# } +# } + it "check keys" do + expect(report.keys).to include( + :queue, + :hash, + :ephemeral_id, + # TODO re-add vertices -- see above +# :vertices + ) + end + end + describe "#events" do let(:report_method) { :events } it "return events information" do - expect(report.keys).to include(:in, :filtered, :out) + expect(report.keys).to include( + :in, + :filtered, + :out, + :duration_in_millis, + :queue_push_duration_in_millis) end end - + describe "#hot_threads" do let(:report_method) { :hot_threads } - + it "should return hot threads information as a string" do expect(report.to_s).to be_a(String) end @@ -35,19 +73,50 @@ describe LogStash::Api::Commands::Stats do describe "memory stats" do let(:report_method) { :memory } - + it "return hot threads information" do expect(report).not_to be_empty end - it "return heap information" do - expect(report.keys).to include(:heap_used_in_bytes) + it "return memory information" do + expect(report.keys).to include( + :heap_used_percent, + :heap_committed_in_bytes, + :heap_max_in_bytes, + :heap_used_in_bytes, + :non_heap_used_in_bytes, + :non_heap_committed_in_bytes, + :pools + ) end + end - it "return non heap information" do - expect(report.keys).to include(:non_heap_used_in_bytes) + describe "jvm stats" do + let(:report_method) { :jvm } + + it "return jvm information" do + expect(report.keys).to include( + :threads, + :mem, + :gc, + :uptime_in_millis + ) + expect(report[:threads].keys).to include( + :count, + :peak_count + ) end + end + describe "reloads stats" do + let(:report_method) { :reloads } + + it "return reloads information" do + expect(report.keys).to include( + :successes, + :failures, + ) + end end describe "pipeline stats" do @@ -74,6 +143,7 @@ describe LogStash::Api::Commands::Stats do ) end end + context "when using multiple pipelines" do before(:each) do expect(LogStash::Config::PipelinesInfo).to receive(:format_pipelines_info).and_return([ diff --git a/logstash-core/spec/logstash/api/modules/node_spec.rb b/logstash-core/spec/logstash/api/modules/node_spec.rb index 7fc7f1271..0f6a71113 100644 --- a/logstash-core/spec/logstash/api/modules/node_spec.rb +++ b/logstash-core/spec/logstash/api/modules/node_spec.rb @@ -123,6 +123,7 @@ describe LogStash::Api::Modules::Node do root_structure = { "pipelines" => { "main" => { + "ephemeral_id" => String, "workers" => Numeric, "batch_size" => Numeric, "batch_delay" => Numeric, diff --git a/logstash-core/spec/logstash/api/modules/node_stats_spec.rb b/logstash-core/spec/logstash/api/modules/node_stats_spec.rb index 729f9aee9..825604a4e 100644 --- a/logstash-core/spec/logstash/api/modules/node_stats_spec.rb +++ b/logstash-core/spec/logstash/api/modules/node_stats_spec.rb @@ -80,12 +80,22 @@ describe LogStash::Api::Modules::NodeStats do "filtered" => Numeric, "out" => Numeric, "queue_push_duration_in_millis" => Numeric - } + }, + "plugins" => { + "inputs" => Array, + "codecs" => Array, + "filters" => Array, + "outputs" => Array, + }, } }, "reloads" => { "successes" => Numeric, "failures" => Numeric + }, + "os" => Hash, + "queue" => { + "events_count" => Numeric } } From 056c3e3bb812f75e84ebec5bb99a4c074b8108d6 Mon Sep 17 00:00:00 2001 From: andsel Date: Fri, 23 Aug 2019 16:33:48 +0200 Subject: [PATCH 0215/1126] Add pipeline.id to log lines fixes #8290, #10521 Fixes #11075 --- config/jvm.options | 3 ++ config/log4j2.properties | 4 +- logstash-core/lib/logstash/agent.rb | 3 +- logstash-core/lib/logstash/java_pipeline.rb | 5 ++ logstash-core/lib/logstash/pipeline.rb | 11 ++++- .../ir/compiler/JavaInputDelegatorExt.java | 5 +- .../fixtures/pipeline_id_log_spec.yml | 12 +++++ qa/integration/specs/pipeline_id_log_spec.rb | 47 +++++++++++++++++++ 8 files changed, 84 insertions(+), 6 deletions(-) create mode 100644 qa/integration/fixtures/pipeline_id_log_spec.yml create mode 100644 qa/integration/specs/pipeline_id_log_spec.rb diff --git a/config/jvm.options b/config/jvm.options index ac27467d0..2d743c8b3 100644 --- a/config/jvm.options +++ b/config/jvm.options @@ -76,3 +76,6 @@ # Entropy source for randomness -Djava.security.egd=file:/dev/urandom + +# Copy the logging context from parent threads to children +-Dlog4j2.isThreadContextMapInheritable=true diff --git a/config/log4j2.properties b/config/log4j2.properties index a9eed0a3e..9a6af06e0 100644 --- a/config/log4j2.properties +++ b/config/log4j2.properties @@ -4,7 +4,7 @@ name = LogstashPropertiesConfig appender.console.type = Console appender.console.name = plain_console appender.console.layout.type = PatternLayout -appender.console.layout.pattern = [%d{ISO8601}][%-5p][%-25c] %m%n +appender.console.layout.pattern = [%d{ISO8601}][%-5p][%-25c]%notEmpty{[%X{pipeline.id}]} %m%n appender.json_console.type = Console appender.json_console.name = json_console @@ -21,7 +21,7 @@ appender.rolling.policies.time.type = TimeBasedTriggeringPolicy appender.rolling.policies.time.interval = 1 appender.rolling.policies.time.modulate = true appender.rolling.layout.type = PatternLayout -appender.rolling.layout.pattern = [%d{ISO8601}][%-5p][%-25c] %-.10000m%n +appender.rolling.layout.pattern = [%d{ISO8601}][%-5p][%-25c]%notEmpty{[%X{pipeline.id}]} %-.10000m%n appender.rolling.policies.size.type = SizeBasedTriggeringPolicy appender.rolling.policies.size.size = 100MB appender.rolling.strategy.type = DefaultRolloverStrategy diff --git a/logstash-core/lib/logstash/agent.rb b/logstash-core/lib/logstash/agent.rb index 94f3cabfb..098fc417d 100644 --- a/logstash-core/lib/logstash/agent.rb +++ b/logstash-core/lib/logstash/agent.rb @@ -89,6 +89,7 @@ class LogStash::Agent def execute @thread = Thread.current # this var is implicitly used by Stud.stop? + LogStash::Util.set_thread_name("Agent thread") logger.debug("Starting agent") transition_to_running @@ -307,7 +308,7 @@ class LogStash::Agent pipeline_actions.map do |action| Thread.new(action, converge_result) do |action, converge_result| - java.lang.Thread.currentThread().setName("Converge #{action}"); + LogStash::Util.set_thread_name("Converge #{action}") # We execute every task we need to converge the current state of pipelines # for every task we will record the action result, that will help us # the results of all the task will determine if the converge was successful or not diff --git a/logstash-core/lib/logstash/java_pipeline.rb b/logstash-core/lib/logstash/java_pipeline.rb index 1360dd5e0..4616ee792 100644 --- a/logstash-core/lib/logstash/java_pipeline.rb +++ b/logstash-core/lib/logstash/java_pipeline.rb @@ -8,6 +8,8 @@ require "logstash/instrument/collector" require "logstash/compiler" require "logstash/config/lir_serializer" +java_import org.apache.logging.log4j.ThreadContext + module LogStash; class JavaPipeline < JavaBasePipeline include LogStash::Util::Loggable attr_reader \ @@ -102,6 +104,7 @@ module LogStash; class JavaPipeline < JavaBasePipeline @thread = Thread.new do begin LogStash::Util.set_thread_name("pipeline.#{pipeline_id}") + ThreadContext.put("pipeline.id", pipeline_id) run @finished_run.make_true rescue => e @@ -236,6 +239,7 @@ module LogStash; class JavaPipeline < JavaBasePipeline pipeline_workers.times do |t| thread = Thread.new do Util.set_thread_name("[#{pipeline_id}]>worker#{t}") + ThreadContext.put("pipeline.id", pipeline_id) org.logstash.execution.WorkerLoop.new( lir_execution, filter_queue_client, @events_filtered, @events_consumed, @flushRequested, @flushing, @shutdownRequested, @drain_queue).run @@ -305,6 +309,7 @@ module LogStash; class JavaPipeline < JavaBasePipeline def inputworker(plugin) Util::set_thread_name("[#{pipeline_id}]<#{plugin.class.config_name}") + ThreadContext.put("pipeline.id", pipeline_id) begin plugin.run(wrapped_write_client(plugin.id.to_sym)) rescue => e diff --git a/logstash-core/lib/logstash/pipeline.rb b/logstash-core/lib/logstash/pipeline.rb index 82add7120..e9eb3d889 100644 --- a/logstash-core/lib/logstash/pipeline.rb +++ b/logstash-core/lib/logstash/pipeline.rb @@ -12,6 +12,8 @@ require "logstash/instrument/collector" require "logstash/filter_delegator" require "logstash/compiler" +java_import org.apache.logging.log4j.ThreadContext + module LogStash; class BasePipeline < AbstractPipeline include LogStash::Util::Loggable @@ -172,7 +174,8 @@ module LogStash; class Pipeline < BasePipeline @thread = Thread.new do begin - LogStash::Util.set_thread_name("pipeline.#{pipeline_id}") + LogStash::Util.set_thread_name("[#{pipeline_id}]-manager") + ThreadContext.put("pipeline.id", pipeline_id) run @finished_run.make_true rescue => e @@ -300,7 +303,8 @@ module LogStash; class Pipeline < BasePipeline pipeline_workers.times do |t| thread = Thread.new(batch_size, batch_delay, self) do |_b_size, _b_delay, _pipeline| - Util.set_thread_name("[#{pipeline_id}]>worker#{t}") + LogStash::Util::set_thread_name("[#{pipeline_id}]>worker#{t}") + ThreadContext.put("pipeline.id", pipeline_id) _pipeline.worker_loop(_b_size, _b_delay) end @worker_threads << thread @@ -430,6 +434,7 @@ module LogStash; class Pipeline < BasePipeline def inputworker(plugin) Util::set_thread_name("[#{pipeline_id}]<#{plugin.class.config_name}") + ThreadContext.put("pipeline.id", pipeline_id) begin plugin.run(wrapped_write_client(plugin.id.to_sym)) rescue => e @@ -535,6 +540,8 @@ module LogStash; class Pipeline < BasePipeline raise "Attempted to start flusher on a stopped pipeline!" if stopped? @flusher_thread = Thread.new do + LogStash::Util.set_thread_name("[#{pipeline_id}]-flusher-thread") + ThreadContext.put("pipeline.id", pipeline_id) while Stud.stoppable_sleep(5, 0.1) { stopped? } flush break if stopped? diff --git a/logstash-core/src/main/java/org/logstash/config/ir/compiler/JavaInputDelegatorExt.java b/logstash-core/src/main/java/org/logstash/config/ir/compiler/JavaInputDelegatorExt.java index 4ceb3f564..e91367f8c 100644 --- a/logstash-core/src/main/java/org/logstash/config/ir/compiler/JavaInputDelegatorExt.java +++ b/logstash-core/src/main/java/org/logstash/config/ir/compiler/JavaInputDelegatorExt.java @@ -60,7 +60,10 @@ public class JavaInputDelegatorExt extends RubyObject { } else { queueWriter = qw; } - Thread t = new Thread(() -> input.start(queueWriter::push)); + Thread t = new Thread(() -> { + org.apache.logging.log4j.ThreadContext.put("pipeline.id", pipeline.pipelineId().toString()); + input.start(queueWriter::push); + }); t.setName(pipeline.pipelineId().asJavaString() + "_" + input.getName() + "_" + input.getId()); t.start(); return JavaObject.wrap(context.getRuntime(), t); diff --git a/qa/integration/fixtures/pipeline_id_log_spec.yml b/qa/integration/fixtures/pipeline_id_log_spec.yml new file mode 100644 index 000000000..661138bdf --- /dev/null +++ b/qa/integration/fixtures/pipeline_id_log_spec.yml @@ -0,0 +1,12 @@ +--- +services: + - logstash +config: |- + input { + generator { + count => 4 + } + } + output { + null {} + } diff --git a/qa/integration/specs/pipeline_id_log_spec.rb b/qa/integration/specs/pipeline_id_log_spec.rb new file mode 100644 index 000000000..b9da009e0 --- /dev/null +++ b/qa/integration/specs/pipeline_id_log_spec.rb @@ -0,0 +1,47 @@ +require_relative '../framework/fixture' +require_relative '../framework/settings' +require_relative '../services/logstash_service' +require_relative '../framework/helpers' +require "logstash/devutils/rspec/spec_helper" +require "yaml" + +describe "Test Logstash Pipeline id" do + before(:all) { + @fixture = Fixture.new(__FILE__) + # used in multiple LS tests + @ls = @fixture.get_service("logstash") + } + + after(:all) { + @fixture.teardown + } + + before(:each) { + # backup the application settings file -- logstash.yml + FileUtils.cp(@ls.application_settings_file, "#{@ls.application_settings_file}.original") + } + + after(:each) { + @ls.teardown + # restore the application settings file -- logstash.yml + FileUtils.mv("#{@ls.application_settings_file}.original", @ls.application_settings_file) + } + + let(:temp_dir) { Stud::Temporary.directory("logstash-pipelinelog-test") } + let(:config) { @fixture.config("root") } + + it "should write logs with pipeline.id" do + pipeline_name = "custom_pipeline" + settings = { + "path.logs" => temp_dir, + "pipeline.id" => pipeline_name + } + IO.write(@ls.application_settings_file, settings.to_yaml) + @ls.spawn_logstash("-w", "1" , "-e", config) + @ls.wait_for_logstash + sleep 2 until @ls.exited? + plainlog_file = "#{temp_dir}/logstash-plain.log" + expect(File.exists?(plainlog_file)).to be true + expect(IO.read(plainlog_file) =~ /\[logstash.javapipeline\s*\]\[#{pipeline_name}\]/).to be > 0 + end +end From 3093384705ef49b202e6f5d0f76c8409db7a345f Mon Sep 17 00:00:00 2001 From: Aarti Gupta <39547049+aagupta1@users.noreply.github.com> Date: Thu, 28 Feb 2019 23:15:32 +0530 Subject: [PATCH 0216/1126] Enhancements to Logstash Benchmarking Tool (#10253) * Adding support for - 1. Custom Data Sets 2. Added heap used statistics to results --- .../logstash/benchmark/cli/BenchmarkMeta.java | 12 ++++- .../benchmark/cli/LsMetricsMonitor.java | 11 ++++- .../java/org/logstash/benchmark/cli/Main.java | 28 ++++++++++- .../benchmark/cli/cases/CustomTestCase.java | 46 +++++++++++++++++++ .../benchmark/cli/ui/LsMetricStats.java | 4 +- .../logstash/benchmark/cli/ui/UserInput.java | 6 ++- .../logstash/benchmark/cli/ui/UserOutput.java | 5 ++ .../org/logstash/benchmark/cli/MainTest.java | 12 +++++ 8 files changed, 117 insertions(+), 7 deletions(-) create mode 100644 tools/benchmark-cli/src/main/java/org/logstash/benchmark/cli/cases/CustomTestCase.java diff --git a/tools/benchmark-cli/src/main/java/org/logstash/benchmark/cli/BenchmarkMeta.java b/tools/benchmark-cli/src/main/java/org/logstash/benchmark/cli/BenchmarkMeta.java index fb20c4ffe..29538855e 100644 --- a/tools/benchmark-cli/src/main/java/org/logstash/benchmark/cli/BenchmarkMeta.java +++ b/tools/benchmark-cli/src/main/java/org/logstash/benchmark/cli/BenchmarkMeta.java @@ -2,6 +2,7 @@ package org.logstash.benchmark.cli; import java.net.InetAddress; import java.net.UnknownHostException; +import java.nio.file.Path; import java.util.Collections; import java.util.HashMap; import java.util.Map; @@ -12,6 +13,8 @@ public final class BenchmarkMeta { private final String testcase; + private final Path configpath; + private final String version; private final LsVersionType vtype; @@ -20,15 +23,17 @@ public final class BenchmarkMeta { private final int batchsize; - BenchmarkMeta(final String testcase, final String version, final LsVersionType vtype, - final int workers, final int batchsize) { + BenchmarkMeta(final String testcase, final Path configpath, final String version, final LsVersionType vtype, + final int workers, final int batchsize) { this.testcase = testcase; + this.configpath = configpath; this.version = version; this.vtype = vtype; this.workers = workers; this.batchsize = batchsize; } + public String getVersion() { return version; } @@ -37,6 +42,8 @@ public final class BenchmarkMeta { return testcase; } + public Path getConfigPath() { return configpath; } + public LsVersionType getVtype() { return vtype; } @@ -52,6 +59,7 @@ public final class BenchmarkMeta { public Map asMap() { final Map result = new HashMap<>(); result.put("test_name", testcase); + result.put("test_config_path", configpath); result.put("os_name", SystemUtils.OS_NAME); result.put("os_version", SystemUtils.OS_VERSION); try { diff --git a/tools/benchmark-cli/src/main/java/org/logstash/benchmark/cli/LsMetricsMonitor.java b/tools/benchmark-cli/src/main/java/org/logstash/benchmark/cli/LsMetricsMonitor.java index 3bf842282..d482cf0bc 100644 --- a/tools/benchmark-cli/src/main/java/org/logstash/benchmark/cli/LsMetricsMonitor.java +++ b/tools/benchmark-cli/src/main/java/org/logstash/benchmark/cli/LsMetricsMonitor.java @@ -40,6 +40,7 @@ public final class LsMetricsMonitor implements Callable testcase = parser.accepts( UserInput.TEST_CASE_PARAM, UserInput.TEST_CASE_HELP ).withRequiredArg().ofType(String.class).defaultsTo(GeneratorToStdout.IDENTIFIER).forHelp(); + final OptionSpec testcaseconfig = parser.accepts( + UserInput.TEST_CASE_CONFIG_PARAM, UserInput.TEST_CASE_CONFIG_HELP + ).withRequiredArg().ofType(File.class).forHelp(); final OptionSpec pwd = parser.accepts( UserInput.WORKING_DIRECTORY_PARAM, UserInput.WORKING_DIRECTORY_HELP ).withRequiredArg().ofType(File.class).defaultsTo(UserInput.WORKING_DIRECTORY_DEFAULT) @@ -108,8 +112,19 @@ public final class Main { settings.setProperty( LsBenchSettings.INPUT_DATA_REPEAT, String.valueOf(options.valueOf(repeats)) ); + + Path testCaseConfigPath = null; + if (options.valueOf(testcase).equals("custom")) { + if (options.has(testcaseconfig)) { + testCaseConfigPath = options.valueOf(testcaseconfig).toPath(); + } + else { + throw new IllegalArgumentException("Path to Test Case Config must be provided"); + } + } + final BenchmarkMeta runConfig = new BenchmarkMeta( - options.valueOf(testcase), version, type, options.valueOf(workers), + options.valueOf(testcase), testCaseConfigPath, version, type, options.valueOf(workers), options.valueOf(batchsize) ); execute( @@ -148,6 +163,12 @@ public final class Main { Integer.parseInt(settings.getProperty(LsBenchSettings.INPUT_DATA_REPEAT)) ) ); + if (runConfig.getTestcase().equals("custom")) { + output.green( + String.format("Test Case Config: %s", runConfig.getConfigPath()) + ); + } + output.printLine(); Files.createDirectories(cwd); final LogstashInstallation logstash; @@ -185,7 +206,10 @@ public final class Main { testcase = new GeneratorToStdout(store, logstash, settings, runConfig); } else if (ApacheLogsComplex.IDENTIFIER.equalsIgnoreCase(test)) { testcase = new ApacheLogsComplex(store, logstash, cwd, settings, output, runConfig); - } else { + } else if (CustomTestCase.IDENTIFIER.equalsIgnoreCase(test)) { + testcase = new CustomTestCase(store, logstash, cwd, settings, output, runConfig); + } + else { throw new IllegalArgumentException(String.format("Unknown test case %s", test)); } return testcase; diff --git a/tools/benchmark-cli/src/main/java/org/logstash/benchmark/cli/cases/CustomTestCase.java b/tools/benchmark-cli/src/main/java/org/logstash/benchmark/cli/cases/CustomTestCase.java new file mode 100644 index 000000000..d06bfe0ee --- /dev/null +++ b/tools/benchmark-cli/src/main/java/org/logstash/benchmark/cli/cases/CustomTestCase.java @@ -0,0 +1,46 @@ +package org.logstash.benchmark.cli.cases; + +import org.apache.commons.io.IOUtils; +import org.logstash.benchmark.cli.*; +import org.logstash.benchmark.cli.ui.LsMetricStats; +import org.logstash.benchmark.cli.ui.UserOutput; +import org.openjdk.jmh.util.ListStatistics; + +import java.io.*; +import java.nio.file.Files; +import java.nio.file.Path; +import java.util.AbstractMap; +import java.util.Properties; +import java.util.concurrent.ExecutionException; +import java.util.concurrent.TimeoutException; + +public class CustomTestCase implements Case { + public static final String IDENTIFIER = "custom"; + + private final LogstashInstallation logstash; + private final DataStore store; + private final Path configpath; + + public CustomTestCase(DataStore store, LogstashInstallation logstash, Path cwd, Properties settings, UserOutput output, BenchmarkMeta runConfig) { + this.logstash = logstash; + logstash.configure(runConfig); + this.store = store; + this.configpath = runConfig.getConfigPath(); + } + + @Override + public AbstractMap run() { + try (final LsMetricsMonitor.MonitorExecution monitor = + new LsMetricsMonitor.MonitorExecution(logstash.metrics(), store)) { + final ByteArrayOutputStream baos = new ByteArrayOutputStream(); + + try (final InputStream cfg = Files.newInputStream(configpath)){ + IOUtils.copy(cfg, baos); + } + logstash.execute(baos.toString()); + return monitor.stopAndGet(); + } catch (final IOException | InterruptedException | ExecutionException | TimeoutException ex) { + throw new IllegalStateException(ex); + } + } +} diff --git a/tools/benchmark-cli/src/main/java/org/logstash/benchmark/cli/ui/LsMetricStats.java b/tools/benchmark-cli/src/main/java/org/logstash/benchmark/cli/ui/LsMetricStats.java index 90cb7d798..7a99b176a 100644 --- a/tools/benchmark-cli/src/main/java/org/logstash/benchmark/cli/ui/LsMetricStats.java +++ b/tools/benchmark-cli/src/main/java/org/logstash/benchmark/cli/ui/LsMetricStats.java @@ -15,5 +15,7 @@ public enum LsMetricStats { /** * Statistics on CPU usage. */ - CPU_USAGE + CPU_USAGE, + + HEAP_USAGE } diff --git a/tools/benchmark-cli/src/main/java/org/logstash/benchmark/cli/ui/UserInput.java b/tools/benchmark-cli/src/main/java/org/logstash/benchmark/cli/ui/UserInput.java index 7347ac462..d5c504474 100644 --- a/tools/benchmark-cli/src/main/java/org/logstash/benchmark/cli/ui/UserInput.java +++ b/tools/benchmark-cli/src/main/java/org/logstash/benchmark/cli/ui/UserInput.java @@ -32,7 +32,7 @@ public final class UserInput { public static final String TEST_CASE_PARAM = "testcase"; public static final String TEST_CASE_HELP = - "Currently available test cases are 'baseline' and 'apache'."; + "Currently available test cases are 'baseline', 'apache' and 'custom'."; public static final String LS_WORKER_THREADS = "ls-workers"; @@ -79,6 +79,10 @@ public final class UserInput { public static final String WORKING_DIRECTORY_HELP = "Working directory to store cached files in."; + public static final String TEST_CASE_CONFIG_PARAM = "config"; + public static final String TEST_CASE_CONFIG_HELP = + "Path to custom logstash config. Required if testcase is set to 'custom'"; + /** * Constructor. */ diff --git a/tools/benchmark-cli/src/main/java/org/logstash/benchmark/cli/ui/UserOutput.java b/tools/benchmark-cli/src/main/java/org/logstash/benchmark/cli/ui/UserOutput.java index a67a3ff89..3b23c73c0 100644 --- a/tools/benchmark-cli/src/main/java/org/logstash/benchmark/cli/ui/UserOutput.java +++ b/tools/benchmark-cli/src/main/java/org/logstash/benchmark/cli/ui/UserOutput.java @@ -80,6 +80,11 @@ public final class UserOutput { "Mean CPU Usage: %.2f%%", stats.get(LsMetricStats.CPU_USAGE).getMean() ) ); + green( + String.format( + "Mean Heap Usage: %.2f%%", stats.get(LsMetricStats.HEAP_USAGE).getMean() + ) + ); } private static String colorize(final String line, final String prefix) { diff --git a/tools/benchmark-cli/src/test/java/org/logstash/benchmark/cli/MainTest.java b/tools/benchmark-cli/src/test/java/org/logstash/benchmark/cli/MainTest.java index 217d9daaa..dab08126a 100644 --- a/tools/benchmark-cli/src/test/java/org/logstash/benchmark/cli/MainTest.java +++ b/tools/benchmark-cli/src/test/java/org/logstash/benchmark/cli/MainTest.java @@ -97,4 +97,16 @@ public final class MainTest { String.format("--%s=%d", UserInput.REPEAT_PARAM, 2) ); } + + /** + * @throws Exception On Failure + */ + @Test + public void runsCustomAgainstLocal() throws Exception { + Main.main( + String.format("--%s=custom", UserInput.TEST_CASE_PARAM), + String.format("--%s=%s", UserInput.TEST_CASE_CONFIG_PARAM, System.getProperty("logstash.benchmark.test.config.path") ), + String.format("--%s=%s", UserInput.LOCAL_VERSION_PARAM, System.getProperty("logstash.benchmark.test.local.path")) + ); + } } From 9bedd9e097e79bda39dac0a18702fac976e08655 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jo=C3=A3o=20Duarte?= Date: Thu, 29 Aug 2019 12:09:13 +0100 Subject: [PATCH 0217/1126] bump 7.x to 7.5.0 (#11091) --- README.md | 16 ++++++++-------- docs/index.asciidoc | 6 +++--- versions.yml | 4 ++-- 3 files changed, 13 insertions(+), 13 deletions(-) diff --git a/README.md b/README.md index a3215db75..6aea530f6 100644 --- a/README.md +++ b/README.md @@ -28,14 +28,14 @@ These builds are created nightly and have undergone no formal QA, so they should | [deb-complete][] | [deb-oss][] | | [rpm-complete][] | [rpm-oss][] | -[tar-complete]: https://snapshots.elastic.co/downloads/logstash/logstash-7.4.0-SNAPSHOT.tar.gz -[zip-complete]: https://snapshots.elastic.co/downloads/logstash/logstash-7.4.0-SNAPSHOT.zip -[deb-complete]: https://snapshots.elastic.co/downloads/logstash/logstash-7.4.0-SNAPSHOT.deb -[rpm-complete]: https://snapshots.elastic.co/downloads/logstash/logstash-7.4.0-SNAPSHOT.rpm -[tar-oss]: https://snapshots.elastic.co/downloads/logstash/logstash-oss-7.4.0-SNAPSHOT.tar.gz -[zip-oss]: https://snapshots.elastic.co/downloads/logstash/logstash-oss-7.4.0-SNAPSHOT.zip -[deb-oss]: https://snapshots.elastic.co/downloads/logstash/logstash-oss-7.4.0-SNAPSHOT.deb -[rpm-oss]: https://snapshots.elastic.co/downloads/logstash/logstash-oss-7.4.0-SNAPSHOT.rpm +[tar-complete]: https://snapshots.elastic.co/downloads/logstash/logstash-7.5.0-SNAPSHOT.tar.gz +[zip-complete]: https://snapshots.elastic.co/downloads/logstash/logstash-7.5.0-SNAPSHOT.zip +[deb-complete]: https://snapshots.elastic.co/downloads/logstash/logstash-7.5.0-SNAPSHOT.deb +[rpm-complete]: https://snapshots.elastic.co/downloads/logstash/logstash-7.5.0-SNAPSHOT.rpm +[tar-oss]: https://snapshots.elastic.co/downloads/logstash/logstash-oss-7.5.0-SNAPSHOT.tar.gz +[zip-oss]: https://snapshots.elastic.co/downloads/logstash/logstash-oss-7.5.0-SNAPSHOT.zip +[deb-oss]: https://snapshots.elastic.co/downloads/logstash/logstash-oss-7.5.0-SNAPSHOT.deb +[rpm-oss]: https://snapshots.elastic.co/downloads/logstash/logstash-oss-7.5.0-SNAPSHOT.rpm ## Need Help? diff --git a/docs/index.asciidoc b/docs/index.asciidoc index 6f54df27a..aa6c1a177 100644 --- a/docs/index.asciidoc +++ b/docs/index.asciidoc @@ -8,9 +8,9 @@ :plugins-repo-dir: {docdir}/../../logstash-docs/docs :branch: 7.x :major-version: 7.x -:logstash_version: 7.4.0 -:elasticsearch_version: 7.4.0 -:kibana_version: 7.4.0 +:logstash_version: 7.5.0 +:elasticsearch_version: 7.5.0 +:kibana_version: 7.5.0 :docker-repo: docker.elastic.co/logstash/logstash :docker-image: {docker-repo}:{logstash_version} diff --git a/versions.yml b/versions.yml index fd4f7d151..172411d47 100644 --- a/versions.yml +++ b/versions.yml @@ -1,7 +1,7 @@ --- # alpha and beta qualifiers are now added via VERSION_QUALIFIER environment var -logstash: 7.4.0 -logstash-core: 7.4.0 +logstash: 7.5.0 +logstash-core: 7.5.0 logstash-core-plugin-api: 2.1.16 # jruby must reference a *released* version of jruby which can be downloaded from the official download url From cd91f9b2b3a8a909a454366fba19eddec1fbcc28 Mon Sep 17 00:00:00 2001 From: Joao Duarte Date: Fri, 23 Aug 2019 15:50:53 +0100 Subject: [PATCH 0218/1126] give multiple pipelines all the settings Previously we'd only give a pipeline the settings related to pipelines The PipelineSettings class was used for this. However a pipeline may need other settings like the keystore location. For this we instead clone the settings object and merge all the pipeline specific settings. This is accomplished with a new method that ensures that only pipeline level settings are overwritten in the clone. Fixes #11076 --- .../lib/logstash/config/source/multi_local.rb | 5 +- .../lib/logstash/pipeline_settings.rb | 55 ------------------- logstash-core/lib/logstash/settings.rb | 42 ++++++++++++++ 3 files changed, 45 insertions(+), 57 deletions(-) delete mode 100644 logstash-core/lib/logstash/pipeline_settings.rb diff --git a/logstash-core/lib/logstash/config/source/multi_local.rb b/logstash-core/lib/logstash/config/source/multi_local.rb index 9f546ef24..c2819d8a2 100644 --- a/logstash-core/lib/logstash/config/source/multi_local.rb +++ b/logstash-core/lib/logstash/config/source/multi_local.rb @@ -1,6 +1,6 @@ # encoding: utf-8 require "logstash/config/source/local" -require "logstash/pipeline_settings" +require "logstash/settings" module LogStash module Config module Source class MultiLocal < Local @@ -15,7 +15,8 @@ module LogStash module Config module Source def pipeline_configs pipelines = retrieve_yaml_pipelines() pipelines_settings = pipelines.map do |pipeline_settings| - ::LogStash::PipelineSettings.from_settings(@original_settings.clone).merge(pipeline_settings) + clone = @original_settings.clone + clone.merge_pipeline_settings(pipeline_settings) end detect_duplicate_pipelines(pipelines_settings) pipeline_configs = pipelines_settings.map do |pipeline_settings| diff --git a/logstash-core/lib/logstash/pipeline_settings.rb b/logstash-core/lib/logstash/pipeline_settings.rb deleted file mode 100644 index 9fabab3a7..000000000 --- a/logstash-core/lib/logstash/pipeline_settings.rb +++ /dev/null @@ -1,55 +0,0 @@ -# encoding: utf-8 -require "logstash/settings" - -module LogStash - class PipelineSettings < Settings - - # there are settings that the pipeline uses and can be changed per pipeline instance - SETTINGS_WHITE_LIST = [ - "config.debug", - "config.support_escapes", - "config.reload.automatic", - "config.reload.interval", - "config.string", - "dead_letter_queue.enable", - "dead_letter_queue.max_bytes", - "metric.collect", - "pipeline.java_execution", - "pipeline.plugin_classloaders", - "path.config", - "path.dead_letter_queue", - "path.queue", - "pipeline.batch.delay", - "pipeline.batch.size", - "pipeline.id", - "pipeline.reloadable", - "pipeline.system", - "pipeline.workers", - "queue.checkpoint.acks", - "queue.checkpoint.interval", - "queue.checkpoint.writes", - "queue.checkpoint.retry", - "queue.drain", - "queue.max_bytes", - "queue.max_events", - "queue.page_capacity", - "queue.type", - ] - - # register a set of settings that is used as the default set of pipelines settings - def self.from_settings(settings) - pipeline_settings = self.new - SETTINGS_WHITE_LIST.each do |setting| - pipeline_settings.register(settings.get_setting(setting).clone) - end - pipeline_settings - end - - def register(setting) - unless SETTINGS_WHITE_LIST.include?(setting.name) - raise ArgumentError.new("Only pipeline related settings can be registered in a PipelineSettings object. Received \"#{setting.name}\". Allowed settings: #{SETTINGS_WHITE_LIST}") - end - super(setting) - end - end -end diff --git a/logstash-core/lib/logstash/settings.rb b/logstash-core/lib/logstash/settings.rb index ecdac5885..c245aa6ab 100644 --- a/logstash-core/lib/logstash/settings.rb +++ b/logstash-core/lib/logstash/settings.rb @@ -10,6 +10,39 @@ module LogStash include LogStash::Util::SubstitutionVariables include LogStash::Util::Loggable + # there are settings that the pipeline uses and can be changed per pipeline instance + PIPELINE_SETTINGS_WHITE_LIST = [ + "config.debug", + "config.support_escapes", + "config.reload.automatic", + "config.reload.interval", + "config.string", + "dead_letter_queue.enable", + "dead_letter_queue.max_bytes", + "metric.collect", + "pipeline.java_execution", + "pipeline.plugin_classloaders", + "path.config", + "path.dead_letter_queue", + "path.queue", + "pipeline.batch.delay", + "pipeline.batch.size", + "pipeline.id", + "pipeline.reloadable", + "pipeline.system", + "pipeline.workers", + "queue.checkpoint.acks", + "queue.checkpoint.interval", + "queue.checkpoint.writes", + "queue.checkpoint.retry", + "queue.drain", + "queue.max_bytes", + "queue.max_events", + "queue.page_capacity", + "queue.type", + ] + + def initialize @settings = {} # Theses settings were loaded from the yaml file @@ -89,6 +122,15 @@ module LogStash self end + def merge_pipeline_settings(hash, graceful = false) + hash.each do |key, _| + unless PIPELINE_SETTINGS_WHITE_LIST.include?(key) + raise ArgumentError.new("Only pipeline related settings are expected. Received \"#{key}\". Allowed settings: #{PIPELINE_SETTINGS_WHITE_LIST}") + end + end + merge(hash, graceful) + end + def format_settings output = [] output << "-------- Logstash Settings (* means modified) ---------" From 5f5bbeed14087c0c230965949d95830182352ade Mon Sep 17 00:00:00 2001 From: Joao Duarte Date: Mon, 26 Aug 2019 16:39:40 +0100 Subject: [PATCH 0219/1126] support substitutions in pipelines.yml file Fixes #11081 --- logstash-core/lib/logstash/config/source/multi_local.rb | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/logstash-core/lib/logstash/config/source/multi_local.rb b/logstash-core/lib/logstash/config/source/multi_local.rb index c2819d8a2..74ea8e97b 100644 --- a/logstash-core/lib/logstash/config/source/multi_local.rb +++ b/logstash-core/lib/logstash/config/source/multi_local.rb @@ -4,6 +4,7 @@ require "logstash/settings" module LogStash module Config module Source class MultiLocal < Local + include LogStash::Util::SubstitutionVariables include LogStash::Util::Loggable def initialize(settings) @@ -13,7 +14,7 @@ module LogStash module Config module Source end def pipeline_configs - pipelines = retrieve_yaml_pipelines() + pipelines = deep_replace(retrieve_yaml_pipelines()) pipelines_settings = pipelines.map do |pipeline_settings| clone = @original_settings.clone clone.merge_pipeline_settings(pipeline_settings) From c12acff1583fcf7f0d59add74e59c41be93bb146 Mon Sep 17 00:00:00 2001 From: Colin Surprenant Date: Tue, 3 Sep 2019 14:22:42 -0400 Subject: [PATCH 0220/1126] use 2048 bits key Fixes #11115 --- logstash-core/spec/logstash/patches_spec.rb | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/logstash-core/spec/logstash/patches_spec.rb b/logstash-core/spec/logstash/patches_spec.rb index f97d4ea20..e9c7739bd 100644 --- a/logstash-core/spec/logstash/patches_spec.rb +++ b/logstash-core/spec/logstash/patches_spec.rb @@ -36,9 +36,7 @@ describe "OpenSSL defaults" do # https://github.com/jordansissel/ruby-flores/blob/master/spec/flores/pki_integration_spec.rb # since these helpers were created to fix this particular issue let(:csr) { Flores::PKI::CertificateSigningRequest.new } - # Here, I use a 1024-bit key for faster tests. - # Please do not use such small keys in production. - let(:key_bits) { 1024 } + let(:key_bits) { 2048 } let(:key) { OpenSSL::PKey::RSA.generate(key_bits, 65537) } let(:certificate_duration) { Flores::Random.number(1..86400) } From 652e1b70ad59b20ea1736e1f37243d2d8f79d7ce Mon Sep 17 00:00:00 2001 From: Pavel Zubkou Date: Tue, 27 Aug 2019 18:34:58 +0300 Subject: [PATCH 0221/1126] Update link to Debugging Java Performance Fixes #11084 --- docs/static/performance-checklist.asciidoc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/static/performance-checklist.asciidoc b/docs/static/performance-checklist.asciidoc index 0a54eeae0..704c14eac 100644 --- a/docs/static/performance-checklist.asciidoc +++ b/docs/static/performance-checklist.asciidoc @@ -99,5 +99,5 @@ In the first example we see that the CPU isn’t being used very efficiently. In Examining the in-depth GC statistics with a tool similar to the excellent https://visualvm.github.io/plugins.html[VisualGC] plugin shows that the over-allocated VM spends very little time in the efficient Eden GC, compared to the time spent in the more resource-intensive Old Gen “Full” GCs. NOTE: As long as the GC pattern is acceptable, heap sizes that occasionally increase to the maximum are acceptable. Such heap size spikes happen in response to a burst of large events passing through the pipeline. In general practice, maintain a gap between the used amount of heap memory and the maximum. -This document is not a comprehensive guide to JVM GC tuning. Read the official http://www.oracle.com/webfolder/technetwork/tutorials/obe/java/gc01/index.html[Oracle guide] for more information on the topic. We also recommend reading http://www.semicomplete.com/blog/geekery/debugging-java-performance.html[Debugging Java Performance]. +This document is not a comprehensive guide to JVM GC tuning. Read the official http://www.oracle.com/webfolder/technetwork/tutorials/obe/java/gc01/index.html[Oracle guide] for more information on the topic. We also recommend reading https://www.semicomplete.com/blog/geekery/debugging-java-performance/[Debugging Java Performance]. From 1cbaeebb4d40b2fc2f7f2fc62abfa8f5b010d5f6 Mon Sep 17 00:00:00 2001 From: andsel Date: Fri, 6 Sep 2019 13:49:15 +0200 Subject: [PATCH 0222/1126] Added origins of pipeline's configuration (es config string, the paths of config files used, module). closes 9630 Fixes #11130 --- logstash-core/lib/logstash/java_pipeline.rb | 13 ++- logstash-core/lib/logstash/pipeline.rb | 16 ++-- .../execution/AbstractPipelineExt.java | 32 +++++++ ..._id_log_spec.yml => pipeline_log_spec.yml} | 0 qa/integration/specs/pipeline_id_log_spec.rb | 47 ----------- qa/integration/specs/pipeline_log_spec.rb | 84 +++++++++++++++++++ 6 files changed, 137 insertions(+), 55 deletions(-) rename qa/integration/fixtures/{pipeline_id_log_spec.yml => pipeline_log_spec.yml} (100%) delete mode 100644 qa/integration/specs/pipeline_id_log_spec.rb create mode 100644 qa/integration/specs/pipeline_log_spec.rb diff --git a/logstash-core/lib/logstash/java_pipeline.rb b/logstash-core/lib/logstash/java_pipeline.rb index 4616ee792..7ebd6b971 100644 --- a/logstash-core/lib/logstash/java_pipeline.rb +++ b/logstash-core/lib/logstash/java_pipeline.rb @@ -109,7 +109,11 @@ module LogStash; class JavaPipeline < JavaBasePipeline @finished_run.make_true rescue => e close - logger.error("Pipeline aborted due to error", default_logging_keys(:exception => e, :backtrace => e.backtrace)) + pipeline_log_params = default_logging_keys( + :exception => e, + :backtrace => e.backtrace, + "pipeline.sources" => pipeline_source_details) + logger.error("Pipeline aborted due to error", pipeline_log_params) ensure @finished_execution.make_true end @@ -225,11 +229,14 @@ module LogStash; class JavaPipeline < JavaBasePipeline config_metric.gauge(:graph, ::LogStash::Config::LIRSerializer.serialize(lir)) config_metric.gauge(:cluster_uuids, resolve_cluster_uuids) - @logger.info("Starting pipeline", default_logging_keys( + pipeline_log_params = default_logging_keys( "pipeline.workers" => pipeline_workers, "pipeline.batch.size" => batch_size, "pipeline.batch.delay" => batch_delay, - "pipeline.max_inflight" => max_inflight)) + "pipeline.max_inflight" => max_inflight, + "pipeline.sources" => pipeline_source_details) + @logger.info("Starting pipeline", pipeline_log_params) + if max_inflight > MAX_INFLIGHT_WARN_THRESHOLD @logger.warn("CAUTION: Recommended inflight events max exceeded! Logstash will run with up to #{max_inflight} events in memory in your current configuration. If your message sizes are large this may cause instability with the default heap size. Please consider setting a non-standard heap size, changing the batch size (currently #{batch_size}), or changing the number of pipeline workers (currently #{pipeline_workers})", default_logging_keys) end diff --git a/logstash-core/lib/logstash/pipeline.rb b/logstash-core/lib/logstash/pipeline.rb index e9eb3d889..b6b818ea5 100644 --- a/logstash-core/lib/logstash/pipeline.rb +++ b/logstash-core/lib/logstash/pipeline.rb @@ -164,10 +164,12 @@ module LogStash; class Pipeline < BasePipeline collect_stats collect_dlq_stats - @logger.info("Starting pipeline", default_logging_keys( - "pipeline.workers" => settings.get("pipeline.workers"), - "pipeline.batch.size" => settings.get("pipeline.batch.size"), - "pipeline.batch.delay" => settings.get("pipeline.batch.delay"))) + pipeline_log_params = default_logging_keys( + "pipeline.workers" => settings.get("pipeline.workers"), + "pipeline.batch.size" => settings.get("pipeline.batch.size"), + "pipeline.batch.delay" => settings.get("pipeline.batch.delay"), + "pipeline.sources" => pipeline_source_details) + @logger.info("Starting pipeline", pipeline_log_params) @finished_execution.make_false @finished_run.make_false @@ -180,7 +182,11 @@ module LogStash; class Pipeline < BasePipeline @finished_run.make_true rescue => e close - @logger.error("Pipeline aborted due to error", default_logging_keys(:exception => e, :backtrace => e.backtrace)) + pipeline_log_params = default_logging_keys( + :exception => e, + :backtrace => e.backtrace, + "pipeline.sources" => pipeline_source_details) + @logger.error("Pipeline aborted due to error", pipeline_log_params) ensure @finished_execution.make_true end diff --git a/logstash-core/src/main/java/org/logstash/execution/AbstractPipelineExt.java b/logstash-core/src/main/java/org/logstash/execution/AbstractPipelineExt.java index 2c6cd93f6..b726ff4a8 100644 --- a/logstash-core/src/main/java/org/logstash/execution/AbstractPipelineExt.java +++ b/logstash-core/src/main/java/org/logstash/execution/AbstractPipelineExt.java @@ -6,7 +6,9 @@ import java.nio.file.Files; import java.nio.file.Paths; import java.security.MessageDigest; import java.security.NoSuchAlgorithmException; +import java.util.ArrayList; import java.util.Arrays; +import java.util.List; import java.util.UUID; import org.apache.commons.codec.binary.Hex; import org.apache.logging.log4j.LogManager; @@ -29,6 +31,7 @@ import org.logstash.ackedqueue.ext.JRubyAckedQueueExt; import org.logstash.ackedqueue.ext.JRubyWrappedAckedQueueExt; import org.logstash.common.DeadLetterQueueFactory; import org.logstash.common.IncompleteSourceWithMetadataException; +import org.logstash.common.SourceWithMetadata; import org.logstash.config.ir.ConfigCompiler; import org.logstash.config.ir.PipelineIR; import org.logstash.ext.JRubyAbstractQueueWriteClientExt; @@ -364,6 +367,35 @@ public class AbstractPipelineExt extends RubyBasicObject { .initialize(inputQueueClient, pipelineId.asJavaString(), metric, pluginId); } + @JRubyMethod(name = "pipeline_source_details", visibility = Visibility.PROTECTED) + @SuppressWarnings("rawtypes") + public RubyArray getPipelineSourceDetails(final ThreadContext context) { + RubyArray res = (RubyArray) pipelineSettings.callMethod(context, "config_parts"); + List pipelineSources = new ArrayList<>(res.size()); + for (IRubyObject part : res.toJavaArray()) { + SourceWithMetadata sourceWithMetadata = part.toJava(SourceWithMetadata.class); + String protocol = sourceWithMetadata.getProtocol(); + switch (protocol) { + case "string": + pipelineSources.add(RubyString.newString(context.runtime, "config string")); + break; + case "file": + pipelineSources.add(RubyString.newString(context.runtime, sourceWithMetadata.getId())); + break; + case "x-pack-metrics": + pipelineSources.add(RubyString.newString(context.runtime, "monitoring pipeline")); + break; + case "x-pack-config-management": + pipelineSources.add(RubyString.newString(context.runtime, "central pipeline management")); + break; + case "module": + pipelineSources.add(RubyString.newString(context.runtime, "module")); + break; + } + } + return RubyArray.newArray(context.runtime, pipelineSources); + } + protected final IRubyObject getSetting(final ThreadContext context, final String name) { return settings.callMethod(context, "get_value", context.runtime.newString(name)); } diff --git a/qa/integration/fixtures/pipeline_id_log_spec.yml b/qa/integration/fixtures/pipeline_log_spec.yml similarity index 100% rename from qa/integration/fixtures/pipeline_id_log_spec.yml rename to qa/integration/fixtures/pipeline_log_spec.yml diff --git a/qa/integration/specs/pipeline_id_log_spec.rb b/qa/integration/specs/pipeline_id_log_spec.rb deleted file mode 100644 index b9da009e0..000000000 --- a/qa/integration/specs/pipeline_id_log_spec.rb +++ /dev/null @@ -1,47 +0,0 @@ -require_relative '../framework/fixture' -require_relative '../framework/settings' -require_relative '../services/logstash_service' -require_relative '../framework/helpers' -require "logstash/devutils/rspec/spec_helper" -require "yaml" - -describe "Test Logstash Pipeline id" do - before(:all) { - @fixture = Fixture.new(__FILE__) - # used in multiple LS tests - @ls = @fixture.get_service("logstash") - } - - after(:all) { - @fixture.teardown - } - - before(:each) { - # backup the application settings file -- logstash.yml - FileUtils.cp(@ls.application_settings_file, "#{@ls.application_settings_file}.original") - } - - after(:each) { - @ls.teardown - # restore the application settings file -- logstash.yml - FileUtils.mv("#{@ls.application_settings_file}.original", @ls.application_settings_file) - } - - let(:temp_dir) { Stud::Temporary.directory("logstash-pipelinelog-test") } - let(:config) { @fixture.config("root") } - - it "should write logs with pipeline.id" do - pipeline_name = "custom_pipeline" - settings = { - "path.logs" => temp_dir, - "pipeline.id" => pipeline_name - } - IO.write(@ls.application_settings_file, settings.to_yaml) - @ls.spawn_logstash("-w", "1" , "-e", config) - @ls.wait_for_logstash - sleep 2 until @ls.exited? - plainlog_file = "#{temp_dir}/logstash-plain.log" - expect(File.exists?(plainlog_file)).to be true - expect(IO.read(plainlog_file) =~ /\[logstash.javapipeline\s*\]\[#{pipeline_name}\]/).to be > 0 - end -end diff --git a/qa/integration/specs/pipeline_log_spec.rb b/qa/integration/specs/pipeline_log_spec.rb new file mode 100644 index 000000000..a8da84eed --- /dev/null +++ b/qa/integration/specs/pipeline_log_spec.rb @@ -0,0 +1,84 @@ +require_relative '../framework/fixture' +require_relative '../framework/settings' +require_relative '../services/logstash_service' +require_relative '../framework/helpers' +require "logstash/devutils/rspec/spec_helper" +require "yaml" + +describe "Test Logstash Pipeline id" do + before(:all) { + @fixture = Fixture.new(__FILE__) + # used in multiple LS tests + @ls = @fixture.get_service("logstash") + } + + after(:all) { + @fixture.teardown + } + + before(:each) { + # backup the application settings file -- logstash.yml + FileUtils.cp(@ls.application_settings_file, "#{@ls.application_settings_file}.original") + } + + after(:each) { + @ls.teardown + # restore the application settings file -- logstash.yml + FileUtils.mv("#{@ls.application_settings_file}.original", @ls.application_settings_file) + } + + let(:temp_dir) { Stud::Temporary.directory("logstash-pipelinelog-test") } + let(:config) { @fixture.config("root") } + let(:initial_config_file) { config_to_temp_file(@fixture.config("root")) } + + it "should write logs with pipeline.id" do + pipeline_name = "custom_pipeline" + settings = { + "path.logs" => temp_dir, + "pipeline.id" => pipeline_name + } + IO.write(@ls.application_settings_file, settings.to_yaml) + @ls.spawn_logstash("-w", "1" , "-e", config) + wait_logstash_process_terminate() + plainlog_file = "#{temp_dir}/logstash-plain.log" + expect(File.exists?(plainlog_file)).to be true + expect(IO.read(plainlog_file) =~ /\[logstash.javapipeline\s*\]\[#{pipeline_name}\]/).to be > 0 + end + + it "write pipeline config in logs - source:config string" do + pipeline_name = "custom_pipeline" + settings = { + "path.logs" => temp_dir, + "pipeline.id" => pipeline_name + } + IO.write(@ls.application_settings_file, settings.to_yaml) + @ls.spawn_logstash("-w", "1" , "-e", config) + wait_logstash_process_terminate() + plainlog_file = "#{temp_dir}/logstash-plain.log" + expect(File.exists?(plainlog_file)).to be true + expect(IO.read(plainlog_file) =~ /Starting pipeline.*"pipeline.sources"=>\["config string"\]/).to be > 0 + end + + it "write pipeline config in logs - source:config file" do + pipeline_name = "custom_pipeline" + settings = { + "path.logs" => temp_dir, + "pipeline.id" => pipeline_name + } + IO.write(@ls.application_settings_file, settings.to_yaml) + @ls.spawn_logstash("-w", "1", "-f", "#{initial_config_file}") + wait_logstash_process_terminate() + plainlog_file = "#{temp_dir}/logstash-plain.log" + expect(File.exists?(plainlog_file)).to be true + expect(IO.read(plainlog_file) =~ /Starting pipeline.*"pipeline.sources"=>\["#{initial_config_file}"\]/).to be > 0 + end + + @private + def wait_logstash_process_terminate + num_retries = 100 + try(num_retries) do + expect(@ls.exited?).to be(true) + end + expect(@ls.exit_code).to be(0) + end +end From 30d3865dccb9d572ce774b95180f9153bc494ec2 Mon Sep 17 00:00:00 2001 From: Kuba Clark Date: Tue, 10 Sep 2019 11:16:18 +0200 Subject: [PATCH 0223/1126] Fixed links in contributing-to-logstash page Fixes #11126 --- docs/static/contributing-to-logstash.asciidoc | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/docs/static/contributing-to-logstash.asciidoc b/docs/static/contributing-to-logstash.asciidoc index 96a45c601..d5102fbf5 100644 --- a/docs/static/contributing-to-logstash.asciidoc +++ b/docs/static/contributing-to-logstash.asciidoc @@ -12,9 +12,9 @@ deploying your own plugin: * <> * <> -* <> -* <> -* <> +* <> +* <> +* <> * <> * <> * <> From 20c4d8639b34c26e43d4e10cded623277a775871 Mon Sep 17 00:00:00 2001 From: Karen Metts <35154725+karenzone@users.noreply.github.com> Date: Thu, 12 Sep 2019 20:16:23 -0400 Subject: [PATCH 0224/1126] Update logstash to use shared version files (#11132) Remove release-state info --- docs/index.asciidoc | 13 +++---------- 1 file changed, 3 insertions(+), 10 deletions(-) diff --git a/docs/index.asciidoc b/docs/index.asciidoc index aa6c1a177..0fc091a98 100644 --- a/docs/index.asciidoc +++ b/docs/index.asciidoc @@ -1,30 +1,23 @@ [[logstash-reference]] = Logstash Reference +include::{asciidoc-dir}/../../shared/versions/stack/{source_branch}.asciidoc[] +include::{asciidoc-dir}/../../shared/attributes.asciidoc[] + :include-xpack: true :lang: en :xls-repo-dir: {docdir}/../x-pack/docs/{lang} :log-repo-dir: {docdir} :plugins-repo-dir: {docdir}/../../logstash-docs/docs -:branch: 7.x -:major-version: 7.x -:logstash_version: 7.5.0 -:elasticsearch_version: 7.5.0 -:kibana_version: 7.5.0 :docker-repo: docker.elastic.co/logstash/logstash :docker-image: {docker-repo}:{logstash_version} -////////// -release-state can be: released | prerelease | unreleased -////////// -:release-state: unreleased :versioned_docs: false :jdk: 1.8.0 :lsissue: https://github.com/elastic/logstash/issues :lsplugindocs: https://www.elastic.co/guide/en/logstash-versioned-plugins/current -include::{asciidoc-dir}/../../shared/attributes.asciidoc[] [[introduction]] == Logstash Introduction From 975ef25a8bf430e97646a5caf805521c7aeedca5 Mon Sep 17 00:00:00 2001 From: Karen Metts Date: Tue, 3 Sep 2019 12:09:17 -0400 Subject: [PATCH 0225/1126] Deprecate LS Netflow module and point to FB Netflow module Fixes #11113 --- docs/static/modules.asciidoc | 2 +- docs/static/netflow-module.asciidoc | 9 ++++++++- 2 files changed, 9 insertions(+), 2 deletions(-) diff --git a/docs/static/modules.asciidoc b/docs/static/modules.asciidoc index 97375825b..17ea9acf6 100644 --- a/docs/static/modules.asciidoc +++ b/docs/static/modules.asciidoc @@ -8,7 +8,7 @@ These modules are available: * <> * <> -* <> +* <> * <> Each module comes pre-packaged with Logstash configurations, Kibana dashboards, diff --git a/docs/static/netflow-module.asciidoc b/docs/static/netflow-module.asciidoc index 404df31fb..b00c4e8f6 100644 --- a/docs/static/netflow-module.asciidoc +++ b/docs/static/netflow-module.asciidoc @@ -2,9 +2,11 @@ === Logstash Netflow Module ++++ -Netflow Module +Netflow Module (deprecated) ++++ +deprecated[7.4.0, Replaced by the {filebeat-ref}/filebeat-module-netflow.html[{Filebeat} Netflow Module] which is compliant with the {ecs-ref}/index.html[Elastic Common Schema (ECS)]] + The Logstash Netflow module simplifies the collection, normalization, and visualization of network flow data. With a single command, the module parses network flow data, indexes the events into Elasticsearch, and installs a suite @@ -12,6 +14,7 @@ of Kibana dashboards to get you exploring your data immediately. Logstash modules support Netflow Version 5 and 9. + ==== What is Flow Data? Netflow is a type of data record streamed from capable network devices. It @@ -34,6 +37,10 @@ install. [[netflow-getting-started]] ==== Getting Started +NOTE: The {ls} Netflow Module has been deprecated and replaced by the +{filebeat-ref}/filebeat-module-netflow.html[{Filebeat} Netflow Module], which is +compliant with the {ecs-ref}/index.html[Elastic Common Schema (ECS)]. + . Start the Logstash Netflow module by running the following command in the Logstash installation directory: + From 0953ad9291b615b15f6fffc4849d895513c1fc2f Mon Sep 17 00:00:00 2001 From: Joao Duarte Date: Thu, 19 Sep 2019 10:31:10 +0100 Subject: [PATCH 0226/1126] remove mention of pipeline to pipeline being Beta Fixes #11150 --- docs/static/pipeline-pipeline-config.asciidoc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/static/pipeline-pipeline-config.asciidoc b/docs/static/pipeline-pipeline-config.asciidoc index b833492ed..816023bda 100644 --- a/docs/static/pipeline-pipeline-config.asciidoc +++ b/docs/static/pipeline-pipeline-config.asciidoc @@ -1,5 +1,5 @@ [[pipeline-to-pipeline]] -=== Pipeline-to-Pipeline Communication (Beta) +=== Pipeline-to-Pipeline Communication When using the multiple pipeline feature of Logstash, you may want to connect multiple pipelines within the same Logstash instance. This configuration can be useful to isolate the execution of these pipelines, as well as to help break-up the logic of complex pipelines. The `pipeline` input/output enables a number of advanced architectural patterns discussed later in this document. From 3e7ec18e31bb0f892158eda57c440aba59af9f60 Mon Sep 17 00:00:00 2001 From: Karen Metts Date: Thu, 19 Sep 2019 13:42:20 -0400 Subject: [PATCH 0227/1126] Add note about illegal reflective access Fixes #11152 --- docs/static/troubleshooting.asciidoc | 53 ++++++++++++++++++++++++++++ 1 file changed, 53 insertions(+) diff --git a/docs/static/troubleshooting.asciidoc b/docs/static/troubleshooting.asciidoc index 6e06d0065..c30f54e18 100644 --- a/docs/static/troubleshooting.asciidoc +++ b/docs/static/troubleshooting.asciidoc @@ -30,6 +30,7 @@ executable files to the temp directory. This situation causes subsequent failure *Sample error* +[source,sh] ----- [2018-03-25T12:23:01,149][ERROR][org.logstash.Logstash ] java.lang.IllegalStateException: org.jruby.exceptions.RaiseException: @@ -45,6 +46,58 @@ Operation not permitted * Specify an alternate directory using the `-Djava.io.tmpdir` setting in the `jvm.options` file. +[float] +[[ts-startup]] +== {ls} start up + +[float] +[[ts-illegal-reflective-error]] +=== 'Illegal reflective access' errors + +// https://github.com/elastic/logstash/issues/10496 and https://github.com/elastic/logstash/issues/10498 + +Running Logstash with Java 11 results in warnings similar to these: + +[source,sh] +----- +WARNING: An illegal reflective access operation has occurred +WARNING: Illegal reflective access by org.jruby.util.SecurityHelper (file:/Users/chrisuser/logstash-6.7.0/logstash-core/lib/jars/jruby-complete-9.2.6.0.jar) to field java.lang.reflect.Field.modifiers +WARNING: Please consider reporting this to the maintainers of org.jruby.util.SecurityHelper +WARNING: Use --illegal-access=warn to enable warnings of further illegal reflective access operations +WARNING: All illegal access operations will be denied in a future release +----- + +These errors appear related to https://github.com/jruby/jruby/issues/4834[a known issue with JRuby]. + +*Work around* + +Try adding these values to the `jvm.options` file. + +[source,sh] +----- +--add-opens=java.base/java.lang=ALL-UNNAMED +--add-opens=java.base/java.security=ALL-UNNAMED +--add-opens=java.base/java.util=ALL-UNNAMED +--add-opens=java.base/java.security.cert=ALL-UNNAMED +--add-opens=java.base/java.util.zip=ALL-UNNAMED +--add-opens=java.base/java.lang.reflect=ALL-UNNAMED +--add-opens=java.base/java.util.regex=ALL-UNNAMED +--add-opens=java.base/java.net=ALL-UNNAMED +--add-opens=java.base/java.io=ALL-UNNAMED +--add-opens=java.base/java.lang=ALL-UNNAMED +--add-opens=java.base/javax.crypto=ALL-UNNAMED +--add-opens=java.management/sun.management=ALL-UNNAMED +----- + +*Notes:* + +* These settings allow Logstash to start without warnings in Java 11, but they +prevent Logstash from starting on Java 8. +* This workaround has been tested with simple pipelines. If you have experiences +to share, please comment in the +https://github.com/elastic/logstash/issues/10496[issue]. + + [float] [[ts-ingest]] == Data ingestion From a91e3b6bed4a14fd65156e9886d24252f6e76694 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jo=C3=A3o=20Duarte?= Date: Tue, 24 Sep 2019 18:39:18 +0100 Subject: [PATCH 0228/1126] Backport release notes to 7.x (#11160) * Release notes for 7.2 (#10863) * 7.2.1 Release notes (#10959) * Add coming tag to 7.2.1 release notes (#10968) * Updated release notes for 7.2.1 (#10996) * Release notes 7.3.0 (#10993) * Release notes for 7.2 (#10863) * add release notes for 7.3.0 * Fix link formatting * Release notes draft for 7.3.1 (#11038) * Release notes draft for 7.3.2 (#11128) * Update release notes for 7.3.2 * Update releasenotes.asciidoc --- docs/static/releasenotes.asciidoc | 202 ++++++++++++++++++++++++++++++ 1 file changed, 202 insertions(+) diff --git a/docs/static/releasenotes.asciidoc b/docs/static/releasenotes.asciidoc index bc1fdd018..475af774b 100644 --- a/docs/static/releasenotes.asciidoc +++ b/docs/static/releasenotes.asciidoc @@ -3,6 +3,11 @@ This section summarizes the changes in the following releases: +* <> +* <> +* <> +* <> +* <> * <> * <> * <> @@ -13,6 +18,203 @@ This section summarizes the changes in the following releases: * <> * <> +[[logstash-7-3-2]] +=== Logstash 7.3.2 Release Notes + +* Bugfix: Avoid variable collision in pipeline stats api (backport of #11059 to 7.x) https://github.com/elastic/logstash/pull/11062[#11062] +* Bugfix: Give multiple pipelines all the settings https://github.com/elastic/logstash/pull/11076[#11076] +* Docs: Hint plugins need to be installed before bundle https://github.com/elastic/logstash/pull/11080[#11080] +* Docs: Fix backticks in how to docs https://github.com/elastic/logstash/pull/11018[#11018] +* Docs: Update link to Debugging Java Performance https://github.com/elastic/logstash/pull/11084[#11084] +* Docs: Add missing "create" privilege to documentation https://github.com/elastic/logstash/pull/11013[#11013] +* Tests: Use 2048 bits key in OpenSSL socket specs https://github.com/elastic/logstash/pull/11115[#11115] + +[[logstash-7-3-1]] +=== Logstash 7.3.1 Release Notes + +* Add regex support for conditionals with constants https://github.com/elastic/logstash/pull/11017[#11017] +* Fix compilation of "[field] in [field]" event conditions https://github.com/elastic/logstash/pull/11026[#11026] +* Add support for boolean evaluation of constants https://github.com/elastic/logstash/pull/11032[#11032] + +==== Plugins + +*Snmp Input* + +* Fixed GAUGE32 integer overflow https://github.com/logstash-plugins/logstash-input-snmp/pull/65[#65] + +[[logstash-7-3-0]] +=== Logstash 7.3.0 Release Notes + +* Fixes a crash that could occur when an illegal field reference was used as part of a field key https://github.com/elastic/logstash/pull/10839[#10839] +* Fixes a stall that could occur when using the Beta Pipeline-to-Pipeline feature by ensuring that a Pipeline Input will not shut down before its upstream pipeline https://github.com/elastic/logstash/pull/10872[#10872] +* Fixes an issue during shutdown where the API could shut down before the pipelines have completed shutting down https://github.com/elastic/logstash/pull/10880[#10880] +* Fixes an issue where the bundled plugins built on the Java Plugin API would fail to load on Java 11 https://github.com/elastic/logstash/pull/10951[#10951] +* Fixes an issue where runaway matchers inside KV and Grok Filter Plugins could fail to respect configured timeouts https://github.com/elastic/logstash/pull/10978[#10978] +* Enhanced `GET _node/stats/pipelines` API for Metricbeat monitoring https://github.com/elastic/logstash/pull/10576[#10576] +* Enhanced `GET /` API to include `workers` and `batch_size` metadata https://github.com/elastic/logstash/pull/10853[#10853] +* Added Plain codec for Java https://github.com/elastic/logstash/pull/10791[#10791] +* Added JMS Input Plugin to the list of default plugins https://github.com/elastic/logstash/pull/10865[#10865] + +==== Plugins + +*Grok Filter* + +* Changed timeout handling using the Timeout class, resolving an issue where Logstash would fail to enforce timeouts https://github.com/logstash-plugins/logstash-filter-grok/pull/147[#147] + +*Http Filter* + +*Jdbc_streaming Filter* + +* Fixed formatting in documentation https://github.com/logstash-plugins/logstash-filter-jdbc_streaming/pull/17[#17] and https://github.com/logstash-plugins/logstash-filter-jdbc_streaming/pull/28[#28] + +*Json Filter* + +* Added better error handling, preventing some classes of malformed inputs from crashing the pipeline. + +*Kv Filter* + +* Changed timeout handling using the Timeout class, resolving an issue where Logstash would fail to enforce timeouts https://github.com/logstash-plugins/logstash-filter-kv/pull/84[#84] + +* Fixed asciidoc formatting in docs + +* Resolved potential race condition in pipeline shutdown where the timeout enforcer could be shut down while work was still in-flight, potentially leading to stuck pipelines. +* Resolved potential race condition in pipeline shutdown where work could be submitted to the timeout enforcer after it had been shutdown, potentially leading to stuck pipelines. + +*Memcached Filter* + +* Fixed link formatting issues in doc https://github.com/logstash-plugins/logstash-filter-memcached/pull/16[#16] + +*Mutate Filter* + +*Useragent Filter* + +* Added support for OS regular expressions that use backreferences https://github.com/logstash-plugins/logstash-filter-useragent/pull/59[#59] + +*Azure_event_hubs Input* + +* Added workaround to fix errors when using this plugin with Java 11 https://github.com/logstash-plugins/logstash-input-azure_event_hubs/pull/38[#38] + +*Kafka Input* + +* Added support for `sasl_jaas_config` setting to allow JAAS config per plugin, rather than per JVM https://github.com/logstash-plugins/logstash-input-kafka/pull/313[#313] + +*Jms Input* + +* The JMS Input is now a default plugin distributed with Logstash + +*Snmp Input* + +* Adding oid_path_length config option https://github.com/logstash-plugins/logstash-input-snmp/pull/59[#59] +* Fixing bug with table support removing index value from OIDs https://github.com/logstash-plugins/logstash-input-snmp/issues/60[#60] + +* Added information and other improvements to documentation https://github.com/logstash-plugins/logstash-input-snmp/pull/57[#57] + +*Tcp Input* + +* Skip empty lines while reading certificate files https://github.com/logstash-plugins/logstash-input-tcp/issues/144[#144] + +*Twitter Input* + +* Updated Twitter gem to v6.2.0, cleaned up obsolete monkey patches, fixed integration tests https://github.com/logstash-plugins/logstash-input-twitter/pull/63[#63] + +*Elastic_app_search Output* + +*Kafka Output* + +* Added support for `sasl_jaas_config` setting to allow JAAS config per plugin, rather than per JVM https://github.com/logstash-plugins/logstash-output-kafka/pull/223[#223] + +[[logstash-7-2-1]] +=== Logstash 7.2.1 Release Notes + +* Changed: Make sure joni regexp interruptability is enabled Fixes https://github.com/elastic/logstash/pull/10978[#10978] +* Fixed: Java core plugin support for Java 11 https://github.com/elastic/logstash/pull/10951[#10951] +* Updated: Jinja2 docker dependency https://github.com/elastic/logstash/pull/10986[#10986] +* Fixed: pipeline to pipeline shutdown ordering https://github.com/elastic/logstash/pull/10872[#10872] +* Changed: Do not shut down API webserver until after pipelines have been shut down https://github.com/elastic/logstash/pull/10880[#10880] +* Documentation: documentation for java plugins: + ** Add java example plugins to skiplist https://github.com/elastic/logstash/pull/10921[#10921] + ** docs for Java plain codec https://github.com/elastic/logstash/pull/10870[#10870] + ** docs for Java line codec https://github.com/elastic/logstash/pull/10869[#10869] + ** docs for java dots codec https://github.com/elastic/logstash/pull/10868[#10868] + ** docs for Java sink output https://github.com/elastic/logstash/pull/10867[#10867] + ** docs for java stdout output https://github.com/elastic/logstash/pull/10866[#10866] + ** docs for the Java UUID filter https://github.com/elastic/logstash/pull/10859[#10859] + ** docs for java stdin input https://github.com/elastic/logstash/pull/10858[#10858] + ** docs for java_generator input https://github.com/elastic/logstash/pull/10857[#10857] +* Documentation: Remove gcs output from skip list https://github.com/elastic/logstash/pull/10919[#10919] +* Documentation: Remove the beta designation from the docs for Java plugins https://github.com/elastic/logstash/pull/10891[#10891] +* Documentation: Add homebrew as installation option https://github.com/elastic/logstash/pull/10874[#10874] +* Documentation: Running Logstash on Windows https://github.com/elastic/logstash/pull/10805[#10805] + +[[logstash-7-2-0]] +=== Logstash 7.2.0 Release Notes + +* Native support for Java Plugins (GA) https://github.com/elastic/logstash/pull/10620[#10620]. Changes to Java plugins for GA include: + + ** BREAKING: The signature for the codec.encode() method was changed to make the codec API easier to use correctly in pipelines with multiple concurrent workers. + ** BREAKING: The return type on the Context::getDlqWriter method was changed to an interface to decouple it from any specific DLQ implementation. + ** BETA: Isolated classloader for Java plugins. When enabled with the pipeline.plugin_classloaders flag, each Java plugin will be loaded with its own parent-last classloader. All dependencies for the Java plugin, with the exception of any classes in org.logstash.* or co.elastic.logstash.* packages, will be loaded first from the plugin's jar file delegating to the main Logstash classloader only if the dependency is not found within the plugin's jar. This allows Java plugins to use dependencies that might clash with the dependencies for other Java plugins or Logstash core itself. + ** Gradle tasks to automate the packaging of Java plugins as Ruby gems. The gem task will bootstrap all JRuby dependencies, automatically generate Gemfile and the gemspec file for the plugin as well as the two "glue" Ruby source files for triggering the loading of the Java class files during Logstash startup, and then invoke the necessary commands to create the gem file itself. The gem task also performs a number of validation checks to proactively identify common problems with the packaging of Java plugins. The clean task will remove all of those generated artifacts. + ** Java plugin validation. At pipeline startup, all Java plugins will be checked to ensure that they implement the same version of the Java plugin API present in the current Logstash version. + ** DLQ writer interface provided to Java plugins. + ** Float, URI, and password config types, each of which provide validation for the supplied config value. + ** New built-in Java plugins: + *** A Java-based generator input for testing with the same capabilities as the Ruby generator input as well as an optional eps option to generate events at a given event-per-second rate for situations where as-fast-as-possible event generation is too much. + *** Also includes a jdots codec that mirrors the Ruby dots codec. + *** Java-based sink output that discards any events received. Analogous to the Ruby null plugin though much faster. + +* Documentation: Add details about Elastic Search dependency https://github.com/elastic/logstash/pull/10852[#10852] +* Fixed parsing of boolean options provided to Java plugins https://github.com/elastic/logstash/pull/10848[#10848] +* Field reference: handle illegal field references in converted maps https://github.com/elastic/logstash/pull/10839[#10839] +* Fixes unit test failures on some runs of ConfigCompilerTest::testComplexConfigToPipelineIR https://github.com/elastic/logstash/pull/10837[#10837] +* Documentation: Value of start_timestamp must to be quoted https://github.com/elastic/logstash/pull/10836[#10836] +* Build: name rpm/deb oss packages as logstash-oss https://github.com/elastic/logstash/pull/10833[#10833] +* LIR support for octal literals in pipeline definitions https://github.com/elastic/logstash/pull/10828[#10828] +* Merge config values in LIR https://github.com/elastic/logstash/pull/10832[#10832] +* Build: generate tarballs for docker images https://github.com/elastic/logstash/pull/10819[#10819] +* Documentation: Document copy semantics of QueueWriter::push method https://github.com/elastic/logstash/pull/10808[#10808] +* Default stack trace size for hot threads to 50 and make it configurable https://github.com/elastic/logstash/pull/10793[#10793] +* Include G1 in JVM heap metrics https://github.com/elastic/logstash/pull/10784[#10784] +* Expose Metrics API to Java plugins https://github.com/elastic/logstash/pull/10761[#10761] +* Documentation: Clarify behavior of ensure_delivery flag https://github.com/elastic/logstash/pull/10754[#10754] +* Fix JRuby resolv.rb leak https://github.com/elastic/logstash/pull/10741[#10741] +* Add LogStash::PluginMetadata for simple key/value plugin metadata https://github.com/elastic/logstash/pull/10691[#10691] +* Fix default codec and buffer handling in Java stdout output https://github.com/elastic/logstash/pull/10673[#10673] +* Collect and expose codec metrics https://github.com/elastic/logstash/pull/10614[#10614] +* Enhance `GET /` API for Metricbeat Merge config values in LIR https://github.com/elastic/logstash/pull/10589[#10589] + + +==== Plugins + +*Es bulk Codec* + +* Fixed deeplink to Elasticsearch Reference https://github.com/logstash-plugins/logstash-codec-es_bulk/pull/18[#18] + +*Dns Filter* + +* Fixed JRuby resolver bug for versions after to 9.2.0.0 https://github.com/logstash-plugins/logstash-filter-dns/pull/51[#51] + +*Geoip Filter* + +* Fixed deeplink to Elasticsearch Reference https://github.com/logstash-plugins/logstash-filter-geoip/pull/151[#151] + +*Jdbc streaming Filter* + +* Fixes connection leak in pipeline reloads by properly disconnecting on plugin close https://github.com/logstash-plugins/logstash-filter-jdbc_streaming/pull/26[#26] + +*Azure event hubs Input* + +* Updated Azure event hub library dependencies https://github.com/logstash-plugins/logstash-input-azure_event_hubs/pull/36[#36] + +*Elasticsearch Input* + +* Fixed deeplink to Elasticsearch Reference https://github.com/logstash-plugins/logstash-input-elasticsearch/pull/103[#103] + +*Elasticsearch Output* + +* Added cluster id tracking through the plugin metadata registry https://github.com/logstash-plugins/logstash-output-elasticsearch/pull/857[#857] + + [[logstash-7-1-1]] === Logstash 7.1.1 Release Notes From dfb3cb5a340fbf444e6b28ce4f259039ffe36b07 Mon Sep 17 00:00:00 2001 From: Rob Bavey Date: Wed, 25 Sep 2019 14:07:12 -0400 Subject: [PATCH 0229/1126] Update version of jrjackson 0.4.10 includes multi-threading improvements Fixes #11164 --- versions.yml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/versions.yml b/versions.yml index 172411d47..88250ee09 100644 --- a/versions.yml +++ b/versions.yml @@ -21,6 +21,6 @@ jruby: # Note: this file is copied to the root of logstash-core because its gemspec needs it when # bundler evaluates the gemspec via bin/logstash # Ensure Jackson version here is kept in sync with version used by jrjackson gem -jrjackson: 0.4.9 +jrjackson: 0.4.10 jackson: 2.9.9 -jackson-databind: 2.9.9.3 \ No newline at end of file +jackson-databind: 2.9.9.3 From fc0db0d95560011b778c496dc6933d6c31df63f2 Mon Sep 17 00:00:00 2001 From: Lisa Cawley Date: Mon, 30 Sep 2019 10:19:35 -0700 Subject: [PATCH 0230/1126] [DOCS] Fixes links to monitoring content (#11166) (#11172) --- docs/static/monitoring/configuring-logstash.asciidoc | 4 ++-- docs/static/monitoring/monitoring-overview.asciidoc | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/docs/static/monitoring/configuring-logstash.asciidoc b/docs/static/monitoring/configuring-logstash.asciidoc index 62fe025e5..30c54d277 100644 --- a/docs/static/monitoring/configuring-logstash.asciidoc +++ b/docs/static/monitoring/configuring-logstash.asciidoc @@ -10,7 +10,7 @@ To monitor Logstash nodes: . Identify where to send monitoring data. This cluster is often referred to as the _production cluster_. For examples of typical monitoring architectures, see -{xpack-ref}/how-monitoring-works.html[How Monitoring Works]. +{ref}/how-monitoring-works.html[How monitoring works]. + -- IMPORTANT: To visualize Logstash as part of the Elastic Stack (as shown in Step @@ -102,6 +102,6 @@ image:static/monitoring/images/monitoring-ui.png["Monitoring",link="monitoring/i When upgrading from older versions of {xpack}, the built-in `logstash_system` user is disabled for security reasons. To resume monitoring, -{xpack-ref}/monitoring-troubleshooting.html[change the password and re-enable the logstash_system user]. +change the password and re-enable the `logstash_system` user. include::{log-repo-dir}/static/settings/monitoring-settings.asciidoc[] diff --git a/docs/static/monitoring/monitoring-overview.asciidoc b/docs/static/monitoring/monitoring-overview.asciidoc index e5a18f3c8..e3e2d86ae 100644 --- a/docs/static/monitoring/monitoring-overview.asciidoc +++ b/docs/static/monitoring/monitoring-overview.asciidoc @@ -29,7 +29,7 @@ expected to be the production cluster. This configuration enables the production {es} cluster to add metadata (for example, its cluster UUID) to the Logstash monitoring data then route it to the monitoring clusters. For more information about typical monitoring architectures, see -{xpack-ref}/how-monitoring-works.html[How Monitoring Works]. +{ref}/how-monitoring-works.html[How monitoring works]. include::collectors.asciidoc[] include::monitoring-output.asciidoc[] From 70c38b596580097ce0a4b25cf6db37a9c37a1a56 Mon Sep 17 00:00:00 2001 From: Andrew Siegman Date: Tue, 1 Oct 2019 11:22:19 -0500 Subject: [PATCH 0231/1126] clarify: config.reload.interval is seconds Fixes #11180 --- docs/static/reloading-config.asciidoc | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/docs/static/reloading-config.asciidoc b/docs/static/reloading-config.asciidoc index db225a102..516fc18f5 100644 --- a/docs/static/reloading-config.asciidoc +++ b/docs/static/reloading-config.asciidoc @@ -13,11 +13,11 @@ bin/logstash –f apache.config --config.reload.automatic ---------------------------------- NOTE: The `--config.reload.automatic` option is not available when you specify the `-e` flag to pass -in configuration settings from the command-line. +in configuration settings from the command-line. By default, Logstash checks for configuration changes every 3 seconds. To change this interval, use the `--config.reload.interval ` option, where `interval` specifies how often Logstash -checks the config files for changes. +checks the config files for changes (in seconds). If Logstash is already running without auto-reload enabled, you can force Logstash to reload the config file and restart the pipeline by sending a SIGHUP (signal hangup) to the From 9c9266fe3a603b2ecd6aaa8dbf38394f0c61b2c5 Mon Sep 17 00:00:00 2001 From: Karen Metts <35154725+karenzone@users.noreply.github.com> Date: Thu, 3 Oct 2019 20:06:28 -0400 Subject: [PATCH 0232/1126] Add metricbeat as monitoring option (#11190) Restructure content Restructure source files Incorporate review comments Incorporate more review comments and fix links --- docs/index.asciidoc | 16 +- docs/static/config-management.asciidoc | 2 - docs/static/monitoring/collectors.asciidoc | 3 +- docs/static/monitoring/index.asciidoc | 5 - docs/static/monitoring/intro.asciidoc | 19 -- .../{ => monitoring}/monitoring-apis.asciidoc | 29 ++- ....asciidoc => monitoring-internal.asciidoc} | 59 +++-- docs/static/monitoring/monitoring-mb.asciidoc | 203 ++++++++++++++++++ .../monitoring/monitoring-output.asciidoc | 2 + .../monitoring/monitoring-overview.asciidoc | 48 ++--- docs/static/monitoring/monitoring-ui.asciidoc | 9 +- .../{ => monitoring}/monitoring.asciidoc | 16 +- .../monitoring/pipeline-viewer.asciidoc | 3 + .../settings/monitoring-settings.asciidoc | 13 +- 14 files changed, 324 insertions(+), 103 deletions(-) delete mode 100644 docs/static/monitoring/index.asciidoc delete mode 100644 docs/static/monitoring/intro.asciidoc rename docs/static/{ => monitoring}/monitoring-apis.asciidoc (98%) rename docs/static/monitoring/{configuring-logstash.asciidoc => monitoring-internal.asciidoc} (64%) create mode 100644 docs/static/monitoring/monitoring-mb.asciidoc rename docs/static/{ => monitoring}/monitoring.asciidoc (62%) diff --git a/docs/index.asciidoc b/docs/index.asciidoc index 0fc091a98..1be85a495 100644 --- a/docs/index.asciidoc +++ b/docs/index.asciidoc @@ -118,19 +118,14 @@ include::static/ingest-convert.asciidoc[] :edit_url: https://github.com/elastic/logstash/edit/{branch}/docs/static/ls-ls-config.asciidoc include::static/ls-ls-config.asciidoc[] -ifdef::include-xpack[] :edit_url: https://github.com/elastic/logstash/edit/{branch}/docs/static/management/configuring-centralized-pipelines.asciidoc include::static/management/configuring-centralized-pipelines.asciidoc[] -:edit_url: https://github.com/elastic/logstash/edit/{branch}/docs/static/monitoring/configuring-logstash.asciidoc -include::static/monitoring/configuring-logstash.asciidoc[] - :edit_url: https://github.com/elastic/logstash/edit/{branch}/docs/static/security/logstash.asciidoc include::static/security/logstash.asciidoc[] :edit_url: https://github.com/elastic/logstash/edit/{branch}/docs/static/setup/configuring-xls.asciidoc include::static/setup/configuring-xls.asciidoc[] -endif::include-xpack[] :edit_url: https://github.com/elastic/logstash/edit/{branch}/docs/static/field-reference.asciidoc include::static/field-reference.asciidoc[] @@ -190,15 +185,16 @@ include::static/deploying.asciidoc[] :edit_url: https://github.com/elastic/logstash/edit/{branch}/docs/static/performance-checklist.asciidoc include::static/performance-checklist.asciidoc[] -// Monitoring overview +// Monitoring :edit_url: https://github.com/elastic/logstash/edit/{branch}/docs/static/monitoring.asciidoc -include::static/monitoring.asciidoc[] +include::static/monitoring/monitoring.asciidoc[] -// Monitoring APIs +// X-Pack Monitoring + +//:edit_url: https://github.com/elastic/logstash/edit/{branch}/docs/static/monitoring/configuring-logstash.asciidoc +include::static/monitoring/monitoring-overview.asciidoc[] -:edit_url: https://github.com/elastic/logstash/edit/{branch}/docs/static/monitoring-apis.asciidoc -include::static/monitoring-apis.asciidoc[] // Working with Plugins diff --git a/docs/static/config-management.asciidoc b/docs/static/config-management.asciidoc index a5d3dd071..2960f651c 100644 --- a/docs/static/config-management.asciidoc +++ b/docs/static/config-management.asciidoc @@ -9,7 +9,5 @@ only. For information about other config management tools, such as Puppet and Chef, see the documentation for those projects. Also take a look at the https://forge.puppet.com/elastic/logstash[Logstash Puppet module documentation]. -ifdef::include-xpack[] :edit_url!: include::management/centralized-pipelines.asciidoc[] -endif::include-xpack[] diff --git a/docs/static/monitoring/collectors.asciidoc b/docs/static/monitoring/collectors.asciidoc index dbe94defd..30a373f24 100644 --- a/docs/static/monitoring/collectors.asciidoc +++ b/docs/static/monitoring/collectors.asciidoc @@ -1,6 +1,7 @@ +[float] [role="xpack"] [[logstash-monitoring-collectors]] -==== Collectors +===== Collectors Collectors, as their name implies, collect things. In {monitoring} for Logstash, collectors are just <> in the same way that ordinary Logstash diff --git a/docs/static/monitoring/index.asciidoc b/docs/static/monitoring/index.asciidoc deleted file mode 100644 index c0041415d..000000000 --- a/docs/static/monitoring/index.asciidoc +++ /dev/null @@ -1,5 +0,0 @@ -include::intro.asciidoc[] -include::monitoring-overview.asciidoc[] -include::monitoring-ui.asciidoc[] -include::pipeline-viewer.asciidoc[] -include::troubleshooting.asciidoc[] diff --git a/docs/static/monitoring/intro.asciidoc b/docs/static/monitoring/intro.asciidoc deleted file mode 100644 index f267c137e..000000000 --- a/docs/static/monitoring/intro.asciidoc +++ /dev/null @@ -1,19 +0,0 @@ - -Alternatively, you can <> to send -data to a monitoring cluster. - -NOTE: Monitoring is an {xpack} feature under the Basic License and is therefore -*free to use*. - -You can use the <> in {xpack} to view the -metrics and gain insight into how your Logstash deployment is running. - -The <> in {xpack} offers additional -visibility into the behavior and performance of complex pipeline configurations. -It shows a graph representation of the overall pipeline topology, data flow, and -branching logic, overlaid with important metrics, like events per second, for -each plugin in the view. - -This documentation focuses on the {monitoring} infrastructure and setup in -Logstash. For an introduction to monitoring your Elastic stack, including {es} -and {kib}, see {xpack-ref}/xpack-monitoring.html[Monitoring the Elastic Stack]. diff --git a/docs/static/monitoring-apis.asciidoc b/docs/static/monitoring/monitoring-apis.asciidoc similarity index 98% rename from docs/static/monitoring-apis.asciidoc rename to docs/static/monitoring/monitoring-apis.asciidoc index a8e7ad1ef..5b26b5519 100644 --- a/docs/static/monitoring-apis.asciidoc +++ b/docs/static/monitoring/monitoring-apis.asciidoc @@ -1,8 +1,9 @@ +[float] [[monitoring]] -== Monitoring APIs +== APIs for monitoring {ls} -Logstash provides the following monitoring APIs to retrieve runtime metrics -about Logstash: +{ls} provides monitoring APIs for retrieving runtime metrics +about {ls}: * <> * <> @@ -35,18 +36,18 @@ instance, you need to launch Logstash with the `--http.port` flag specified to b [float] [[monitoring-common-options]] -=== Common Options +==== Common Options The following options can be applied to all of the Logstash monitoring APIs. [float] -==== Pretty Results +===== Pretty Results When appending `?pretty=true` to any request made, the JSON returned will be pretty formatted (use it for debugging only!). [float] -==== Human-Readable Output +===== Human-Readable Output NOTE: For Logstash {logstash_version}, the `human` option is supported for the <> only. When you specify `human=true`, the results are returned in plain text instead of @@ -61,6 +62,7 @@ being consumed by a monitoring tool, rather than intended for human consumption. The default for the `human` flag is `false`. + [[node-info-api]] === Node Info API @@ -86,8 +88,9 @@ Gets node-level JVM info, including info about threads. See <> for a list of options that can be applied to all Logstash monitoring APIs. +[float] [[node-pipeline-info]] -==== Pipeline Info +===== Pipeline Info The following request returns a JSON document that shows pipeline info, such as the number of workers, batch size, and batch delay: @@ -133,7 +136,7 @@ curl -XGET 'localhost:9600/_node/pipelines/test?pretty' Example response: -[source,json] +[source,js] ---------- { "pipelines" : { @@ -149,6 +152,7 @@ Example response: If you specify an invalid pipeline ID, the request returns a 404 Not Found error. +[float] [[node-os-info]] ==== OS Info @@ -173,6 +177,7 @@ Example response: } -------------------------------------------------- +[float] [[node-jvm-info]] ==== JVM Info @@ -210,6 +215,7 @@ Example response: } -------------------------------------------------- + [[plugins-api]] === Plugins Info API @@ -255,6 +261,7 @@ Example response: ] -------------------------------------------------- + [[node-stats-api]] === Node Stats API @@ -288,6 +295,7 @@ Gets runtime stats about cgroups when Logstash is running in a container. See <> for a list of options that can be applied to all Logstash monitoring APIs. +[float] [[jvm-stats]] ==== JVM Stats @@ -355,6 +363,7 @@ Example response: } -------------------------------------------------- +[float] [[process-stats]] ==== Process Stats @@ -387,6 +396,7 @@ Example response: } -------------------------------------------------- +[float] [[event-stats]] ==== Event Stats @@ -412,6 +422,7 @@ Example response: } -------------------------------------------------- +[float] [[pipeline-stats]] ==== Pipeline Stats @@ -613,6 +624,7 @@ Example response: } -------------------------------------------------- +[float] [[reload-stats]] ==== Reload Stats @@ -635,6 +647,7 @@ Example response: } -------------------------------------------------- +[float] [[os-stats]] ==== OS Stats diff --git a/docs/static/monitoring/configuring-logstash.asciidoc b/docs/static/monitoring/monitoring-internal.asciidoc similarity index 64% rename from docs/static/monitoring/configuring-logstash.asciidoc rename to docs/static/monitoring/monitoring-internal.asciidoc index 30c54d277..05773f1f7 100644 --- a/docs/static/monitoring/configuring-logstash.asciidoc +++ b/docs/static/monitoring/monitoring-internal.asciidoc @@ -1,14 +1,46 @@ [role="xpack"] -[[configuring-logstash]] -=== Configuring Monitoring for Logstash Nodes -[subs="attributes"] +[[monitoring-internal-collection]] +=== Collect {ls} monitoring data using internal collectors ++++ -{monitoring} +Internal collection +++++ + +Using internal collectors for {ls} {monitoring} these components: + +* <> +* <> + +These pieces live outside of the default Logstash pipeline in a dedicated monitoring +pipeline. This configuration ensures that all data and processing has a minimal +impact on ordinary Logstash processing. Existing Logstash features, such as the +<>, can be reused to +benefit from its retry policies. + +NOTE: The `elasticsearch` output that is used by {monitoring} for Logstash is +configured exclusively via settings found in `logstash.yml`. It is not +configured by using anything from the Logstash configurations that might also be +using their own separate `elasticsearch` outputs. + +The {es} cluster that is configured for use with {monitoring} for Logstash is +expected to be the production cluster. This configuration enables the production +{es} cluster to add metadata (for example, its cluster UUID) to the Logstash +monitoring data then route it to the monitoring clusters. For more information +about typical monitoring architectures, see +{ref}/how-monitoring-works.html[How monitoring works] in the {ref}[Elasticsearch Reference]. + +include::collectors.asciidoc[] +include::monitoring-output.asciidoc[] + + +[[configure-internal-collectors]] +==== Configure {ls} monitoring with internal collectors +++++ +Configure internal collection ++++ To monitor Logstash nodes: -. Identify where to send monitoring data. This cluster is often referred to as +. Specify where to send monitoring data. This cluster is often referred to as the _production cluster_. For examples of typical monitoring architectures, see {ref}/how-monitoring-works.html[How monitoring works]. + @@ -24,9 +56,10 @@ production cluster. If that setting is `false`, the collection of monitoring dat is disabled in {es} and data is ignored from all other sources. . Configure your Logstash nodes to send metrics by setting the -`xpack.monitoring.elasticsearch.hosts` in `logstash.yml`. If {security} is enabled, -you also need to specify the credentials for the -{stack-ov}/built-in-users.html[built-in `logstash_system` user]. For more information about these settings, see <>. +`xpack.monitoring.elasticsearch.hosts` in `logstash.yml`. If {security} is +enabled, you also need to specify the credentials for the +{stack-ov}/built-in-users.html[built-in `logstash_system` user]. For more +information about these settings, see <>. + -- [source,yaml] @@ -35,6 +68,7 @@ xpack.monitoring.elasticsearch.hosts: ["http://es-prod-node-1:9200", "http://es- xpack.monitoring.elasticsearch.username: "logstash_system" <2> xpack.monitoring.elasticsearch.password: "changeme" -------------------------------------------------- + <1> If SSL/TLS is enabled on the production cluster, you must connect through HTTPS. As of v5.2.1, you can specify multiple Elasticsearch hosts as an array as well as specifying a single @@ -94,14 +128,15 @@ your Logstash nodes should be visible in the Logstash section. When security is enabled, to view the monitoring dashboards you must log in to {kib} as a user who has the `kibana_user` and `monitoring_user` roles. + -image:static/monitoring/images/monitoring-ui.png["Monitoring",link="monitoring/images/monitoring-ui.png"] +image::images/monitoring-ui.png["Monitoring",link="monitoring/images/monitoring-ui.png"] [float] [[monitoring-upgraded-logstash]] -==== Re-enabling Logstash Monitoring After Upgrading +===== Re-enabling Logstash Monitoring After Upgrading When upgrading from older versions of {xpack}, the built-in `logstash_system` user is disabled for security reasons. To resume monitoring, -change the password and re-enable the `logstash_system` user. +change the password and re-enable the logstash_system user. + +include::../settings/monitoring-settings.asciidoc[] -include::{log-repo-dir}/static/settings/monitoring-settings.asciidoc[] diff --git a/docs/static/monitoring/monitoring-mb.asciidoc b/docs/static/monitoring/monitoring-mb.asciidoc new file mode 100644 index 000000000..f549937c2 --- /dev/null +++ b/docs/static/monitoring/monitoring-mb.asciidoc @@ -0,0 +1,203 @@ +[role="xpack"] +[[monitoring-with-metricbeat]] +=== Collect {ls} monitoring data with {metricbeat} +[subs="attributes"] +++++ +{metricbeat} collection +++++ + +In 7.3 and later, you can use {metricbeat} to collect data about {ls} +and ship it to the monitoring cluster, rather than routing it through the +production cluster as described in <>. + +//NOTE: The tagged regions are re-used in the Stack Overview. + +To collect and ship monitoring data: + +. <> +. <> + +[float] +[[disable-default]] +==== Disable default collection of {ls} monitoring metrics + +-- +// tag::disable-ls-collection[] +The `monitoring` setting is in the {ls} configuration file (logstash.yml), but is +commented out: + +[source,yaml] +---------------------------------- +monitoring.enabled: false +---------------------------------- + +Remove the `#` at the beginning of the line to enable the setting. +// end::disable-ls-collection[] + +-- + + +[float] +[[configure-metricbeat]] +==== Install and configure {metricbeat} + +. {metricbeat-ref}/metricbeat-installation.html[Install {metricbeat}] on the +same server as {ls}. + +. Enable the `logstash-xpack` module in {metricbeat}. + ++ +-- +// tag::enable-ls-module[] +To enable the default configuration in the {metricbeat} `modules.d` directory, +run: + +*deb, rpm, or brew:* + + +["source","sh",subs="attributes"] +---- +metricbeat modules enable logstash-xpack +---- + +*linux or mac:* + +["source","sh",subs="attributes"] +---- +./metricbeat modules enable logstash-xpack +---- + +*win:* + +["source","sh",subs="attributes"] +---- +PS > .{backslash}metricbeat.exe modules enable logstash-xpack +---- + +For more information, see +{metricbeat-ref}/configuration-metricbeat.html[Specify which modules to run] and +{metricbeat-ref}/metricbeat-module-beat.html[beat module]. +// end::enable-beat-module[] +-- + +. Configure the `logstash-xpack` module in {metricbeat}. + ++ +-- +// tag::configure-beat-module[] +The `modules.d/logstash-xpack.yml` file contains these settings: + +[source,yaml] +---------------------------------- + - module: logstash + metricsets: + - node + - node_stats + period: 10s + hosts: ["localhost:9600"] + #username: "user" + #password: "secret" + xpack.enabled: true +---------------------------------- + +Set the `hosts`, `username`, and `password` to authenticate with {ls}. +For other module settings, it's recommended that you accept the +defaults. + +By default, the module collects {ls} monitoring data from +`localhost:9600`. + +To monitor multiple {ls} instances, specify a list of hosts, for example: +[source,yaml] +---------------------------------- +hosts: ["http://localhost:9601","http://localhost:9602","http://localhost:9603"] +---------------------------------- + +*Encrypted communications.* If you configured {ls} to use encrypted communications, you must access +it using HTTPS. For example, use a `hosts` setting like `https://localhost:9600`. +// end::configure-ls-module[] + +// tag::remote-monitoring-user[] +*Elastic security.* If the Elastic {security-features} are enabled, provide a user +ID and password so that {metricbeat} can collect metrics successfully: + +.. Create a user on the production cluster that has the +`remote_monitoring_collector` {stack-ov}/built-in-roles.html[built-in role]. +Alternatively, use the `remote_monitoring_user` +{stack-ov}/built-in-users.html[built-in user]. + +.. Add the `username` and `password` settings to the module configuration +file (`logstash-xpack.yml`). +// end::remote-monitoring-user[] +-- + +. Optional: Disable the system module in the {metricbeat}. ++ +-- +// tag::disable-system-module[] +By default, the {metricbeat-ref}/metricbeat-module-system.html[system module] is +enabled. The information it collects, however, is not shown on the +*Stack Monitoring* page in {kib}. Unless you want to use that information for +other purposes, run the following command: + +["source","sh",subs="attributes,callouts"] +---------------------------------------------------------------------- +metricbeat modules disable system +---------------------------------------------------------------------- +// end::disable-system-module[] +-- + +. Identify where to send the monitoring data. + ++ +-- +TIP: In production environments, we strongly recommend using a separate cluster +(referred to as the _monitoring cluster_) to store the data. Using a separate +monitoring cluster prevents production cluster outages from impacting your +ability to access your monitoring data. It also prevents monitoring activities +from impacting the performance of your production cluster. + +For example, specify the {es} output information in the {metricbeat} +configuration file (`metricbeat.yml`): + +[source,yaml] +---------------------------------- +output.elasticsearch: + # Array of hosts to connect to. + hosts: ["http://es-mon-1:9200", "http://es-mon2:9200"] <1> + + # Optional protocol and basic auth credentials. + #protocol: "https" + #username: "elastic" + #password: "changeme" +---------------------------------- +<1> In this example, the data is stored on a monitoring cluster with nodes +`es-mon-1` and `es-mon-2`. + +If you configured the monitoring cluster to use encrypted communications, you +must access it via HTTPS. For example, use a `hosts` setting like +`https://es-mon-1:9200`. + +IMPORTANT: The {es} {monitor-features} use ingest pipelines, therefore the +cluster that stores the monitoring data must have at least one ingest node. + +If the {es} {security-features} are enabled on the monitoring cluster, you +must provide a valid user ID and password so that {metricbeat} can send metrics +successfully: + +.. Create a user on the monitoring cluster that has the +`remote_monitoring_agent` {stack-ov}/built-in-roles.html[built-in role]. +Alternatively, use the `remote_monitoring_user` +{stack-ov}/built-in-users.html[built-in user]. ++ +TIP: If you're using index lifecycle management, the remote monitoring user +requires additional privileges to create and read indices. For more +information, see `<>`. + +.. Add the `username` and `password` settings to the {es} output information in +the {metricbeat} configuration file. + +For more information about these configuration options, see +{metricbeat-ref}/elasticsearch-output.html[Configure the {es} output]. +-- + +. {metricbeat-ref}/metricbeat-starting.html[Start {metricbeat}] to begin +collecting monitoring data. + +. {kibana-ref}/monitoring-data.html[View the monitoring data in {kib}]. diff --git a/docs/static/monitoring/monitoring-output.asciidoc b/docs/static/monitoring/monitoring-output.asciidoc index 45b3008f3..08ce60ecf 100644 --- a/docs/static/monitoring/monitoring-output.asciidoc +++ b/docs/static/monitoring/monitoring-output.asciidoc @@ -1,3 +1,4 @@ +[float] [role="xpack"] [[logstash-monitoring-output]] ==== Output @@ -15,6 +16,7 @@ collection when issues exist with the output. IMPORTANT: It is critical that all Logstash nodes share the same setup. Otherwise, monitoring data might be routed in different ways or to different places. +[float] [[logstash-monitoring-default]] ===== Default Configuration diff --git a/docs/static/monitoring/monitoring-overview.asciidoc b/docs/static/monitoring/monitoring-overview.asciidoc index e3e2d86ae..ba8ee1643 100644 --- a/docs/static/monitoring/monitoring-overview.asciidoc +++ b/docs/static/monitoring/monitoring-overview.asciidoc @@ -1,35 +1,27 @@ [role="xpack"] -[[logstash-monitoring-overview]] -=== {monitoring} Overview -++++ -Overview -++++ +[[configuring-logstash]] +== Monitoring {ls} with {xpack} -This section deals with Logstash, including an explanation of its internal parts -at a high level. {monitoring} for Logstash represents a total of two pieces: +Use the {stack} {monitor-features} to gain insight into the health of +{ls} instances running in your environment. -* <> -* <> +For an introduction to monitoring your Elastic stack, including {es} +and {kib}, see {xpack-ref}/xpack-monitoring.html[Monitoring the Elastic Stack]. -These pieces are created when {monitoring} for Logstash is enabled, and they -live outside of the default Logstash pipeline in a dedicated monitoring -pipeline. This configuration means that all data and processing has a minimal -impact on ordinary Logstash processing. As a secondary benefit of existing in a -separate pipeline, existing Logstash features, such as the -<>, can be reused to -benefit from its retry policies. -NOTE: The `elasticsearch` output that is used by {monitoring} for Logstash is -configured exclusively via settings found in `logstash.yml`. It is not -configured by using anything from the Logstash configurations that might also be -using their own separate `elasticsearch` outputs. +[float] +[[configuring-logstash-xpack]] +=== Configuring {xpack} monitoring for {ls} -The {es} cluster that is configured for use with {monitoring} for Logstash is -expected to be the production cluster. This configuration enables the production -{es} cluster to add metadata (for example, its cluster UUID) to the Logstash -monitoring data then route it to the monitoring clusters. For more information -about typical monitoring architectures, see -{ref}/how-monitoring-works.html[How monitoring works]. +Make sure monitoring is enabled on your {es} cluster. Then configure one of +these methods to collect {ls} metrics: -include::collectors.asciidoc[] -include::monitoring-output.asciidoc[] +* <> +* <> + + +include::monitoring-mb.asciidoc[] +include::monitoring-internal.asciidoc[] +include::monitoring-ui.asciidoc[] +include::pipeline-viewer.asciidoc[] +include::troubleshooting.asciidoc[] diff --git a/docs/static/monitoring/monitoring-ui.asciidoc b/docs/static/monitoring/monitoring-ui.asciidoc index 73062b904..7ca430d11 100644 --- a/docs/static/monitoring/monitoring-ui.asciidoc +++ b/docs/static/monitoring/monitoring-ui.asciidoc @@ -2,11 +2,10 @@ [[logstash-monitoring-ui]] === Monitoring UI -When running Logstash 5.2 or greater, you can use the -https://www.elastic.co/products/x-pack/monitoring[monitoring feature in X-Pack] -to gain deep visibility into metrics about your Logstash deployment. In the -overview dashboard, you can see all events received and sent by Logstash, plus -info about memory usage and uptime: +Use the https://www.elastic.co/products/x-pack/monitoring[monitoring feature in +X-Pack] to view metrics and gain insight into how your Logstash deployment is +running. In the overview dashboard, you can see all events received and sent by +Logstash, plus info about memory usage and uptime: image::static/monitoring/images/overviewstats.png[Logstash monitoring overview dashboard in Kibana] diff --git a/docs/static/monitoring.asciidoc b/docs/static/monitoring/monitoring.asciidoc similarity index 62% rename from docs/static/monitoring.asciidoc rename to docs/static/monitoring/monitoring.asciidoc index f52093f10..6b85a7830 100644 --- a/docs/static/monitoring.asciidoc +++ b/docs/static/monitoring/monitoring.asciidoc @@ -1,5 +1,5 @@ [[monitoring-logstash]] -== Monitoring Logstash +== Monitoring Logstash with APIs When you run Logstash, it automatically captures runtime metrics that you can use to monitor the health and performance of your Logstash deployment. @@ -12,11 +12,15 @@ The metrics collected by Logstash include: runtime stats. * Hot threads. -You can use the basic <> provided by Logstash +You can use <> provided by Logstash to retrieve these metrics. These APIs are available by default without requiring any extra configuration. -ifdef::include-xpack[] -:edit_url!: -include::monitoring/index.asciidoc[] -endif::include-xpack[] +Alternatively, you can <> to send +data to a monitoring cluster. + +NOTE: {monitoring} is a feature under the Basic License and is therefore +*free to use*. + + +include::monitoring-apis.asciidoc[] diff --git a/docs/static/monitoring/pipeline-viewer.asciidoc b/docs/static/monitoring/pipeline-viewer.asciidoc index f7a6d86ad..90b4978ae 100644 --- a/docs/static/monitoring/pipeline-viewer.asciidoc +++ b/docs/static/monitoring/pipeline-viewer.asciidoc @@ -2,6 +2,9 @@ [[logstash-pipeline-viewer]] === Pipeline Viewer UI + +The pipeline viewer UI offers additional visibility into the behavior and +performance of complex pipeline configurations. Use the pipeline viewer to visualize and monitor the behavior of complex Logstash pipeline configurations. You can see and interact with a tree view that illustrates the pipeline topology, data flow, and branching logic. diff --git a/docs/static/settings/monitoring-settings.asciidoc b/docs/static/settings/monitoring-settings.asciidoc index ecf579353..de1a4376f 100644 --- a/docs/static/settings/monitoring-settings.asciidoc +++ b/docs/static/settings/monitoring-settings.asciidoc @@ -1,6 +1,6 @@ [role="xpack"] [[monitoring-settings]] -==== Monitoring Settings in Logstash +==== Monitoring settings for internal collection ++++ Monitoring Settings ++++ @@ -10,9 +10,9 @@ control how monitoring data is collected from your Logstash nodes. However, the defaults work best in most circumstances. For more information about configuring Logstash, see <>. -[float] + [[monitoring-general-settings]] -===== General Monitoring Settings +===== General monitoring settings `xpack.monitoring.enabled`:: @@ -35,9 +35,8 @@ username and password that the Logstash instance uses to authenticate for shipping monitoring data. -[float] [[monitoring-collection-settings]] -==== Monitoring Collection Settings +===== Monitoring collection settings `xpack.monitoring.collection.interval`:: @@ -45,9 +44,9 @@ Controls how often data samples are collected and shipped on the Logstash side. Defaults to `10s`. If you modify the collection interval, set the `xpack.monitoring.min_interval_seconds` option in `kibana.yml` to the same value. -[float] + [[monitoring-ssl-settings]] -===== {monitoring} TLS/SSL Settings +===== {monitoring} TLS/SSL settings You can configure the following Transport Layer Security (TLS) or Secure Sockets Layer (SSL) settings. For more information, see From 0d6bb46edc4bda53d68954c773b943599cce7d52 Mon Sep 17 00:00:00 2001 From: Jason Tedor Date: Mon, 16 Sep 2019 11:53:53 -0700 Subject: [PATCH 0233/1126] Clarify monitoring hosts should not be master-only This commit clarifies that Logstash monitoring metrics should not be routed through master-only nodes, and should instead prefer coordinating nodes. Fixes #11194 --- docs/static/settings/monitoring-settings.asciidoc | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/docs/static/settings/monitoring-settings.asciidoc b/docs/static/settings/monitoring-settings.asciidoc index de1a4376f..a7c882832 100644 --- a/docs/static/settings/monitoring-settings.asciidoc +++ b/docs/static/settings/monitoring-settings.asciidoc @@ -28,6 +28,12 @@ Logstash metrics must be routed through your production cluster. You can specify a single host as a string, or specify multiple hosts as an array. Defaults to `http://localhost:9200`. +NOTE: If your Elasticsearch cluster is configured with dedicated master-eliglble +nodes, Logstash metrics should _not_ be routed to these nodes, as doing so can +create resource contention and impact the stability of the Elasticsearch +cluster. Therefore, do not include such nodes in +`xpack.monitoring.elasticsearch.hosts`. + `xpack.monitoring.elasticsearch.username` and `xpack.monitoring.elasticsearch.password`:: If your {es} is protected with basic authentication, these settings provide the From fc9c0e0ca29eee5cbe3e2c6d455bcdafbce26f38 Mon Sep 17 00:00:00 2001 From: andsel Date: Wed, 28 Aug 2019 11:23:42 +0200 Subject: [PATCH 0234/1126] Added LS configuration variable 'pipeline.separate_logs' to separate logs per pipelines - use log4j RoutingAppender - avoid output to main log files when log per pipeline is enabled - closes 10427 Fixes #11108 --- config/jvm.options | 3 + config/log4j2.properties | 34 +++++ config/logstash.yml | 4 + logstash-core/benchmarks/build.gradle | 13 +- .../benchmark/LogPerPipelineBenchmark.java | 60 ++++++++ .../resources/log4j2-with-script.properties | 49 +++++++ .../log4j2-without-script.properties | 21 +++ logstash-core/lib/logstash/environment.rb | 1 + logstash-core/lib/logstash/runner.rb | 1 + .../log/LogstashConfigurationFactory.java | 50 +++++++ .../log/LogstashConfigurationFactoryTest.java | 130 ++++++++++++++++++ .../log4j2-log-pipeline-test.properties | 31 +++++ qa/integration/specs/pipeline_log_spec.rb | 51 +++++++ 13 files changed, 443 insertions(+), 5 deletions(-) create mode 100644 logstash-core/benchmarks/src/main/java/org/logstash/benchmark/LogPerPipelineBenchmark.java create mode 100644 logstash-core/benchmarks/src/main/resources/log4j2-with-script.properties create mode 100644 logstash-core/benchmarks/src/main/resources/log4j2-without-script.properties create mode 100644 logstash-core/src/main/java/org/logstash/log/LogstashConfigurationFactory.java create mode 100644 logstash-core/src/test/java/org/logstash/log/LogstashConfigurationFactoryTest.java create mode 100644 logstash-core/src/test/resources/log4j2-log-pipeline-test.properties diff --git a/config/jvm.options b/config/jvm.options index 2d743c8b3..cebdf7984 100644 --- a/config/jvm.options +++ b/config/jvm.options @@ -79,3 +79,6 @@ # Copy the logging context from parent threads to children -Dlog4j2.isThreadContextMapInheritable=true + +# Avoid Nashorn deprecation logs in JDK > 11 +-Dnashorn.args=--no-deprecation-warning \ No newline at end of file diff --git a/config/log4j2.properties b/config/log4j2.properties index 9a6af06e0..e9cb7517e 100644 --- a/config/log4j2.properties +++ b/config/log4j2.properties @@ -26,6 +26,11 @@ appender.rolling.policies.size.type = SizeBasedTriggeringPolicy appender.rolling.policies.size.size = 100MB appender.rolling.strategy.type = DefaultRolloverStrategy appender.rolling.strategy.max = 30 +appender.rolling.avoid_pipelined_filter.type = ScriptFilter +appender.rolling.avoid_pipelined_filter.script.type = Script +appender.rolling.avoid_pipelined_filter.script.name = filter_no_pipelined +appender.rolling.avoid_pipelined_filter.script.language = JavaScript +appender.rolling.avoid_pipelined_filter.script.value = ${sys:ls.pipeline.separate_logs} == false || !(logEvent.getContextData().containsKey("pipeline.id")) appender.json_rolling.type = RollingFile appender.json_rolling.name = json_rolling @@ -42,10 +47,39 @@ appender.json_rolling.policies.size.type = SizeBasedTriggeringPolicy appender.json_rolling.policies.size.size = 100MB appender.json_rolling.strategy.type = DefaultRolloverStrategy appender.json_rolling.strategy.max = 30 +appender.json_rolling.avoid_pipelined_filter.type = ScriptFilter +appender.json_rolling.avoid_pipelined_filter.script.type = Script +appender.json_rolling.avoid_pipelined_filter.script.name = filter_no_pipelined +appender.json_rolling.avoid_pipelined_filter.script.language = JavaScript +appender.json_rolling.avoid_pipelined_filter.script.value = ${sys:ls.pipeline.separate_logs} == false || !(logEvent.getContextData().containsKey("pipeline.id")) + +appender.routing.type = Routing +appender.routing.name = pipeline_routing_appender +appender.routing.routes.type = Routes +appender.routing.routes.script.type = Script +appender.routing.routes.script.name = routing_script +appender.routing.routes.script.language = JavaScript +appender.routing.routes.script.value = logEvent.getContextData().containsKey("pipeline.id") ? logEvent.getContextData().getValue("pipeline.id") : "sink"; +appender.routing.routes.route_pipelines.type = Route +appender.routing.routes.route_pipelines.rolling.type = RollingFile +appender.routing.routes.route_pipelines.rolling.name = appender-${ctx:pipeline.id} +appender.routing.routes.route_pipelines.rolling.fileName = ${sys:ls.logs}/pipeline_${ctx:pipeline.id}.log +appender.routing.routes.route_pipelines.rolling.filePattern = ${sys:ls.logs}/pipeline_${ctx:pipeline.id}.%i.log.gz +appender.routing.routes.route_pipelines.rolling.layout.type = PatternLayout +appender.routing.routes.route_pipelines.rolling.layout.pattern = [%d{ISO8601}][%-5p][%-25c] %-.10000m%n +appender.routing.routes.route_pipelines.rolling.policy.type = SizeBasedTriggeringPolicy +appender.routing.routes.route_pipelines.rolling.policy.size = 100MB +appender.routing.routes.route_pipelines.strategy.type = DefaultRolloverStrategy +appender.routing.routes.route_pipelines.strategy.max = 30 +appender.routing.routes.route_sink.type = Route +appender.routing.routes.route_sink.key = sink +appender.routing.routes.route_sink.null.type = Null +appender.routing.routes.route_sink.null.name = drop-appender rootLogger.level = ${sys:ls.log.level} rootLogger.appenderRef.console.ref = ${sys:ls.log.format}_console rootLogger.appenderRef.rolling.ref = ${sys:ls.log.format}_rolling +rootLogger.appenderRef.routing.ref = pipeline_routing_appender # Slowlog diff --git a/config/logstash.yml b/config/logstash.yml index db8ca3cd0..8ca9602aa 100644 --- a/config/logstash.yml +++ b/config/logstash.yml @@ -212,6 +212,10 @@ # Where to find custom plugins # path.plugins: [] # +# Flag to output log lines of each pipeline in its separate log file. Each log filename contains the pipeline.name +# Default is false +# pipeline.separate_logs: false +# # ------------ X-Pack Settings (not applicable for OSS build)-------------- # # X-Pack Monitoring diff --git a/logstash-core/benchmarks/build.gradle b/logstash-core/benchmarks/build.gradle index 7261b40cb..99efbd904 100644 --- a/logstash-core/benchmarks/build.gradle +++ b/logstash-core/benchmarks/build.gradle @@ -63,13 +63,16 @@ task jmh(type: JavaExec, dependsOn: [':logstash-core-benchmarks:clean', ':logsta main = "-jar" + def include = project.properties.get('include', '') + doFirst { args = [ - "-Djava.io.tmpdir=${buildDir.absolutePath}", - "-XX:+UseParNewGC", "-XX:+UseConcMarkSweepGC", "-XX:CMSInitiatingOccupancyFraction=75", - "-XX:+UseCMSInitiatingOccupancyOnly", "-XX:+DisableExplicitGC", - "-XX:+HeapDumpOnOutOfMemoryError", "-Xms2g", "-Xmx2g", - shadowJar.archivePath, + "-Djava.io.tmpdir=${buildDir.absolutePath}", + "-XX:+UseParNewGC", "-XX:+UseConcMarkSweepGC", "-XX:CMSInitiatingOccupancyFraction=75", + "-XX:+UseCMSInitiatingOccupancyOnly", "-XX:+DisableExplicitGC", + "-XX:+HeapDumpOnOutOfMemoryError", "-Xms2g", "-Xmx2g", + shadowJar.archivePath, + include ] } } diff --git a/logstash-core/benchmarks/src/main/java/org/logstash/benchmark/LogPerPipelineBenchmark.java b/logstash-core/benchmarks/src/main/java/org/logstash/benchmark/LogPerPipelineBenchmark.java new file mode 100644 index 000000000..d86566254 --- /dev/null +++ b/logstash-core/benchmarks/src/main/java/org/logstash/benchmark/LogPerPipelineBenchmark.java @@ -0,0 +1,60 @@ +package org.logstash.benchmark; + +import org.apache.logging.log4j.LogManager; +import org.apache.logging.log4j.Logger; +import org.apache.logging.log4j.ThreadContext; +import org.apache.logging.log4j.core.LoggerContext; +import org.openjdk.jmh.annotations.*; + +import java.util.concurrent.TimeUnit; + +@Warmup(iterations = 3, time = 100, timeUnit = TimeUnit.MILLISECONDS) +@Measurement(iterations = 10, time = 100, timeUnit = TimeUnit.MILLISECONDS) +@Fork(1) +@BenchmarkMode(Mode.Throughput) +@OutputTimeUnit(TimeUnit.MILLISECONDS) +@State(Scope.Thread) +public class LogPerPipelineBenchmark { + + private static final int EVENTS_PER_INVOCATION = 10_000_000; + + @Setup + public void setUp() { + System.setProperty("ls.log.format", "plain"); + } + + @Benchmark + @OperationsPerInvocation(EVENTS_PER_INVOCATION) + public final void logWithScriptingCodeToExecuteAndOneLogPerPipelineEnabled() { + System.setProperty("log4j.configurationFile", "log4j2-with-script.properties"); + System.setProperty("ls.pipeline.separate_logs", "true"); + logManyLines(); + } + + @Benchmark + @OperationsPerInvocation(EVENTS_PER_INVOCATION) + public final void logWithScriptingCodeToExecuteAndOneLogPerPipelineDisabled() { + System.setProperty("log4j.configurationFile", "log4j2-with-script.properties"); + System.setProperty("ls.pipeline.separate_logs", "false"); + logManyLines(); + } + + @Benchmark + @OperationsPerInvocation(EVENTS_PER_INVOCATION) + public final void logWithoutScriptingCodeToExecute() { + System.setProperty("log4j.configurationFile", "log4j2-without-script.properties"); + + logManyLines(); + } + + private void logManyLines() { + LoggerContext context = LoggerContext.getContext(false); + context.reconfigure(); + ThreadContext.put("pipeline.id", "pipeline_1"); + Logger logger = LogManager.getLogger(LogPerPipelineBenchmark.class); + + for (int i = 0; i < EVENTS_PER_INVOCATION; ++i) { + logger.info("log for pipeline 1"); + } + } +} diff --git a/logstash-core/benchmarks/src/main/resources/log4j2-with-script.properties b/logstash-core/benchmarks/src/main/resources/log4j2-with-script.properties new file mode 100644 index 000000000..10f087d96 --- /dev/null +++ b/logstash-core/benchmarks/src/main/resources/log4j2-with-script.properties @@ -0,0 +1,49 @@ +status = error +name = LogstashPropertiesConfig + +appender.rolling.type = RollingFile +appender.rolling.name = plain_rolling +appender.rolling.fileName = ${sys:ls.logs}/logstash-${sys:ls.log.format}.log +appender.rolling.filePattern = ${sys:ls.logs}/logstash-${sys:ls.log.format}-%d{yyyy-MM-dd}-%i.log.gz +appender.rolling.policies.type = Policies +appender.rolling.policies.time.type = TimeBasedTriggeringPolicy +appender.rolling.policies.time.interval = 1 +appender.rolling.policies.time.modulate = true +appender.rolling.layout.type = PatternLayout +appender.rolling.layout.pattern = [%d{ISO8601}][%-5p][%-25c]%notEmpty{[%X{pipeline.id}]} %-.10000m%n +appender.rolling.policies.size.type = SizeBasedTriggeringPolicy +appender.rolling.policies.size.size = 100MB +appender.rolling.strategy.type = DefaultRolloverStrategy +appender.rolling.strategy.max = 30 +appender.rolling.avoid_pipelined_filter.type = ScriptFilter +appender.rolling.avoid_pipelined_filter.script.type = Script +appender.rolling.avoid_pipelined_filter.script.name = filter_no_pipelined +appender.rolling.avoid_pipelined_filter.script.language = JavaScript +appender.rolling.avoid_pipelined_filter.script.value = ${sys:ls.pipeline.separate_logs} == false || !(logEvent.getContextData().containsKey("pipeline.id")) + +appender.routing.type = Routing +appender.routing.name = pipeline_routing_appender +appender.routing.routes.type = Routes +appender.routing.routes.script.type = Script +appender.routing.routes.script.name = routing_script +appender.routing.routes.script.language = JavaScript +appender.routing.routes.script.value = logEvent.getContextData().containsKey("pipeline.id") ? logEvent.getContextData().getValue("pipeline.id") : "sink"; +appender.routing.routes.route_pipelines.type = Route +appender.routing.routes.route_pipelines.rolling.type = RollingFile +appender.routing.routes.route_pipelines.rolling.name = appender-${ctx:pipeline.id} +appender.routing.routes.route_pipelines.rolling.fileName = ${sys:ls.logs}/pipeline_${ctx:pipeline.id}.log +appender.routing.routes.route_pipelines.rolling.filePattern = ${sys:ls.logs}/pipeline_${ctx:pipeline.id}.%i.log.gz +appender.routing.routes.route_pipelines.rolling.layout.type = PatternLayout +appender.routing.routes.route_pipelines.rolling.layout.pattern = [%d{ISO8601}][%-5p][%-25c] %-.10000m%n +appender.routing.routes.route_pipelines.rolling.policy.type = SizeBasedTriggeringPolicy +appender.routing.routes.route_pipelines.rolling.policy.size = 100MB +appender.routing.routes.route_pipelines.strategy.type = DefaultRolloverStrategy +appender.routing.routes.route_pipelines.strategy.max = 30 +appender.routing.routes.route_sink.type = Route +appender.routing.routes.route_sink.key = sink +appender.routing.routes.route_sink.null.type = Null +appender.routing.routes.route_sink.null.name = drop-appender + +rootLogger.level = INFO +rootLogger.appenderRef.rolling.ref = ${sys:ls.log.format}_rolling +rootLogger.appenderRef.routing.ref = pipeline_routing_appender diff --git a/logstash-core/benchmarks/src/main/resources/log4j2-without-script.properties b/logstash-core/benchmarks/src/main/resources/log4j2-without-script.properties new file mode 100644 index 000000000..ea5a09542 --- /dev/null +++ b/logstash-core/benchmarks/src/main/resources/log4j2-without-script.properties @@ -0,0 +1,21 @@ +status = error +name = LogstashPropertiesConfig + +appender.rolling.type = RollingFile +appender.rolling.name = plain_rolling +appender.rolling.fileName = ${sys:ls.logs}/logstash-${sys:ls.log.format}.log +appender.rolling.filePattern = ${sys:ls.logs}/logstash-${sys:ls.log.format}-%d{yyyy-MM-dd}-%i.log.gz +appender.rolling.policies.type = Policies +appender.rolling.policies.time.type = TimeBasedTriggeringPolicy +appender.rolling.policies.time.interval = 1 +appender.rolling.policies.time.modulate = true +appender.rolling.layout.type = PatternLayout +appender.rolling.layout.pattern = [%d{ISO8601}][%-5p][%-25c]%notEmpty{[%X{pipeline.id}]} %-.10000m%n +appender.rolling.policies.size.type = SizeBasedTriggeringPolicy +appender.rolling.policies.size.size = 100MB +appender.rolling.strategy.type = DefaultRolloverStrategy +appender.rolling.strategy.max = 30 + +rootLogger.level = INFO +rootLogger.appenderRef.rolling.ref = ${sys:ls.log.format}_rolling +rootLogger.appenderRef.routing.ref = pipeline_routing_appender diff --git a/logstash-core/lib/logstash/environment.rb b/logstash-core/lib/logstash/environment.rb index 8e8dd22ec..24f00ab20 100644 --- a/logstash-core/lib/logstash/environment.rb +++ b/logstash-core/lib/logstash/environment.rb @@ -44,6 +44,7 @@ module LogStash Setting::Boolean.new("pipeline.java_execution", true), Setting::Boolean.new("pipeline.reloadable", true), Setting::Boolean.new("pipeline.plugin_classloaders", false), + Setting::Boolean.new("pipeline.separate_logs", false), Setting.new("path.plugins", Array, []), Setting::NullableString.new("interactive", nil, false), Setting::Boolean.new("config.debug", false), diff --git a/logstash-core/lib/logstash/runner.rb b/logstash-core/lib/logstash/runner.rb index e89b2a9d5..24a9a68a7 100644 --- a/logstash-core/lib/logstash/runner.rb +++ b/logstash-core/lib/logstash/runner.rb @@ -254,6 +254,7 @@ class LogStash::Runner < Clamp::StrictCommand java.lang.System.setProperty("ls.logs", setting("path.logs")) java.lang.System.setProperty("ls.log.format", setting("log.format")) java.lang.System.setProperty("ls.log.level", setting("log.level")) + java.lang.System.setProperty("ls.pipeline.separate_logs", setting("pipeline.separate_logs").to_s) unless java.lang.System.getProperty("log4j.configurationFile") log4j_config_location = ::File.join(setting("path.settings"), "log4j2.properties") diff --git a/logstash-core/src/main/java/org/logstash/log/LogstashConfigurationFactory.java b/logstash-core/src/main/java/org/logstash/log/LogstashConfigurationFactory.java new file mode 100644 index 000000000..024c64e39 --- /dev/null +++ b/logstash-core/src/main/java/org/logstash/log/LogstashConfigurationFactory.java @@ -0,0 +1,50 @@ +package org.logstash.log; + +import org.apache.logging.log4j.core.LoggerContext; +import org.apache.logging.log4j.core.config.ConfigurationException; +import org.apache.logging.log4j.core.config.ConfigurationFactory; +import org.apache.logging.log4j.core.config.ConfigurationSource; +import org.apache.logging.log4j.core.config.Order; +import org.apache.logging.log4j.core.config.plugins.Plugin; +import org.apache.logging.log4j.core.config.properties.PropertiesConfiguration; +import org.apache.logging.log4j.core.config.properties.PropertiesConfigurationBuilder; + +import java.io.IOException; +import java.io.InputStream; +import java.util.Properties; + +@Plugin(name = "LogstashConfigurationFactory", category = ConfigurationFactory.CATEGORY) +@Order(9) +public class LogstashConfigurationFactory extends ConfigurationFactory { + + static final String PIPELINE_ROUTING_APPENDER_NAME = "pipeline_routing_appender"; + public static final String PIPELINE_SEPARATE_LOGS = "ls.pipeline.separate_logs"; + + @Override + protected String[] getSupportedTypes() { + return new String[] {".properties"}; + } + + @Override + public PropertiesConfiguration getConfiguration(final LoggerContext loggerContext, final ConfigurationSource source) { + final Properties properties = new Properties(); + try (final InputStream configStream = source.getInputStream()) { + properties.load(configStream); + } catch (final IOException ioe) { + throw new ConfigurationException("Unable to load " + source.toString(), ioe); + } + PropertiesConfiguration propertiesConfiguration = new PropertiesConfigurationBuilder() + .setConfigurationSource(source) + .setRootProperties(properties) + .setLoggerContext(loggerContext) + .build(); + + if (System.getProperty(PIPELINE_SEPARATE_LOGS, "false").equals("false")) { + // force init to avoid overwrite of appenders section + propertiesConfiguration.initialize(); + propertiesConfiguration.removeAppender(PIPELINE_ROUTING_APPENDER_NAME); + } + + return propertiesConfiguration; + } +} diff --git a/logstash-core/src/test/java/org/logstash/log/LogstashConfigurationFactoryTest.java b/logstash-core/src/test/java/org/logstash/log/LogstashConfigurationFactoryTest.java new file mode 100644 index 000000000..edc3f0480 --- /dev/null +++ b/logstash-core/src/test/java/org/logstash/log/LogstashConfigurationFactoryTest.java @@ -0,0 +1,130 @@ +package org.logstash.log; + +import org.apache.logging.log4j.LogManager; +import org.apache.logging.log4j.Logger; +import org.apache.logging.log4j.ThreadContext; +import org.apache.logging.log4j.core.Appender; +import org.apache.logging.log4j.core.LogEvent; +import org.apache.logging.log4j.core.appender.routing.RoutingAppender; +import org.apache.logging.log4j.core.config.AppenderControl; +import org.apache.logging.log4j.core.config.Configuration; + +import org.apache.logging.log4j.core.LoggerContext; +import org.apache.logging.log4j.test.appender.ListAppender; +import org.junit.*; + +import java.util.HashMap; +import java.util.List; +import java.util.Map; + +import static junit.framework.TestCase.assertNotNull; +import static junit.framework.TestCase.assertNull; +import static junit.framework.TestCase.assertEquals; + +public class LogstashConfigurationFactoryTest { + + private static final String CONFIG = "log4j2-log-pipeline-test.properties"; + + private static Map systemPropertiesDump = new HashMap<>(); + private static Map dumpedLog4jThreadContext; + + @BeforeClass + public static void beforeClass() { + dumpSystemProperty("log4j.configurationFile"); + dumpSystemProperty("ls.log.format"); + dumpSystemProperty("ls.logs"); + dumpSystemProperty(LogstashConfigurationFactory.PIPELINE_SEPARATE_LOGS); + + dumpedLog4jThreadContext = ThreadContext.getImmutableContext(); + } + + private static void dumpSystemProperty(String propertyName) { + systemPropertiesDump.put(propertyName, System.getProperty(propertyName)); + } + + @AfterClass + public static void afterClass() { + ThreadContext.putAll(dumpedLog4jThreadContext); + + restoreSystemProperty("log4j.configurationFile"); + restoreSystemProperty("ls.log.format"); + restoreSystemProperty("ls.logs"); + restoreSystemProperty(LogstashConfigurationFactory.PIPELINE_SEPARATE_LOGS); + } + + private static void restoreSystemProperty(String propertyName) { + if (systemPropertiesDump.get(propertyName) == null) { + System.clearProperty(propertyName); + } else { + System.setProperty(propertyName, systemPropertiesDump.get(propertyName)); + } + } + + @Before + public void setUp() { + System.setProperty("log4j.configurationFile", CONFIG); + System.setProperty("ls.log.format", "plain"); + System.setProperty("ls.logs", "build/logs"); + System.setProperty(LogstashConfigurationFactory.PIPELINE_SEPARATE_LOGS, "true"); + + ThreadContext.clearAll(); + } + + @Test + public void testAppenderPerPipelineIsCreatedAfterLogLine() { + forceLog4JContextRefresh(); + + Logger logger = LogManager.getLogger(LogstashConfigurationFactoryTest.class); + ThreadContext.put("pipeline.id", "pipeline_1"); + logger.info("log for pipeline 1"); + + ThreadContext.remove("pipeline_1"); + ThreadContext.put("pipeline.id", "pipeline_2"); + logger.info("log for pipeline 2"); + + verifyPipelineReceived("pipeline_1", "log for pipeline 1"); + verifyPipelineReceived("pipeline_2", "log for pipeline 2"); + } + + private void verifyPipelineReceived(String pipelineSubAppenderName, String expectedMessage) { + LoggerContext context = LoggerContext.getContext(false); + final Configuration config = context.getConfiguration(); + RoutingAppender routingApp = config.getAppender(LogstashConfigurationFactory.PIPELINE_ROUTING_APPENDER_NAME); + Map appenders = routingApp.getAppenders(); + assertNotNull("Routing appenders MUST be defined", appenders); + AppenderControl appenderControl = appenders.get(pipelineSubAppenderName); + assertNotNull("sub-appender for pipeline " + pipelineSubAppenderName + " MUST be defined", appenderControl); + Appender appender = appenderControl.getAppender(); + assertNotNull("Appender for pipeline " + pipelineSubAppenderName + " can't be NULL", appender); + ListAppender pipeline1Appender = (ListAppender) appender; + List pipeline1LogEvents = pipeline1Appender.getEvents(); + assertEquals(1, pipeline1LogEvents.size()); + assertEquals(expectedMessage, pipeline1LogEvents.get(0).getMessage().getFormattedMessage()); + } + + @Test + public void testDisableAppenderPerPipelineIsCreatedAfterLogLine() { + System.setProperty(LogstashConfigurationFactory.PIPELINE_SEPARATE_LOGS, Boolean.FALSE.toString()); + forceLog4JContextRefresh(); + + Logger logger = LogManager.getLogger(LogstashConfigurationFactoryTest.class); + + ThreadContext.put("pipeline.id", "pipeline_1"); + logger.info("log for pipeline 1"); + + ThreadContext.remove("pipeline_1"); + ThreadContext.put("pipeline.id", "pipeline_2"); + logger.info("log for pipeline 2"); + + LoggerContext context = LoggerContext.getContext(false); + final Configuration config = context.getConfiguration(); + RoutingAppender routingApp = config.getAppender(LogstashConfigurationFactory.PIPELINE_ROUTING_APPENDER_NAME); + assertNull("No routing appender should be present", routingApp); + } + + private void forceLog4JContextRefresh() { + LoggerContext context = LoggerContext.getContext(false); + context.reconfigure(); + } + +} \ No newline at end of file diff --git a/logstash-core/src/test/resources/log4j2-log-pipeline-test.properties b/logstash-core/src/test/resources/log4j2-log-pipeline-test.properties new file mode 100644 index 000000000..ca06848e2 --- /dev/null +++ b/logstash-core/src/test/resources/log4j2-log-pipeline-test.properties @@ -0,0 +1,31 @@ +status = error +name = LogstashPropertiesConfig + +appender.rolling.type = RollingFile +appender.rolling.name = plain_rolling +appender.rolling.fileName = ${sys:ls.logs}/logstash-${sys:ls.log.format}.log +appender.rolling.filePattern = ${sys:ls.logs}/logstash-${sys:ls.log.format}-%d{yyyy-MM-dd}-%i.log.gz +appender.rolling.policies.type = Policies +appender.rolling.policies.time.type = TimeBasedTriggeringPolicy +appender.rolling.policies.time.interval = 1 +appender.rolling.policies.time.modulate = true +appender.rolling.layout.type = PatternLayout +appender.rolling.layout.pattern = [%d{ISO8601}][%-5p][%-25c]%notEmpty{[%X{plugin.name}]} %-.10000m%n +appender.rolling.policies.size.type = SizeBasedTriggeringPolicy +appender.rolling.policies.size.size = 100MB +appender.rolling.strategy.type = DefaultRolloverStrategy +appender.rolling.strategy.max = 30 + +appender.routing.type = Routing +appender.routing.name = pipeline_routing_appender +appender.routing.routes.type = Routes +appender.routing.routes.script.type = Script +appender.routing.routes.script.name = routing_script +appender.routing.routes.script.language = JavaScript +appender.routing.routes.script.value = logEvent.getContextMap().get("pipeline.id") +appender.routing.routes.route1.type = Route +appender.routing.routes.route1.list.type = List +appender.routing.routes.route1.list.name = appender-${mdc:pipeline.id} + +rootLogger.level = DEBUG +rootLogger.appenderRef.routing.ref = pipeline_routing_appender diff --git a/qa/integration/specs/pipeline_log_spec.rb b/qa/integration/specs/pipeline_log_spec.rb index a8da84eed..fcc18a395 100644 --- a/qa/integration/specs/pipeline_log_spec.rb +++ b/qa/integration/specs/pipeline_log_spec.rb @@ -73,6 +73,57 @@ describe "Test Logstash Pipeline id" do expect(IO.read(plainlog_file) =~ /Starting pipeline.*"pipeline.sources"=>\["#{initial_config_file}"\]/).to be > 0 end + it "should separate pipeline output in its own log file" do + pipeline_name = "custom_pipeline" + settings = { + "path.logs" => temp_dir, + "pipeline.id" => pipeline_name, + "pipeline.separate_logs" => true + } + IO.write(@ls.application_settings_file, settings.to_yaml) + @ls.spawn_logstash("-w", "1" , "-e", config) + wait_logstash_process_terminate() + + pipeline_log_file = "#{temp_dir}/pipeline_#{pipeline_name}.log" + expect(File.exists?(pipeline_log_file)).to be true + content = IO.read(pipeline_log_file) + expect(content =~ /Pipeline started {"pipeline.id"=>"#{pipeline_name}"}/).to be > 0 + + plainlog_file = "#{temp_dir}/logstash-plain.log" + expect(File.exists?(plainlog_file)).to be true + plaing_log_content = IO.read(plainlog_file) + expect(plaing_log_content =~ /Pipeline started {"pipeline.id"=>"#{pipeline_name}"}/).to be_nil + end + + it "should not create separate pipelines log files if not enabled" do + pipeline_name = "custom_pipeline" + settings = { + "path.logs" => temp_dir, + "pipeline.id" => pipeline_name, + "pipeline.separate_logs" => false + } + IO.write(@ls.application_settings_file, settings.to_yaml) + @ls.spawn_logstash("-w", "1" , "-e", config) + wait_logstash_process_terminate() + + pipeline_log_file = "#{temp_dir}/pipeline_#{pipeline_name}.log" + expect(File.exists?(pipeline_log_file)).to be false + + plainlog_file = "#{temp_dir}/logstash-plain.log" + expect(File.exists?(plainlog_file)).to be true + plaing_log_content = IO.read(plainlog_file) + expect(plaing_log_content =~ /Pipeline started {"pipeline.id"=>"#{pipeline_name}"}/).to be > 0 + end + + @private + def wait_logstash_process_terminate + num_retries = 100 + try(num_retries) do + expect(@ls.exited?).to be(true) + end + expect(@ls.exit_code).to be >= 0 + end + @private def wait_logstash_process_terminate num_retries = 100 From 3db93d5ebd37de4c147ebf4f8703ed2252b1a75f Mon Sep 17 00:00:00 2001 From: andsel Date: Tue, 1 Oct 2019 09:29:10 +0200 Subject: [PATCH 0235/1126] Added section in logstash.yml documentation to describe feature Fixes #11177 --- docs/static/settings-file.asciidoc | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/docs/static/settings-file.asciidoc b/docs/static/settings-file.asciidoc index df14f9d96..00795bbad 100644 --- a/docs/static/settings-file.asciidoc +++ b/docs/static/settings-file.asciidoc @@ -232,6 +232,12 @@ The log level. Valid options are: | The directory where Logstash will write its log to. | `LOGSTASH_HOME/logs` +| `pipeline.separate_logs` +| This a boolean setting to enable separation of logs per pipeline in different log files. If enabled Logstash will create a different log file for each pipeline, +using the pipeline.id as name of the file. The destination directory is taken from the `path.log`s setting. When there are many pipelines configured in Logstash, +separating each log lines per pipeline could be helpful in case you need to troubleshoot what’s happening in a single pipeline, without interference of the other ones. +| `false` + | `path.plugins` | Where to find custom plugins. You can specify this setting multiple times to include multiple paths. Plugins are expected to be in a specific directory hierarchy: @@ -240,4 +246,3 @@ The log level. Valid options are: | Platform-specific. See <>. |======================================================================= - From 32b831010b50b20df8a6e0dc5a5d89817321ee9e Mon Sep 17 00:00:00 2001 From: Karen Metts Date: Tue, 8 Oct 2019 12:22:59 -0400 Subject: [PATCH 0236/1126] Add remaining review comments from #11033 Fixes #11197 --- docs/static/monitoring/monitoring-mb.asciidoc | 4 ++-- docs/static/monitoring/monitoring-overview.asciidoc | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/docs/static/monitoring/monitoring-mb.asciidoc b/docs/static/monitoring/monitoring-mb.asciidoc index f549937c2..6281fbe5e 100644 --- a/docs/static/monitoring/monitoring-mb.asciidoc +++ b/docs/static/monitoring/monitoring-mb.asciidoc @@ -120,8 +120,6 @@ ID and password so that {metricbeat} can collect metrics successfully: .. Create a user on the production cluster that has the `remote_monitoring_collector` {stack-ov}/built-in-roles.html[built-in role]. -Alternatively, use the `remote_monitoring_user` -{stack-ov}/built-in-users.html[built-in user]. .. Add the `username` and `password` settings to the module configuration file (`logstash-xpack.yml`). @@ -201,3 +199,5 @@ For more information about these configuration options, see collecting monitoring data. . {kibana-ref}/monitoring-data.html[View the monitoring data in {kib}]. + +Your monitoring setup is complete. diff --git a/docs/static/monitoring/monitoring-overview.asciidoc b/docs/static/monitoring/monitoring-overview.asciidoc index ba8ee1643..0a4aba6cd 100644 --- a/docs/static/monitoring/monitoring-overview.asciidoc +++ b/docs/static/monitoring/monitoring-overview.asciidoc @@ -13,7 +13,7 @@ and {kib}, see {xpack-ref}/xpack-monitoring.html[Monitoring the Elastic Stack]. [[configuring-logstash-xpack]] === Configuring {xpack} monitoring for {ls} -Make sure monitoring is enabled on your {es} cluster. Then configure one of +Make sure monitoring is enabled on your {es} cluster. Then configure *one* of these methods to collect {ls} metrics: * <> From 15f0de34870d13b3f7ad0a8ee772976148e801a1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jo=C3=A3o=20Duarte?= Date: Thu, 10 Oct 2019 10:29:43 +0100 Subject: [PATCH 0237/1126] remove 10k character truncation from log4j2.properties Quite often we see log entries that are truncated by this limit since java stack traces can be very verbose. This prevents us from seeing the real issue and require us to ask for users to remove the limitation and trigger the issue again so we can see the full problem. This commit removes this truncation. Fixes #11206 --- config/log4j2.properties | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/config/log4j2.properties b/config/log4j2.properties index e9cb7517e..ca4342c50 100644 --- a/config/log4j2.properties +++ b/config/log4j2.properties @@ -21,7 +21,7 @@ appender.rolling.policies.time.type = TimeBasedTriggeringPolicy appender.rolling.policies.time.interval = 1 appender.rolling.policies.time.modulate = true appender.rolling.layout.type = PatternLayout -appender.rolling.layout.pattern = [%d{ISO8601}][%-5p][%-25c]%notEmpty{[%X{pipeline.id}]} %-.10000m%n +appender.rolling.layout.pattern = [%d{ISO8601}][%-5p][%-25c]%notEmpty{[%X{pipeline.id}]} %m%n appender.rolling.policies.size.type = SizeBasedTriggeringPolicy appender.rolling.policies.size.size = 100MB appender.rolling.strategy.type = DefaultRolloverStrategy @@ -66,7 +66,7 @@ appender.routing.routes.route_pipelines.rolling.name = appender-${ctx:pipeline.i appender.routing.routes.route_pipelines.rolling.fileName = ${sys:ls.logs}/pipeline_${ctx:pipeline.id}.log appender.routing.routes.route_pipelines.rolling.filePattern = ${sys:ls.logs}/pipeline_${ctx:pipeline.id}.%i.log.gz appender.routing.routes.route_pipelines.rolling.layout.type = PatternLayout -appender.routing.routes.route_pipelines.rolling.layout.pattern = [%d{ISO8601}][%-5p][%-25c] %-.10000m%n +appender.routing.routes.route_pipelines.rolling.layout.pattern = [%d{ISO8601}][%-5p][%-25c] %m%n appender.routing.routes.route_pipelines.rolling.policy.type = SizeBasedTriggeringPolicy appender.routing.routes.route_pipelines.rolling.policy.size = 100MB appender.routing.routes.route_pipelines.strategy.type = DefaultRolloverStrategy @@ -103,7 +103,7 @@ appender.rolling_slowlog.policies.time.type = TimeBasedTriggeringPolicy appender.rolling_slowlog.policies.time.interval = 1 appender.rolling_slowlog.policies.time.modulate = true appender.rolling_slowlog.layout.type = PatternLayout -appender.rolling_slowlog.layout.pattern = [%d{ISO8601}][%-5p][%-25c] %.10000m%n +appender.rolling_slowlog.layout.pattern = [%d{ISO8601}][%-5p][%-25c] %m%n appender.rolling_slowlog.policies.size.type = SizeBasedTriggeringPolicy appender.rolling_slowlog.policies.size.size = 100MB appender.rolling_slowlog.strategy.type = DefaultRolloverStrategy From 8d19b5f0789f8a04bff9c02be7a6193aa6c6d8fb Mon Sep 17 00:00:00 2001 From: Joao Duarte Date: Thu, 10 Oct 2019 11:17:14 +0100 Subject: [PATCH 0238/1126] handling missing gems during generatePluginsVersion Fixes #11207 --- rakelib/default_plugins.rb | 3 +++ 1 file changed, 3 insertions(+) diff --git a/rakelib/default_plugins.rb b/rakelib/default_plugins.rb index 2600602c1..095cbe29a 100644 --- a/rakelib/default_plugins.rb +++ b/rakelib/default_plugins.rb @@ -14,6 +14,9 @@ module LogStash def self.is_released?(plugin) require 'gems' Gems.info(plugin) != "This rubygem could not be found." + rescue Gems::NotFound => e + puts "Could not find gem #{plugin}" + false end def self.fetch_plugins_for(type) From f48b261af94518914bd580c51cf95ad4d738312e Mon Sep 17 00:00:00 2001 From: Karen Metts Date: Wed, 9 Oct 2019 14:16:44 -0400 Subject: [PATCH 0239/1126] Update reference to last 6.x version to be 6.8 Fixes #11200 --- docs/static/upgrading.asciidoc | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/docs/static/upgrading.asciidoc b/docs/static/upgrading.asciidoc index b46d7891d..c62afc4ea 100644 --- a/docs/static/upgrading.asciidoc +++ b/docs/static/upgrading.asciidoc @@ -117,21 +117,21 @@ NOTE: Upgrading between non-consecutive major versions (5.x to 7.x, for example) supported. We recommend that you upgrade to 6.x, and then upgrade to 7.x. [float] -[[upgrade-to-6.7-rec]] -==== Upgrade to {ls} 6.7 before upgrading to 7.0 +[[upgrade-to-6.8-rec]] +==== Upgrade to {ls} 6.8 before upgrading to 7.0 -If you haven't already, upgrade to version 6.7 before you upgrade to 7.0. If +If you haven't already, upgrade to version 6.8 before you upgrade to 7.0. If you're using other products in the {stack}, upgrade {ls} as part of the {stack-ref}/upgrading-elastic-stack.html[{stack} upgrade process]. -TIP: Upgrading to {ls} 6.7 will give you a head-start on new 7.0 features, including +TIP: Upgrading to {ls} 6.8 will give you a head-start on new 7.0 features, including the java execution engine and the strict field reference parser, while you're still running 6.x. This step helps reduce risk and makes roll backs easier if you hit a snag. //TO DO: Add links [[field-ref-strict]] and [[java-exec-default]] after upgrade docs are merged -Upgrading to 6.7 is required because the {es} index template was modified to +Upgrading to 6.8 is required because the {es} index template was modified to be compatible with {es} 7.0 (the `_type` setting changed from `doc` to `_doc`). From afcb045774e8bccb8ddc252aeac387cbd8e988db Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jo=C3=A3o=20Duarte?= Date: Wed, 9 Oct 2019 09:40:49 +0100 Subject: [PATCH 0240/1126] Update .ruby-version to jruby-9.2.8.0 Fixes #11198 --- .ruby-version | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.ruby-version b/.ruby-version index 87d3afa18..4a6e0a691 100644 --- a/.ruby-version +++ b/.ruby-version @@ -1 +1 @@ -jruby-9.1.12.0 +jruby-9.2.8.0 From a6f02a3826aaa1d4a62b9fe52ed29944614b41c4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jo=C3=A3o=20Duarte?= Date: Fri, 11 Oct 2019 09:31:17 +0100 Subject: [PATCH 0241/1126] replace YAML.parse with YAML.safe_load in release tool YAML.parse returns Psych nodes that then need to be converted to plain ruby objects. Calling YAML.safe_load outputs basic ruby objects already and also increases security as it greatly restricts the classes it deserializes. Fixes #11208 --- tools/release/bump_plugin_versions.rb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tools/release/bump_plugin_versions.rb b/tools/release/bump_plugin_versions.rb index 0506dcdeb..6f38a7c1f 100755 --- a/tools/release/bump_plugin_versions.rb +++ b/tools/release/bump_plugin_versions.rb @@ -96,7 +96,7 @@ puts "Pushing commit.." `git remote add upstream git@github.com:elastic/logstash.git` `git push upstream #{branch_name}` -current_release = YAML.parse(IO.read("versions.yml"))["logstash"] +current_release = YAML.safe_load(IO.read("versions.yml"))["logstash"] puts "Creating Pull Request" pr_title = "bump lock file for #{current_release}" From a9def1e108935d60ef6c0f56bdf3f7b35442e0e6 Mon Sep 17 00:00:00 2001 From: Sachin Frayne <32795683+sachinfrayne@users.noreply.github.com> Date: Tue, 15 Oct 2019 11:53:23 +0100 Subject: [PATCH 0242/1126] syntax fix Fixes #11220 --- docs/static/upgrading.asciidoc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/static/upgrading.asciidoc b/docs/static/upgrading.asciidoc index c62afc4ea..c81e4b5a9 100644 --- a/docs/static/upgrading.asciidoc +++ b/docs/static/upgrading.asciidoc @@ -165,7 +165,7 @@ the persistent queue before you upgrade from version 6.2.x and earlier. To drain the queue: -. In the logstash.yml file, set `queue.drain:true`. +. In the logstash.yml file, set `queue.drain: true`. . Restart Logstash for this setting to take effect. . Shutdown Logstash (using CTRL+C or SIGTERM), and wait for the queue to empty. From 96dfeb5016914b6d424f4c8a6eeeab0a00b4c1f4 Mon Sep 17 00:00:00 2001 From: Ry Biesemeyer Date: Mon, 7 Oct 2019 23:14:47 +0000 Subject: [PATCH 0243/1126] add tasks for generating config parsers Fixes #11195 --- build.gradle | 6 ++++++ rakelib/compile.rake | 5 ++++- 2 files changed, 10 insertions(+), 1 deletion(-) diff --git a/build.gradle b/build.gradle index 21bbd3209..d110e7d0d 100644 --- a/build.gradle +++ b/build.gradle @@ -141,6 +141,12 @@ task installTestGems(dependsOn: assemblyDeps) { } } +task compileGrammar(dependsOn: assemblyDeps) { + doLast { + rake(projectDir, buildDir, 'compile:grammar') + } +} + task assembleTarDistribution(dependsOn: assemblyDeps) { inputs.files fileTree("${projectDir}/rakelib") inputs.files fileTree("${projectDir}/bin") diff --git a/rakelib/compile.rake b/rakelib/compile.rake index 1935f2cba..53c7f8c9a 100644 --- a/rakelib/compile.rake +++ b/rakelib/compile.rake @@ -8,7 +8,10 @@ end namespace "compile" do desc "Compile the config grammar" - task "grammar" => "logstash-core/lib/logstash/config/grammar.rb" + task "grammar" => %w( + logstash-core/lib/logstash/config/grammar.rb + logstash-core/lib/logstash/compiler/lscl/lscl_grammar.rb + ) def safe_system(*args) if !system(*args) From 138e1f91e5779a2b4fd29112b53024b6dcc99834 Mon Sep 17 00:00:00 2001 From: Ry Biesemeyer Date: Mon, 7 Oct 2019 23:17:38 +0000 Subject: [PATCH 0244/1126] regenerate config parsers from unmodified grammar definitions `touch logstash-core/**/*.treetop && ./gradlew compileGrammar` Fixes #11195 --- .../logstash/compiler/lscl/lscl_grammar.rb | 723 ++++++++++-------- logstash-core/lib/logstash/config/grammar.rb | 723 ++++++++++-------- 2 files changed, 800 insertions(+), 646 deletions(-) diff --git a/logstash-core/lib/logstash/compiler/lscl/lscl_grammar.rb b/logstash-core/lib/logstash/compiler/lscl/lscl_grammar.rb index e391b93d6..e215f0bfa 100644 --- a/logstash-core/lib/logstash/compiler/lscl/lscl_grammar.rb +++ b/logstash-core/lib/logstash/compiler/lscl/lscl_grammar.rb @@ -44,7 +44,7 @@ module LogStashCompilerLSCLGrammar if node_cache[:config].has_key?(index) cached = node_cache[:config][index] if cached - cached = SyntaxNode.new(input, index...(index + 1)) if cached == true + node_cache[:config][index] = cached = SyntaxNode.new(input, index...(index + 1)) if cached == true @index = cached.interval.end end return cached @@ -112,7 +112,7 @@ module LogStashCompilerLSCLGrammar if node_cache[:comment].has_key?(index) cached = node_cache[:comment][index] if cached - cached = SyntaxNode.new(input, index...(index + 1)) if cached == true + node_cache[:comment][index] = cached = SyntaxNode.new(input, index...(index + 1)) if cached == true @index = cached.interval.end end return cached @@ -129,21 +129,22 @@ module LogStashCompilerLSCLGrammar end s1 << r2 if r2 - if has_terminal?("#", false, index) - r4 = instantiate_node(SyntaxNode,input, index...(index + 1)) - @index += 1 + if (match_len = has_terminal?("#", false, index)) + r4 = true + @index += match_len else - terminal_parse_failure("#") + terminal_parse_failure('"#"') r4 = nil end s1 << r4 if r4 s5, i5 = [], index loop do - if has_terminal?('\G[^\\r\\n]', true, index) + if has_terminal?(@regexps[gr = '\A[^\\r\\n]'] ||= Regexp.new(gr), :regexp, index) r6 = true @index += 1 else + terminal_parse_failure('[^\\r\\n]') r6 = nil end if r6 @@ -155,11 +156,11 @@ module LogStashCompilerLSCLGrammar r5 = instantiate_node(SyntaxNode,input, i5...index, s5) s1 << r5 if r5 - if has_terminal?("\r", false, index) - r8 = instantiate_node(SyntaxNode,input, index...(index + 1)) - @index += 1 + if (match_len = has_terminal?("\r", false, index)) + r8 = true + @index += match_len else - terminal_parse_failure("\r") + terminal_parse_failure('"\\r"') r8 = nil end if r8 @@ -169,11 +170,11 @@ module LogStashCompilerLSCLGrammar end s1 << r7 if r7 - if has_terminal?("\n", false, index) - r9 = instantiate_node(SyntaxNode,input, index...(index + 1)) - @index += 1 + if (match_len = has_terminal?("\n", false, index)) + r9 = true + @index += match_len else - terminal_parse_failure("\n") + terminal_parse_failure('"\\n"') r9 = nil end s1 << r9 @@ -211,7 +212,7 @@ module LogStashCompilerLSCLGrammar if node_cache[:_].has_key?(index) cached = node_cache[:_][index] if cached - cached = SyntaxNode.new(input, index...(index + 1)) if cached == true + node_cache[:_][index] = cached = SyntaxNode.new(input, index...(index + 1)) if cached == true @index = cached.interval.end end return cached @@ -222,10 +223,12 @@ module LogStashCompilerLSCLGrammar i1 = index r2 = _nt_comment if r2 + r2 = SyntaxNode.new(input, (index-1)...index) if r2 == true r1 = r2 else r3 = _nt_whitespace if r3 + r3 = SyntaxNode.new(input, (index-1)...index) if r3 == true r1 = r3 else @index = i1 @@ -250,7 +253,7 @@ module LogStashCompilerLSCLGrammar if node_cache[:whitespace].has_key?(index) cached = node_cache[:whitespace][index] if cached - cached = SyntaxNode.new(input, index...(index + 1)) if cached == true + node_cache[:whitespace][index] = cached = SyntaxNode.new(input, index...(index + 1)) if cached == true @index = cached.interval.end end return cached @@ -258,10 +261,11 @@ module LogStashCompilerLSCLGrammar s0, i0 = [], index loop do - if has_terminal?('\G[ \\t\\r\\n]', true, index) + if has_terminal?(@regexps[gr = '\A[ \\t\\r\\n]'] ||= Regexp.new(gr), :regexp, index) r1 = true @index += 1 else + terminal_parse_failure('[ \\t\\r\\n]') r1 = nil end if r1 @@ -312,7 +316,7 @@ module LogStashCompilerLSCLGrammar if node_cache[:plugin_section].has_key?(index) cached = node_cache[:plugin_section][index] if cached - cached = SyntaxNode.new(input, index...(index + 1)) if cached == true + node_cache[:plugin_section][index] = cached = SyntaxNode.new(input, index...(index + 1)) if cached == true @index = cached.interval.end end return cached @@ -325,11 +329,11 @@ module LogStashCompilerLSCLGrammar r2 = _nt__ s0 << r2 if r2 - if has_terminal?("{", false, index) - r3 = instantiate_node(SyntaxNode,input, index...(index + 1)) - @index += 1 + if (match_len = has_terminal?("{", false, index)) + r3 = true + @index += match_len else - terminal_parse_failure("{") + terminal_parse_failure('"{"') r3 = nil end s0 << r3 @@ -362,11 +366,11 @@ module LogStashCompilerLSCLGrammar r5 = instantiate_node(SyntaxNode,input, i5...index, s5) s0 << r5 if r5 - if has_terminal?("}", false, index) - r9 = instantiate_node(SyntaxNode,input, index...(index + 1)) - @index += 1 + if (match_len = has_terminal?("}", false, index)) + r9 = true + @index += match_len else - terminal_parse_failure("}") + terminal_parse_failure('"}"') r9 = nil end s0 << r9 @@ -393,7 +397,7 @@ module LogStashCompilerLSCLGrammar if node_cache[:branch_or_plugin].has_key?(index) cached = node_cache[:branch_or_plugin][index] if cached - cached = SyntaxNode.new(input, index...(index + 1)) if cached == true + node_cache[:branch_or_plugin][index] = cached = SyntaxNode.new(input, index...(index + 1)) if cached == true @index = cached.interval.end end return cached @@ -402,10 +406,12 @@ module LogStashCompilerLSCLGrammar i0 = index r1 = _nt_branch if r1 + r1 = SyntaxNode.new(input, (index-1)...index) if r1 == true r0 = r1 else r2 = _nt_plugin if r2 + r2 = SyntaxNode.new(input, (index-1)...index) if r2 == true r0 = r2 else @index = i0 @@ -423,41 +429,44 @@ module LogStashCompilerLSCLGrammar if node_cache[:plugin_type].has_key?(index) cached = node_cache[:plugin_type][index] if cached - cached = SyntaxNode.new(input, index...(index + 1)) if cached == true + node_cache[:plugin_type][index] = cached = SyntaxNode.new(input, index...(index + 1)) if cached == true @index = cached.interval.end end return cached end i0 = index - if has_terminal?("input", false, index) - r1 = instantiate_node(SyntaxNode,input, index...(index + 5)) - @index += 5 + if (match_len = has_terminal?("input", false, index)) + r1 = instantiate_node(SyntaxNode,input, index...(index + match_len)) + @index += match_len else - terminal_parse_failure("input") + terminal_parse_failure('"input"') r1 = nil end if r1 + r1 = SyntaxNode.new(input, (index-1)...index) if r1 == true r0 = r1 else - if has_terminal?("filter", false, index) - r2 = instantiate_node(SyntaxNode,input, index...(index + 6)) - @index += 6 + if (match_len = has_terminal?("filter", false, index)) + r2 = instantiate_node(SyntaxNode,input, index...(index + match_len)) + @index += match_len else - terminal_parse_failure("filter") + terminal_parse_failure('"filter"') r2 = nil end if r2 + r2 = SyntaxNode.new(input, (index-1)...index) if r2 == true r0 = r2 else - if has_terminal?("output", false, index) - r3 = instantiate_node(SyntaxNode,input, index...(index + 6)) - @index += 6 + if (match_len = has_terminal?("output", false, index)) + r3 = instantiate_node(SyntaxNode,input, index...(index + match_len)) + @index += match_len else - terminal_parse_failure("output") + terminal_parse_failure('"output"') r3 = nil end if r3 + r3 = SyntaxNode.new(input, (index-1)...index) if r3 == true r0 = r3 else @index = i0 @@ -493,7 +502,7 @@ module LogStashCompilerLSCLGrammar if node_cache[:plugins].has_key?(index) cached = node_cache[:plugins][index] if cached - cached = SyntaxNode.new(input, index...(index + 1)) if cached == true + node_cache[:plugins][index] = cached = SyntaxNode.new(input, index...(index + 1)) if cached == true @index = cached.interval.end end return cached @@ -595,7 +604,7 @@ module LogStashCompilerLSCLGrammar if node_cache[:plugin].has_key?(index) cached = node_cache[:plugin][index] if cached - cached = SyntaxNode.new(input, index...(index + 1)) if cached == true + node_cache[:plugin][index] = cached = SyntaxNode.new(input, index...(index + 1)) if cached == true @index = cached.interval.end end return cached @@ -608,11 +617,11 @@ module LogStashCompilerLSCLGrammar r2 = _nt__ s0 << r2 if r2 - if has_terminal?("{", false, index) - r3 = instantiate_node(SyntaxNode,input, index...(index + 1)) - @index += 1 + if (match_len = has_terminal?("{", false, index)) + r3 = true + @index += match_len else - terminal_parse_failure("{") + terminal_parse_failure('"{"') r3 = nil end s0 << r3 @@ -670,11 +679,11 @@ module LogStashCompilerLSCLGrammar r13 = _nt__ s0 << r13 if r13 - if has_terminal?("}", false, index) - r14 = instantiate_node(SyntaxNode,input, index...(index + 1)) - @index += 1 + if (match_len = has_terminal?("}", false, index)) + r14 = true + @index += match_len else - terminal_parse_failure("}") + terminal_parse_failure('"}"') r14 = nil end s0 << r14 @@ -702,7 +711,7 @@ module LogStashCompilerLSCLGrammar if node_cache[:name].has_key?(index) cached = node_cache[:name][index] if cached - cached = SyntaxNode.new(input, index...(index + 1)) if cached == true + node_cache[:name][index] = cached = SyntaxNode.new(input, index...(index + 1)) if cached == true @index = cached.interval.end end return cached @@ -711,10 +720,11 @@ module LogStashCompilerLSCLGrammar i0 = index s1, i1 = [], index loop do - if has_terminal?('\G[A-Za-z0-9_-]', true, index) + if has_terminal?(@regexps[gr = '\A[A-Za-z0-9_-]'] ||= Regexp.new(gr), :regexp, index) r2 = true @index += 1 else + terminal_parse_failure('[A-Za-z0-9_-]') r2 = nil end if r2 @@ -730,10 +740,12 @@ module LogStashCompilerLSCLGrammar r1 = instantiate_node(LogStash::Compiler::LSCL::AST::Name,input, i1...index, s1) end if r1 + r1 = SyntaxNode.new(input, (index-1)...index) if r1 == true r0 = r1 else r3 = _nt_string if r3 + r3 = SyntaxNode.new(input, (index-1)...index) if r3 == true r0 = r3 else @index = i0 @@ -769,7 +781,7 @@ module LogStashCompilerLSCLGrammar if node_cache[:attribute].has_key?(index) cached = node_cache[:attribute][index] if cached - cached = SyntaxNode.new(input, index...(index + 1)) if cached == true + node_cache[:attribute][index] = cached = SyntaxNode.new(input, index...(index + 1)) if cached == true @index = cached.interval.end end return cached @@ -782,11 +794,11 @@ module LogStashCompilerLSCLGrammar r2 = _nt__ s0 << r2 if r2 - if has_terminal?("=>", false, index) - r3 = instantiate_node(SyntaxNode,input, index...(index + 2)) - @index += 2 + if (match_len = has_terminal?("=>", false, index)) + r3 = instantiate_node(SyntaxNode,input, index...(index + match_len)) + @index += match_len else - terminal_parse_failure("=>") + terminal_parse_failure('"=>"') r3 = nil end s0 << r3 @@ -818,7 +830,7 @@ module LogStashCompilerLSCLGrammar if node_cache[:value].has_key?(index) cached = node_cache[:value][index] if cached - cached = SyntaxNode.new(input, index...(index + 1)) if cached == true + node_cache[:value][index] = cached = SyntaxNode.new(input, index...(index + 1)) if cached == true @index = cached.interval.end end return cached @@ -827,26 +839,32 @@ module LogStashCompilerLSCLGrammar i0 = index r1 = _nt_plugin if r1 + r1 = SyntaxNode.new(input, (index-1)...index) if r1 == true r0 = r1 else r2 = _nt_bareword if r2 + r2 = SyntaxNode.new(input, (index-1)...index) if r2 == true r0 = r2 else r3 = _nt_string if r3 + r3 = SyntaxNode.new(input, (index-1)...index) if r3 == true r0 = r3 else r4 = _nt_number if r4 + r4 = SyntaxNode.new(input, (index-1)...index) if r4 == true r0 = r4 else r5 = _nt_array if r5 + r5 = SyntaxNode.new(input, (index-1)...index) if r5 == true r0 = r5 else r6 = _nt_hash if r6 + r6 = SyntaxNode.new(input, (index-1)...index) if r6 == true r0 = r6 else @index = i0 @@ -868,7 +886,7 @@ module LogStashCompilerLSCLGrammar if node_cache[:array_value].has_key?(index) cached = node_cache[:array_value][index] if cached - cached = SyntaxNode.new(input, index...(index + 1)) if cached == true + node_cache[:array_value][index] = cached = SyntaxNode.new(input, index...(index + 1)) if cached == true @index = cached.interval.end end return cached @@ -877,22 +895,27 @@ module LogStashCompilerLSCLGrammar i0 = index r1 = _nt_bareword if r1 + r1 = SyntaxNode.new(input, (index-1)...index) if r1 == true r0 = r1 else r2 = _nt_string if r2 + r2 = SyntaxNode.new(input, (index-1)...index) if r2 == true r0 = r2 else r3 = _nt_number if r3 + r3 = SyntaxNode.new(input, (index-1)...index) if r3 == true r0 = r3 else r4 = _nt_array if r4 + r4 = SyntaxNode.new(input, (index-1)...index) if r4 == true r0 = r4 else r5 = _nt_hash if r5 + r5 = SyntaxNode.new(input, (index-1)...index) if r5 == true r0 = r5 else @index = i0 @@ -916,27 +939,29 @@ module LogStashCompilerLSCLGrammar if node_cache[:bareword].has_key?(index) cached = node_cache[:bareword][index] if cached - cached = SyntaxNode.new(input, index...(index + 1)) if cached == true + node_cache[:bareword][index] = cached = SyntaxNode.new(input, index...(index + 1)) if cached == true @index = cached.interval.end end return cached end i0, s0 = index, [] - if has_terminal?('\G[A-Za-z_]', true, index) + if has_terminal?(@regexps[gr = '\A[A-Za-z_]'] ||= Regexp.new(gr), :regexp, index) r1 = true @index += 1 else + terminal_parse_failure('[A-Za-z_]') r1 = nil end s0 << r1 if r1 s2, i2 = [], index loop do - if has_terminal?('\G[A-Za-z0-9_]', true, index) + if has_terminal?(@regexps[gr = '\A[A-Za-z0-9_]'] ||= Regexp.new(gr), :regexp, index) r3 = true @index += 1 else + terminal_parse_failure('[A-Za-z0-9_]') r3 = nil end if r3 @@ -977,18 +1002,18 @@ module LogStashCompilerLSCLGrammar if node_cache[:double_quoted_string].has_key?(index) cached = node_cache[:double_quoted_string][index] if cached - cached = SyntaxNode.new(input, index...(index + 1)) if cached == true + node_cache[:double_quoted_string][index] = cached = SyntaxNode.new(input, index...(index + 1)) if cached == true @index = cached.interval.end end return cached end i0, s0 = index, [] - if has_terminal?('"', false, index) - r1 = instantiate_node(SyntaxNode,input, index...(index + 1)) - @index += 1 + if (match_len = has_terminal?('"', false, index)) + r1 = true + @index += match_len else - terminal_parse_failure('"') + terminal_parse_failure('\'"\'') r1 = nil end s0 << r1 @@ -996,35 +1021,39 @@ module LogStashCompilerLSCLGrammar s2, i2 = [], index loop do i3 = index - if has_terminal?('\"', false, index) - r4 = instantiate_node(SyntaxNode,input, index...(index + 2)) - @index += 2 + if (match_len = has_terminal?('\"', false, index)) + r4 = instantiate_node(SyntaxNode,input, index...(index + match_len)) + @index += match_len else - terminal_parse_failure('\"') + terminal_parse_failure('\'\\"\'') r4 = nil end if r4 + r4 = SyntaxNode.new(input, (index-1)...index) if r4 == true r3 = r4 else i5, s5 = index, [] i6 = index - if has_terminal?('"', false, index) - r7 = instantiate_node(SyntaxNode,input, index...(index + 1)) - @index += 1 + if (match_len = has_terminal?('"', false, index)) + r7 = true + @index += match_len else - terminal_parse_failure('"') + terminal_parse_failure('\'"\'') r7 = nil end if r7 + @index = i6 r6 = nil + terminal_parse_failure('\'"\'', true) else + @terminal_failures.pop @index = i6 r6 = instantiate_node(SyntaxNode,input, index...index) end s5 << r6 if r6 if index < input_length - r8 = instantiate_node(SyntaxNode,input, index...(index + 1)) + r8 = true @index += 1 else terminal_parse_failure("any character") @@ -1040,6 +1069,7 @@ module LogStashCompilerLSCLGrammar r5 = nil end if r5 + r5 = SyntaxNode.new(input, (index-1)...index) if r5 == true r3 = r5 else @index = i3 @@ -1055,11 +1085,11 @@ module LogStashCompilerLSCLGrammar r2 = instantiate_node(SyntaxNode,input, i2...index, s2) s0 << r2 if r2 - if has_terminal?('"', false, index) - r9 = instantiate_node(SyntaxNode,input, index...(index + 1)) - @index += 1 + if (match_len = has_terminal?('"', false, index)) + r9 = true + @index += match_len else - terminal_parse_failure('"') + terminal_parse_failure('\'"\'') r9 = nil end s0 << r9 @@ -1089,18 +1119,18 @@ module LogStashCompilerLSCLGrammar if node_cache[:single_quoted_string].has_key?(index) cached = node_cache[:single_quoted_string][index] if cached - cached = SyntaxNode.new(input, index...(index + 1)) if cached == true + node_cache[:single_quoted_string][index] = cached = SyntaxNode.new(input, index...(index + 1)) if cached == true @index = cached.interval.end end return cached end i0, s0 = index, [] - if has_terminal?("'", false, index) - r1 = instantiate_node(SyntaxNode,input, index...(index + 1)) - @index += 1 + if (match_len = has_terminal?("'", false, index)) + r1 = true + @index += match_len else - terminal_parse_failure("'") + terminal_parse_failure('"\'"') r1 = nil end s0 << r1 @@ -1108,35 +1138,39 @@ module LogStashCompilerLSCLGrammar s2, i2 = [], index loop do i3 = index - if has_terminal?("\\'", false, index) - r4 = instantiate_node(SyntaxNode,input, index...(index + 2)) - @index += 2 + if (match_len = has_terminal?("\\'", false, index)) + r4 = instantiate_node(SyntaxNode,input, index...(index + match_len)) + @index += match_len else - terminal_parse_failure("\\'") + terminal_parse_failure('"\\\\\'"') r4 = nil end if r4 + r4 = SyntaxNode.new(input, (index-1)...index) if r4 == true r3 = r4 else i5, s5 = index, [] i6 = index - if has_terminal?("'", false, index) - r7 = instantiate_node(SyntaxNode,input, index...(index + 1)) - @index += 1 + if (match_len = has_terminal?("'", false, index)) + r7 = true + @index += match_len else - terminal_parse_failure("'") + terminal_parse_failure('"\'"') r7 = nil end if r7 + @index = i6 r6 = nil + terminal_parse_failure('"\'"', true) else + @terminal_failures.pop @index = i6 r6 = instantiate_node(SyntaxNode,input, index...index) end s5 << r6 if r6 if index < input_length - r8 = instantiate_node(SyntaxNode,input, index...(index + 1)) + r8 = true @index += 1 else terminal_parse_failure("any character") @@ -1152,6 +1186,7 @@ module LogStashCompilerLSCLGrammar r5 = nil end if r5 + r5 = SyntaxNode.new(input, (index-1)...index) if r5 == true r3 = r5 else @index = i3 @@ -1167,11 +1202,11 @@ module LogStashCompilerLSCLGrammar r2 = instantiate_node(SyntaxNode,input, i2...index, s2) s0 << r2 if r2 - if has_terminal?("'", false, index) - r9 = instantiate_node(SyntaxNode,input, index...(index + 1)) - @index += 1 + if (match_len = has_terminal?("'", false, index)) + r9 = true + @index += match_len else - terminal_parse_failure("'") + terminal_parse_failure('"\'"') r9 = nil end s0 << r9 @@ -1195,7 +1230,7 @@ module LogStashCompilerLSCLGrammar if node_cache[:string].has_key?(index) cached = node_cache[:string][index] if cached - cached = SyntaxNode.new(input, index...(index + 1)) if cached == true + node_cache[:string][index] = cached = SyntaxNode.new(input, index...(index + 1)) if cached == true @index = cached.interval.end end return cached @@ -1204,10 +1239,12 @@ module LogStashCompilerLSCLGrammar i0 = index r1 = _nt_double_quoted_string if r1 + r1 = SyntaxNode.new(input, (index-1)...index) if r1 == true r0 = r1 else r2 = _nt_single_quoted_string if r2 + r2 = SyntaxNode.new(input, (index-1)...index) if r2 == true r0 = r2 else @index = i0 @@ -1231,18 +1268,18 @@ module LogStashCompilerLSCLGrammar if node_cache[:regexp].has_key?(index) cached = node_cache[:regexp][index] if cached - cached = SyntaxNode.new(input, index...(index + 1)) if cached == true + node_cache[:regexp][index] = cached = SyntaxNode.new(input, index...(index + 1)) if cached == true @index = cached.interval.end end return cached end i0, s0 = index, [] - if has_terminal?('/', false, index) - r1 = instantiate_node(SyntaxNode,input, index...(index + 1)) - @index += 1 + if (match_len = has_terminal?('/', false, index)) + r1 = true + @index += match_len else - terminal_parse_failure('/') + terminal_parse_failure('\'/\'') r1 = nil end s0 << r1 @@ -1250,35 +1287,39 @@ module LogStashCompilerLSCLGrammar s2, i2 = [], index loop do i3 = index - if has_terminal?('\/', false, index) - r4 = instantiate_node(SyntaxNode,input, index...(index + 2)) - @index += 2 + if (match_len = has_terminal?('\/', false, index)) + r4 = instantiate_node(SyntaxNode,input, index...(index + match_len)) + @index += match_len else - terminal_parse_failure('\/') + terminal_parse_failure('\'\\/\'') r4 = nil end if r4 + r4 = SyntaxNode.new(input, (index-1)...index) if r4 == true r3 = r4 else i5, s5 = index, [] i6 = index - if has_terminal?('/', false, index) - r7 = instantiate_node(SyntaxNode,input, index...(index + 1)) - @index += 1 + if (match_len = has_terminal?('/', false, index)) + r7 = true + @index += match_len else - terminal_parse_failure('/') + terminal_parse_failure('\'/\'') r7 = nil end if r7 + @index = i6 r6 = nil + terminal_parse_failure('\'/\'', true) else + @terminal_failures.pop @index = i6 r6 = instantiate_node(SyntaxNode,input, index...index) end s5 << r6 if r6 if index < input_length - r8 = instantiate_node(SyntaxNode,input, index...(index + 1)) + r8 = true @index += 1 else terminal_parse_failure("any character") @@ -1294,6 +1335,7 @@ module LogStashCompilerLSCLGrammar r5 = nil end if r5 + r5 = SyntaxNode.new(input, (index-1)...index) if r5 == true r3 = r5 else @index = i3 @@ -1309,11 +1351,11 @@ module LogStashCompilerLSCLGrammar r2 = instantiate_node(SyntaxNode,input, i2...index, s2) s0 << r2 if r2 - if has_terminal?('/', false, index) - r9 = instantiate_node(SyntaxNode,input, index...(index + 1)) - @index += 1 + if (match_len = has_terminal?('/', false, index)) + r9 = true + @index += match_len else - terminal_parse_failure('/') + terminal_parse_failure('\'/\'') r9 = nil end s0 << r9 @@ -1343,18 +1385,18 @@ module LogStashCompilerLSCLGrammar if node_cache[:number].has_key?(index) cached = node_cache[:number][index] if cached - cached = SyntaxNode.new(input, index...(index + 1)) if cached == true + node_cache[:number][index] = cached = SyntaxNode.new(input, index...(index + 1)) if cached == true @index = cached.interval.end end return cached end i0, s0 = index, [] - if has_terminal?("-", false, index) - r2 = instantiate_node(SyntaxNode,input, index...(index + 1)) - @index += 1 + if (match_len = has_terminal?("-", false, index)) + r2 = true + @index += match_len else - terminal_parse_failure("-") + terminal_parse_failure('"-"') r2 = nil end if r2 @@ -1366,10 +1408,11 @@ module LogStashCompilerLSCLGrammar if r1 s3, i3 = [], index loop do - if has_terminal?('\G[0-9]', true, index) + if has_terminal?(@regexps[gr = '\A[0-9]'] ||= Regexp.new(gr), :regexp, index) r4 = true @index += 1 else + terminal_parse_failure('[0-9]') r4 = nil end if r4 @@ -1387,21 +1430,22 @@ module LogStashCompilerLSCLGrammar s0 << r3 if r3 i6, s6 = index, [] - if has_terminal?(".", false, index) - r7 = instantiate_node(SyntaxNode,input, index...(index + 1)) - @index += 1 + if (match_len = has_terminal?(".", false, index)) + r7 = true + @index += match_len else - terminal_parse_failure(".") + terminal_parse_failure('"."') r7 = nil end s6 << r7 if r7 s8, i8 = [], index loop do - if has_terminal?('\G[0-9]', true, index) + if has_terminal?(@regexps[gr = '\A[0-9]'] ||= Regexp.new(gr), :regexp, index) r9 = true @index += 1 else + terminal_parse_failure('[0-9]') r9 = nil end if r9 @@ -1478,18 +1522,18 @@ module LogStashCompilerLSCLGrammar if node_cache[:array].has_key?(index) cached = node_cache[:array][index] if cached - cached = SyntaxNode.new(input, index...(index + 1)) if cached == true + node_cache[:array][index] = cached = SyntaxNode.new(input, index...(index + 1)) if cached == true @index = cached.interval.end end return cached end i0, s0 = index, [] - if has_terminal?("[", false, index) - r1 = instantiate_node(SyntaxNode,input, index...(index + 1)) - @index += 1 + if (match_len = has_terminal?("[", false, index)) + r1 = true + @index += match_len else - terminal_parse_failure("[") + terminal_parse_failure('"["') r1 = nil end s0 << r1 @@ -1507,11 +1551,11 @@ module LogStashCompilerLSCLGrammar r8 = _nt__ s7 << r8 if r8 - if has_terminal?(",", false, index) - r9 = instantiate_node(SyntaxNode,input, index...(index + 1)) - @index += 1 + if (match_len = has_terminal?(",", false, index)) + r9 = true + @index += match_len else - terminal_parse_failure(",") + terminal_parse_failure('","') r9 = nil end s7 << r9 @@ -1557,11 +1601,11 @@ module LogStashCompilerLSCLGrammar r12 = _nt__ s0 << r12 if r12 - if has_terminal?("]", false, index) - r13 = instantiate_node(SyntaxNode,input, index...(index + 1)) - @index += 1 + if (match_len = has_terminal?("]", false, index)) + r13 = true + @index += match_len else - terminal_parse_failure("]") + terminal_parse_failure('"]"') r13 = nil end s0 << r13 @@ -1598,18 +1642,18 @@ module LogStashCompilerLSCLGrammar if node_cache[:hash].has_key?(index) cached = node_cache[:hash][index] if cached - cached = SyntaxNode.new(input, index...(index + 1)) if cached == true + node_cache[:hash][index] = cached = SyntaxNode.new(input, index...(index + 1)) if cached == true @index = cached.interval.end end return cached end i0, s0 = index, [] - if has_terminal?("{", false, index) - r1 = instantiate_node(SyntaxNode,input, index...(index + 1)) - @index += 1 + if (match_len = has_terminal?("{", false, index)) + r1 = true + @index += match_len else - terminal_parse_failure("{") + terminal_parse_failure('"{"') r1 = nil end s0 << r1 @@ -1628,11 +1672,11 @@ module LogStashCompilerLSCLGrammar r5 = _nt__ s0 << r5 if r5 - if has_terminal?("}", false, index) - r6 = instantiate_node(SyntaxNode,input, index...(index + 1)) - @index += 1 + if (match_len = has_terminal?("}", false, index)) + r6 = true + @index += match_len else - terminal_parse_failure("}") + terminal_parse_failure('"}"') r6 = nil end s0 << r6 @@ -1675,7 +1719,7 @@ module LogStashCompilerLSCLGrammar if node_cache[:hashentries].has_key?(index) cached = node_cache[:hashentries][index] if cached - cached = SyntaxNode.new(input, index...(index + 1)) if cached == true + node_cache[:hashentries][index] = cached = SyntaxNode.new(input, index...(index + 1)) if cached == true @index = cached.interval.end end return cached @@ -1746,7 +1790,7 @@ module LogStashCompilerLSCLGrammar if node_cache[:hashentry].has_key?(index) cached = node_cache[:hashentry][index] if cached - cached = SyntaxNode.new(input, index...(index + 1)) if cached == true + node_cache[:hashentry][index] = cached = SyntaxNode.new(input, index...(index + 1)) if cached == true @index = cached.interval.end end return cached @@ -1756,14 +1800,17 @@ module LogStashCompilerLSCLGrammar i1 = index r2 = _nt_number if r2 + r2 = SyntaxNode.new(input, (index-1)...index) if r2 == true r1 = r2 else r3 = _nt_bareword if r3 + r3 = SyntaxNode.new(input, (index-1)...index) if r3 == true r1 = r3 else r4 = _nt_string if r4 + r4 = SyntaxNode.new(input, (index-1)...index) if r4 == true r1 = r4 else @index = i1 @@ -1776,11 +1823,11 @@ module LogStashCompilerLSCLGrammar r5 = _nt__ s0 << r5 if r5 - if has_terminal?("=>", false, index) - r6 = instantiate_node(SyntaxNode,input, index...(index + 2)) - @index += 2 + if (match_len = has_terminal?("=>", false, index)) + r6 = instantiate_node(SyntaxNode,input, index...(index + match_len)) + @index += match_len else - terminal_parse_failure("=>") + terminal_parse_failure('"=>"') r6 = nil end s0 << r6 @@ -1839,7 +1886,7 @@ module LogStashCompilerLSCLGrammar if node_cache[:branch].has_key?(index) cached = node_cache[:branch][index] if cached - cached = SyntaxNode.new(input, index...(index + 1)) if cached == true + node_cache[:branch][index] = cached = SyntaxNode.new(input, index...(index + 1)) if cached == true @index = cached.interval.end end return cached @@ -1943,18 +1990,18 @@ module LogStashCompilerLSCLGrammar if node_cache[:if].has_key?(index) cached = node_cache[:if][index] if cached - cached = SyntaxNode.new(input, index...(index + 1)) if cached == true + node_cache[:if][index] = cached = SyntaxNode.new(input, index...(index + 1)) if cached == true @index = cached.interval.end end return cached end i0, s0 = index, [] - if has_terminal?("if", false, index) - r1 = instantiate_node(SyntaxNode,input, index...(index + 2)) - @index += 2 + if (match_len = has_terminal?("if", false, index)) + r1 = instantiate_node(SyntaxNode,input, index...(index + match_len)) + @index += match_len else - terminal_parse_failure("if") + terminal_parse_failure('"if"') r1 = nil end s0 << r1 @@ -1968,11 +2015,11 @@ module LogStashCompilerLSCLGrammar r4 = _nt__ s0 << r4 if r4 - if has_terminal?("{", false, index) - r5 = instantiate_node(SyntaxNode,input, index...(index + 1)) - @index += 1 + if (match_len = has_terminal?("{", false, index)) + r5 = true + @index += match_len else - terminal_parse_failure("{") + terminal_parse_failure('"{"') r5 = nil end s0 << r5 @@ -2005,11 +2052,11 @@ module LogStashCompilerLSCLGrammar r7 = instantiate_node(SyntaxNode,input, i7...index, s7) s0 << r7 if r7 - if has_terminal?("}", false, index) - r11 = instantiate_node(SyntaxNode,input, index...(index + 1)) - @index += 1 + if (match_len = has_terminal?("}", false, index)) + r11 = true + @index += match_len else - terminal_parse_failure("}") + terminal_parse_failure('"}"') r11 = nil end s0 << r11 @@ -2071,18 +2118,18 @@ module LogStashCompilerLSCLGrammar if node_cache[:else_if].has_key?(index) cached = node_cache[:else_if][index] if cached - cached = SyntaxNode.new(input, index...(index + 1)) if cached == true + node_cache[:else_if][index] = cached = SyntaxNode.new(input, index...(index + 1)) if cached == true @index = cached.interval.end end return cached end i0, s0 = index, [] - if has_terminal?("else", false, index) - r1 = instantiate_node(SyntaxNode,input, index...(index + 4)) - @index += 4 + if (match_len = has_terminal?("else", false, index)) + r1 = instantiate_node(SyntaxNode,input, index...(index + match_len)) + @index += match_len else - terminal_parse_failure("else") + terminal_parse_failure('"else"') r1 = nil end s0 << r1 @@ -2090,11 +2137,11 @@ module LogStashCompilerLSCLGrammar r2 = _nt__ s0 << r2 if r2 - if has_terminal?("if", false, index) - r3 = instantiate_node(SyntaxNode,input, index...(index + 2)) - @index += 2 + if (match_len = has_terminal?("if", false, index)) + r3 = instantiate_node(SyntaxNode,input, index...(index + match_len)) + @index += match_len else - terminal_parse_failure("if") + terminal_parse_failure('"if"') r3 = nil end s0 << r3 @@ -2108,11 +2155,11 @@ module LogStashCompilerLSCLGrammar r6 = _nt__ s0 << r6 if r6 - if has_terminal?("{", false, index) - r7 = instantiate_node(SyntaxNode,input, index...(index + 1)) - @index += 1 + if (match_len = has_terminal?("{", false, index)) + r7 = true + @index += match_len else - terminal_parse_failure("{") + terminal_parse_failure('"{"') r7 = nil end s0 << r7 @@ -2145,11 +2192,11 @@ module LogStashCompilerLSCLGrammar r9 = instantiate_node(SyntaxNode,input, i9...index, s9) s0 << r9 if r9 - if has_terminal?("}", false, index) - r13 = instantiate_node(SyntaxNode,input, index...(index + 1)) - @index += 1 + if (match_len = has_terminal?("}", false, index)) + r13 = true + @index += match_len else - terminal_parse_failure("}") + terminal_parse_failure('"}"') r13 = nil end s0 << r13 @@ -2201,18 +2248,18 @@ module LogStashCompilerLSCLGrammar if node_cache[:else].has_key?(index) cached = node_cache[:else][index] if cached - cached = SyntaxNode.new(input, index...(index + 1)) if cached == true + node_cache[:else][index] = cached = SyntaxNode.new(input, index...(index + 1)) if cached == true @index = cached.interval.end end return cached end i0, s0 = index, [] - if has_terminal?("else", false, index) - r1 = instantiate_node(SyntaxNode,input, index...(index + 4)) - @index += 4 + if (match_len = has_terminal?("else", false, index)) + r1 = instantiate_node(SyntaxNode,input, index...(index + match_len)) + @index += match_len else - terminal_parse_failure("else") + terminal_parse_failure('"else"') r1 = nil end s0 << r1 @@ -2220,11 +2267,11 @@ module LogStashCompilerLSCLGrammar r2 = _nt__ s0 << r2 if r2 - if has_terminal?("{", false, index) - r3 = instantiate_node(SyntaxNode,input, index...(index + 1)) - @index += 1 + if (match_len = has_terminal?("{", false, index)) + r3 = true + @index += match_len else - terminal_parse_failure("{") + terminal_parse_failure('"{"') r3 = nil end s0 << r3 @@ -2257,11 +2304,11 @@ module LogStashCompilerLSCLGrammar r5 = instantiate_node(SyntaxNode,input, i5...index, s5) s0 << r5 if r5 - if has_terminal?("}", false, index) - r9 = instantiate_node(SyntaxNode,input, index...(index + 1)) - @index += 1 + if (match_len = has_terminal?("}", false, index)) + r9 = true + @index += match_len else - terminal_parse_failure("}") + terminal_parse_failure('"}"') r9 = nil end s0 << r9 @@ -2313,7 +2360,7 @@ module LogStashCompilerLSCLGrammar if node_cache[:condition].has_key?(index) cached = node_cache[:condition][index] if cached - cached = SyntaxNode.new(input, index...(index + 1)) if cached == true + node_cache[:condition][index] = cached = SyntaxNode.new(input, index...(index + 1)) if cached == true @index = cached.interval.end end return cached @@ -2389,7 +2436,7 @@ module LogStashCompilerLSCLGrammar if node_cache[:expression].has_key?(index) cached = node_cache[:expression][index] if cached - cached = SyntaxNode.new(input, index...(index + 1)) if cached == true + node_cache[:expression][index] = cached = SyntaxNode.new(input, index...(index + 1)) if cached == true @index = cached.interval.end end return cached @@ -2397,11 +2444,11 @@ module LogStashCompilerLSCLGrammar i0 = index i1, s1 = index, [] - if has_terminal?("(", false, index) - r2 = instantiate_node(SyntaxNode,input, index...(index + 1)) - @index += 1 + if (match_len = has_terminal?("(", false, index)) + r2 = true + @index += match_len else - terminal_parse_failure("(") + terminal_parse_failure('"("') r2 = nil end s1 << r2 @@ -2415,11 +2462,11 @@ module LogStashCompilerLSCLGrammar r5 = _nt__ s1 << r5 if r5 - if has_terminal?(")", false, index) - r6 = instantiate_node(SyntaxNode,input, index...(index + 1)) - @index += 1 + if (match_len = has_terminal?(")", false, index)) + r6 = true + @index += match_len else - terminal_parse_failure(")") + terminal_parse_failure('")"') r6 = nil end s1 << r6 @@ -2435,36 +2482,43 @@ module LogStashCompilerLSCLGrammar r1 = nil end if r1 + r1 = SyntaxNode.new(input, (index-1)...index) if r1 == true r0 = r1 r0.extend(LogStash::Compiler::LSCL::AST::Expression) else r7 = _nt_negative_expression if r7 + r7 = SyntaxNode.new(input, (index-1)...index) if r7 == true r0 = r7 r0.extend(LogStash::Compiler::LSCL::AST::Expression) else r8 = _nt_in_expression if r8 + r8 = SyntaxNode.new(input, (index-1)...index) if r8 == true r0 = r8 r0.extend(LogStash::Compiler::LSCL::AST::Expression) else r9 = _nt_not_in_expression if r9 + r9 = SyntaxNode.new(input, (index-1)...index) if r9 == true r0 = r9 r0.extend(LogStash::Compiler::LSCL::AST::Expression) else r10 = _nt_compare_expression if r10 + r10 = SyntaxNode.new(input, (index-1)...index) if r10 == true r0 = r10 r0.extend(LogStash::Compiler::LSCL::AST::Expression) else r11 = _nt_regexp_expression if r11 + r11 = SyntaxNode.new(input, (index-1)...index) if r11 == true r0 = r11 r0.extend(LogStash::Compiler::LSCL::AST::Expression) else r12 = _nt_rvalue if r12 + r12 = SyntaxNode.new(input, (index-1)...index) if r12 == true r0 = r12 r0.extend(LogStash::Compiler::LSCL::AST::Expression) else @@ -2517,7 +2571,7 @@ module LogStashCompilerLSCLGrammar if node_cache[:negative_expression].has_key?(index) cached = node_cache[:negative_expression][index] if cached - cached = SyntaxNode.new(input, index...(index + 1)) if cached == true + node_cache[:negative_expression][index] = cached = SyntaxNode.new(input, index...(index + 1)) if cached == true @index = cached.interval.end end return cached @@ -2525,11 +2579,11 @@ module LogStashCompilerLSCLGrammar i0 = index i1, s1 = index, [] - if has_terminal?("!", false, index) - r2 = instantiate_node(SyntaxNode,input, index...(index + 1)) - @index += 1 + if (match_len = has_terminal?("!", false, index)) + r2 = true + @index += match_len else - terminal_parse_failure("!") + terminal_parse_failure('"!"') r2 = nil end s1 << r2 @@ -2537,11 +2591,11 @@ module LogStashCompilerLSCLGrammar r3 = _nt__ s1 << r3 if r3 - if has_terminal?("(", false, index) - r4 = instantiate_node(SyntaxNode,input, index...(index + 1)) - @index += 1 + if (match_len = has_terminal?("(", false, index)) + r4 = true + @index += match_len else - terminal_parse_failure("(") + terminal_parse_failure('"("') r4 = nil end s1 << r4 @@ -2555,11 +2609,11 @@ module LogStashCompilerLSCLGrammar r7 = _nt__ s1 << r7 if r7 - if has_terminal?(")", false, index) - r8 = instantiate_node(SyntaxNode,input, index...(index + 1)) - @index += 1 + if (match_len = has_terminal?(")", false, index)) + r8 = true + @index += match_len else - terminal_parse_failure(")") + terminal_parse_failure('")"') r8 = nil end s1 << r8 @@ -2577,15 +2631,16 @@ module LogStashCompilerLSCLGrammar r1 = nil end if r1 + r1 = SyntaxNode.new(input, (index-1)...index) if r1 == true r0 = r1 r0.extend(LogStash::Compiler::LSCL::AST::NegativeExpression) else i9, s9 = index, [] - if has_terminal?("!", false, index) - r10 = instantiate_node(SyntaxNode,input, index...(index + 1)) - @index += 1 + if (match_len = has_terminal?("!", false, index)) + r10 = true + @index += match_len else - terminal_parse_failure("!") + terminal_parse_failure('"!"') r10 = nil end s9 << r10 @@ -2605,6 +2660,7 @@ module LogStashCompilerLSCLGrammar r9 = nil end if r9 + r9 = SyntaxNode.new(input, (index-1)...index) if r9 == true r0 = r9 r0.extend(LogStash::Compiler::LSCL::AST::NegativeExpression) else @@ -2645,7 +2701,7 @@ module LogStashCompilerLSCLGrammar if node_cache[:in_expression].has_key?(index) cached = node_cache[:in_expression][index] if cached - cached = SyntaxNode.new(input, index...(index + 1)) if cached == true + node_cache[:in_expression][index] = cached = SyntaxNode.new(input, index...(index + 1)) if cached == true @index = cached.interval.end end return cached @@ -2710,7 +2766,7 @@ module LogStashCompilerLSCLGrammar if node_cache[:not_in_expression].has_key?(index) cached = node_cache[:not_in_expression][index] if cached - cached = SyntaxNode.new(input, index...(index + 1)) if cached == true + node_cache[:not_in_expression][index] = cached = SyntaxNode.new(input, index...(index + 1)) if cached == true @index = cached.interval.end end return cached @@ -2753,17 +2809,17 @@ module LogStashCompilerLSCLGrammar if node_cache[:in_operator].has_key?(index) cached = node_cache[:in_operator][index] if cached - cached = SyntaxNode.new(input, index...(index + 1)) if cached == true + node_cache[:in_operator][index] = cached = SyntaxNode.new(input, index...(index + 1)) if cached == true @index = cached.interval.end end return cached end - if has_terminal?("in", false, index) - r0 = instantiate_node(SyntaxNode,input, index...(index + 2)) - @index += 2 + if (match_len = has_terminal?("in", false, index)) + r0 = instantiate_node(SyntaxNode,input, index...(index + match_len)) + @index += match_len else - terminal_parse_failure("in") + terminal_parse_failure('"in"') r0 = nil end @@ -2784,18 +2840,18 @@ module LogStashCompilerLSCLGrammar if node_cache[:not_in_operator].has_key?(index) cached = node_cache[:not_in_operator][index] if cached - cached = SyntaxNode.new(input, index...(index + 1)) if cached == true + node_cache[:not_in_operator][index] = cached = SyntaxNode.new(input, index...(index + 1)) if cached == true @index = cached.interval.end end return cached end i0, s0 = index, [] - if has_terminal?("not ", false, index) - r1 = instantiate_node(SyntaxNode,input, index...(index + 4)) - @index += 4 + if (match_len = has_terminal?("not ", false, index)) + r1 = instantiate_node(SyntaxNode,input, index...(index + match_len)) + @index += match_len else - terminal_parse_failure("not ") + terminal_parse_failure('"not "') r1 = nil end s0 << r1 @@ -2803,11 +2859,11 @@ module LogStashCompilerLSCLGrammar r2 = _nt__ s0 << r2 if r2 - if has_terminal?("in", false, index) - r3 = instantiate_node(SyntaxNode,input, index...(index + 2)) - @index += 2 + if (match_len = has_terminal?("in", false, index)) + r3 = instantiate_node(SyntaxNode,input, index...(index + match_len)) + @index += match_len else - terminal_parse_failure("in") + terminal_parse_failure('"in"') r3 = nil end s0 << r3 @@ -2831,7 +2887,7 @@ module LogStashCompilerLSCLGrammar if node_cache[:rvalue].has_key?(index) cached = node_cache[:rvalue][index] if cached - cached = SyntaxNode.new(input, index...(index + 1)) if cached == true + node_cache[:rvalue][index] = cached = SyntaxNode.new(input, index...(index + 1)) if cached == true @index = cached.interval.end end return cached @@ -2840,26 +2896,32 @@ module LogStashCompilerLSCLGrammar i0 = index r1 = _nt_string if r1 + r1 = SyntaxNode.new(input, (index-1)...index) if r1 == true r0 = r1 else r2 = _nt_number if r2 + r2 = SyntaxNode.new(input, (index-1)...index) if r2 == true r0 = r2 else r3 = _nt_selector if r3 + r3 = SyntaxNode.new(input, (index-1)...index) if r3 == true r0 = r3 else r4 = _nt_array if r4 + r4 = SyntaxNode.new(input, (index-1)...index) if r4 == true r0 = r4 else r5 = _nt_method_call if r5 + r5 = SyntaxNode.new(input, (index-1)...index) if r5 == true r0 = r5 else r6 = _nt_regexp if r6 + r6 = SyntaxNode.new(input, (index-1)...index) if r6 == true r0 = r6 else @index = i0 @@ -2921,7 +2983,7 @@ module LogStashCompilerLSCLGrammar if node_cache[:method_call].has_key?(index) cached = node_cache[:method_call][index] if cached - cached = SyntaxNode.new(input, index...(index + 1)) if cached == true + node_cache[:method_call][index] = cached = SyntaxNode.new(input, index...(index + 1)) if cached == true @index = cached.interval.end end return cached @@ -2934,11 +2996,11 @@ module LogStashCompilerLSCLGrammar r2 = _nt__ s0 << r2 if r2 - if has_terminal?("(", false, index) - r3 = instantiate_node(SyntaxNode,input, index...(index + 1)) - @index += 1 + if (match_len = has_terminal?("(", false, index)) + r3 = true + @index += match_len else - terminal_parse_failure("(") + terminal_parse_failure('"("') r3 = nil end s0 << r3 @@ -2956,11 +3018,11 @@ module LogStashCompilerLSCLGrammar r10 = _nt__ s9 << r10 if r10 - if has_terminal?(",", false, index) - r11 = instantiate_node(SyntaxNode,input, index...(index + 1)) - @index += 1 + if (match_len = has_terminal?(",", false, index)) + r11 = true + @index += match_len else - terminal_parse_failure(",") + terminal_parse_failure('","') r11 = nil end s9 << r11 @@ -3006,11 +3068,11 @@ module LogStashCompilerLSCLGrammar r14 = _nt__ s0 << r14 if r14 - if has_terminal?(")", false, index) - r15 = instantiate_node(SyntaxNode,input, index...(index + 1)) - @index += 1 + if (match_len = has_terminal?(")", false, index)) + r15 = true + @index += match_len else - terminal_parse_failure(")") + terminal_parse_failure('")"') r15 = nil end s0 << r15 @@ -3038,7 +3100,7 @@ module LogStashCompilerLSCLGrammar if node_cache[:method].has_key?(index) cached = node_cache[:method][index] if cached - cached = SyntaxNode.new(input, index...(index + 1)) if cached == true + node_cache[:method][index] = cached = SyntaxNode.new(input, index...(index + 1)) if cached == true @index = cached.interval.end end return cached @@ -3078,7 +3140,7 @@ module LogStashCompilerLSCLGrammar if node_cache[:compare_expression].has_key?(index) cached = node_cache[:compare_expression][index] if cached - cached = SyntaxNode.new(input, index...(index + 1)) if cached == true + node_cache[:compare_expression][index] = cached = SyntaxNode.new(input, index...(index + 1)) if cached == true @index = cached.interval.end end return cached @@ -3121,76 +3183,82 @@ module LogStashCompilerLSCLGrammar if node_cache[:compare_operator].has_key?(index) cached = node_cache[:compare_operator][index] if cached - cached = SyntaxNode.new(input, index...(index + 1)) if cached == true + node_cache[:compare_operator][index] = cached = SyntaxNode.new(input, index...(index + 1)) if cached == true @index = cached.interval.end end return cached end i0 = index - if has_terminal?("==", false, index) - r1 = instantiate_node(SyntaxNode,input, index...(index + 2)) - @index += 2 + if (match_len = has_terminal?("==", false, index)) + r1 = instantiate_node(SyntaxNode,input, index...(index + match_len)) + @index += match_len else - terminal_parse_failure("==") + terminal_parse_failure('"=="') r1 = nil end if r1 + r1 = SyntaxNode.new(input, (index-1)...index) if r1 == true r0 = r1 r0.extend(LogStash::Compiler::LSCL::AST::ComparisonOperator) else - if has_terminal?("!=", false, index) - r2 = instantiate_node(SyntaxNode,input, index...(index + 2)) - @index += 2 + if (match_len = has_terminal?("!=", false, index)) + r2 = instantiate_node(SyntaxNode,input, index...(index + match_len)) + @index += match_len else - terminal_parse_failure("!=") + terminal_parse_failure('"!="') r2 = nil end if r2 + r2 = SyntaxNode.new(input, (index-1)...index) if r2 == true r0 = r2 r0.extend(LogStash::Compiler::LSCL::AST::ComparisonOperator) else - if has_terminal?("<=", false, index) - r3 = instantiate_node(SyntaxNode,input, index...(index + 2)) - @index += 2 + if (match_len = has_terminal?("<=", false, index)) + r3 = instantiate_node(SyntaxNode,input, index...(index + match_len)) + @index += match_len else - terminal_parse_failure("<=") + terminal_parse_failure('"<="') r3 = nil end if r3 + r3 = SyntaxNode.new(input, (index-1)...index) if r3 == true r0 = r3 r0.extend(LogStash::Compiler::LSCL::AST::ComparisonOperator) else - if has_terminal?(">=", false, index) - r4 = instantiate_node(SyntaxNode,input, index...(index + 2)) - @index += 2 + if (match_len = has_terminal?(">=", false, index)) + r4 = instantiate_node(SyntaxNode,input, index...(index + match_len)) + @index += match_len else - terminal_parse_failure(">=") + terminal_parse_failure('">="') r4 = nil end if r4 + r4 = SyntaxNode.new(input, (index-1)...index) if r4 == true r0 = r4 r0.extend(LogStash::Compiler::LSCL::AST::ComparisonOperator) else - if has_terminal?("<", false, index) - r5 = instantiate_node(SyntaxNode,input, index...(index + 1)) - @index += 1 + if (match_len = has_terminal?("<", false, index)) + r5 = true + @index += match_len else - terminal_parse_failure("<") + terminal_parse_failure('"<"') r5 = nil end if r5 + r5 = SyntaxNode.new(input, (index-1)...index) if r5 == true r0 = r5 r0.extend(LogStash::Compiler::LSCL::AST::ComparisonOperator) else - if has_terminal?(">", false, index) - r6 = instantiate_node(SyntaxNode,input, index...(index + 1)) - @index += 1 + if (match_len = has_terminal?(">", false, index)) + r6 = true + @index += match_len else - terminal_parse_failure(">") + terminal_parse_failure('">"') r6 = nil end if r6 + r6 = SyntaxNode.new(input, (index-1)...index) if r6 == true r0 = r6 r0.extend(LogStash::Compiler::LSCL::AST::ComparisonOperator) else @@ -3232,7 +3300,7 @@ module LogStashCompilerLSCLGrammar if node_cache[:regexp_expression].has_key?(index) cached = node_cache[:regexp_expression][index] if cached - cached = SyntaxNode.new(input, index...(index + 1)) if cached == true + node_cache[:regexp_expression][index] = cached = SyntaxNode.new(input, index...(index + 1)) if cached == true @index = cached.interval.end end return cached @@ -3254,10 +3322,12 @@ module LogStashCompilerLSCLGrammar i5 = index r6 = _nt_string if r6 + r6 = SyntaxNode.new(input, (index-1)...index) if r6 == true r5 = r6 else r7 = _nt_regexp if r7 + r7 = SyntaxNode.new(input, (index-1)...index) if r7 == true r5 = r7 else @index = i5 @@ -3287,32 +3357,34 @@ module LogStashCompilerLSCLGrammar if node_cache[:regexp_operator].has_key?(index) cached = node_cache[:regexp_operator][index] if cached - cached = SyntaxNode.new(input, index...(index + 1)) if cached == true + node_cache[:regexp_operator][index] = cached = SyntaxNode.new(input, index...(index + 1)) if cached == true @index = cached.interval.end end return cached end i0 = index - if has_terminal?("=~", false, index) - r1 = instantiate_node(SyntaxNode,input, index...(index + 2)) - @index += 2 + if (match_len = has_terminal?("=~", false, index)) + r1 = instantiate_node(SyntaxNode,input, index...(index + match_len)) + @index += match_len else - terminal_parse_failure("=~") + terminal_parse_failure('"=~"') r1 = nil end if r1 + r1 = SyntaxNode.new(input, (index-1)...index) if r1 == true r0 = r1 r0.extend(LogStash::Compiler::LSCL::AST::RegExpOperator) else - if has_terminal?("!~", false, index) - r2 = instantiate_node(SyntaxNode,input, index...(index + 2)) - @index += 2 + if (match_len = has_terminal?("!~", false, index)) + r2 = instantiate_node(SyntaxNode,input, index...(index + match_len)) + @index += match_len else - terminal_parse_failure("!~") + terminal_parse_failure('"!~"') r2 = nil end if r2 + r2 = SyntaxNode.new(input, (index-1)...index) if r2 == true r0 = r2 r0.extend(LogStash::Compiler::LSCL::AST::RegExpOperator) else @@ -3331,54 +3403,58 @@ module LogStashCompilerLSCLGrammar if node_cache[:boolean_operator].has_key?(index) cached = node_cache[:boolean_operator][index] if cached - cached = SyntaxNode.new(input, index...(index + 1)) if cached == true + node_cache[:boolean_operator][index] = cached = SyntaxNode.new(input, index...(index + 1)) if cached == true @index = cached.interval.end end return cached end i0 = index - if has_terminal?("and", false, index) - r1 = instantiate_node(SyntaxNode,input, index...(index + 3)) - @index += 3 + if (match_len = has_terminal?("and", false, index)) + r1 = instantiate_node(SyntaxNode,input, index...(index + match_len)) + @index += match_len else - terminal_parse_failure("and") + terminal_parse_failure('"and"') r1 = nil end if r1 + r1 = SyntaxNode.new(input, (index-1)...index) if r1 == true r0 = r1 r0.extend(LogStash::Compiler::LSCL::AST::BooleanOperator) else - if has_terminal?("or", false, index) - r2 = instantiate_node(SyntaxNode,input, index...(index + 2)) - @index += 2 + if (match_len = has_terminal?("or", false, index)) + r2 = instantiate_node(SyntaxNode,input, index...(index + match_len)) + @index += match_len else - terminal_parse_failure("or") + terminal_parse_failure('"or"') r2 = nil end if r2 + r2 = SyntaxNode.new(input, (index-1)...index) if r2 == true r0 = r2 r0.extend(LogStash::Compiler::LSCL::AST::BooleanOperator) else - if has_terminal?("xor", false, index) - r3 = instantiate_node(SyntaxNode,input, index...(index + 3)) - @index += 3 + if (match_len = has_terminal?("xor", false, index)) + r3 = instantiate_node(SyntaxNode,input, index...(index + match_len)) + @index += match_len else - terminal_parse_failure("xor") + terminal_parse_failure('"xor"') r3 = nil end if r3 + r3 = SyntaxNode.new(input, (index-1)...index) if r3 == true r0 = r3 r0.extend(LogStash::Compiler::LSCL::AST::BooleanOperator) else - if has_terminal?("nand", false, index) - r4 = instantiate_node(SyntaxNode,input, index...(index + 4)) - @index += 4 + if (match_len = has_terminal?("nand", false, index)) + r4 = instantiate_node(SyntaxNode,input, index...(index + match_len)) + @index += match_len else - terminal_parse_failure("nand") + terminal_parse_failure('"nand"') r4 = nil end if r4 + r4 = SyntaxNode.new(input, (index-1)...index) if r4 == true r0 = r4 r0.extend(LogStash::Compiler::LSCL::AST::BooleanOperator) else @@ -3399,7 +3475,7 @@ module LogStashCompilerLSCLGrammar if node_cache[:selector].has_key?(index) cached = node_cache[:selector][index] if cached - cached = SyntaxNode.new(input, index...(index + 1)) if cached == true + node_cache[:selector][index] = cached = SyntaxNode.new(input, index...(index + 1)) if cached == true @index = cached.interval.end end return cached @@ -3434,28 +3510,29 @@ module LogStashCompilerLSCLGrammar if node_cache[:selector_element].has_key?(index) cached = node_cache[:selector_element][index] if cached - cached = SyntaxNode.new(input, index...(index + 1)) if cached == true + node_cache[:selector_element][index] = cached = SyntaxNode.new(input, index...(index + 1)) if cached == true @index = cached.interval.end end return cached end i0, s0 = index, [] - if has_terminal?("[", false, index) - r1 = instantiate_node(SyntaxNode,input, index...(index + 1)) - @index += 1 + if (match_len = has_terminal?("[", false, index)) + r1 = true + @index += match_len else - terminal_parse_failure("[") + terminal_parse_failure('"["') r1 = nil end s0 << r1 if r1 s2, i2 = [], index loop do - if has_terminal?('\G[^\\],]', true, index) + if has_terminal?(@regexps[gr = '\A[^\\],]'] ||= Regexp.new(gr), :regexp, index) r3 = true @index += 1 else + terminal_parse_failure('[^\\],]') r3 = nil end if r3 @@ -3472,11 +3549,11 @@ module LogStashCompilerLSCLGrammar end s0 << r2 if r2 - if has_terminal?("]", false, index) - r4 = instantiate_node(SyntaxNode,input, index...(index + 1)) - @index += 1 + if (match_len = has_terminal?("]", false, index)) + r4 = true + @index += match_len else - terminal_parse_failure("]") + terminal_parse_failure('"]"') r4 = nil end s0 << r4 diff --git a/logstash-core/lib/logstash/config/grammar.rb b/logstash-core/lib/logstash/config/grammar.rb index af56cf3a1..452626881 100644 --- a/logstash-core/lib/logstash/config/grammar.rb +++ b/logstash-core/lib/logstash/config/grammar.rb @@ -44,7 +44,7 @@ module LogStashConfig if node_cache[:config].has_key?(index) cached = node_cache[:config][index] if cached - cached = SyntaxNode.new(input, index...(index + 1)) if cached == true + node_cache[:config][index] = cached = SyntaxNode.new(input, index...(index + 1)) if cached == true @index = cached.interval.end end return cached @@ -112,7 +112,7 @@ module LogStashConfig if node_cache[:comment].has_key?(index) cached = node_cache[:comment][index] if cached - cached = SyntaxNode.new(input, index...(index + 1)) if cached == true + node_cache[:comment][index] = cached = SyntaxNode.new(input, index...(index + 1)) if cached == true @index = cached.interval.end end return cached @@ -129,21 +129,22 @@ module LogStashConfig end s1 << r2 if r2 - if has_terminal?("#", false, index) - r4 = instantiate_node(SyntaxNode,input, index...(index + 1)) - @index += 1 + if (match_len = has_terminal?("#", false, index)) + r4 = true + @index += match_len else - terminal_parse_failure("#") + terminal_parse_failure('"#"') r4 = nil end s1 << r4 if r4 s5, i5 = [], index loop do - if has_terminal?('\G[^\\r\\n]', true, index) + if has_terminal?(@regexps[gr = '\A[^\\r\\n]'] ||= Regexp.new(gr), :regexp, index) r6 = true @index += 1 else + terminal_parse_failure('[^\\r\\n]') r6 = nil end if r6 @@ -155,11 +156,11 @@ module LogStashConfig r5 = instantiate_node(SyntaxNode,input, i5...index, s5) s1 << r5 if r5 - if has_terminal?("\r", false, index) - r8 = instantiate_node(SyntaxNode,input, index...(index + 1)) - @index += 1 + if (match_len = has_terminal?("\r", false, index)) + r8 = true + @index += match_len else - terminal_parse_failure("\r") + terminal_parse_failure('"\\r"') r8 = nil end if r8 @@ -169,11 +170,11 @@ module LogStashConfig end s1 << r7 if r7 - if has_terminal?("\n", false, index) - r9 = instantiate_node(SyntaxNode,input, index...(index + 1)) - @index += 1 + if (match_len = has_terminal?("\n", false, index)) + r9 = true + @index += match_len else - terminal_parse_failure("\n") + terminal_parse_failure('"\\n"') r9 = nil end s1 << r9 @@ -211,7 +212,7 @@ module LogStashConfig if node_cache[:_].has_key?(index) cached = node_cache[:_][index] if cached - cached = SyntaxNode.new(input, index...(index + 1)) if cached == true + node_cache[:_][index] = cached = SyntaxNode.new(input, index...(index + 1)) if cached == true @index = cached.interval.end end return cached @@ -222,10 +223,12 @@ module LogStashConfig i1 = index r2 = _nt_comment if r2 + r2 = SyntaxNode.new(input, (index-1)...index) if r2 == true r1 = r2 else r3 = _nt_whitespace if r3 + r3 = SyntaxNode.new(input, (index-1)...index) if r3 == true r1 = r3 else @index = i1 @@ -250,7 +253,7 @@ module LogStashConfig if node_cache[:whitespace].has_key?(index) cached = node_cache[:whitespace][index] if cached - cached = SyntaxNode.new(input, index...(index + 1)) if cached == true + node_cache[:whitespace][index] = cached = SyntaxNode.new(input, index...(index + 1)) if cached == true @index = cached.interval.end end return cached @@ -258,10 +261,11 @@ module LogStashConfig s0, i0 = [], index loop do - if has_terminal?('\G[ \\t\\r\\n]', true, index) + if has_terminal?(@regexps[gr = '\A[ \\t\\r\\n]'] ||= Regexp.new(gr), :regexp, index) r1 = true @index += 1 else + terminal_parse_failure('[ \\t\\r\\n]') r1 = nil end if r1 @@ -312,7 +316,7 @@ module LogStashConfig if node_cache[:plugin_section].has_key?(index) cached = node_cache[:plugin_section][index] if cached - cached = SyntaxNode.new(input, index...(index + 1)) if cached == true + node_cache[:plugin_section][index] = cached = SyntaxNode.new(input, index...(index + 1)) if cached == true @index = cached.interval.end end return cached @@ -325,11 +329,11 @@ module LogStashConfig r2 = _nt__ s0 << r2 if r2 - if has_terminal?("{", false, index) - r3 = instantiate_node(SyntaxNode,input, index...(index + 1)) - @index += 1 + if (match_len = has_terminal?("{", false, index)) + r3 = true + @index += match_len else - terminal_parse_failure("{") + terminal_parse_failure('"{"') r3 = nil end s0 << r3 @@ -362,11 +366,11 @@ module LogStashConfig r5 = instantiate_node(SyntaxNode,input, i5...index, s5) s0 << r5 if r5 - if has_terminal?("}", false, index) - r9 = instantiate_node(SyntaxNode,input, index...(index + 1)) - @index += 1 + if (match_len = has_terminal?("}", false, index)) + r9 = true + @index += match_len else - terminal_parse_failure("}") + terminal_parse_failure('"}"') r9 = nil end s0 << r9 @@ -393,7 +397,7 @@ module LogStashConfig if node_cache[:branch_or_plugin].has_key?(index) cached = node_cache[:branch_or_plugin][index] if cached - cached = SyntaxNode.new(input, index...(index + 1)) if cached == true + node_cache[:branch_or_plugin][index] = cached = SyntaxNode.new(input, index...(index + 1)) if cached == true @index = cached.interval.end end return cached @@ -402,10 +406,12 @@ module LogStashConfig i0 = index r1 = _nt_branch if r1 + r1 = SyntaxNode.new(input, (index-1)...index) if r1 == true r0 = r1 else r2 = _nt_plugin if r2 + r2 = SyntaxNode.new(input, (index-1)...index) if r2 == true r0 = r2 else @index = i0 @@ -423,41 +429,44 @@ module LogStashConfig if node_cache[:plugin_type].has_key?(index) cached = node_cache[:plugin_type][index] if cached - cached = SyntaxNode.new(input, index...(index + 1)) if cached == true + node_cache[:plugin_type][index] = cached = SyntaxNode.new(input, index...(index + 1)) if cached == true @index = cached.interval.end end return cached end i0 = index - if has_terminal?("input", false, index) - r1 = instantiate_node(SyntaxNode,input, index...(index + 5)) - @index += 5 + if (match_len = has_terminal?("input", false, index)) + r1 = instantiate_node(SyntaxNode,input, index...(index + match_len)) + @index += match_len else - terminal_parse_failure("input") + terminal_parse_failure('"input"') r1 = nil end if r1 + r1 = SyntaxNode.new(input, (index-1)...index) if r1 == true r0 = r1 else - if has_terminal?("filter", false, index) - r2 = instantiate_node(SyntaxNode,input, index...(index + 6)) - @index += 6 + if (match_len = has_terminal?("filter", false, index)) + r2 = instantiate_node(SyntaxNode,input, index...(index + match_len)) + @index += match_len else - terminal_parse_failure("filter") + terminal_parse_failure('"filter"') r2 = nil end if r2 + r2 = SyntaxNode.new(input, (index-1)...index) if r2 == true r0 = r2 else - if has_terminal?("output", false, index) - r3 = instantiate_node(SyntaxNode,input, index...(index + 6)) - @index += 6 + if (match_len = has_terminal?("output", false, index)) + r3 = instantiate_node(SyntaxNode,input, index...(index + match_len)) + @index += match_len else - terminal_parse_failure("output") + terminal_parse_failure('"output"') r3 = nil end if r3 + r3 = SyntaxNode.new(input, (index-1)...index) if r3 == true r0 = r3 else @index = i0 @@ -493,7 +502,7 @@ module LogStashConfig if node_cache[:plugins].has_key?(index) cached = node_cache[:plugins][index] if cached - cached = SyntaxNode.new(input, index...(index + 1)) if cached == true + node_cache[:plugins][index] = cached = SyntaxNode.new(input, index...(index + 1)) if cached == true @index = cached.interval.end end return cached @@ -595,7 +604,7 @@ module LogStashConfig if node_cache[:plugin].has_key?(index) cached = node_cache[:plugin][index] if cached - cached = SyntaxNode.new(input, index...(index + 1)) if cached == true + node_cache[:plugin][index] = cached = SyntaxNode.new(input, index...(index + 1)) if cached == true @index = cached.interval.end end return cached @@ -608,11 +617,11 @@ module LogStashConfig r2 = _nt__ s0 << r2 if r2 - if has_terminal?("{", false, index) - r3 = instantiate_node(SyntaxNode,input, index...(index + 1)) - @index += 1 + if (match_len = has_terminal?("{", false, index)) + r3 = true + @index += match_len else - terminal_parse_failure("{") + terminal_parse_failure('"{"') r3 = nil end s0 << r3 @@ -670,11 +679,11 @@ module LogStashConfig r13 = _nt__ s0 << r13 if r13 - if has_terminal?("}", false, index) - r14 = instantiate_node(SyntaxNode,input, index...(index + 1)) - @index += 1 + if (match_len = has_terminal?("}", false, index)) + r14 = true + @index += match_len else - terminal_parse_failure("}") + terminal_parse_failure('"}"') r14 = nil end s0 << r14 @@ -702,7 +711,7 @@ module LogStashConfig if node_cache[:name].has_key?(index) cached = node_cache[:name][index] if cached - cached = SyntaxNode.new(input, index...(index + 1)) if cached == true + node_cache[:name][index] = cached = SyntaxNode.new(input, index...(index + 1)) if cached == true @index = cached.interval.end end return cached @@ -711,10 +720,11 @@ module LogStashConfig i0 = index s1, i1 = [], index loop do - if has_terminal?('\G[A-Za-z0-9_-]', true, index) + if has_terminal?(@regexps[gr = '\A[A-Za-z0-9_-]'] ||= Regexp.new(gr), :regexp, index) r2 = true @index += 1 else + terminal_parse_failure('[A-Za-z0-9_-]') r2 = nil end if r2 @@ -730,10 +740,12 @@ module LogStashConfig r1 = instantiate_node(LogStash::Config::AST::Name,input, i1...index, s1) end if r1 + r1 = SyntaxNode.new(input, (index-1)...index) if r1 == true r0 = r1 else r3 = _nt_string if r3 + r3 = SyntaxNode.new(input, (index-1)...index) if r3 == true r0 = r3 else @index = i0 @@ -769,7 +781,7 @@ module LogStashConfig if node_cache[:attribute].has_key?(index) cached = node_cache[:attribute][index] if cached - cached = SyntaxNode.new(input, index...(index + 1)) if cached == true + node_cache[:attribute][index] = cached = SyntaxNode.new(input, index...(index + 1)) if cached == true @index = cached.interval.end end return cached @@ -782,11 +794,11 @@ module LogStashConfig r2 = _nt__ s0 << r2 if r2 - if has_terminal?("=>", false, index) - r3 = instantiate_node(SyntaxNode,input, index...(index + 2)) - @index += 2 + if (match_len = has_terminal?("=>", false, index)) + r3 = instantiate_node(SyntaxNode,input, index...(index + match_len)) + @index += match_len else - terminal_parse_failure("=>") + terminal_parse_failure('"=>"') r3 = nil end s0 << r3 @@ -818,7 +830,7 @@ module LogStashConfig if node_cache[:value].has_key?(index) cached = node_cache[:value][index] if cached - cached = SyntaxNode.new(input, index...(index + 1)) if cached == true + node_cache[:value][index] = cached = SyntaxNode.new(input, index...(index + 1)) if cached == true @index = cached.interval.end end return cached @@ -827,26 +839,32 @@ module LogStashConfig i0 = index r1 = _nt_plugin if r1 + r1 = SyntaxNode.new(input, (index-1)...index) if r1 == true r0 = r1 else r2 = _nt_bareword if r2 + r2 = SyntaxNode.new(input, (index-1)...index) if r2 == true r0 = r2 else r3 = _nt_string if r3 + r3 = SyntaxNode.new(input, (index-1)...index) if r3 == true r0 = r3 else r4 = _nt_number if r4 + r4 = SyntaxNode.new(input, (index-1)...index) if r4 == true r0 = r4 else r5 = _nt_array if r5 + r5 = SyntaxNode.new(input, (index-1)...index) if r5 == true r0 = r5 else r6 = _nt_hash if r6 + r6 = SyntaxNode.new(input, (index-1)...index) if r6 == true r0 = r6 else @index = i0 @@ -868,7 +886,7 @@ module LogStashConfig if node_cache[:array_value].has_key?(index) cached = node_cache[:array_value][index] if cached - cached = SyntaxNode.new(input, index...(index + 1)) if cached == true + node_cache[:array_value][index] = cached = SyntaxNode.new(input, index...(index + 1)) if cached == true @index = cached.interval.end end return cached @@ -877,22 +895,27 @@ module LogStashConfig i0 = index r1 = _nt_bareword if r1 + r1 = SyntaxNode.new(input, (index-1)...index) if r1 == true r0 = r1 else r2 = _nt_string if r2 + r2 = SyntaxNode.new(input, (index-1)...index) if r2 == true r0 = r2 else r3 = _nt_number if r3 + r3 = SyntaxNode.new(input, (index-1)...index) if r3 == true r0 = r3 else r4 = _nt_array if r4 + r4 = SyntaxNode.new(input, (index-1)...index) if r4 == true r0 = r4 else r5 = _nt_hash if r5 + r5 = SyntaxNode.new(input, (index-1)...index) if r5 == true r0 = r5 else @index = i0 @@ -916,27 +939,29 @@ module LogStashConfig if node_cache[:bareword].has_key?(index) cached = node_cache[:bareword][index] if cached - cached = SyntaxNode.new(input, index...(index + 1)) if cached == true + node_cache[:bareword][index] = cached = SyntaxNode.new(input, index...(index + 1)) if cached == true @index = cached.interval.end end return cached end i0, s0 = index, [] - if has_terminal?('\G[A-Za-z_]', true, index) + if has_terminal?(@regexps[gr = '\A[A-Za-z_]'] ||= Regexp.new(gr), :regexp, index) r1 = true @index += 1 else + terminal_parse_failure('[A-Za-z_]') r1 = nil end s0 << r1 if r1 s2, i2 = [], index loop do - if has_terminal?('\G[A-Za-z0-9_]', true, index) + if has_terminal?(@regexps[gr = '\A[A-Za-z0-9_]'] ||= Regexp.new(gr), :regexp, index) r3 = true @index += 1 else + terminal_parse_failure('[A-Za-z0-9_]') r3 = nil end if r3 @@ -977,18 +1002,18 @@ module LogStashConfig if node_cache[:double_quoted_string].has_key?(index) cached = node_cache[:double_quoted_string][index] if cached - cached = SyntaxNode.new(input, index...(index + 1)) if cached == true + node_cache[:double_quoted_string][index] = cached = SyntaxNode.new(input, index...(index + 1)) if cached == true @index = cached.interval.end end return cached end i0, s0 = index, [] - if has_terminal?('"', false, index) - r1 = instantiate_node(SyntaxNode,input, index...(index + 1)) - @index += 1 + if (match_len = has_terminal?('"', false, index)) + r1 = true + @index += match_len else - terminal_parse_failure('"') + terminal_parse_failure('\'"\'') r1 = nil end s0 << r1 @@ -996,35 +1021,39 @@ module LogStashConfig s2, i2 = [], index loop do i3 = index - if has_terminal?('\"', false, index) - r4 = instantiate_node(SyntaxNode,input, index...(index + 2)) - @index += 2 + if (match_len = has_terminal?('\"', false, index)) + r4 = instantiate_node(SyntaxNode,input, index...(index + match_len)) + @index += match_len else - terminal_parse_failure('\"') + terminal_parse_failure('\'\\"\'') r4 = nil end if r4 + r4 = SyntaxNode.new(input, (index-1)...index) if r4 == true r3 = r4 else i5, s5 = index, [] i6 = index - if has_terminal?('"', false, index) - r7 = instantiate_node(SyntaxNode,input, index...(index + 1)) - @index += 1 + if (match_len = has_terminal?('"', false, index)) + r7 = true + @index += match_len else - terminal_parse_failure('"') + terminal_parse_failure('\'"\'') r7 = nil end if r7 + @index = i6 r6 = nil + terminal_parse_failure('\'"\'', true) else + @terminal_failures.pop @index = i6 r6 = instantiate_node(SyntaxNode,input, index...index) end s5 << r6 if r6 if index < input_length - r8 = instantiate_node(SyntaxNode,input, index...(index + 1)) + r8 = true @index += 1 else terminal_parse_failure("any character") @@ -1040,6 +1069,7 @@ module LogStashConfig r5 = nil end if r5 + r5 = SyntaxNode.new(input, (index-1)...index) if r5 == true r3 = r5 else @index = i3 @@ -1055,11 +1085,11 @@ module LogStashConfig r2 = instantiate_node(SyntaxNode,input, i2...index, s2) s0 << r2 if r2 - if has_terminal?('"', false, index) - r9 = instantiate_node(SyntaxNode,input, index...(index + 1)) - @index += 1 + if (match_len = has_terminal?('"', false, index)) + r9 = true + @index += match_len else - terminal_parse_failure('"') + terminal_parse_failure('\'"\'') r9 = nil end s0 << r9 @@ -1089,18 +1119,18 @@ module LogStashConfig if node_cache[:single_quoted_string].has_key?(index) cached = node_cache[:single_quoted_string][index] if cached - cached = SyntaxNode.new(input, index...(index + 1)) if cached == true + node_cache[:single_quoted_string][index] = cached = SyntaxNode.new(input, index...(index + 1)) if cached == true @index = cached.interval.end end return cached end i0, s0 = index, [] - if has_terminal?("'", false, index) - r1 = instantiate_node(SyntaxNode,input, index...(index + 1)) - @index += 1 + if (match_len = has_terminal?("'", false, index)) + r1 = true + @index += match_len else - terminal_parse_failure("'") + terminal_parse_failure('"\'"') r1 = nil end s0 << r1 @@ -1108,35 +1138,39 @@ module LogStashConfig s2, i2 = [], index loop do i3 = index - if has_terminal?("\\'", false, index) - r4 = instantiate_node(SyntaxNode,input, index...(index + 2)) - @index += 2 + if (match_len = has_terminal?("\\'", false, index)) + r4 = instantiate_node(SyntaxNode,input, index...(index + match_len)) + @index += match_len else - terminal_parse_failure("\\'") + terminal_parse_failure('"\\\\\'"') r4 = nil end if r4 + r4 = SyntaxNode.new(input, (index-1)...index) if r4 == true r3 = r4 else i5, s5 = index, [] i6 = index - if has_terminal?("'", false, index) - r7 = instantiate_node(SyntaxNode,input, index...(index + 1)) - @index += 1 + if (match_len = has_terminal?("'", false, index)) + r7 = true + @index += match_len else - terminal_parse_failure("'") + terminal_parse_failure('"\'"') r7 = nil end if r7 + @index = i6 r6 = nil + terminal_parse_failure('"\'"', true) else + @terminal_failures.pop @index = i6 r6 = instantiate_node(SyntaxNode,input, index...index) end s5 << r6 if r6 if index < input_length - r8 = instantiate_node(SyntaxNode,input, index...(index + 1)) + r8 = true @index += 1 else terminal_parse_failure("any character") @@ -1152,6 +1186,7 @@ module LogStashConfig r5 = nil end if r5 + r5 = SyntaxNode.new(input, (index-1)...index) if r5 == true r3 = r5 else @index = i3 @@ -1167,11 +1202,11 @@ module LogStashConfig r2 = instantiate_node(SyntaxNode,input, i2...index, s2) s0 << r2 if r2 - if has_terminal?("'", false, index) - r9 = instantiate_node(SyntaxNode,input, index...(index + 1)) - @index += 1 + if (match_len = has_terminal?("'", false, index)) + r9 = true + @index += match_len else - terminal_parse_failure("'") + terminal_parse_failure('"\'"') r9 = nil end s0 << r9 @@ -1195,7 +1230,7 @@ module LogStashConfig if node_cache[:string].has_key?(index) cached = node_cache[:string][index] if cached - cached = SyntaxNode.new(input, index...(index + 1)) if cached == true + node_cache[:string][index] = cached = SyntaxNode.new(input, index...(index + 1)) if cached == true @index = cached.interval.end end return cached @@ -1204,10 +1239,12 @@ module LogStashConfig i0 = index r1 = _nt_double_quoted_string if r1 + r1 = SyntaxNode.new(input, (index-1)...index) if r1 == true r0 = r1 else r2 = _nt_single_quoted_string if r2 + r2 = SyntaxNode.new(input, (index-1)...index) if r2 == true r0 = r2 else @index = i0 @@ -1231,18 +1268,18 @@ module LogStashConfig if node_cache[:regexp].has_key?(index) cached = node_cache[:regexp][index] if cached - cached = SyntaxNode.new(input, index...(index + 1)) if cached == true + node_cache[:regexp][index] = cached = SyntaxNode.new(input, index...(index + 1)) if cached == true @index = cached.interval.end end return cached end i0, s0 = index, [] - if has_terminal?('/', false, index) - r1 = instantiate_node(SyntaxNode,input, index...(index + 1)) - @index += 1 + if (match_len = has_terminal?('/', false, index)) + r1 = true + @index += match_len else - terminal_parse_failure('/') + terminal_parse_failure('\'/\'') r1 = nil end s0 << r1 @@ -1250,35 +1287,39 @@ module LogStashConfig s2, i2 = [], index loop do i3 = index - if has_terminal?('\/', false, index) - r4 = instantiate_node(SyntaxNode,input, index...(index + 2)) - @index += 2 + if (match_len = has_terminal?('\/', false, index)) + r4 = instantiate_node(SyntaxNode,input, index...(index + match_len)) + @index += match_len else - terminal_parse_failure('\/') + terminal_parse_failure('\'\\/\'') r4 = nil end if r4 + r4 = SyntaxNode.new(input, (index-1)...index) if r4 == true r3 = r4 else i5, s5 = index, [] i6 = index - if has_terminal?('/', false, index) - r7 = instantiate_node(SyntaxNode,input, index...(index + 1)) - @index += 1 + if (match_len = has_terminal?('/', false, index)) + r7 = true + @index += match_len else - terminal_parse_failure('/') + terminal_parse_failure('\'/\'') r7 = nil end if r7 + @index = i6 r6 = nil + terminal_parse_failure('\'/\'', true) else + @terminal_failures.pop @index = i6 r6 = instantiate_node(SyntaxNode,input, index...index) end s5 << r6 if r6 if index < input_length - r8 = instantiate_node(SyntaxNode,input, index...(index + 1)) + r8 = true @index += 1 else terminal_parse_failure("any character") @@ -1294,6 +1335,7 @@ module LogStashConfig r5 = nil end if r5 + r5 = SyntaxNode.new(input, (index-1)...index) if r5 == true r3 = r5 else @index = i3 @@ -1309,11 +1351,11 @@ module LogStashConfig r2 = instantiate_node(SyntaxNode,input, i2...index, s2) s0 << r2 if r2 - if has_terminal?('/', false, index) - r9 = instantiate_node(SyntaxNode,input, index...(index + 1)) - @index += 1 + if (match_len = has_terminal?('/', false, index)) + r9 = true + @index += match_len else - terminal_parse_failure('/') + terminal_parse_failure('\'/\'') r9 = nil end s0 << r9 @@ -1343,18 +1385,18 @@ module LogStashConfig if node_cache[:number].has_key?(index) cached = node_cache[:number][index] if cached - cached = SyntaxNode.new(input, index...(index + 1)) if cached == true + node_cache[:number][index] = cached = SyntaxNode.new(input, index...(index + 1)) if cached == true @index = cached.interval.end end return cached end i0, s0 = index, [] - if has_terminal?("-", false, index) - r2 = instantiate_node(SyntaxNode,input, index...(index + 1)) - @index += 1 + if (match_len = has_terminal?("-", false, index)) + r2 = true + @index += match_len else - terminal_parse_failure("-") + terminal_parse_failure('"-"') r2 = nil end if r2 @@ -1366,10 +1408,11 @@ module LogStashConfig if r1 s3, i3 = [], index loop do - if has_terminal?('\G[0-9]', true, index) + if has_terminal?(@regexps[gr = '\A[0-9]'] ||= Regexp.new(gr), :regexp, index) r4 = true @index += 1 else + terminal_parse_failure('[0-9]') r4 = nil end if r4 @@ -1387,21 +1430,22 @@ module LogStashConfig s0 << r3 if r3 i6, s6 = index, [] - if has_terminal?(".", false, index) - r7 = instantiate_node(SyntaxNode,input, index...(index + 1)) - @index += 1 + if (match_len = has_terminal?(".", false, index)) + r7 = true + @index += match_len else - terminal_parse_failure(".") + terminal_parse_failure('"."') r7 = nil end s6 << r7 if r7 s8, i8 = [], index loop do - if has_terminal?('\G[0-9]', true, index) + if has_terminal?(@regexps[gr = '\A[0-9]'] ||= Regexp.new(gr), :regexp, index) r9 = true @index += 1 else + terminal_parse_failure('[0-9]') r9 = nil end if r9 @@ -1478,18 +1522,18 @@ module LogStashConfig if node_cache[:array].has_key?(index) cached = node_cache[:array][index] if cached - cached = SyntaxNode.new(input, index...(index + 1)) if cached == true + node_cache[:array][index] = cached = SyntaxNode.new(input, index...(index + 1)) if cached == true @index = cached.interval.end end return cached end i0, s0 = index, [] - if has_terminal?("[", false, index) - r1 = instantiate_node(SyntaxNode,input, index...(index + 1)) - @index += 1 + if (match_len = has_terminal?("[", false, index)) + r1 = true + @index += match_len else - terminal_parse_failure("[") + terminal_parse_failure('"["') r1 = nil end s0 << r1 @@ -1507,11 +1551,11 @@ module LogStashConfig r8 = _nt__ s7 << r8 if r8 - if has_terminal?(",", false, index) - r9 = instantiate_node(SyntaxNode,input, index...(index + 1)) - @index += 1 + if (match_len = has_terminal?(",", false, index)) + r9 = true + @index += match_len else - terminal_parse_failure(",") + terminal_parse_failure('","') r9 = nil end s7 << r9 @@ -1557,11 +1601,11 @@ module LogStashConfig r12 = _nt__ s0 << r12 if r12 - if has_terminal?("]", false, index) - r13 = instantiate_node(SyntaxNode,input, index...(index + 1)) - @index += 1 + if (match_len = has_terminal?("]", false, index)) + r13 = true + @index += match_len else - terminal_parse_failure("]") + terminal_parse_failure('"]"') r13 = nil end s0 << r13 @@ -1598,18 +1642,18 @@ module LogStashConfig if node_cache[:hash].has_key?(index) cached = node_cache[:hash][index] if cached - cached = SyntaxNode.new(input, index...(index + 1)) if cached == true + node_cache[:hash][index] = cached = SyntaxNode.new(input, index...(index + 1)) if cached == true @index = cached.interval.end end return cached end i0, s0 = index, [] - if has_terminal?("{", false, index) - r1 = instantiate_node(SyntaxNode,input, index...(index + 1)) - @index += 1 + if (match_len = has_terminal?("{", false, index)) + r1 = true + @index += match_len else - terminal_parse_failure("{") + terminal_parse_failure('"{"') r1 = nil end s0 << r1 @@ -1628,11 +1672,11 @@ module LogStashConfig r5 = _nt__ s0 << r5 if r5 - if has_terminal?("}", false, index) - r6 = instantiate_node(SyntaxNode,input, index...(index + 1)) - @index += 1 + if (match_len = has_terminal?("}", false, index)) + r6 = true + @index += match_len else - terminal_parse_failure("}") + terminal_parse_failure('"}"') r6 = nil end s0 << r6 @@ -1675,7 +1719,7 @@ module LogStashConfig if node_cache[:hashentries].has_key?(index) cached = node_cache[:hashentries][index] if cached - cached = SyntaxNode.new(input, index...(index + 1)) if cached == true + node_cache[:hashentries][index] = cached = SyntaxNode.new(input, index...(index + 1)) if cached == true @index = cached.interval.end end return cached @@ -1746,7 +1790,7 @@ module LogStashConfig if node_cache[:hashentry].has_key?(index) cached = node_cache[:hashentry][index] if cached - cached = SyntaxNode.new(input, index...(index + 1)) if cached == true + node_cache[:hashentry][index] = cached = SyntaxNode.new(input, index...(index + 1)) if cached == true @index = cached.interval.end end return cached @@ -1756,14 +1800,17 @@ module LogStashConfig i1 = index r2 = _nt_number if r2 + r2 = SyntaxNode.new(input, (index-1)...index) if r2 == true r1 = r2 else r3 = _nt_bareword if r3 + r3 = SyntaxNode.new(input, (index-1)...index) if r3 == true r1 = r3 else r4 = _nt_string if r4 + r4 = SyntaxNode.new(input, (index-1)...index) if r4 == true r1 = r4 else @index = i1 @@ -1776,11 +1823,11 @@ module LogStashConfig r5 = _nt__ s0 << r5 if r5 - if has_terminal?("=>", false, index) - r6 = instantiate_node(SyntaxNode,input, index...(index + 2)) - @index += 2 + if (match_len = has_terminal?("=>", false, index)) + r6 = instantiate_node(SyntaxNode,input, index...(index + match_len)) + @index += match_len else - terminal_parse_failure("=>") + terminal_parse_failure('"=>"') r6 = nil end s0 << r6 @@ -1839,7 +1886,7 @@ module LogStashConfig if node_cache[:branch].has_key?(index) cached = node_cache[:branch][index] if cached - cached = SyntaxNode.new(input, index...(index + 1)) if cached == true + node_cache[:branch][index] = cached = SyntaxNode.new(input, index...(index + 1)) if cached == true @index = cached.interval.end end return cached @@ -1943,18 +1990,18 @@ module LogStashConfig if node_cache[:if].has_key?(index) cached = node_cache[:if][index] if cached - cached = SyntaxNode.new(input, index...(index + 1)) if cached == true + node_cache[:if][index] = cached = SyntaxNode.new(input, index...(index + 1)) if cached == true @index = cached.interval.end end return cached end i0, s0 = index, [] - if has_terminal?("if", false, index) - r1 = instantiate_node(SyntaxNode,input, index...(index + 2)) - @index += 2 + if (match_len = has_terminal?("if", false, index)) + r1 = instantiate_node(SyntaxNode,input, index...(index + match_len)) + @index += match_len else - terminal_parse_failure("if") + terminal_parse_failure('"if"') r1 = nil end s0 << r1 @@ -1968,11 +2015,11 @@ module LogStashConfig r4 = _nt__ s0 << r4 if r4 - if has_terminal?("{", false, index) - r5 = instantiate_node(SyntaxNode,input, index...(index + 1)) - @index += 1 + if (match_len = has_terminal?("{", false, index)) + r5 = true + @index += match_len else - terminal_parse_failure("{") + terminal_parse_failure('"{"') r5 = nil end s0 << r5 @@ -2005,11 +2052,11 @@ module LogStashConfig r7 = instantiate_node(SyntaxNode,input, i7...index, s7) s0 << r7 if r7 - if has_terminal?("}", false, index) - r11 = instantiate_node(SyntaxNode,input, index...(index + 1)) - @index += 1 + if (match_len = has_terminal?("}", false, index)) + r11 = true + @index += match_len else - terminal_parse_failure("}") + terminal_parse_failure('"}"') r11 = nil end s0 << r11 @@ -2071,18 +2118,18 @@ module LogStashConfig if node_cache[:else_if].has_key?(index) cached = node_cache[:else_if][index] if cached - cached = SyntaxNode.new(input, index...(index + 1)) if cached == true + node_cache[:else_if][index] = cached = SyntaxNode.new(input, index...(index + 1)) if cached == true @index = cached.interval.end end return cached end i0, s0 = index, [] - if has_terminal?("else", false, index) - r1 = instantiate_node(SyntaxNode,input, index...(index + 4)) - @index += 4 + if (match_len = has_terminal?("else", false, index)) + r1 = instantiate_node(SyntaxNode,input, index...(index + match_len)) + @index += match_len else - terminal_parse_failure("else") + terminal_parse_failure('"else"') r1 = nil end s0 << r1 @@ -2090,11 +2137,11 @@ module LogStashConfig r2 = _nt__ s0 << r2 if r2 - if has_terminal?("if", false, index) - r3 = instantiate_node(SyntaxNode,input, index...(index + 2)) - @index += 2 + if (match_len = has_terminal?("if", false, index)) + r3 = instantiate_node(SyntaxNode,input, index...(index + match_len)) + @index += match_len else - terminal_parse_failure("if") + terminal_parse_failure('"if"') r3 = nil end s0 << r3 @@ -2108,11 +2155,11 @@ module LogStashConfig r6 = _nt__ s0 << r6 if r6 - if has_terminal?("{", false, index) - r7 = instantiate_node(SyntaxNode,input, index...(index + 1)) - @index += 1 + if (match_len = has_terminal?("{", false, index)) + r7 = true + @index += match_len else - terminal_parse_failure("{") + terminal_parse_failure('"{"') r7 = nil end s0 << r7 @@ -2145,11 +2192,11 @@ module LogStashConfig r9 = instantiate_node(SyntaxNode,input, i9...index, s9) s0 << r9 if r9 - if has_terminal?("}", false, index) - r13 = instantiate_node(SyntaxNode,input, index...(index + 1)) - @index += 1 + if (match_len = has_terminal?("}", false, index)) + r13 = true + @index += match_len else - terminal_parse_failure("}") + terminal_parse_failure('"}"') r13 = nil end s0 << r13 @@ -2201,18 +2248,18 @@ module LogStashConfig if node_cache[:else].has_key?(index) cached = node_cache[:else][index] if cached - cached = SyntaxNode.new(input, index...(index + 1)) if cached == true + node_cache[:else][index] = cached = SyntaxNode.new(input, index...(index + 1)) if cached == true @index = cached.interval.end end return cached end i0, s0 = index, [] - if has_terminal?("else", false, index) - r1 = instantiate_node(SyntaxNode,input, index...(index + 4)) - @index += 4 + if (match_len = has_terminal?("else", false, index)) + r1 = instantiate_node(SyntaxNode,input, index...(index + match_len)) + @index += match_len else - terminal_parse_failure("else") + terminal_parse_failure('"else"') r1 = nil end s0 << r1 @@ -2220,11 +2267,11 @@ module LogStashConfig r2 = _nt__ s0 << r2 if r2 - if has_terminal?("{", false, index) - r3 = instantiate_node(SyntaxNode,input, index...(index + 1)) - @index += 1 + if (match_len = has_terminal?("{", false, index)) + r3 = true + @index += match_len else - terminal_parse_failure("{") + terminal_parse_failure('"{"') r3 = nil end s0 << r3 @@ -2257,11 +2304,11 @@ module LogStashConfig r5 = instantiate_node(SyntaxNode,input, i5...index, s5) s0 << r5 if r5 - if has_terminal?("}", false, index) - r9 = instantiate_node(SyntaxNode,input, index...(index + 1)) - @index += 1 + if (match_len = has_terminal?("}", false, index)) + r9 = true + @index += match_len else - terminal_parse_failure("}") + terminal_parse_failure('"}"') r9 = nil end s0 << r9 @@ -2313,7 +2360,7 @@ module LogStashConfig if node_cache[:condition].has_key?(index) cached = node_cache[:condition][index] if cached - cached = SyntaxNode.new(input, index...(index + 1)) if cached == true + node_cache[:condition][index] = cached = SyntaxNode.new(input, index...(index + 1)) if cached == true @index = cached.interval.end end return cached @@ -2389,7 +2436,7 @@ module LogStashConfig if node_cache[:expression].has_key?(index) cached = node_cache[:expression][index] if cached - cached = SyntaxNode.new(input, index...(index + 1)) if cached == true + node_cache[:expression][index] = cached = SyntaxNode.new(input, index...(index + 1)) if cached == true @index = cached.interval.end end return cached @@ -2397,11 +2444,11 @@ module LogStashConfig i0 = index i1, s1 = index, [] - if has_terminal?("(", false, index) - r2 = instantiate_node(SyntaxNode,input, index...(index + 1)) - @index += 1 + if (match_len = has_terminal?("(", false, index)) + r2 = true + @index += match_len else - terminal_parse_failure("(") + terminal_parse_failure('"("') r2 = nil end s1 << r2 @@ -2415,11 +2462,11 @@ module LogStashConfig r5 = _nt__ s1 << r5 if r5 - if has_terminal?(")", false, index) - r6 = instantiate_node(SyntaxNode,input, index...(index + 1)) - @index += 1 + if (match_len = has_terminal?(")", false, index)) + r6 = true + @index += match_len else - terminal_parse_failure(")") + terminal_parse_failure('")"') r6 = nil end s1 << r6 @@ -2435,36 +2482,43 @@ module LogStashConfig r1 = nil end if r1 + r1 = SyntaxNode.new(input, (index-1)...index) if r1 == true r0 = r1 r0.extend(LogStash::Config::AST::Expression) else r7 = _nt_negative_expression if r7 + r7 = SyntaxNode.new(input, (index-1)...index) if r7 == true r0 = r7 r0.extend(LogStash::Config::AST::Expression) else r8 = _nt_in_expression if r8 + r8 = SyntaxNode.new(input, (index-1)...index) if r8 == true r0 = r8 r0.extend(LogStash::Config::AST::Expression) else r9 = _nt_not_in_expression if r9 + r9 = SyntaxNode.new(input, (index-1)...index) if r9 == true r0 = r9 r0.extend(LogStash::Config::AST::Expression) else r10 = _nt_compare_expression if r10 + r10 = SyntaxNode.new(input, (index-1)...index) if r10 == true r0 = r10 r0.extend(LogStash::Config::AST::Expression) else r11 = _nt_regexp_expression if r11 + r11 = SyntaxNode.new(input, (index-1)...index) if r11 == true r0 = r11 r0.extend(LogStash::Config::AST::Expression) else r12 = _nt_rvalue if r12 + r12 = SyntaxNode.new(input, (index-1)...index) if r12 == true r0 = r12 r0.extend(LogStash::Config::AST::Expression) else @@ -2517,7 +2571,7 @@ module LogStashConfig if node_cache[:negative_expression].has_key?(index) cached = node_cache[:negative_expression][index] if cached - cached = SyntaxNode.new(input, index...(index + 1)) if cached == true + node_cache[:negative_expression][index] = cached = SyntaxNode.new(input, index...(index + 1)) if cached == true @index = cached.interval.end end return cached @@ -2525,11 +2579,11 @@ module LogStashConfig i0 = index i1, s1 = index, [] - if has_terminal?("!", false, index) - r2 = instantiate_node(SyntaxNode,input, index...(index + 1)) - @index += 1 + if (match_len = has_terminal?("!", false, index)) + r2 = true + @index += match_len else - terminal_parse_failure("!") + terminal_parse_failure('"!"') r2 = nil end s1 << r2 @@ -2537,11 +2591,11 @@ module LogStashConfig r3 = _nt__ s1 << r3 if r3 - if has_terminal?("(", false, index) - r4 = instantiate_node(SyntaxNode,input, index...(index + 1)) - @index += 1 + if (match_len = has_terminal?("(", false, index)) + r4 = true + @index += match_len else - terminal_parse_failure("(") + terminal_parse_failure('"("') r4 = nil end s1 << r4 @@ -2555,11 +2609,11 @@ module LogStashConfig r7 = _nt__ s1 << r7 if r7 - if has_terminal?(")", false, index) - r8 = instantiate_node(SyntaxNode,input, index...(index + 1)) - @index += 1 + if (match_len = has_terminal?(")", false, index)) + r8 = true + @index += match_len else - terminal_parse_failure(")") + terminal_parse_failure('")"') r8 = nil end s1 << r8 @@ -2577,15 +2631,16 @@ module LogStashConfig r1 = nil end if r1 + r1 = SyntaxNode.new(input, (index-1)...index) if r1 == true r0 = r1 r0.extend(LogStash::Config::AST::NegativeExpression) else i9, s9 = index, [] - if has_terminal?("!", false, index) - r10 = instantiate_node(SyntaxNode,input, index...(index + 1)) - @index += 1 + if (match_len = has_terminal?("!", false, index)) + r10 = true + @index += match_len else - terminal_parse_failure("!") + terminal_parse_failure('"!"') r10 = nil end s9 << r10 @@ -2605,6 +2660,7 @@ module LogStashConfig r9 = nil end if r9 + r9 = SyntaxNode.new(input, (index-1)...index) if r9 == true r0 = r9 r0.extend(LogStash::Config::AST::NegativeExpression) else @@ -2645,7 +2701,7 @@ module LogStashConfig if node_cache[:in_expression].has_key?(index) cached = node_cache[:in_expression][index] if cached - cached = SyntaxNode.new(input, index...(index + 1)) if cached == true + node_cache[:in_expression][index] = cached = SyntaxNode.new(input, index...(index + 1)) if cached == true @index = cached.interval.end end return cached @@ -2710,7 +2766,7 @@ module LogStashConfig if node_cache[:not_in_expression].has_key?(index) cached = node_cache[:not_in_expression][index] if cached - cached = SyntaxNode.new(input, index...(index + 1)) if cached == true + node_cache[:not_in_expression][index] = cached = SyntaxNode.new(input, index...(index + 1)) if cached == true @index = cached.interval.end end return cached @@ -2753,17 +2809,17 @@ module LogStashConfig if node_cache[:in_operator].has_key?(index) cached = node_cache[:in_operator][index] if cached - cached = SyntaxNode.new(input, index...(index + 1)) if cached == true + node_cache[:in_operator][index] = cached = SyntaxNode.new(input, index...(index + 1)) if cached == true @index = cached.interval.end end return cached end - if has_terminal?("in", false, index) - r0 = instantiate_node(SyntaxNode,input, index...(index + 2)) - @index += 2 + if (match_len = has_terminal?("in", false, index)) + r0 = instantiate_node(SyntaxNode,input, index...(index + match_len)) + @index += match_len else - terminal_parse_failure("in") + terminal_parse_failure('"in"') r0 = nil end @@ -2784,18 +2840,18 @@ module LogStashConfig if node_cache[:not_in_operator].has_key?(index) cached = node_cache[:not_in_operator][index] if cached - cached = SyntaxNode.new(input, index...(index + 1)) if cached == true + node_cache[:not_in_operator][index] = cached = SyntaxNode.new(input, index...(index + 1)) if cached == true @index = cached.interval.end end return cached end i0, s0 = index, [] - if has_terminal?("not ", false, index) - r1 = instantiate_node(SyntaxNode,input, index...(index + 4)) - @index += 4 + if (match_len = has_terminal?("not ", false, index)) + r1 = instantiate_node(SyntaxNode,input, index...(index + match_len)) + @index += match_len else - terminal_parse_failure("not ") + terminal_parse_failure('"not "') r1 = nil end s0 << r1 @@ -2803,11 +2859,11 @@ module LogStashConfig r2 = _nt__ s0 << r2 if r2 - if has_terminal?("in", false, index) - r3 = instantiate_node(SyntaxNode,input, index...(index + 2)) - @index += 2 + if (match_len = has_terminal?("in", false, index)) + r3 = instantiate_node(SyntaxNode,input, index...(index + match_len)) + @index += match_len else - terminal_parse_failure("in") + terminal_parse_failure('"in"') r3 = nil end s0 << r3 @@ -2831,7 +2887,7 @@ module LogStashConfig if node_cache[:rvalue].has_key?(index) cached = node_cache[:rvalue][index] if cached - cached = SyntaxNode.new(input, index...(index + 1)) if cached == true + node_cache[:rvalue][index] = cached = SyntaxNode.new(input, index...(index + 1)) if cached == true @index = cached.interval.end end return cached @@ -2840,26 +2896,32 @@ module LogStashConfig i0 = index r1 = _nt_string if r1 + r1 = SyntaxNode.new(input, (index-1)...index) if r1 == true r0 = r1 else r2 = _nt_number if r2 + r2 = SyntaxNode.new(input, (index-1)...index) if r2 == true r0 = r2 else r3 = _nt_selector if r3 + r3 = SyntaxNode.new(input, (index-1)...index) if r3 == true r0 = r3 else r4 = _nt_array if r4 + r4 = SyntaxNode.new(input, (index-1)...index) if r4 == true r0 = r4 else r5 = _nt_method_call if r5 + r5 = SyntaxNode.new(input, (index-1)...index) if r5 == true r0 = r5 else r6 = _nt_regexp if r6 + r6 = SyntaxNode.new(input, (index-1)...index) if r6 == true r0 = r6 else @index = i0 @@ -2921,7 +2983,7 @@ module LogStashConfig if node_cache[:method_call].has_key?(index) cached = node_cache[:method_call][index] if cached - cached = SyntaxNode.new(input, index...(index + 1)) if cached == true + node_cache[:method_call][index] = cached = SyntaxNode.new(input, index...(index + 1)) if cached == true @index = cached.interval.end end return cached @@ -2934,11 +2996,11 @@ module LogStashConfig r2 = _nt__ s0 << r2 if r2 - if has_terminal?("(", false, index) - r3 = instantiate_node(SyntaxNode,input, index...(index + 1)) - @index += 1 + if (match_len = has_terminal?("(", false, index)) + r3 = true + @index += match_len else - terminal_parse_failure("(") + terminal_parse_failure('"("') r3 = nil end s0 << r3 @@ -2956,11 +3018,11 @@ module LogStashConfig r10 = _nt__ s9 << r10 if r10 - if has_terminal?(",", false, index) - r11 = instantiate_node(SyntaxNode,input, index...(index + 1)) - @index += 1 + if (match_len = has_terminal?(",", false, index)) + r11 = true + @index += match_len else - terminal_parse_failure(",") + terminal_parse_failure('","') r11 = nil end s9 << r11 @@ -3006,11 +3068,11 @@ module LogStashConfig r14 = _nt__ s0 << r14 if r14 - if has_terminal?(")", false, index) - r15 = instantiate_node(SyntaxNode,input, index...(index + 1)) - @index += 1 + if (match_len = has_terminal?(")", false, index)) + r15 = true + @index += match_len else - terminal_parse_failure(")") + terminal_parse_failure('")"') r15 = nil end s0 << r15 @@ -3038,7 +3100,7 @@ module LogStashConfig if node_cache[:method].has_key?(index) cached = node_cache[:method][index] if cached - cached = SyntaxNode.new(input, index...(index + 1)) if cached == true + node_cache[:method][index] = cached = SyntaxNode.new(input, index...(index + 1)) if cached == true @index = cached.interval.end end return cached @@ -3078,7 +3140,7 @@ module LogStashConfig if node_cache[:compare_expression].has_key?(index) cached = node_cache[:compare_expression][index] if cached - cached = SyntaxNode.new(input, index...(index + 1)) if cached == true + node_cache[:compare_expression][index] = cached = SyntaxNode.new(input, index...(index + 1)) if cached == true @index = cached.interval.end end return cached @@ -3121,76 +3183,82 @@ module LogStashConfig if node_cache[:compare_operator].has_key?(index) cached = node_cache[:compare_operator][index] if cached - cached = SyntaxNode.new(input, index...(index + 1)) if cached == true + node_cache[:compare_operator][index] = cached = SyntaxNode.new(input, index...(index + 1)) if cached == true @index = cached.interval.end end return cached end i0 = index - if has_terminal?("==", false, index) - r1 = instantiate_node(SyntaxNode,input, index...(index + 2)) - @index += 2 + if (match_len = has_terminal?("==", false, index)) + r1 = instantiate_node(SyntaxNode,input, index...(index + match_len)) + @index += match_len else - terminal_parse_failure("==") + terminal_parse_failure('"=="') r1 = nil end if r1 + r1 = SyntaxNode.new(input, (index-1)...index) if r1 == true r0 = r1 r0.extend(LogStash::Config::AST::ComparisonOperator) else - if has_terminal?("!=", false, index) - r2 = instantiate_node(SyntaxNode,input, index...(index + 2)) - @index += 2 + if (match_len = has_terminal?("!=", false, index)) + r2 = instantiate_node(SyntaxNode,input, index...(index + match_len)) + @index += match_len else - terminal_parse_failure("!=") + terminal_parse_failure('"!="') r2 = nil end if r2 + r2 = SyntaxNode.new(input, (index-1)...index) if r2 == true r0 = r2 r0.extend(LogStash::Config::AST::ComparisonOperator) else - if has_terminal?("<=", false, index) - r3 = instantiate_node(SyntaxNode,input, index...(index + 2)) - @index += 2 + if (match_len = has_terminal?("<=", false, index)) + r3 = instantiate_node(SyntaxNode,input, index...(index + match_len)) + @index += match_len else - terminal_parse_failure("<=") + terminal_parse_failure('"<="') r3 = nil end if r3 + r3 = SyntaxNode.new(input, (index-1)...index) if r3 == true r0 = r3 r0.extend(LogStash::Config::AST::ComparisonOperator) else - if has_terminal?(">=", false, index) - r4 = instantiate_node(SyntaxNode,input, index...(index + 2)) - @index += 2 + if (match_len = has_terminal?(">=", false, index)) + r4 = instantiate_node(SyntaxNode,input, index...(index + match_len)) + @index += match_len else - terminal_parse_failure(">=") + terminal_parse_failure('">="') r4 = nil end if r4 + r4 = SyntaxNode.new(input, (index-1)...index) if r4 == true r0 = r4 r0.extend(LogStash::Config::AST::ComparisonOperator) else - if has_terminal?("<", false, index) - r5 = instantiate_node(SyntaxNode,input, index...(index + 1)) - @index += 1 + if (match_len = has_terminal?("<", false, index)) + r5 = true + @index += match_len else - terminal_parse_failure("<") + terminal_parse_failure('"<"') r5 = nil end if r5 + r5 = SyntaxNode.new(input, (index-1)...index) if r5 == true r0 = r5 r0.extend(LogStash::Config::AST::ComparisonOperator) else - if has_terminal?(">", false, index) - r6 = instantiate_node(SyntaxNode,input, index...(index + 1)) - @index += 1 + if (match_len = has_terminal?(">", false, index)) + r6 = true + @index += match_len else - terminal_parse_failure(">") + terminal_parse_failure('">"') r6 = nil end if r6 + r6 = SyntaxNode.new(input, (index-1)...index) if r6 == true r0 = r6 r0.extend(LogStash::Config::AST::ComparisonOperator) else @@ -3232,7 +3300,7 @@ module LogStashConfig if node_cache[:regexp_expression].has_key?(index) cached = node_cache[:regexp_expression][index] if cached - cached = SyntaxNode.new(input, index...(index + 1)) if cached == true + node_cache[:regexp_expression][index] = cached = SyntaxNode.new(input, index...(index + 1)) if cached == true @index = cached.interval.end end return cached @@ -3254,10 +3322,12 @@ module LogStashConfig i5 = index r6 = _nt_string if r6 + r6 = SyntaxNode.new(input, (index-1)...index) if r6 == true r5 = r6 else r7 = _nt_regexp if r7 + r7 = SyntaxNode.new(input, (index-1)...index) if r7 == true r5 = r7 else @index = i5 @@ -3287,32 +3357,34 @@ module LogStashConfig if node_cache[:regexp_operator].has_key?(index) cached = node_cache[:regexp_operator][index] if cached - cached = SyntaxNode.new(input, index...(index + 1)) if cached == true + node_cache[:regexp_operator][index] = cached = SyntaxNode.new(input, index...(index + 1)) if cached == true @index = cached.interval.end end return cached end i0 = index - if has_terminal?("=~", false, index) - r1 = instantiate_node(SyntaxNode,input, index...(index + 2)) - @index += 2 + if (match_len = has_terminal?("=~", false, index)) + r1 = instantiate_node(SyntaxNode,input, index...(index + match_len)) + @index += match_len else - terminal_parse_failure("=~") + terminal_parse_failure('"=~"') r1 = nil end if r1 + r1 = SyntaxNode.new(input, (index-1)...index) if r1 == true r0 = r1 r0.extend(LogStash::Config::AST::RegExpOperator) else - if has_terminal?("!~", false, index) - r2 = instantiate_node(SyntaxNode,input, index...(index + 2)) - @index += 2 + if (match_len = has_terminal?("!~", false, index)) + r2 = instantiate_node(SyntaxNode,input, index...(index + match_len)) + @index += match_len else - terminal_parse_failure("!~") + terminal_parse_failure('"!~"') r2 = nil end if r2 + r2 = SyntaxNode.new(input, (index-1)...index) if r2 == true r0 = r2 r0.extend(LogStash::Config::AST::RegExpOperator) else @@ -3331,54 +3403,58 @@ module LogStashConfig if node_cache[:boolean_operator].has_key?(index) cached = node_cache[:boolean_operator][index] if cached - cached = SyntaxNode.new(input, index...(index + 1)) if cached == true + node_cache[:boolean_operator][index] = cached = SyntaxNode.new(input, index...(index + 1)) if cached == true @index = cached.interval.end end return cached end i0 = index - if has_terminal?("and", false, index) - r1 = instantiate_node(SyntaxNode,input, index...(index + 3)) - @index += 3 + if (match_len = has_terminal?("and", false, index)) + r1 = instantiate_node(SyntaxNode,input, index...(index + match_len)) + @index += match_len else - terminal_parse_failure("and") + terminal_parse_failure('"and"') r1 = nil end if r1 + r1 = SyntaxNode.new(input, (index-1)...index) if r1 == true r0 = r1 r0.extend(LogStash::Config::AST::BooleanOperator) else - if has_terminal?("or", false, index) - r2 = instantiate_node(SyntaxNode,input, index...(index + 2)) - @index += 2 + if (match_len = has_terminal?("or", false, index)) + r2 = instantiate_node(SyntaxNode,input, index...(index + match_len)) + @index += match_len else - terminal_parse_failure("or") + terminal_parse_failure('"or"') r2 = nil end if r2 + r2 = SyntaxNode.new(input, (index-1)...index) if r2 == true r0 = r2 r0.extend(LogStash::Config::AST::BooleanOperator) else - if has_terminal?("xor", false, index) - r3 = instantiate_node(SyntaxNode,input, index...(index + 3)) - @index += 3 + if (match_len = has_terminal?("xor", false, index)) + r3 = instantiate_node(SyntaxNode,input, index...(index + match_len)) + @index += match_len else - terminal_parse_failure("xor") + terminal_parse_failure('"xor"') r3 = nil end if r3 + r3 = SyntaxNode.new(input, (index-1)...index) if r3 == true r0 = r3 r0.extend(LogStash::Config::AST::BooleanOperator) else - if has_terminal?("nand", false, index) - r4 = instantiate_node(SyntaxNode,input, index...(index + 4)) - @index += 4 + if (match_len = has_terminal?("nand", false, index)) + r4 = instantiate_node(SyntaxNode,input, index...(index + match_len)) + @index += match_len else - terminal_parse_failure("nand") + terminal_parse_failure('"nand"') r4 = nil end if r4 + r4 = SyntaxNode.new(input, (index-1)...index) if r4 == true r0 = r4 r0.extend(LogStash::Config::AST::BooleanOperator) else @@ -3399,7 +3475,7 @@ module LogStashConfig if node_cache[:selector].has_key?(index) cached = node_cache[:selector][index] if cached - cached = SyntaxNode.new(input, index...(index + 1)) if cached == true + node_cache[:selector][index] = cached = SyntaxNode.new(input, index...(index + 1)) if cached == true @index = cached.interval.end end return cached @@ -3434,28 +3510,29 @@ module LogStashConfig if node_cache[:selector_element].has_key?(index) cached = node_cache[:selector_element][index] if cached - cached = SyntaxNode.new(input, index...(index + 1)) if cached == true + node_cache[:selector_element][index] = cached = SyntaxNode.new(input, index...(index + 1)) if cached == true @index = cached.interval.end end return cached end i0, s0 = index, [] - if has_terminal?("[", false, index) - r1 = instantiate_node(SyntaxNode,input, index...(index + 1)) - @index += 1 + if (match_len = has_terminal?("[", false, index)) + r1 = true + @index += match_len else - terminal_parse_failure("[") + terminal_parse_failure('"["') r1 = nil end s0 << r1 if r1 s2, i2 = [], index loop do - if has_terminal?('\G[^\\],]', true, index) + if has_terminal?(@regexps[gr = '\A[^\\],]'] ||= Regexp.new(gr), :regexp, index) r3 = true @index += 1 else + terminal_parse_failure('[^\\],]') r3 = nil end if r3 @@ -3472,11 +3549,11 @@ module LogStashConfig end s0 << r2 if r2 - if has_terminal?("]", false, index) - r4 = instantiate_node(SyntaxNode,input, index...(index + 1)) - @index += 1 + if (match_len = has_terminal?("]", false, index)) + r4 = true + @index += match_len else - terminal_parse_failure("]") + terminal_parse_failure('"]"') r4 = nil end s0 << r4 From 08fd76ab300e6b3ee694a29ce4ce201064c737e5 Mon Sep 17 00:00:00 2001 From: Ry Biesemeyer Date: Mon, 7 Oct 2019 23:20:57 +0000 Subject: [PATCH 0245/1126] make pipeline grammars more accurately capture field references Certain malformed field reference literals (e.g., those containing a series of multiple open-brackets `[[`) were propagated undetected by the parser, only to create a crashing error when used. Starting Logstash with the `--config.test_and_exit` flag (or `-t` shorthand) would validate the config, even though it could not be used in practice. By updating the grammar(s) to exclude the use of an open square bracket (`[`), we more closely match the formal grammar and ensure these malformed literals are rejected closer to the source. NOTE: this PR only affects field reference _literals_, and does not resolve a similar issue with field references in quoted format strings. Resolves: https://github.com/elastic/logstash/issues/11022 Fixes #11195 --- logstash-core/lib/logstash/compiler/lscl/lscl_grammar.rb | 4 ++-- .../lib/logstash/compiler/lscl/lscl_grammar.treetop | 2 +- logstash-core/lib/logstash/config/grammar.rb | 4 ++-- logstash-core/lib/logstash/config/grammar.treetop | 2 +- logstash-core/spec/logstash/runner_spec.rb | 8 ++++++++ 5 files changed, 14 insertions(+), 6 deletions(-) diff --git a/logstash-core/lib/logstash/compiler/lscl/lscl_grammar.rb b/logstash-core/lib/logstash/compiler/lscl/lscl_grammar.rb index e215f0bfa..6befae201 100644 --- a/logstash-core/lib/logstash/compiler/lscl/lscl_grammar.rb +++ b/logstash-core/lib/logstash/compiler/lscl/lscl_grammar.rb @@ -3528,11 +3528,11 @@ module LogStashCompilerLSCLGrammar if r1 s2, i2 = [], index loop do - if has_terminal?(@regexps[gr = '\A[^\\],]'] ||= Regexp.new(gr), :regexp, index) + if has_terminal?(@regexps[gr = '\A[^\\]\\[,]'] ||= Regexp.new(gr), :regexp, index) r3 = true @index += 1 else - terminal_parse_failure('[^\\],]') + terminal_parse_failure('[^\\]\\[,]') r3 = nil end if r3 diff --git a/logstash-core/lib/logstash/compiler/lscl/lscl_grammar.treetop b/logstash-core/lib/logstash/compiler/lscl/lscl_grammar.treetop index 095c8e912..9463528a3 100644 --- a/logstash-core/lib/logstash/compiler/lscl/lscl_grammar.treetop +++ b/logstash-core/lib/logstash/compiler/lscl/lscl_grammar.treetop @@ -234,7 +234,7 @@ grammar LogStashCompilerLSCLGrammar end rule selector_element - "[" [^\],]+ "]" + "[" [^\]\[,]+ "]" end diff --git a/logstash-core/lib/logstash/config/grammar.rb b/logstash-core/lib/logstash/config/grammar.rb index 452626881..5e4effe51 100644 --- a/logstash-core/lib/logstash/config/grammar.rb +++ b/logstash-core/lib/logstash/config/grammar.rb @@ -3528,11 +3528,11 @@ module LogStashConfig if r1 s2, i2 = [], index loop do - if has_terminal?(@regexps[gr = '\A[^\\],]'] ||= Regexp.new(gr), :regexp, index) + if has_terminal?(@regexps[gr = '\A[^\\]\\[,]'] ||= Regexp.new(gr), :regexp, index) r3 = true @index += 1 else - terminal_parse_failure('[^\\],]') + terminal_parse_failure('[^\\]\\[,]') r3 = nil end if r3 diff --git a/logstash-core/lib/logstash/config/grammar.treetop b/logstash-core/lib/logstash/config/grammar.treetop index e46fc5530..710684dee 100644 --- a/logstash-core/lib/logstash/config/grammar.treetop +++ b/logstash-core/lib/logstash/config/grammar.treetop @@ -234,7 +234,7 @@ grammar LogStashConfig end rule selector_element - "[" [^\],]+ "]" + "[" [^\]\[,]+ "]" end diff --git a/logstash-core/spec/logstash/runner_spec.rb b/logstash-core/spec/logstash/runner_spec.rb index 7ed516144..6a591e308 100644 --- a/logstash-core/spec/logstash/runner_spec.rb +++ b/logstash-core/spec/logstash/runner_spec.rb @@ -147,6 +147,14 @@ describe LogStash::Runner do expect(subject.run(args)).to eq(1) end end + + context "with invalid field reference literal" do + let(:pipeline_string) { "input { } output { if [[f[[[oo] == [bar] { } }" } + it "should fail by returning a bad exit code" do + expect(logger).to receive(:fatal) + expect(subject.run(args)).to eq(1) + end + end end describe "pipeline settings" do let(:pipeline_string) { "input { stdin {} } output { stdout {} }" } From d278efda40fe0f8fbd7c269b6a4a3441a7a79685 Mon Sep 17 00:00:00 2001 From: Ry Biesemeyer Date: Mon, 14 Oct 2019 14:46:31 -0700 Subject: [PATCH 0246/1126] doc: replace unicode non-breaking hyphen U+8211 with ASCII hyphen Fixes #11217 --- docs/static/reloading-config.asciidoc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/static/reloading-config.asciidoc b/docs/static/reloading-config.asciidoc index 516fc18f5..7b5d520ce 100644 --- a/docs/static/reloading-config.asciidoc +++ b/docs/static/reloading-config.asciidoc @@ -9,7 +9,7 @@ command-line option specified. For example: [source,shell] ---------------------------------- -bin/logstash –f apache.config --config.reload.automatic +bin/logstash -f apache.config --config.reload.automatic ---------------------------------- NOTE: The `--config.reload.automatic` option is not available when you specify the `-e` flag to pass From 5a8cef4e8f73a25a626b3e9190ca75e6c82f8d86 Mon Sep 17 00:00:00 2001 From: Ry Biesemeyer Date: Tue, 15 Oct 2019 00:54:59 +0000 Subject: [PATCH 0247/1126] plugins: replace rabbitmq input/output with integration Fixes #11218 --- rakelib/plugins-metadata.json | 12 ++++++++---- 1 file changed, 8 insertions(+), 4 deletions(-) diff --git a/rakelib/plugins-metadata.json b/rakelib/plugins-metadata.json index f073fd749..c7c710f27 100644 --- a/rakelib/plugins-metadata.json +++ b/rakelib/plugins-metadata.json @@ -349,8 +349,8 @@ "skip-list": false }, "logstash-input-rabbitmq": { - "default-plugins": true, - "skip-list": false + "default-plugins": false, + "skip-list": true }, "logstash-input-rackspace": { "default-plugins": false, @@ -402,6 +402,10 @@ "default-plugins": true, "skip-list": false }, + "logstash-integration-rabbitmq": { + "default-plugins": true, + "skip-list": false + }, "logstash-output-cloudwatch": { "default-plugins": true, "skip-list": false @@ -482,8 +486,8 @@ "skip-list": false }, "logstash-output-rabbitmq": { - "default-plugins": true, - "skip-list": false + "default-plugins": false, + "skip-list": true }, "logstash-output-rackspace": { "default-plugins": false, From 1cf8a7b8d4f9a63db78ef376ba2dd9d2ead247d9 Mon Sep 17 00:00:00 2001 From: Ry Biesemeyer Date: Tue, 15 Oct 2019 00:55:55 +0000 Subject: [PATCH 0248/1126] plugins: replace kafka input/output with integration Fixes #11218 --- qa/integration/specs/cli/remove_spec.rb | 4 ++-- rakelib/plugins-metadata.json | 12 ++++++++---- 2 files changed, 10 insertions(+), 6 deletions(-) diff --git a/qa/integration/specs/cli/remove_spec.rb b/qa/integration/specs/cli/remove_spec.rb index b9bdcefd0..343b96849 100644 --- a/qa/integration/specs/cli/remove_spec.rb +++ b/qa/integration/specs/cli/remove_spec.rb @@ -45,7 +45,7 @@ describe "CLI > logstash-plugin remove" do expect(execute.exit_code).to eq(1) expect(execute.stderr_and_stdout).to match(/Failed to remove "logstash-codec-json"/) - expect(execute.stderr_and_stdout).to match(/logstash-input-kafka/) # one of the dependency + expect(execute.stderr_and_stdout).to match(/logstash-integration-kafka/) # one of the dependency expect(execute.stderr_and_stdout).to match(/logstash-output-udp/) # one of the dependency presence_check = @logstash_plugin.list("logstash-codec-json") @@ -78,7 +78,7 @@ describe "CLI > logstash-plugin remove" do expect(execute.exit_code).to eq(1) expect(execute.stderr_and_stdout).to match(/Failed to remove "logstash-codec-json"/) - expect(execute.stderr_and_stdout).to match(/logstash-input-kafka/) # one of the dependency + expect(execute.stderr_and_stdout).to match(/logstash-integration-kafka/) # one of the dependency expect(execute.stderr_and_stdout).to match(/logstash-output-udp/) # one of the dependency presence_check = @logstash_plugin.list("logstash-codec-json") diff --git a/rakelib/plugins-metadata.json b/rakelib/plugins-metadata.json index c7c710f27..25fe9d24d 100644 --- a/rakelib/plugins-metadata.json +++ b/rakelib/plugins-metadata.json @@ -329,8 +329,8 @@ "skip-list": true }, "logstash-input-kafka": { - "default-plugins": true, - "skip-list": false + "default-plugins": false, + "skip-list": true }, "logstash-input-log4j2": { "default-plugins": false, @@ -402,6 +402,10 @@ "default-plugins": true, "skip-list": false }, + "logstash-integration-kafka": { + "default-plugins": true, + "skip-list": false + }, "logstash-integration-rabbitmq": { "default-plugins": true, "skip-list": false @@ -453,8 +457,8 @@ "skip-list": true }, "logstash-output-kafka": { - "default-plugins": true, - "skip-list": false + "default-plugins": false, + "skip-list": true }, "logstash-output-logentries": { "default-plugins": false, From f63c6234bab5429405b4c965df0af03ade62c4c9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jo=C3=A3o=20Duarte?= Date: Wed, 16 Oct 2019 15:25:33 +0100 Subject: [PATCH 0249/1126] bump to 7.6.0 (#11224) --- README.md | 16 ++++++++-------- versions.yml | 4 ++-- 2 files changed, 10 insertions(+), 10 deletions(-) diff --git a/README.md b/README.md index 6aea530f6..ed72e329f 100644 --- a/README.md +++ b/README.md @@ -28,14 +28,14 @@ These builds are created nightly and have undergone no formal QA, so they should | [deb-complete][] | [deb-oss][] | | [rpm-complete][] | [rpm-oss][] | -[tar-complete]: https://snapshots.elastic.co/downloads/logstash/logstash-7.5.0-SNAPSHOT.tar.gz -[zip-complete]: https://snapshots.elastic.co/downloads/logstash/logstash-7.5.0-SNAPSHOT.zip -[deb-complete]: https://snapshots.elastic.co/downloads/logstash/logstash-7.5.0-SNAPSHOT.deb -[rpm-complete]: https://snapshots.elastic.co/downloads/logstash/logstash-7.5.0-SNAPSHOT.rpm -[tar-oss]: https://snapshots.elastic.co/downloads/logstash/logstash-oss-7.5.0-SNAPSHOT.tar.gz -[zip-oss]: https://snapshots.elastic.co/downloads/logstash/logstash-oss-7.5.0-SNAPSHOT.zip -[deb-oss]: https://snapshots.elastic.co/downloads/logstash/logstash-oss-7.5.0-SNAPSHOT.deb -[rpm-oss]: https://snapshots.elastic.co/downloads/logstash/logstash-oss-7.5.0-SNAPSHOT.rpm +[tar-complete]: https://snapshots.elastic.co/downloads/logstash/logstash-7.6.0-SNAPSHOT.tar.gz +[zip-complete]: https://snapshots.elastic.co/downloads/logstash/logstash-7.6.0-SNAPSHOT.zip +[deb-complete]: https://snapshots.elastic.co/downloads/logstash/logstash-7.6.0-SNAPSHOT.deb +[rpm-complete]: https://snapshots.elastic.co/downloads/logstash/logstash-7.6.0-SNAPSHOT.rpm +[tar-oss]: https://snapshots.elastic.co/downloads/logstash/logstash-oss-7.6.0-SNAPSHOT.tar.gz +[zip-oss]: https://snapshots.elastic.co/downloads/logstash/logstash-oss-7.6.0-SNAPSHOT.zip +[deb-oss]: https://snapshots.elastic.co/downloads/logstash/logstash-oss-7.6.0-SNAPSHOT.deb +[rpm-oss]: https://snapshots.elastic.co/downloads/logstash/logstash-oss-7.6.0-SNAPSHOT.rpm ## Need Help? diff --git a/versions.yml b/versions.yml index 88250ee09..d32ee88f1 100644 --- a/versions.yml +++ b/versions.yml @@ -1,7 +1,7 @@ --- # alpha and beta qualifiers are now added via VERSION_QUALIFIER environment var -logstash: 7.5.0 -logstash-core: 7.5.0 +logstash: 7.6.0 +logstash-core: 7.6.0 logstash-core-plugin-api: 2.1.16 # jruby must reference a *released* version of jruby which can be downloaded from the official download url From 391169b3d734d65ddac6327f775ee59c72d3c163 Mon Sep 17 00:00:00 2001 From: andsel Date: Wed, 16 Oct 2019 12:10:21 +0200 Subject: [PATCH 0250/1126] Fix to avoid Nashorn error regarding the unknown flag `--no-deprecation-warning` for JDK < 11. closes 11221 Fixes #11225 --- config/jvm.options | 3 --- .../src/main/java/org/logstash/Logstash.java | 11 +++++++++++ 2 files changed, 11 insertions(+), 3 deletions(-) diff --git a/config/jvm.options b/config/jvm.options index cebdf7984..2d743c8b3 100644 --- a/config/jvm.options +++ b/config/jvm.options @@ -79,6 +79,3 @@ # Copy the logging context from parent threads to children -Dlog4j2.isThreadContextMapInheritable=true - -# Avoid Nashorn deprecation logs in JDK > 11 --Dnashorn.args=--no-deprecation-warning \ No newline at end of file diff --git a/logstash-core/src/main/java/org/logstash/Logstash.java b/logstash-core/src/main/java/org/logstash/Logstash.java index 98f5c525a..cf156c856 100644 --- a/logstash-core/src/main/java/org/logstash/Logstash.java +++ b/logstash-core/src/main/java/org/logstash/Logstash.java @@ -38,6 +38,8 @@ public final class Logstash implements Runnable, AutoCloseable { "LS_HOME environment variable must be set. This is likely a bug that should be reported." ); } + configureNashornDeprecationSwitchForJavaAbove11(); + final Path home = Paths.get(lsHome).toAbsolutePath(); try ( final Logstash logstash = new Logstash(home, args, System.out, System.err, System.in) @@ -61,6 +63,15 @@ public final class Logstash implements Runnable, AutoCloseable { System.exit(0); } + private static void configureNashornDeprecationSwitchForJavaAbove11() { + final String javaVersion = System.getProperty("java.version"); + // match version 1.x.y, 9.x.y and 10.x.y + if (!javaVersion.matches("^1\\.\\d\\..*") && !javaVersion.matches("^(9|10)\\.\\d\\..*")) { + // Avoid Nashorn deprecation logs in JDK >= 11 + System.setProperty("nashorn.args", "--no-deprecation-warning"); + } + } + private static void handleCriticalError(Throwable t, String[] errorMessage) { LOGGER.error(t); if (errorMessage != null) { From 472d333ad97c76755198d0da53d8526069675732 Mon Sep 17 00:00:00 2001 From: Joao Duarte Date: Thu, 17 Oct 2019 12:27:12 +0100 Subject: [PATCH 0251/1126] more resilient testing of logging level setting Fixes #11230 --- qa/integration/specs/monitoring_api_spec.rb | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/qa/integration/specs/monitoring_api_spec.rb b/qa/integration/specs/monitoring_api_spec.rb index c40e5302b..0a3270988 100644 --- a/qa/integration/specs/monitoring_api_spec.rb +++ b/qa/integration/specs/monitoring_api_spec.rb @@ -129,10 +129,10 @@ describe "Test Monitoring API" do result = logstash_service.monitoring_api.logging_get result["loggers"].each do | k, v | #since we explicitly set the logstash.agent logger above, the logger.logstash parent logger will not take precedence - if k.eql?("logstash.agent") || k.start_with?("org.logstash") || k.eql?("org.reflections.Reflections") - expect(v).to eq("INFO") - else + if !k.eql?("logstash.agent") && (k.start_with?("logstash") || k.start_with?("slowlog")) expect(v).to eq("ERROR") + else + expect(v).to eq("INFO") end end From 2d868cfb65be0d6be4ccb7ad7a719ec2dcea6143 Mon Sep 17 00:00:00 2001 From: Karen Metts <35154725+karenzone@users.noreply.github.com> Date: Thu, 17 Oct 2019 10:21:51 -0400 Subject: [PATCH 0252/1126] Fix typo in doc-for-plugin Fixes #11232 --- docs/static/doc-for-plugin.asciidoc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/static/doc-for-plugin.asciidoc b/docs/static/doc-for-plugin.asciidoc index 9a10f5442..fc549ab1a 100644 --- a/docs/static/doc-for-plugin.asciidoc +++ b/docs/static/doc-for-plugin.asciidoc @@ -180,5 +180,5 @@ For tips on contributing and changelog guidelines, see https://github.com/elastic/logstash/blob/master/CONTRIBUTING.md#logstash-plugin-changelog-guidelines[CONTRIBUTING.md]. For general information about contributing, see -{logstash-ref}/contributing-to-logstash.html[Contributing to Logtash]. +{logstash-ref}/contributing-to-logstash.html[Contributing to Logstash]. From 0a89c4cee23776181ee6895970c3e5becd7e443f Mon Sep 17 00:00:00 2001 From: Ry Biesemeyer Date: Fri, 18 Oct 2019 00:26:54 +0000 Subject: [PATCH 0253/1126] validate plugin list output respecting integration plugins Fixes #11240 --- .../cli/logstash-plugin/list.rb | 22 +++++++++++++++++-- 1 file changed, 20 insertions(+), 2 deletions(-) diff --git a/qa/acceptance/spec/shared_examples/cli/logstash-plugin/list.rb b/qa/acceptance/spec/shared_examples/cli/logstash-plugin/list.rb index 5f1e00fd2..026897c69 100644 --- a/qa/acceptance/spec/shared_examples/cli/logstash-plugin/list.rb +++ b/qa/acceptance/spec/shared_examples/cli/logstash-plugin/list.rb @@ -13,6 +13,9 @@ shared_examples "logstash list" do |logstash| logstash.uninstall end + let(:plugin_name) { /logstash-(?\w+)-(?\w+)/ } + let(:plugin_name_with_version) { /#{plugin_name}\s\(\d+\.\d+.\d+(.\w+)?\)/ } + context "without a specific plugin" do it "display a list of plugins" do result = logstash.run_command_in_path("bin/logstash-plugin list") @@ -26,8 +29,23 @@ shared_examples "logstash list" do |logstash| it "list the plugins with their versions" do result = logstash.run_command_in_path("bin/logstash-plugin list --verbose") - result.stdout.split("\n").each do |plugin| - expect(plugin).to match(/^logstash-\w+-\w+\s\(\d+\.\d+.\d+(.\w+)?\)/) + + stdout = StringIO.new(result.stdout) + while line = stdout.gets + expect(line).to match(/^#{plugin_name_with_version}$/) + + # Integration Plugins list their sub-plugins, e.g., + # ~~~ + # logstash-integration-kafka (10.0.0) + # ├── logstash-input-kafka + # └── logstash-output-kafka + # ~~~ + if Regexp.last_match[:type] == 'integration' + while line = stdout.gets + expect(line).to match(/^(?: [├└]── )#{plugin_name}$/) + break if line.start_with?(' └') + end + end end end end From 331e8678c18fa888b3039d96b8d904f6570d3832 Mon Sep 17 00:00:00 2001 From: andsel Date: Fri, 18 Oct 2019 12:19:10 +0200 Subject: [PATCH 0254/1126] Fixes intermittent failing build due to Puma server going down bad on shutdown request Fixes #11242 --- qa/integration/specs/pipeline_log_spec.rb | 9 --------- 1 file changed, 9 deletions(-) diff --git a/qa/integration/specs/pipeline_log_spec.rb b/qa/integration/specs/pipeline_log_spec.rb index fcc18a395..37ee8424f 100644 --- a/qa/integration/specs/pipeline_log_spec.rb +++ b/qa/integration/specs/pipeline_log_spec.rb @@ -123,13 +123,4 @@ describe "Test Logstash Pipeline id" do end expect(@ls.exit_code).to be >= 0 end - - @private - def wait_logstash_process_terminate - num_retries = 100 - try(num_retries) do - expect(@ls.exited?).to be(true) - end - expect(@ls.exit_code).to be(0) - end end From e22868db52d7ff7ff7d9cf5326302b27cba011a6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jo=C3=A3o=20Duarte?= Date: Fri, 18 Oct 2019 12:22:03 +0100 Subject: [PATCH 0255/1126] Disable dlq integration tests due to multiple intermittent failures Fixes #11244 --- qa/integration/specs/dlq_spec.rb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/qa/integration/specs/dlq_spec.rb b/qa/integration/specs/dlq_spec.rb index 1b4db43c8..d31691776 100644 --- a/qa/integration/specs/dlq_spec.rb +++ b/qa/integration/specs/dlq_spec.rb @@ -39,7 +39,7 @@ describe "Test Dead Letter Queue" do let!(:settings_dir) { Stud::Temporary.directory } shared_examples_for "it can send 1000 documents to and index from the dlq" do - it 'should index all documents' do + xit 'should index all documents' do es_service = @fixture.get_service("elasticsearch") es_client = es_service.get_client # test if all data was indexed by ES, but first refresh manually From b9039dcb57f1e0a149f230b969173f9589270ac1 Mon Sep 17 00:00:00 2001 From: Joao Duarte Date: Fri, 18 Oct 2019 17:05:02 +0100 Subject: [PATCH 0256/1126] ensure output of plugin list is utf8 Fixes #11246 --- qa/acceptance/spec/shared_examples/cli/logstash-plugin/list.rb | 1 + 1 file changed, 1 insertion(+) diff --git a/qa/acceptance/spec/shared_examples/cli/logstash-plugin/list.rb b/qa/acceptance/spec/shared_examples/cli/logstash-plugin/list.rb index 026897c69..e8e0d1dac 100644 --- a/qa/acceptance/spec/shared_examples/cli/logstash-plugin/list.rb +++ b/qa/acceptance/spec/shared_examples/cli/logstash-plugin/list.rb @@ -31,6 +31,7 @@ shared_examples "logstash list" do |logstash| result = logstash.run_command_in_path("bin/logstash-plugin list --verbose") stdout = StringIO.new(result.stdout) + stdout.set_encoding(Encoding::UTF_8) while line = stdout.gets expect(line).to match(/^#{plugin_name_with_version}$/) From 382baf40167349609c73dcca7c2647f8e5dda27d Mon Sep 17 00:00:00 2001 From: lcawl Date: Thu, 17 Oct 2019 14:24:14 -0700 Subject: [PATCH 0257/1126] Fixes links to Stack Overview Fixes #11239 --- docs/static/azure-module.asciidoc | 2 +- docs/static/deploying.asciidoc | 2 +- docs/static/monitoring/monitoring-internal.asciidoc | 2 +- docs/static/monitoring/monitoring-mb.asciidoc | 6 +++--- docs/static/security/logstash.asciidoc | 2 +- 5 files changed, 7 insertions(+), 7 deletions(-) diff --git a/docs/static/azure-module.asciidoc b/docs/static/azure-module.asciidoc index 1f2028771..06c22d9e7 100644 --- a/docs/static/azure-module.asciidoc +++ b/docs/static/azure-module.asciidoc @@ -492,7 +492,7 @@ the event originated. ==== Deploying the module in production Use security best practices to secure your configuration. -See {stack-ov}/elasticsearch-security.html[Securing the {stack}] for details and recommendations. +See {ref}/secure-cluster.html[Secure a cluster] for details and recommendations. [[azure-resources]] ==== Microsoft Azure resources diff --git a/docs/static/deploying.asciidoc b/docs/static/deploying.asciidoc index 8813bd3c8..4f25da382 100644 --- a/docs/static/deploying.asciidoc +++ b/docs/static/deploying.asciidoc @@ -124,7 +124,7 @@ Enterprise-grade security is available across the entire delivery chain. * There’s a wealth of security options when communicating with Elasticsearch including basic authentication, TLS, PKI, LDAP, AD, and other custom realms. To enable Elasticsearch security, see -{stack-ov}/elasticsearch-security.html[Securing the {stack}]. +{ref}/secure-cluster.html[Secure a cluster]. [float] ==== Monitoring diff --git a/docs/static/monitoring/monitoring-internal.asciidoc b/docs/static/monitoring/monitoring-internal.asciidoc index 05773f1f7..86bfc27ec 100644 --- a/docs/static/monitoring/monitoring-internal.asciidoc +++ b/docs/static/monitoring/monitoring-internal.asciidoc @@ -58,7 +58,7 @@ is disabled in {es} and data is ignored from all other sources. . Configure your Logstash nodes to send metrics by setting the `xpack.monitoring.elasticsearch.hosts` in `logstash.yml`. If {security} is enabled, you also need to specify the credentials for the -{stack-ov}/built-in-users.html[built-in `logstash_system` user]. For more +{ref}/built-in-users.html[built-in `logstash_system` user]. For more information about these settings, see <>. + -- diff --git a/docs/static/monitoring/monitoring-mb.asciidoc b/docs/static/monitoring/monitoring-mb.asciidoc index 6281fbe5e..2272227cb 100644 --- a/docs/static/monitoring/monitoring-mb.asciidoc +++ b/docs/static/monitoring/monitoring-mb.asciidoc @@ -119,7 +119,7 @@ it using HTTPS. For example, use a `hosts` setting like `https://localhost:9600` ID and password so that {metricbeat} can collect metrics successfully: .. Create a user on the production cluster that has the -`remote_monitoring_collector` {stack-ov}/built-in-roles.html[built-in role]. +`remote_monitoring_collector` {ref}/built-in-roles.html[built-in role]. .. Add the `username` and `password` settings to the module configuration file (`logstash-xpack.yml`). @@ -180,9 +180,9 @@ must provide a valid user ID and password so that {metricbeat} can send metrics successfully: .. Create a user on the monitoring cluster that has the -`remote_monitoring_agent` {stack-ov}/built-in-roles.html[built-in role]. +`remote_monitoring_agent` {ref}/built-in-roles.html[built-in role]. Alternatively, use the `remote_monitoring_user` -{stack-ov}/built-in-users.html[built-in user]. +{ref}/built-in-users.html[built-in user]. + TIP: If you're using index lifecycle management, the remote monitoring user requires additional privileges to create and read indices. For more diff --git a/docs/static/security/logstash.asciidoc b/docs/static/security/logstash.asciidoc index 42c499196..58113c9a9 100644 --- a/docs/static/security/logstash.asciidoc +++ b/docs/static/security/logstash.asciidoc @@ -204,7 +204,7 @@ data to a secure cluster, you need to configure the username and password that Logstash uses to authenticate for shipping monitoring data. {security} comes preconfigured with a -{stack-ov}/built-in-users.html[`logstash_system` built-in user] +{ref}/built-in-users.html[`logstash_system` built-in user] for this purpose. This user has the minimum permissions necessary for the monitoring function, and _should not_ be used for any other purpose - it is specifically _not intended_ for use within a Logstash pipeline. From bb4b62d06efc5812f5c414316a4c94f4687772ce Mon Sep 17 00:00:00 2001 From: Joao Duarte Date: Fri, 18 Oct 2019 17:35:12 +0100 Subject: [PATCH 0258/1126] Revert "Update .ruby-version to jruby-9.2.8.0" This reverts commit 89479e00fb59c30ec3677f1c92616f49276e8152. Fixes #11248 --- .ruby-version | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.ruby-version b/.ruby-version index 4a6e0a691..87d3afa18 100644 --- a/.ruby-version +++ b/.ruby-version @@ -1 +1 @@ -jruby-9.2.8.0 +jruby-9.1.12.0 From 1c874854d9223c5c0e2c3c2862406edb958e0c94 Mon Sep 17 00:00:00 2001 From: Joao Duarte Date: Fri, 18 Oct 2019 11:15:32 +0100 Subject: [PATCH 0259/1126] upgrade puma to 4.x --- NOTICE.TXT | 2 +- logstash-core/logstash-core.gemspec | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/NOTICE.TXT b/NOTICE.TXT index f72c1c4ff..6289b9e8e 100644 --- a/NOTICE.TXT +++ b/NOTICE.TXT @@ -13009,7 +13009,7 @@ OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. -------------------------------------------------- -Library: puma v2.16.0 +Library: puma v4.2.1 Url: http://puma.io License: BSD-3-Clause diff --git a/logstash-core/logstash-core.gemspec b/logstash-core/logstash-core.gemspec index c2603b4f4..05b45491d 100644 --- a/logstash-core/logstash-core.gemspec +++ b/logstash-core/logstash-core.gemspec @@ -55,7 +55,7 @@ Gem::Specification.new do |gem| gem.add_runtime_dependency "concurrent-ruby", "~> 1" gem.add_runtime_dependency "rack", '~> 1', '>= 1.6.11' gem.add_runtime_dependency "sinatra", '~> 1', '>= 1.4.6' - gem.add_runtime_dependency 'puma', '~> 2' + gem.add_runtime_dependency 'puma', '~> 4' gem.add_runtime_dependency "jruby-openssl", "~> 0.10" # >= 0.9.13 Required to support TLSv1.2 gem.add_runtime_dependency "chronic_duration", "~> 0.10" From afe4f8189dd445026f76e6ff893bea6c4fb11f7b Mon Sep 17 00:00:00 2001 From: Joao Duarte Date: Fri, 30 Aug 2019 18:24:19 +0100 Subject: [PATCH 0260/1126] update core jars. remove dependency on org.eclipse Fixes #11103 --- logstash-core/build.gradle | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) diff --git a/logstash-core/build.gradle b/logstash-core/build.gradle index 5a5d5f51b..b9e555ac2 100644 --- a/logstash-core/build.gradle +++ b/logstash-core/build.gradle @@ -127,18 +127,18 @@ def customJRubyDir = project.hasProperty("custom.jruby.path") ? project.property def customJRubyVersion = customJRubyDir == "" ? "" : Files.readAllLines(Paths.get(customJRubyDir, "VERSION")).get(0).trim() dependencies { - compile 'org.apache.logging.log4j:log4j-api:2.11.1' - compile 'org.apache.logging.log4j:log4j-core:2.11.1' - runtime 'org.apache.logging.log4j:log4j-slf4j-impl:2.11.1' + compile 'org.apache.logging.log4j:log4j-api:2.12.1' + compile 'org.apache.logging.log4j:log4j-core:2.12.1' + runtime 'org.apache.logging.log4j:log4j-slf4j-impl:2.12.1' compile('org.reflections:reflections:0.9.11') { exclude group: 'com.google.guava', module: 'guava' } - compile 'commons-codec:commons-codec:1.11' + compile 'commons-codec:commons-codec:1.13' // Jackson version moved to versions.yml in the project root (the JrJackson version is there too) compile "com.fasterxml.jackson.core:jackson-core:${jacksonVersion}" compile "com.fasterxml.jackson.core:jackson-databind:${jacksonDatabindVersion}" compile "com.fasterxml.jackson.core:jackson-annotations:${jacksonVersion}" - compile 'org.codehaus.janino:janino:3.0.11' + compile 'org.codehaus.janino:janino:3.0.15' compile "com.fasterxml.jackson.dataformat:jackson-dataformat-cbor:${jacksonVersion}" if (customJRubyDir == "") { compile "org.jruby:jruby-complete:${jrubyVersion}" @@ -148,12 +148,12 @@ dependencies { compile group: 'com.google.guava', name: 'guava', version: '22.0' // Do not upgrade this, later versions require GPL licensed code in javac-shaded that is // Apache2 incompatible - compile('com.google.googlejavaformat:google-java-format:1.1') { + compile('com.google.googlejavaformat:google-java-format:1.7') { exclude group: 'com.google.guava', module: 'guava' } - compile 'org.javassist:javassist:3.24.0-GA' - compile 'com.google.guava:guava:20.0' - testCompile 'org.apache.logging.log4j:log4j-core:2.11.1:tests' + compile 'org.javassist:javassist:3.26.0-GA' + compile 'com.google.guava:guava:22.0' + testCompile 'org.apache.logging.log4j:log4j-core:2.12.1:tests' testCompile 'junit:junit:4.12' testCompile 'net.javacrumbs.json-unit:json-unit:2.3.0' testCompile 'org.elasticsearch:securemock:1.2' From 743723bf968d9bf4eec88deb5fc830804e13d7e1 Mon Sep 17 00:00:00 2001 From: Joao Duarte Date: Wed, 23 Oct 2019 10:30:25 +0100 Subject: [PATCH 0261/1126] update jar dependencies Fixes #11103 --- logstash-core/build.gradle | 4 ++-- .../logstash/config/ir/compiler/ComputeStepSyntaxElement.java | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/logstash-core/build.gradle b/logstash-core/build.gradle index b9e555ac2..e963df82d 100644 --- a/logstash-core/build.gradle +++ b/logstash-core/build.gradle @@ -138,7 +138,7 @@ dependencies { compile "com.fasterxml.jackson.core:jackson-core:${jacksonVersion}" compile "com.fasterxml.jackson.core:jackson-databind:${jacksonDatabindVersion}" compile "com.fasterxml.jackson.core:jackson-annotations:${jacksonVersion}" - compile 'org.codehaus.janino:janino:3.0.15' + compile 'org.codehaus.janino:janino:3.1.0' compile "com.fasterxml.jackson.dataformat:jackson-dataformat-cbor:${jacksonVersion}" if (customJRubyDir == "") { compile "org.jruby:jruby-complete:${jrubyVersion}" @@ -152,7 +152,7 @@ dependencies { exclude group: 'com.google.guava', module: 'guava' } compile 'org.javassist:javassist:3.26.0-GA' - compile 'com.google.guava:guava:22.0' + //compile 'com.google.guava:guava:22.0' testCompile 'org.apache.logging.log4j:log4j-core:2.12.1:tests' testCompile 'junit:junit:4.12' testCompile 'net.javacrumbs.json-unit:json-unit:2.3.0' diff --git a/logstash-core/src/main/java/org/logstash/config/ir/compiler/ComputeStepSyntaxElement.java b/logstash-core/src/main/java/org/logstash/config/ir/compiler/ComputeStepSyntaxElement.java index bfd3bf56a..33d3b14b4 100644 --- a/logstash-core/src/main/java/org/logstash/config/ir/compiler/ComputeStepSyntaxElement.java +++ b/logstash-core/src/main/java/org/logstash/config/ir/compiler/ComputeStepSyntaxElement.java @@ -15,8 +15,8 @@ import java.util.regex.Pattern; import java.util.stream.Collectors; import java.util.stream.StreamSupport; import org.codehaus.commons.compiler.CompileException; -import org.codehaus.commons.compiler.ICookable; import org.codehaus.commons.compiler.ISimpleCompiler; +import org.codehaus.janino.Scanner; import org.codehaus.janino.SimpleCompiler; /** @@ -132,7 +132,7 @@ public final class ComputeStepSyntaxElement { Path sourceDir = null; try { final Path parentDir; - final String dir = System.getProperty(ICookable.SYSTEM_PROPERTY_SOURCE_DEBUGGING_DIR); + final String dir = System.getProperty(Scanner.SYSTEM_PROPERTY_SOURCE_DEBUGGING_DIR); if (dir != null) { parentDir = Paths.get(dir); sourceDir = parentDir.resolve("org").resolve("logstash").resolve("generated"); From 4fd33e40aa2e0309f7845352af6ff9d33e336952 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jo=C3=A3o=20Duarte?= Date: Wed, 23 Oct 2019 11:07:31 +0100 Subject: [PATCH 0262/1126] Update logstash-core/build.gradle Fixes #11103 --- logstash-core/build.gradle | 1 - 1 file changed, 1 deletion(-) diff --git a/logstash-core/build.gradle b/logstash-core/build.gradle index e963df82d..d86742f13 100644 --- a/logstash-core/build.gradle +++ b/logstash-core/build.gradle @@ -152,7 +152,6 @@ dependencies { exclude group: 'com.google.guava', module: 'guava' } compile 'org.javassist:javassist:3.26.0-GA' - //compile 'com.google.guava:guava:22.0' testCompile 'org.apache.logging.log4j:log4j-core:2.12.1:tests' testCompile 'junit:junit:4.12' testCompile 'net.javacrumbs.json-unit:json-unit:2.3.0' From 5b5e47972583b55e1d98198de67dc2892ba0c5ee Mon Sep 17 00:00:00 2001 From: Karen Metts Date: Tue, 22 Oct 2019 16:19:12 -0400 Subject: [PATCH 0263/1126] Remove edit_me link overrides for monitoring topics Fixes #11259 --- docs/index.asciidoc | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/docs/index.asciidoc b/docs/index.asciidoc index 1be85a495..9a22a833e 100644 --- a/docs/index.asciidoc +++ b/docs/index.asciidoc @@ -186,13 +186,11 @@ include::static/deploying.asciidoc[] include::static/performance-checklist.asciidoc[] // Monitoring - -:edit_url: https://github.com/elastic/logstash/edit/{branch}/docs/static/monitoring.asciidoc +:edit_url!: include::static/monitoring/monitoring.asciidoc[] // X-Pack Monitoring - -//:edit_url: https://github.com/elastic/logstash/edit/{branch}/docs/static/monitoring/configuring-logstash.asciidoc +:edit_url!: include::static/monitoring/monitoring-overview.asciidoc[] From 6bf1ed932c4b37833561eccb76d38fabe98d30b8 Mon Sep 17 00:00:00 2001 From: Joao Duarte Date: Wed, 23 Oct 2019 16:18:47 +0100 Subject: [PATCH 0264/1126] improve reliability of webserver port binding use "127.0.0.1" instead of "localhost" to avoid binding to ipv4 and ipv6 don't assume port 10006 will be open in the machine rely on the ranges and the actual bound port for the assertions Fixes #11263 --- logstash-core/spec/logstash/webserver_spec.rb | 14 +++++++++----- 1 file changed, 9 insertions(+), 5 deletions(-) diff --git a/logstash-core/spec/logstash/webserver_spec.rb b/logstash-core/spec/logstash/webserver_spec.rb index a398e3eb8..285f922ba 100644 --- a/logstash-core/spec/logstash/webserver_spec.rb +++ b/logstash-core/spec/logstash/webserver_spec.rb @@ -12,7 +12,7 @@ def block_ports(range) range.each do |port| begin - server = TCPServer.new("localhost", port) + server = TCPServer.new("127.0.0.1", port) servers << server rescue => e # The port can already be taken @@ -45,7 +45,7 @@ describe LogStash::WebServer do subject { LogStash::WebServer.new(logger, agent, - { :http_host => "localhost", :http_ports => port_range })} + { :http_host => "127.0.0.1", :http_ports => port_range })} let(:port_range) { 10000..10010 } @@ -89,8 +89,9 @@ describe LogStash::WebServer do after(:each) { free_ports(@servers) } context "when we have available ports" do + let(:blocked_range) { 10000..10005 } before(:each) do - @servers = block_ports(10000..10005) + @servers = block_ports(blocked_range) end it "successfully find an available port" do @@ -99,10 +100,13 @@ describe LogStash::WebServer do end sleep(1) + address = subject.address + port = address.split(":").last.to_i + expect(port_range).to cover(port) + expect(blocked_range).to_not cover(port) - response = open("http://localhost:10006").read + response = open("http://#{address}").read expect { LogStash::Json.load(response) }.not_to raise_error - expect(subject.address).to eq("localhost:10006") subject.stop t.join From 382f6d76dd8293e62909632799b587c07293bbce Mon Sep 17 00:00:00 2001 From: Joao Duarte Date: Fri, 25 Oct 2019 09:33:57 +0100 Subject: [PATCH 0265/1126] remove logging setting in cgroup_spec.rb Fixes #11271 --- .../spec/logstash/instrument/periodic_poller/cgroup_spec.rb | 2 -- 1 file changed, 2 deletions(-) diff --git a/logstash-core/spec/logstash/instrument/periodic_poller/cgroup_spec.rb b/logstash-core/spec/logstash/instrument/periodic_poller/cgroup_spec.rb index 4a8eab8eb..735e6732e 100644 --- a/logstash-core/spec/logstash/instrument/periodic_poller/cgroup_spec.rb +++ b/logstash-core/spec/logstash/instrument/periodic_poller/cgroup_spec.rb @@ -2,8 +2,6 @@ require "logstash/instrument/periodic_poller/cgroup" require "spec_helper" -LogStash::Logging::Logger::configure_logging("DEBUG") - module LogStash module Instrument module PeriodicPoller describe "cgroup stats" do let(:relative_path) { "/docker/a1f61" } From 1f14cba3e3f52e34031229a3bfe993b31592c597 Mon Sep 17 00:00:00 2001 From: Joao Duarte Date: Fri, 25 Oct 2019 09:28:18 +0100 Subject: [PATCH 0266/1126] dont mutate SETTINGS object in keystore specs Fixes #11270 --- .../spec/logstash/util/secretstore_spec.rb | 19 ++++++++++--------- 1 file changed, 10 insertions(+), 9 deletions(-) diff --git a/logstash-core/spec/logstash/util/secretstore_spec.rb b/logstash-core/spec/logstash/util/secretstore_spec.rb index bb9221ad6..9ba0417bd 100644 --- a/logstash-core/spec/logstash/util/secretstore_spec.rb +++ b/logstash-core/spec/logstash/util/secretstore_spec.rb @@ -5,31 +5,32 @@ java_import "org.logstash.secret.store.SecretStoreExt" describe SecretStoreExt do subject {SecretStoreExt} + let(:settings) { LogStash::SETTINGS.clone } describe "with missing keystore" do before :each do - LogStash::SETTINGS.set("keystore.file", File.join(File.dirname(__FILE__), "nothing_here")) + settings.set("keystore.file", File.join(File.dirname(__FILE__), "nothing_here")) end it "should be not exist" do - expect(subject.exists(LogStash::SETTINGS.get_setting("keystore.file").value, LogStash::SETTINGS.get_setting("keystore.classname").value)).to be_falsey - expect(subject.getIfExists(LogStash::SETTINGS.get_setting("keystore.file").value, LogStash::SETTINGS.get_setting("keystore.classname").value)).to be_nil + expect(subject.exists(settings.get_setting("keystore.file").value, settings.get_setting("keystore.classname").value)).to be_falsey + expect(subject.getIfExists(settings.get_setting("keystore.file").value, settings.get_setting("keystore.classname").value)).to be_nil end end describe "with implicit password keystore" do before :each do - LogStash::SETTINGS.set("keystore.file", File.join(File.dirname(__FILE__), "../../../src/test/resources/logstash.keystore.with.default.pass")) + settings.set("keystore.file", File.join(File.dirname(__FILE__), "../../../src/test/resources/logstash.keystore.with.default.pass")) end it "should be readable" do - expect(subject.getIfExists(LogStash::SETTINGS.get_setting("keystore.file").value, LogStash::SETTINGS.get_setting("keystore.classname").value).list).to include(subject.get_store_id("keystore.seed")) + expect(subject.getIfExists(settings.get_setting("keystore.file").value, settings.get_setting("keystore.classname").value).list).to include(subject.get_store_id("keystore.seed")) end end describe "with explicit password keystore" do before :each do - LogStash::SETTINGS.set("keystore.file", File.join(File.dirname(__FILE__), "../../../src/test/resources/logstash.keystore.with.defined.pass")) + settings.set("keystore.file", File.join(File.dirname(__FILE__), "../../../src/test/resources/logstash.keystore.with.defined.pass")) end describe "and correct password" do @@ -42,7 +43,7 @@ describe SecretStoreExt do end it "should be readable" do - expect(subject.getIfExists(LogStash::SETTINGS.get_setting("keystore.file").value, LogStash::SETTINGS.get_setting("keystore.classname").value).list).to include(subject.get_store_id("keystore.seed")) + expect(subject.getIfExists(settings.get_setting("keystore.file").value, settings.get_setting("keystore.classname").value).list).to include(subject.get_store_id("keystore.seed")) end end @@ -56,13 +57,13 @@ describe SecretStoreExt do end it "should be not readable" do - expect {subject.getIfExists(LogStash::SETTINGS.get_setting("keystore.file").value, LogStash::SETTINGS.get_setting("keystore.classname").value)}.to raise_error.with_message(/Can not access Logstash keystore/) + expect {subject.getIfExists(settings.get_setting("keystore.file").value, settings.get_setting("keystore.classname").value)}.to raise_error.with_message(/Can not access Logstash keystore/) end end describe "and missing password" do it "should be not readable" do - expect {subject.getIfExists(LogStash::SETTINGS.get_setting("keystore.file").value, LogStash::SETTINGS.get_setting("keystore.classname").value)}.to raise_error.with_message(/Could not determine keystore password/) + expect {subject.getIfExists(settings.get_setting("keystore.file").value, settings.get_setting("keystore.classname").value)}.to raise_error.with_message(/Could not determine keystore password/) end end end From 81e7b18b25f30d99d5ec30b50889c41da32516f8 Mon Sep 17 00:00:00 2001 From: Joao Duarte Date: Sat, 26 Oct 2019 19:55:14 +0100 Subject: [PATCH 0267/1126] don't rely on expect match and last_match in qa test Fixes #11273 --- .../spec/shared_examples/cli/logstash-plugin/list.rb | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/qa/acceptance/spec/shared_examples/cli/logstash-plugin/list.rb b/qa/acceptance/spec/shared_examples/cli/logstash-plugin/list.rb index e8e0d1dac..1a04858e1 100644 --- a/qa/acceptance/spec/shared_examples/cli/logstash-plugin/list.rb +++ b/qa/acceptance/spec/shared_examples/cli/logstash-plugin/list.rb @@ -33,7 +33,8 @@ shared_examples "logstash list" do |logstash| stdout = StringIO.new(result.stdout) stdout.set_encoding(Encoding::UTF_8) while line = stdout.gets - expect(line).to match(/^#{plugin_name_with_version}$/) + match = line.match(/^#{plugin_name_with_version}$/) + expect(match).to_not be_nil # Integration Plugins list their sub-plugins, e.g., # ~~~ @@ -41,9 +42,10 @@ shared_examples "logstash list" do |logstash| # ├── logstash-input-kafka # └── logstash-output-kafka # ~~~ - if Regexp.last_match[:type] == 'integration' + if match[:type] == 'integration' while line = stdout.gets - expect(line).to match(/^(?: [├└]── )#{plugin_name}$/) + match = line.match(/^(?: [├└]── )#{plugin_name}$/) + expect(match).to_not be_nil break if line.start_with?(' └') end end From 3dd117a3453076e05333b97b49518b095ca09e34 Mon Sep 17 00:00:00 2001 From: "amitav.mohanty" Date: Thu, 31 Oct 2019 00:18:39 +0530 Subject: [PATCH 0268/1126] Mention the path of DLQ to indicate DLQ if full for which pipeline Fixes #11280 --- .../main/java/org/logstash/common/io/DeadLetterQueueWriter.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/logstash-core/src/main/java/org/logstash/common/io/DeadLetterQueueWriter.java b/logstash-core/src/main/java/org/logstash/common/io/DeadLetterQueueWriter.java index bc333bc70..d9159e201 100644 --- a/logstash-core/src/main/java/org/logstash/common/io/DeadLetterQueueWriter.java +++ b/logstash-core/src/main/java/org/logstash/common/io/DeadLetterQueueWriter.java @@ -131,7 +131,7 @@ public final class DeadLetterQueueWriter implements Closeable { byte[] record = entry.serialize(); int eventPayloadSize = RECORD_HEADER_SIZE + record.length; if (currentQueueSize.longValue() + eventPayloadSize > maxQueueSize) { - logger.error("cannot write event to DLQ: reached maxQueueSize of " + maxQueueSize); + logger.error("cannot write event to DLQ(path: " + this.queuePath + "): reached maxQueueSize of " + maxQueueSize); return; } else if (currentWriter.getPosition() + eventPayloadSize > maxSegmentSize) { currentWriter.close(); From 9b308ae67328413a26b8a95abd32e58ce04d8150 Mon Sep 17 00:00:00 2001 From: andsel Date: Wed, 23 Oct 2019 09:56:36 +0200 Subject: [PATCH 0269/1126] Introduced DeprecationLogger for use in core code and exposed to Java and Ruby plugins. Closes 11049 Fixes #11260 --- config/log4j2.properties | 26 +++++++ logstash-core/lib/logstash/plugin.rb | 1 + logstash-core/spec/logstash/plugin_spec.rb | 25 +++++++ .../java/co/elastic/logstash/api/Context.java | 7 ++ .../logstash/api/DeprecationLogger.java | 16 +++++ .../src/main/java/org/logstash/RubyUtil.java | 7 ++ .../log/DefaultDeprecationLogger.java | 48 +++++++++++++ .../logstash/log/DeprecationLoggerExt.java | 38 ++++++++++ .../java/org/logstash/log/LoggableExt.java | 33 ++++++++- .../org/logstash/plugins/ContextImpl.java | 14 ++-- .../log/DefaultDeprecationLoggerTest.java | 69 +++++++++++++++++++ .../java/org/logstash/log/LogTestUtils.java | 34 +++++++++ .../log/LogstashConfigurationFactoryTest.java | 29 ++------ .../log/PluginDeprecationLoggerTest.java | 61 ++++++++++++++++ .../log/SystemPropsSnapshotHelper.java | 36 ++++++++++ .../log/TestingDeprecationPlugin.java | 56 +++++++++++++++ .../org/logstash/plugins/TestContext.java | 11 +-- .../log4j2-log-deprecation-test.properties | 28 ++++++++ .../fixtures/deprecation_log_spec.yml | 17 +++++ qa/integration/specs/deprecation_log_spec.rb | 59 ++++++++++++++++ qa/integration/specs/monitoring_api_spec.rb | 5 +- 21 files changed, 581 insertions(+), 39 deletions(-) create mode 100644 logstash-core/src/main/java/co/elastic/logstash/api/DeprecationLogger.java create mode 100644 logstash-core/src/main/java/org/logstash/log/DefaultDeprecationLogger.java create mode 100644 logstash-core/src/main/java/org/logstash/log/DeprecationLoggerExt.java create mode 100644 logstash-core/src/test/java/org/logstash/log/DefaultDeprecationLoggerTest.java create mode 100644 logstash-core/src/test/java/org/logstash/log/LogTestUtils.java create mode 100644 logstash-core/src/test/java/org/logstash/log/PluginDeprecationLoggerTest.java create mode 100644 logstash-core/src/test/java/org/logstash/log/SystemPropsSnapshotHelper.java create mode 100644 logstash-core/src/test/java/org/logstash/log/TestingDeprecationPlugin.java create mode 100644 logstash-core/src/test/resources/log4j2-log-deprecation-test.properties create mode 100644 qa/integration/fixtures/deprecation_log_spec.yml create mode 100644 qa/integration/specs/deprecation_log_spec.rb diff --git a/config/log4j2.properties b/config/log4j2.properties index ca4342c50..19ec491ba 100644 --- a/config/log4j2.properties +++ b/config/log4j2.properties @@ -133,3 +133,29 @@ logger.slowlog.additivity = false logger.licensereader.name = logstash.licensechecker.licensereader logger.licensereader.level = error + +# Deprecation log +appender.deprecation_rolling.type = RollingFile +appender.deprecation_rolling.name = deprecation_plain_rolling +appender.deprecation_rolling.fileName = ${sys:ls.logs}/logstash-deprecation.log +appender.deprecation_rolling.filePattern = ${sys:ls.logs}/logstash-deprecation-%d{yyyy-MM-dd}-%i.log.gz +appender.deprecation_rolling.policies.type = Policies +appender.deprecation_rolling.policies.time.type = TimeBasedTriggeringPolicy +appender.deprecation_rolling.policies.time.interval = 1 +appender.deprecation_rolling.policies.time.modulate = true +appender.deprecation_rolling.layout.type = PatternLayout +appender.deprecation_rolling.layout.pattern = [%d{ISO8601}][%-5p][%-25c]%notEmpty{[%X{pipeline.id}]} %m%n +appender.deprecation_rolling.policies.size.type = SizeBasedTriggeringPolicy +appender.deprecation_rolling.policies.size.size = 100MB +appender.deprecation_rolling.strategy.type = DefaultRolloverStrategy +appender.deprecation_rolling.strategy.max = 30 + +logger.deprecation.name = org.logstash.deprecation, deprecation +logger.deprecation.level = WARN +logger.deprecation.appenderRef.deprecation_rolling.ref = deprecation_plain_rolling +logger.deprecation.additivity = false + +logger.deprecation_root.name = deprecation +logger.deprecation_root.level = WARN +logger.deprecation_root.appenderRef.deprecation_rolling.ref = deprecation_plain_rolling +logger.deprecation_root.additivity = false \ No newline at end of file diff --git a/logstash-core/lib/logstash/plugin.rb b/logstash-core/lib/logstash/plugin.rb index e332f6c00..1bf346446 100644 --- a/logstash-core/lib/logstash/plugin.rb +++ b/logstash-core/lib/logstash/plugin.rb @@ -46,6 +46,7 @@ class LogStash::Plugin def initialize(params=nil) @logger = self.logger + @deprecation_logger = self.deprecation_logger # need to access settings statically because plugins are initialized in config_ast with no context. settings = LogStash::SETTINGS @slow_logger = self.slow_logger(settings.get("slowlog.threshold.warn"), diff --git a/logstash-core/spec/logstash/plugin_spec.rb b/logstash-core/spec/logstash/plugin_spec.rb index 48497f09e..91808a98f 100644 --- a/logstash-core/spec/logstash/plugin_spec.rb +++ b/logstash-core/spec/logstash/plugin_spec.rb @@ -7,6 +7,15 @@ require "logstash/inputs/base" require "logstash/filters/base" require "support/shared_contexts" +class CustomFilterDeprecable < LogStash::Filters::Base + config_name "simple_plugin" + config :host, :validate => :string + + def register + @deprecation_logger.deprecated("Deprecated feature {}", "hydrocarbon car") + end +end + describe LogStash::Plugin do context "reloadable" do context "by default" do @@ -377,6 +386,22 @@ describe LogStash::Plugin do end end + describe "deprecation logger" do + let(:config) do + { + "host" => "127.0.0.1" + } + end + + context "when a plugin is registered" do + subject { CustomFilterDeprecable.new(config) } + + it "deprecation logger is available to be used" do + subject.register + expect(subject.deprecation_logger).not_to be_nil + end + end + end context "When the plugin record a metric" do let(:config) { {} } diff --git a/logstash-core/src/main/java/co/elastic/logstash/api/Context.java b/logstash-core/src/main/java/co/elastic/logstash/api/Context.java index 457903f5f..4fb6db6fc 100644 --- a/logstash-core/src/main/java/co/elastic/logstash/api/Context.java +++ b/logstash-core/src/main/java/co/elastic/logstash/api/Context.java @@ -29,6 +29,13 @@ public interface Context { */ Logger getLogger(Plugin plugin); + /** + * Provides a {@link Logger} instance to plugins. + * @param plugin The plugin for which the logger should be supplied. + * @return The supplied Logger instance. + */ + DeprecationLogger getDeprecationLogger(Plugin plugin); + /** * Provides an {@link EventFactory} to constructs instance of {@link Event}. * @return The event factory. diff --git a/logstash-core/src/main/java/co/elastic/logstash/api/DeprecationLogger.java b/logstash-core/src/main/java/co/elastic/logstash/api/DeprecationLogger.java new file mode 100644 index 000000000..61827aa2e --- /dev/null +++ b/logstash-core/src/main/java/co/elastic/logstash/api/DeprecationLogger.java @@ -0,0 +1,16 @@ +package co.elastic.logstash.api; + +/** + * Used to log deprecation notices. + * */ +public interface DeprecationLogger { + + /** + * Print to deprecation log the message with placeholder replaced by param values. The placeholder + * are {} form, like in log4j's syntax. + * + * @param message string message with parameter's placeholders. + * @param params var args with all the replacement parameters. + * */ + void deprecated(String message, Object... params); +} diff --git a/logstash-core/src/main/java/org/logstash/RubyUtil.java b/logstash-core/src/main/java/org/logstash/RubyUtil.java index 24fc92623..83b038b52 100644 --- a/logstash-core/src/main/java/org/logstash/RubyUtil.java +++ b/logstash-core/src/main/java/org/logstash/RubyUtil.java @@ -46,6 +46,7 @@ import org.logstash.instrument.metrics.NamespacedMetricExt; import org.logstash.instrument.metrics.NullMetricExt; import org.logstash.instrument.metrics.NullNamespacedMetricExt; import org.logstash.instrument.metrics.SnapshotExt; +import org.logstash.log.DeprecationLoggerExt; import org.logstash.log.LoggableExt; import org.logstash.log.LoggerExt; import org.logstash.log.SlowLoggerExt; @@ -177,6 +178,8 @@ public final class RubyUtil { public static final RubyModule LOGGABLE_MODULE; + public static final RubyClass DEPRECATION_LOGGER; + public static final RubyClass SLOW_LOGGER; public static final RubyModule UTIL_MODULE; @@ -446,6 +449,10 @@ public final class RubyUtil { SLOW_LOGGER = loggingModule.defineClassUnder( "SlowLogger", RUBY.getObject(), SlowLoggerExt::new); SLOW_LOGGER.defineAnnotatedMethods(SlowLoggerExt.class); + DEPRECATION_LOGGER = loggingModule.defineClassUnder( + "DeprecationLogger", RUBY.getObject(), DeprecationLoggerExt::new); + DEPRECATION_LOGGER.defineAnnotatedMethods(DeprecationLoggerExt.class); + LOGGABLE_MODULE = UTIL_MODULE.defineModuleUnder("Loggable"); LOGGABLE_MODULE.defineAnnotatedMethods(LoggableExt.class); ABSTRACT_PIPELINE_CLASS = diff --git a/logstash-core/src/main/java/org/logstash/log/DefaultDeprecationLogger.java b/logstash-core/src/main/java/org/logstash/log/DefaultDeprecationLogger.java new file mode 100644 index 000000000..e0c018912 --- /dev/null +++ b/logstash-core/src/main/java/org/logstash/log/DefaultDeprecationLogger.java @@ -0,0 +1,48 @@ +package org.logstash.log; + +import co.elastic.logstash.api.DeprecationLogger; +import org.apache.logging.log4j.LogManager; +import org.apache.logging.log4j.Logger; + +/** + * Logger used to output deprecation warnings. It handles specific log4j loggers + * + * Inspired by ElasticSearch's org.elasticsearch.common.logging.DeprecationLogger + * */ +public class DefaultDeprecationLogger implements DeprecationLogger { + + private final Logger logger; + + /** + * Creates a new deprecation logger based on the parent logger. Automatically + * prefixes the logger name with "deprecation", if it starts with "org.logstash.", + * it replaces "org.logstash" with "org.logstash.deprecation" to maintain + * the "org.logstash" namespace. + * + * @param parentLogger parent logger to decorate + */ + public DefaultDeprecationLogger(Logger parentLogger) { + String name = parentLogger.getName(); + name = reworkLoggerName(name); + this.logger = LogManager.getLogger(name); + } + + DefaultDeprecationLogger(String pluginName) { + String name = reworkLoggerName(pluginName); + this.logger = LogManager.getLogger(name); + } + + private String reworkLoggerName(String name) { + if (name.startsWith("org.logstash")) { + name = name.replace("org.logstash.", "org.logstash.deprecation."); + } else { + name = "deprecation." + name; + } + return name; + } + + @Override + public void deprecated(String message, Object... params) { + logger.warn(message, params); + } +} diff --git a/logstash-core/src/main/java/org/logstash/log/DeprecationLoggerExt.java b/logstash-core/src/main/java/org/logstash/log/DeprecationLoggerExt.java new file mode 100644 index 000000000..003df1ce4 --- /dev/null +++ b/logstash-core/src/main/java/org/logstash/log/DeprecationLoggerExt.java @@ -0,0 +1,38 @@ +package org.logstash.log; + +import co.elastic.logstash.api.DeprecationLogger; +import org.jruby.Ruby; +import org.jruby.RubyClass; +import org.jruby.RubyObject; +import org.jruby.anno.JRubyClass; +import org.jruby.anno.JRubyMethod; +import org.jruby.runtime.ThreadContext; +import org.jruby.runtime.builtin.IRubyObject; + +@JRubyClass(name = "DeprecationLogger") +public class DeprecationLoggerExt extends RubyObject { + + private static final long serialVersionUID = 1L; + + private DeprecationLogger logger; + + public DeprecationLoggerExt(final Ruby runtime, final RubyClass metaClass) { + super(runtime, metaClass); + } + + @JRubyMethod + public DeprecationLoggerExt initialize(final ThreadContext context, final IRubyObject loggerName) { + logger = new DefaultDeprecationLogger(loggerName.asJavaString()); + return this; + } + + @JRubyMethod(name = "deprecated", required = 1, optional = 1) + public IRubyObject rubyDeprecated(final ThreadContext context, final IRubyObject[] args) { + if (args.length > 1) { + logger.deprecated(args[0].asJavaString(), args[1]); + } else { + logger.deprecated(args[0].asJavaString()); + } + return this; + } +} diff --git a/logstash-core/src/main/java/org/logstash/log/LoggableExt.java b/logstash-core/src/main/java/org/logstash/log/LoggableExt.java index f16386238..7499dca62 100644 --- a/logstash-core/src/main/java/org/logstash/log/LoggableExt.java +++ b/logstash-core/src/main/java/org/logstash/log/LoggableExt.java @@ -1,15 +1,22 @@ package org.logstash.log; +import co.elastic.logstash.api.DeprecationLogger; +import org.apache.logging.log4j.LogManager; +import org.apache.logging.log4j.Logger; import org.jruby.RubyClass; import org.jruby.RubyModule; import org.jruby.RubyString; import org.jruby.anno.JRubyMethod; import org.jruby.anno.JRubyModule; +import org.jruby.javasupport.JavaUtil; import org.jruby.runtime.Block; import org.jruby.runtime.ThreadContext; import org.jruby.runtime.builtin.IRubyObject; import org.jruby.runtime.builtin.InstanceVariables; import org.logstash.RubyUtil; +import org.logstash.common.SourceWithMetadata; + +import static org.logstash.RubyUtil.RUBY; @JRubyModule(name = "Loggable") public final class LoggableExt { @@ -37,11 +44,16 @@ public final class LoggableExt { return self.getSingletonClass().callMethod(context, "slow_logger", args); } + @JRubyMethod(name= "deprecation_logger") + public static IRubyObject deprecationLogger(final ThreadContext context, final IRubyObject self) { + return self.getSingletonClass().callMethod(context, "deprecation_logger"); + } + private static RubyString log4jName(final ThreadContext context, final RubyModule self) { IRubyObject name = self.name19(); if (name.isNil()) { final RubyClass clazz; - if(self instanceof RubyClass) { + if (self instanceof RubyClass) { clazz = ((RubyClass) self).getRealClass(); } else { clazz = self.getMetaClass(); @@ -52,7 +64,7 @@ public final class LoggableExt { } } return ((RubyString) ((RubyString) name).gsub( - context, RubyUtil.RUBY.newString("::"), RubyUtil.RUBY.newString("."), + context, RUBY.newString("::"), RUBY.newString("."), Block.NULL_BLOCK )).downcase(context); } @@ -103,5 +115,22 @@ public final class LoggableExt { } return logger; } + + @JRubyMethod(name = "deprecation_logger", meta = true) + public static IRubyObject deprecationLogger(final ThreadContext context, final IRubyObject self) { + final InstanceVariables instanceVariables; + if (self instanceof RubyClass) { + instanceVariables = ((RubyClass) self).getRealClass().getInstanceVariables(); + } else { + instanceVariables = self.getInstanceVariables(); + } + IRubyObject logger = instanceVariables.getInstanceVariable("deprecation_logger"); + if (logger == null || logger.isNil()) { + logger = new DeprecationLoggerExt(context.runtime, RubyUtil.DEPRECATION_LOGGER) + .initialize(context, LoggableExt.log4jName(context, (RubyModule) self)); + instanceVariables.setInstanceVariable("deprecation_logger", logger); + } + return logger; + } } } diff --git a/logstash-core/src/main/java/org/logstash/plugins/ContextImpl.java b/logstash-core/src/main/java/org/logstash/plugins/ContextImpl.java index f795e3930..a1b5be8ce 100644 --- a/logstash-core/src/main/java/org/logstash/plugins/ContextImpl.java +++ b/logstash-core/src/main/java/org/logstash/plugins/ContextImpl.java @@ -1,15 +1,10 @@ package org.logstash.plugins; -import co.elastic.logstash.api.Context; -import co.elastic.logstash.api.DeadLetterQueueWriter; -import co.elastic.logstash.api.Event; -import co.elastic.logstash.api.EventFactory; -import co.elastic.logstash.api.Metric; -import co.elastic.logstash.api.NamespacedMetric; -import co.elastic.logstash.api.Plugin; +import co.elastic.logstash.api.*; import org.apache.logging.log4j.LogManager; import org.apache.logging.log4j.Logger; import org.logstash.ConvertedMap; +import org.logstash.log.DefaultDeprecationLogger; import java.io.Serializable; import java.util.Map; @@ -43,6 +38,11 @@ public class ContextImpl implements Context { return LogManager.getLogger(plugin.getClass()); } + @Override + public DeprecationLogger getDeprecationLogger(Plugin plugin) { + return new DefaultDeprecationLogger(getLogger(plugin)); + } + @Override public EventFactory getEventFactory() { return new EventFactory() { diff --git a/logstash-core/src/test/java/org/logstash/log/DefaultDeprecationLoggerTest.java b/logstash-core/src/test/java/org/logstash/log/DefaultDeprecationLoggerTest.java new file mode 100644 index 000000000..89ab17502 --- /dev/null +++ b/logstash-core/src/test/java/org/logstash/log/DefaultDeprecationLoggerTest.java @@ -0,0 +1,69 @@ +package org.logstash.log; + +import org.apache.logging.log4j.LogManager; +import org.junit.AfterClass; +import org.junit.Before; +import org.junit.BeforeClass; +import org.junit.Test; +import org.junit.After; + +import java.io.IOException; + +import static org.junit.Assert.assertTrue; + +public class DefaultDeprecationLoggerTest { + + private static final String CONFIG = "log4j2-log-deprecation-test.properties"; + private static SystemPropsSnapshotHelper snapshotHelper = new SystemPropsSnapshotHelper(); + + @BeforeClass + public static void beforeClass() { + snapshotHelper.takeSnapshot("log4j.configurationFile", "ls.log.format", "ls.logs", + LogstashConfigurationFactory.PIPELINE_SEPARATE_LOGS); + LogTestUtils.reloadLogConfiguration(); + } + + @AfterClass + public static void afterClass() { + snapshotHelper.restoreSnapshot("log4j.configurationFile", "ls.log.format", "ls.logs", + LogstashConfigurationFactory.PIPELINE_SEPARATE_LOGS); + } + + @Before + public void setUp() throws IOException { + System.setProperty("log4j.configurationFile", CONFIG); + System.setProperty("ls.log.format", "plain"); + System.setProperty("ls.logs", "build/logs"); + + LogTestUtils.deleteLogFile("logstash-deprecation.log"); + } + + @After + public void tearDown() throws IOException { + LogTestUtils.reloadLogConfiguration(); + + LogTestUtils.deleteLogFile("logstash-deprecation.log"); + } + + @Test + public void testDeprecationLoggerWriteOut_root() throws IOException { + final DefaultDeprecationLogger deprecationLogger = new DefaultDeprecationLogger(LogManager.getLogger("test")); + + // Exercise + deprecationLogger.deprecated("Simple deprecation message"); + + String logs = LogTestUtils.loadLogFileContent("logstash-deprecation.log"); + assertTrue("Deprecation logs MUST contains the out line", logs.matches(".*\\[deprecation\\.test.*\\].*Simple deprecation message")); + } + + @Test + public void testDeprecationLoggerWriteOut_nested() throws IOException { + final DefaultDeprecationLogger deprecationLogger = new DefaultDeprecationLogger(LogManager.getLogger("org.logstash.my_nested_logger")); + + // Exercise + deprecationLogger.deprecated("Simple deprecation message"); + + String logs = LogTestUtils.loadLogFileContent("logstash-deprecation.log"); + assertTrue("Deprecation logs MUST contains the out line", logs.matches(".*\\[org\\.logstash\\.deprecation\\.my_nested_logger.*\\].*Simple deprecation message")); + } +} \ No newline at end of file diff --git a/logstash-core/src/test/java/org/logstash/log/LogTestUtils.java b/logstash-core/src/test/java/org/logstash/log/LogTestUtils.java new file mode 100644 index 000000000..db76a8a60 --- /dev/null +++ b/logstash-core/src/test/java/org/logstash/log/LogTestUtils.java @@ -0,0 +1,34 @@ +package org.logstash.log; + +import org.apache.logging.log4j.core.LoggerContext; + +import java.io.IOException; +import java.nio.file.FileSystems; +import java.nio.file.Files; +import java.nio.file.Path; +import java.util.concurrent.TimeUnit; +import java.util.stream.Collectors; + +import static org.junit.Assert.assertTrue; + +class LogTestUtils { + + static String loadLogFileContent(String logfileName) throws IOException { + Path path = FileSystems.getDefault() + .getPath(System.getProperty("user.dir"), System.getProperty("ls.logs"), logfileName); + + assertTrue("Log [" + path.toString() + "] file MUST exists", Files.exists(path)); + return Files.lines(path).collect(Collectors.joining()); + } + + static void reloadLogConfiguration() { + LoggerContext context = LoggerContext.getContext(false); + context.stop(1, TimeUnit.SECONDS); // this forces the Log4j config to be discarded + } + + static void deleteLogFile(String logfileName) throws IOException { + Path path = FileSystems.getDefault() + .getPath(System.getProperty("user.dir"), System.getProperty("ls.logs"), logfileName); + Files.deleteIfExists(path); + } +} diff --git a/logstash-core/src/test/java/org/logstash/log/LogstashConfigurationFactoryTest.java b/logstash-core/src/test/java/org/logstash/log/LogstashConfigurationFactoryTest.java index edc3f0480..3102335eb 100644 --- a/logstash-core/src/test/java/org/logstash/log/LogstashConfigurationFactoryTest.java +++ b/logstash-core/src/test/java/org/logstash/log/LogstashConfigurationFactoryTest.java @@ -13,7 +13,6 @@ import org.apache.logging.log4j.core.LoggerContext; import org.apache.logging.log4j.test.appender.ListAppender; import org.junit.*; -import java.util.HashMap; import java.util.List; import java.util.Map; @@ -25,39 +24,21 @@ public class LogstashConfigurationFactoryTest { private static final String CONFIG = "log4j2-log-pipeline-test.properties"; - private static Map systemPropertiesDump = new HashMap<>(); private static Map dumpedLog4jThreadContext; + private static SystemPropsSnapshotHelper snapshotHelper = new SystemPropsSnapshotHelper(); @BeforeClass public static void beforeClass() { - dumpSystemProperty("log4j.configurationFile"); - dumpSystemProperty("ls.log.format"); - dumpSystemProperty("ls.logs"); - dumpSystemProperty(LogstashConfigurationFactory.PIPELINE_SEPARATE_LOGS); - + snapshotHelper.takeSnapshot("log4j.configurationFile", "ls.log.format", "ls.logs", + LogstashConfigurationFactory.PIPELINE_SEPARATE_LOGS); dumpedLog4jThreadContext = ThreadContext.getImmutableContext(); } - private static void dumpSystemProperty(String propertyName) { - systemPropertiesDump.put(propertyName, System.getProperty(propertyName)); - } - @AfterClass public static void afterClass() { ThreadContext.putAll(dumpedLog4jThreadContext); - - restoreSystemProperty("log4j.configurationFile"); - restoreSystemProperty("ls.log.format"); - restoreSystemProperty("ls.logs"); - restoreSystemProperty(LogstashConfigurationFactory.PIPELINE_SEPARATE_LOGS); - } - - private static void restoreSystemProperty(String propertyName) { - if (systemPropertiesDump.get(propertyName) == null) { - System.clearProperty(propertyName); - } else { - System.setProperty(propertyName, systemPropertiesDump.get(propertyName)); - } + snapshotHelper.restoreSnapshot("log4j.configurationFile", "ls.log.format", "ls.logs", + LogstashConfigurationFactory.PIPELINE_SEPARATE_LOGS); } @Before diff --git a/logstash-core/src/test/java/org/logstash/log/PluginDeprecationLoggerTest.java b/logstash-core/src/test/java/org/logstash/log/PluginDeprecationLoggerTest.java new file mode 100644 index 000000000..3d598355f --- /dev/null +++ b/logstash-core/src/test/java/org/logstash/log/PluginDeprecationLoggerTest.java @@ -0,0 +1,61 @@ +package org.logstash.log; + +import org.junit.*; +import org.logstash.Event; +import org.logstash.plugins.ConfigurationImpl; +import org.logstash.plugins.ContextImpl; + +import java.io.IOException; +import java.util.Collections; +import java.util.HashMap; +import java.util.Map; + +import static org.junit.Assert.assertTrue; + +public class PluginDeprecationLoggerTest { + + private static final String CONFIG = "log4j2-log-deprecation-test.properties"; + private static SystemPropsSnapshotHelper snapshotHelper = new SystemPropsSnapshotHelper(); + + @BeforeClass + public static void beforeClass() { + snapshotHelper.takeSnapshot("log4j.configurationFile", "ls.log.format", "ls.logs", + LogstashConfigurationFactory.PIPELINE_SEPARATE_LOGS); + LogTestUtils.reloadLogConfiguration(); + } + + @AfterClass + public static void afterClass() { + snapshotHelper.restoreSnapshot("log4j.configurationFile", "ls.log.format", "ls.logs", + LogstashConfigurationFactory.PIPELINE_SEPARATE_LOGS); + } + + @Before + public void setUp() throws IOException { + System.setProperty("log4j.configurationFile", CONFIG); + System.setProperty("ls.log.format", "plain"); + System.setProperty("ls.logs", "build/logs"); + + LogTestUtils.deleteLogFile("logstash-deprecation.log"); + } + + @After + public void tearDown() throws IOException { + LogTestUtils.reloadLogConfiguration(); + LogTestUtils.deleteLogFile("logstash-deprecation.log"); + } + + @Test + public void testJavaPluginUsesDeprecationLogger() throws IOException { + Map config = new HashMap<>(); + TestingDeprecationPlugin sut = new TestingDeprecationPlugin(new ConfigurationImpl(config), new ContextImpl(null, null)); + + // Exercise + Event evt = new Event(Collections.singletonMap("message", "Spock move me back")); + sut.encode(evt, null); + + // Verify + String logs = LogTestUtils.loadLogFileContent("logstash-deprecation.log"); + assertTrue("Deprecation logs MUST contains the out line", logs.matches(".*Deprecated feature teleportation")); + } +} diff --git a/logstash-core/src/test/java/org/logstash/log/SystemPropsSnapshotHelper.java b/logstash-core/src/test/java/org/logstash/log/SystemPropsSnapshotHelper.java new file mode 100644 index 000000000..c39014020 --- /dev/null +++ b/logstash-core/src/test/java/org/logstash/log/SystemPropsSnapshotHelper.java @@ -0,0 +1,36 @@ +package org.logstash.log; + +import java.util.HashMap; +import java.util.Map; + +/** + * Utility class to save & restore a specified list of System properties + * */ +class SystemPropsSnapshotHelper { + + private final Map systemPropertiesDump = new HashMap<>(); + + public void takeSnapshot(String... propertyNames) { + for (String propertyName : propertyNames) { + dumpSystemProperty(propertyName); + } + } + + public void restoreSnapshot(String... propertyNames) { + for (String propertyName : propertyNames) { + dumpSystemProperty(propertyName); + } + } + + private void dumpSystemProperty(String propertyName) { + systemPropertiesDump.put(propertyName, System.getProperty(propertyName)); + } + + private void restoreSystemProperty(String propertyName) { + if (systemPropertiesDump.get(propertyName) == null) { + System.clearProperty(propertyName); + } else { + System.setProperty(propertyName, systemPropertiesDump.get(propertyName)); + } + } +} diff --git a/logstash-core/src/test/java/org/logstash/log/TestingDeprecationPlugin.java b/logstash-core/src/test/java/org/logstash/log/TestingDeprecationPlugin.java new file mode 100644 index 000000000..c4622e2eb --- /dev/null +++ b/logstash-core/src/test/java/org/logstash/log/TestingDeprecationPlugin.java @@ -0,0 +1,56 @@ +package org.logstash.log; + +import co.elastic.logstash.api.*; + +import java.io.IOException; +import java.io.OutputStream; +import java.nio.ByteBuffer; +import java.util.Collection; +import java.util.Map; +import java.util.function.Consumer; + +@LogstashPlugin(name = "java_deprecation_plugin") +public class TestingDeprecationPlugin implements Codec { + + private final DeprecationLogger deprecationLogger; + + /** + * Required constructor. + * + * @param configuration Logstash Configuration + * @param context Logstash Context + */ + public TestingDeprecationPlugin(final Configuration configuration, final Context context) { + deprecationLogger = context.getDeprecationLogger(this); + } + + @Override + public Collection> configSchema() { + return null; + } + + @Override + public String getId() { + return null; + } + + @Override + public void decode(ByteBuffer buffer, Consumer> eventConsumer) { + + } + + @Override + public void flush(ByteBuffer buffer, Consumer> eventConsumer) { + + } + + @Override + public void encode(Event event, OutputStream output) throws IOException { + deprecationLogger.deprecated("Deprecated feature {}", "teleportation"); + } + + @Override + public Codec cloneCodec() { + return null; + } +} diff --git a/logstash-core/src/test/java/org/logstash/plugins/TestContext.java b/logstash-core/src/test/java/org/logstash/plugins/TestContext.java index 5fa3117c8..4966fe956 100644 --- a/logstash-core/src/test/java/org/logstash/plugins/TestContext.java +++ b/logstash-core/src/test/java/org/logstash/plugins/TestContext.java @@ -1,10 +1,6 @@ package org.logstash.plugins; -import co.elastic.logstash.api.Context; -import co.elastic.logstash.api.DeadLetterQueueWriter; -import co.elastic.logstash.api.EventFactory; -import co.elastic.logstash.api.NamespacedMetric; -import co.elastic.logstash.api.Plugin; +import co.elastic.logstash.api.*; import org.apache.logging.log4j.Logger; public class TestContext implements Context { @@ -24,6 +20,11 @@ public class TestContext implements Context { return null; } + @Override + public DeprecationLogger getDeprecationLogger(Plugin plugin) { + return null; + } + @Override public EventFactory getEventFactory() { return null; } diff --git a/logstash-core/src/test/resources/log4j2-log-deprecation-test.properties b/logstash-core/src/test/resources/log4j2-log-deprecation-test.properties new file mode 100644 index 000000000..6794c96e1 --- /dev/null +++ b/logstash-core/src/test/resources/log4j2-log-deprecation-test.properties @@ -0,0 +1,28 @@ +status = error +name = LogstashPropertiesConfig + +# Deprecation log +appender.deprecation_rolling.type = RollingFile +appender.deprecation_rolling.name = deprecation_plain_rolling +appender.deprecation_rolling.fileName = ${sys:ls.logs}/logstash-deprecation.log +appender.deprecation_rolling.filePattern = ${sys:ls.logs}/logstash-deprecation-%d{yyyy-MM-dd}-%i.log.gz +appender.deprecation_rolling.policies.type = Policies +appender.deprecation_rolling.policies.time.type = TimeBasedTriggeringPolicy +appender.deprecation_rolling.policies.time.interval = 1 +appender.deprecation_rolling.policies.time.modulate = true +appender.deprecation_rolling.layout.type = PatternLayout +appender.deprecation_rolling.layout.pattern = [%d{ISO8601}][%-5p][%-25c]%notEmpty{[%X{pipeline.id}]} %m%n +appender.deprecation_rolling.policies.size.type = SizeBasedTriggeringPolicy +appender.deprecation_rolling.policies.size.size = 100MB +appender.deprecation_rolling.strategy.type = DefaultRolloverStrategy +appender.deprecation_rolling.strategy.max = 30 + +logger.deprecation.name = org.logstash.deprecation +logger.deprecation.level = WARN +logger.deprecation.appenderRef.deprecation_rolling.ref = deprecation_plain_rolling +logger.deprecation.additivity = false + +logger.deprecation_root.name = deprecation +logger.deprecation_root.level = WARN +logger.deprecation_root.appenderRef.deprecation_rolling.ref = deprecation_plain_rolling +logger.deprecation_root.additivity = false diff --git a/qa/integration/fixtures/deprecation_log_spec.yml b/qa/integration/fixtures/deprecation_log_spec.yml new file mode 100644 index 000000000..93e3bc94a --- /dev/null +++ b/qa/integration/fixtures/deprecation_log_spec.yml @@ -0,0 +1,17 @@ +--- +services: + - logstash +config: |- + input { + generator { + count => 4 + } + } + filter { + ruby { + code => '@deprecation_logger.deprecated "Teleport"' + } + } + output { + null {} + } diff --git a/qa/integration/specs/deprecation_log_spec.rb b/qa/integration/specs/deprecation_log_spec.rb new file mode 100644 index 000000000..d80ed0873 --- /dev/null +++ b/qa/integration/specs/deprecation_log_spec.rb @@ -0,0 +1,59 @@ +require_relative '../framework/fixture' +require_relative '../framework/settings' +require_relative '../services/logstash_service' +require_relative '../framework/helpers' +require "logstash/devutils/rspec/spec_helper" +require "yaml" + +describe "Test Logstash Pipeline id" do + before(:all) { + @fixture = Fixture.new(__FILE__) + # used in multiple LS tests + @ls = @fixture.get_service("logstash") + } + + after(:all) { + @fixture.teardown + } + + before(:each) { + # backup the application settings file -- logstash.yml + FileUtils.cp(@ls.application_settings_file, "#{@ls.application_settings_file}.original") + } + + after(:each) { + @ls.teardown + # restore the application settings file -- logstash.yml + FileUtils.mv("#{@ls.application_settings_file}.original", @ls.application_settings_file) + } + + let(:temp_dir) { Stud::Temporary.directory("logstash-pipelinelog-test") } + let(:config) { @fixture.config("root") } + let(:initial_config_file) { config_to_temp_file(@fixture.config("root")) } + + it "should not create separate pipelines log files if not enabled" do + pipeline_name = "custom_pipeline" + settings = { + "path.logs" => temp_dir, + "pipeline.id" => pipeline_name, + "pipeline.separate_logs" => false + } + IO.write(@ls.application_settings_file, settings.to_yaml) + @ls.spawn_logstash("-w", "1" , "-e", config) + wait_logstash_process_terminate + + deprecation_log_file = "#{temp_dir}/logstash-deprecation.log" + expect(File.exists?(deprecation_log_file)).to be true + deprecation_log_content = IO.read(deprecation_log_file) + expect(deprecation_log_content =~ /\[deprecation.logstash.filters.ruby\].*Teleport/).to be > 0 + end + + @private + def wait_logstash_process_terminate + num_retries = 100 + try(num_retries) do + expect(@ls.exited?).to be(true) + end + expect(@ls.exit_code).to be >= 0 + end +end diff --git a/qa/integration/specs/monitoring_api_spec.rb b/qa/integration/specs/monitoring_api_spec.rb index 0a3270988..426263010 100644 --- a/qa/integration/specs/monitoring_api_spec.rb +++ b/qa/integration/specs/monitoring_api_spec.rb @@ -126,10 +126,13 @@ describe "Test Monitoring API" do logging_put_assert logstash_service.monitoring_api.logging_put({"logger.logstash" => "ERROR"}) logging_put_assert logstash_service.monitoring_api.logging_put({"logger.slowlog" => "ERROR"}) + #deprecation package loggers + logging_put_assert logstash_service.monitoring_api.logging_put({"logger.deprecation.logstash" => "ERROR"}) + result = logstash_service.monitoring_api.logging_get result["loggers"].each do | k, v | #since we explicitly set the logstash.agent logger above, the logger.logstash parent logger will not take precedence - if !k.eql?("logstash.agent") && (k.start_with?("logstash") || k.start_with?("slowlog")) + if !k.eql?("logstash.agent") && (k.start_with?("logstash") || k.start_with?("slowlog") || k.start_with?("deprecation")) expect(v).to eq("ERROR") else expect(v).to eq("INFO") From 4654b605074957064c2e521f17c9316fbc3bc145 Mon Sep 17 00:00:00 2001 From: Karen Metts Date: Fri, 15 Nov 2019 20:37:39 -0500 Subject: [PATCH 0270/1126] Restructure configuration content Fixes #11310 --- docs/index.asciidoc | 31 +++++++++++-------- docs/static/configuration-advanced.asciidoc | 6 ++++ docs/static/pipeline-pipeline-config.asciidoc | 2 +- 3 files changed, 25 insertions(+), 14 deletions(-) create mode 100644 docs/static/configuration-advanced.asciidoc diff --git a/docs/index.asciidoc b/docs/index.asciidoc index 9a22a833e..d3386f2e1 100644 --- a/docs/index.asciidoc +++ b/docs/index.asciidoc @@ -94,40 +94,45 @@ include::static/upgrading.asciidoc[] // Configuring Logstash -:edit_url: https://github.com/elastic/logstash/edit/{branch}/docs/static/configuration.asciidoc +:edit_url!: include::static/configuration.asciidoc[] -:edit_url: https://github.com/elastic/logstash/edit/{branch}/docs/static/multiple-pipelines.asciidoc +// Advanced Logstash Configurion + +:edit_url!: +include::static/configuration-advanced.asciidoc[] + +:edit_url!: include::static/multiple-pipelines.asciidoc[] -:edit_url: https://github.com/elastic/logstash/edit/{branch}/docs/static/pipeline-pipeline-config.asciidoc +:edit_url!: include::static/pipeline-pipeline-config.asciidoc[] -:edit_url: https://github.com/elastic/logstash/edit/{branch}/docs/static/reloading-config.asciidoc +:edit_url!: include::static/reloading-config.asciidoc[] -:edit_url: https://github.com/elastic/logstash/edit/{branch}/docs/static/managing-multiline-events.asciidoc +:edit_url!: include::static/managing-multiline-events.asciidoc[] -:edit_url: https://github.com/elastic/logstash/edit/{branch}/docs/static/glob-support.asciidoc +:edit_url!: include::static/glob-support.asciidoc[] -:edit_url: https://github.com/elastic/logstash/edit/{branch}/docs/static/ingest-convert.asciidoc +:edit_url!: include::static/ingest-convert.asciidoc[] -:edit_url: https://github.com/elastic/logstash/edit/{branch}/docs/static/ls-ls-config.asciidoc +:edit_url!: include::static/ls-ls-config.asciidoc[] -:edit_url: https://github.com/elastic/logstash/edit/{branch}/docs/static/management/configuring-centralized-pipelines.asciidoc +:edit_url!: include::static/management/configuring-centralized-pipelines.asciidoc[] -:edit_url: https://github.com/elastic/logstash/edit/{branch}/docs/static/security/logstash.asciidoc +:edit_url!: include::static/security/logstash.asciidoc[] -:edit_url: https://github.com/elastic/logstash/edit/{branch}/docs/static/setup/configuring-xls.asciidoc +:edit_url!: include::static/setup/configuring-xls.asciidoc[] -:edit_url: https://github.com/elastic/logstash/edit/{branch}/docs/static/field-reference.asciidoc +:edit_url!: include::static/field-reference.asciidoc[] //The `field-reference.asciidoc` file (included above) contains a @@ -135,7 +140,7 @@ include::static/field-reference.asciidoc[] //Ref, but not appear in the main TOC. The `exclude`attribute was carrying //forward for all subsequent topics under the `configuration.asciidoc` heading. //This include should remain after includes for all other topics under the -//`Configuring Logstash` heading. +//`Advanced Logstash Configuration` heading. // Centralized configuration managements :edit_url: https://github.com/elastic/logstash/edit/{branch}/docs/static/config-management.asciidoc diff --git a/docs/static/configuration-advanced.asciidoc b/docs/static/configuration-advanced.asciidoc new file mode 100644 index 000000000..54d02619b --- /dev/null +++ b/docs/static/configuration-advanced.asciidoc @@ -0,0 +1,6 @@ +[[configuration-advanced]] +== Advanced Logstash Configurations + +You can take {ls} beyond basic configuration to handle more advanced +requirements, such as multiple pipelines, communication between {ls} pipelines, +and multiple line events. diff --git a/docs/static/pipeline-pipeline-config.asciidoc b/docs/static/pipeline-pipeline-config.asciidoc index 816023bda..5b73a030f 100644 --- a/docs/static/pipeline-pipeline-config.asciidoc +++ b/docs/static/pipeline-pipeline-config.asciidoc @@ -34,7 +34,7 @@ When events are sent across pipelines, their data is fully copied. Modifications The `pipeline` plugin may be the most efficient way to communicate between pipelines, but it still incurs a performance cost. Logstash must duplicate each event in full on the Java heap for each downstream pipeline. Using this feature may affect the heap memory utilization of Logstash. [[delivery-guarantees]] -===== Delivery Guarantees +===== Delivery guarantees In its standard configuration the `pipeline` input/output has at-least-once delivery guarantees. The output will be blocked if the address is blocked or unavailable. From e7d87d0da8a452cc8b84087a9a031288ce1e5533 Mon Sep 17 00:00:00 2001 From: Karen Metts Date: Mon, 18 Nov 2019 17:21:18 -0500 Subject: [PATCH 0271/1126] Remove xls settings page Fixes #11319 --- docs/index.asciidoc | 9 +++------ docs/static/settings-file.asciidoc | 2 +- docs/static/setup/configuring-xls.asciidoc | 11 ----------- 3 files changed, 4 insertions(+), 18 deletions(-) delete mode 100644 docs/static/setup/configuring-xls.asciidoc diff --git a/docs/index.asciidoc b/docs/index.asciidoc index d3386f2e1..9519e6d65 100644 --- a/docs/index.asciidoc +++ b/docs/index.asciidoc @@ -97,6 +97,9 @@ include::static/upgrading.asciidoc[] :edit_url!: include::static/configuration.asciidoc[] +:edit_url!: +include::static/security/logstash.asciidoc[] + // Advanced Logstash Configurion :edit_url!: @@ -126,12 +129,6 @@ include::static/ls-ls-config.asciidoc[] :edit_url!: include::static/management/configuring-centralized-pipelines.asciidoc[] -:edit_url!: -include::static/security/logstash.asciidoc[] - -:edit_url!: -include::static/setup/configuring-xls.asciidoc[] - :edit_url!: include::static/field-reference.asciidoc[] diff --git a/docs/static/settings-file.asciidoc b/docs/static/settings-file.asciidoc index 00795bbad..68addeaef 100644 --- a/docs/static/settings-file.asciidoc +++ b/docs/static/settings-file.asciidoc @@ -63,7 +63,7 @@ modules: IMPORTANT: If the <> `--modules` is used, any modules defined in the `logstash.yml` file will be ignored. -The `logstash.yml` file includes the following settings. If you are using X-Pack, also see {logstash-ref}/settings-xpack.html[X-Pack Settings in Logstash]. +The `logstash.yml` file includes the following settings. [options="header"] |======================================================================= diff --git a/docs/static/setup/configuring-xls.asciidoc b/docs/static/setup/configuring-xls.asciidoc deleted file mode 100644 index a4702e36e..000000000 --- a/docs/static/setup/configuring-xls.asciidoc +++ /dev/null @@ -1,11 +0,0 @@ -[role="xpack"] -[[settings-xpack]] -=== {xpack} Settings in Logstash -[subs="attributes"] -++++ -{xpack} Settings -++++ - -include::{asciidoc-dir}/../../shared/settings.asciidoc[] - -For more Logstash configuration settings, see <>. From 764589e2caf5b3431b4f788179efa923185a6700 Mon Sep 17 00:00:00 2001 From: Dan Hermann Date: Mon, 18 Nov 2019 15:41:29 -0600 Subject: [PATCH 0272/1126] correct directory for versions.yml file Fixes #11318 --- rubyUtils.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/rubyUtils.gradle b/rubyUtils.gradle index e286d703e..2b5a02a9f 100644 --- a/rubyUtils.gradle +++ b/rubyUtils.gradle @@ -183,7 +183,7 @@ task downloadJRuby(type: Download) { description "Download JRuby artifact from this specific URL: ${jRubyURL}" src jRubyURL onlyIfNewer true - inputs.file("${projectDir}/versions.yml") + inputs.file(versionsPath) outputs.file(jrubyTarPath) dest new File("${projectDir}/vendor/_", "jruby-dist-${jRubyVersion}-bin.tar.gz") } From 17f584a847dcfee0ef9a8f11653e41b759a454cf Mon Sep 17 00:00:00 2001 From: andsel Date: Mon, 18 Nov 2019 09:37:40 +0100 Subject: [PATCH 0273/1126] Fixed: avoid touch of log files before deleting it (issue #11307) Fixes #11311 --- .../java/org/logstash/log/DefaultDeprecationLoggerTest.java | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/logstash-core/src/test/java/org/logstash/log/DefaultDeprecationLoggerTest.java b/logstash-core/src/test/java/org/logstash/log/DefaultDeprecationLoggerTest.java index 89ab17502..8388bd8cb 100644 --- a/logstash-core/src/test/java/org/logstash/log/DefaultDeprecationLoggerTest.java +++ b/logstash-core/src/test/java/org/logstash/log/DefaultDeprecationLoggerTest.java @@ -40,9 +40,8 @@ public class DefaultDeprecationLoggerTest { @After public void tearDown() throws IOException { - LogTestUtils.reloadLogConfiguration(); - LogTestUtils.deleteLogFile("logstash-deprecation.log"); + LogTestUtils.reloadLogConfiguration(); } @Test From 189c2c222ffaf9f14d9167402350cc4ccbc5ca0c Mon Sep 17 00:00:00 2001 From: Logstash Machine <43502315+logstashmachine@users.noreply.github.com> Date: Mon, 30 Sep 2019 17:55:41 +0200 Subject: [PATCH 0274/1126] Release notes for 7.4 (#11163 #11229 #11282) * Release notes for 7.4.0 * Release notes for 7.4.1 * Release notes for 7.4.2 Fixes #11326 --- docs/static/releasenotes.asciidoc | 119 ++++++++++++++++++++++++++++++ 1 file changed, 119 insertions(+) diff --git a/docs/static/releasenotes.asciidoc b/docs/static/releasenotes.asciidoc index 475af774b..3fd624769 100644 --- a/docs/static/releasenotes.asciidoc +++ b/docs/static/releasenotes.asciidoc @@ -3,6 +3,9 @@ This section summarizes the changes in the following releases: +* <> +* <> +* <> * <> * <> * <> @@ -18,6 +21,122 @@ This section summarizes the changes in the following releases: * <> * <> +[[logstash-7-4-2]] +=== Logstash 7.4.2 Release Notes + +No user facing changes in this release. + +[[logstash-7-4-1]] +=== Logstash 7.4.1 Release Notes + +* Update patch plugin versions in gemfile lock for 7.4.1 https://github.com/elastic/logstash/pull/11181[#11181] +* Update JrJackson to 0.4.10 https://github.com/elastic/logstash/pull/11184[#11184] +* Remove 10k character truncation from log4j2.properties https://github.com/elastic/logstash/pull/11206[#11206] +* [DOCS] replace unicode non-breaking hyphen U+8211 with ASCII hyphen https://github.com/elastic/logstash/pull/11217[#11217] +* [DOCS] Clarify monitoring hosts should not be master-only https://github.com/elastic/logstash/pull/11194[#11194] +* [DOCS] Add metricbeat as monitoring option https://github.com/elastic/logstash/pull/11191[#11191] + +==== Plugins + +*Cef Codec* + +* Fixed support for deep dot notation https://github.com/logstash-plugins/logstash-codec-cef/pull/73[#73] + +*Aggregate Filter* + +* bugfix: fix inactivity timeout feature when processing old logs (PR https://github.com/logstash-plugins/logstash-filter-aggregate/pull/103[#103], thanks @jdratlif for his contribution!) +* docs: fix several typos in documentation +* docs: enhance example 4 documentation +* ci: enhance plugin continuous integration + +*Cidr Filter* + +* Support string arrays in network setting https://github.com/logstash-plugins/logstash-filter-cidr/pull/21[#21] + +*Prune Filter* + +* Fixed regex to prevent Exception in sprintf call https://github.com/logstash-plugins/logstash-filter-prune/pull/25[#25] +* Changed testing to docker https://github.com/logstash-plugins/logstash-filter-prune/pull/27[#27] + +*Beats Input* + +* Fixed configuration example in doc https://github.com/logstash-plugins/logstash-input-beats/pull/371[#371] +* Improved handling of invalid compressed content https://github.com/logstash-plugins/logstash-input-beats/pull/368[#368] + +*Exec Input* + +* Docs: improved doc on memory usage https://github.com/logstash-plugins/logstash-input-exec/pull/27[#27] + +*File Input* + +* Fixed link to FAQ https://github.com/logstash-plugins/logstash-input-file/pull/247[#247] + +*Imap Input* + +* Added facility to use IMAP uid to retrieve new mails instead of "NOT SEEN" https://github.com/logstash-plugins/logstash-input-imap/pull/36[#36] + +*Jdbc Input* + +* Add support for prepared statements https://github.com/logstash-plugins/logstash-input-jdbc/issues/233[#233] +* Use atomic booleam to load drivers once +* Added support for driver loading in JDK 9+ https://github.com/logstash-plugins/logstash-input-jdbc/issues/331[#331] + +[[logstash-7-4-0]] +=== Logstash 7.4.0 Release Notes + +* Improved logging of version mismatch in DLQ file reader (RecordIOReader) https://github.com/elastic/logstash/pull/11039[#11039] +* Update jruby to 9.2.8.0 https://github.com/elastic/logstash/pull/11041[#11041] +* Integration test for Java plugins https://github.com/elastic/logstash/pull/11054[#11054] +* Use correct execution engine for test-and-exit mode https://github.com/elastic/logstash/pull/11067[#11067] +* Support substitutions in pipelines.yml file https://github.com/elastic/logstash/pull/11081[#11081] +* Do not write generated Java files to disk unless debug flag is set https://github.com/elastic/logstash/pull/11082[#11082] +* Add pipeline.id to log lines https://github.com/elastic/logstash/pull/11087[#11087] +* Prepare 7.4 branch for 7.4.0 https://github.com/elastic/logstash/pull/11092[#11092] +* Update minor plugin versions in gemfile lock for 7.4 https://github.com/elastic/logstash/pull/11096[#11096] +* Use 2048 bits key in OpenSSL socket specs https://github.com/elastic/logstash/pull/11115[#11115] +* Remove mention of pipeline to pipeline being Beta https://github.com/elastic/logstash/pull/11150[#11150] +* Backport release notes to 7.4 branch https://github.com/elastic/logstash/pull/11159[#11159] +* Docs: Fix backticks in how to docs https://github.com/elastic/logstash/pull/11018[#11018] + +NOTICE: Deprecate {ls} Netflow module and point to {filebeat} Netflow module https://github.com/elastic/logstash/pull/11113[#11113] + +==== Plugins + +*Geoip Filter* + +* Fixed docs for missing region_code https://github.com/logstash-plugins/logstash-filter-geoip/pull/158[#158] + +* Update of GeoLite2 DB https://github.com/logstash-plugins/logstash-filter-geoip/pull/157[#157] + +*Beats Input* + +* Updated Jackson dependencies https://github.com/logstash-plugins/logstash-input-beats/pull/366[#366] + +*Gelf Input* + +* Updated library to gelfd2 https://github.com/logstash-plugins/logstash-input-gelf/pull/48[#48] + +*Kafka Input* + +* Updated Kafka client version to 2.3.0 + +*Redis Input* + +* Updated redis client dependency to ~> 4 +* Changed `redis_type` to `data_type` in .rb file https://github.com/logstash-plugins/logstash-input-redis/issues/70[#70] and asciidoc file https://github.com/logstash-plugins/logstash-input-redis/issues/71[#71] +* Added support for renamed redis commands https://github.com/logstash-plugins/logstash-input-redis/issues/29[#29] +* Add channel to the event https://github.com/logstash-plugins/logstash-input-redis/issues/46[#46] +* Add support for SSL https://github.com/logstash-plugins/logstash-input-redis/issues/61[#61] +* Add support for Redis unix sockets https://github.com/logstash-plugins/logstash-input-redis/issues/64[#64] + +*Kafka Output* + +* Updated kafka client to version 2.3.0 + +*S3 Output* + +* Added clarification for endpoint in documentation https://github.com/logstash-plugins/logstash-output-s3/pull/198[#198] + [[logstash-7-3-2]] === Logstash 7.3.2 Release Notes From 5aa8c706836a4df57c19c59347e27caff4c1b325 Mon Sep 17 00:00:00 2001 From: Ry Biesemeyer Date: Mon, 18 Nov 2019 17:27:48 +0000 Subject: [PATCH 0275/1126] docgen: no-op refactor bringing plugin types list out of regexp Fixes #11315 --- rakelib/plugins_docs_dependencies.rake | 11 ++++++++++- 1 file changed, 10 insertions(+), 1 deletion(-) diff --git a/rakelib/plugins_docs_dependencies.rake b/rakelib/plugins_docs_dependencies.rake index a3aaf34b8..763b7c6ad 100644 --- a/rakelib/plugins_docs_dependencies.rake +++ b/rakelib/plugins_docs_dependencies.rake @@ -5,6 +5,15 @@ class PluginVersionWorking EXPORT_FILE = ::File.expand_path(::File.join(::File.dirname(__FILE__), "..", "plugins_version_docs.json")) PLUGIN_METADATA = JSON.parse(IO.read(::File.expand_path(::File.join(::File.dirname(__FILE__), "plugins-metadata.json")))) + PLUGIN_PACKAGE_TYPES = %w( + input + output + codec + filter + ).freeze + + PLUGIN_PACKAGE_NAME_PATTERN = %r{^logstash-#{Regexp::union(PLUGIN_PACKAGE_TYPES)}-} + # Simple class to make sure we get the right version for the document # since we will record multiple versions for one plugin class VersionDependencies @@ -117,7 +126,7 @@ class PluginVersionWorking # Bundler doesn't seem to provide us with `spec.metadata` for remotely # discovered plugins (via rubygems.org api), so we have to choose by # a name pattern instead of by checking spec.metadata["logstash_plugin"] - definition.resolve.select { |spec| spec.name =~ /^logstash-(input|filter|output|codec)-/ }.each do |spec| + definition.resolve.select { |spec| spec.name =~ PLUGIN_PACKAGE_NAME_PATTERN }.each do |spec| dependencies[spec.name] ||= [] dependencies[spec.name] << VersionDependencies.new(spec.version, from) end From fc5d39c68278c24293b3db9523dfd63f034d63c9 Mon Sep 17 00:00:00 2001 From: Ry Biesemeyer Date: Mon, 18 Nov 2019 17:29:12 +0000 Subject: [PATCH 0276/1126] docgen: add integration plugins for plugin discovery Fixes #11315 --- rakelib/plugins_docs_dependencies.rake | 1 + 1 file changed, 1 insertion(+) diff --git a/rakelib/plugins_docs_dependencies.rake b/rakelib/plugins_docs_dependencies.rake index 763b7c6ad..69e4d9f53 100644 --- a/rakelib/plugins_docs_dependencies.rake +++ b/rakelib/plugins_docs_dependencies.rake @@ -10,6 +10,7 @@ class PluginVersionWorking output codec filter + integration ).freeze PLUGIN_PACKAGE_NAME_PATTERN = %r{^logstash-#{Regexp::union(PLUGIN_PACKAGE_TYPES)}-} From 6346d03f6dc54cc6eb20997b33d0f238f2f83c46 Mon Sep 17 00:00:00 2001 From: Joao Duarte Date: Wed, 30 Oct 2019 20:55:37 +0000 Subject: [PATCH 0277/1126] update jruby to 9.2.9.0 Fixes #11281 --- rubyUtils.gradle | 2 +- versions.yml | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/rubyUtils.gradle b/rubyUtils.gradle index 2b5a02a9f..bf9d2cc8f 100644 --- a/rubyUtils.gradle +++ b/rubyUtils.gradle @@ -6,7 +6,7 @@ buildscript { dependencies { classpath 'org.yaml:snakeyaml:1.23' classpath "de.undercouch:gradle-download-task:3.2.0" - classpath "org.jruby:jruby-complete:9.2.8.0" + classpath "org.jruby:jruby-complete:9.2.9.0" } } diff --git a/versions.yml b/versions.yml index d32ee88f1..57eda209f 100644 --- a/versions.yml +++ b/versions.yml @@ -7,8 +7,8 @@ logstash-core-plugin-api: 2.1.16 # jruby must reference a *released* version of jruby which can be downloaded from the official download url # *and* for which jars artifacts are published for compile-time jruby: - version: 9.2.8.0 - sha1: 5b0b73b3d696afaeac92e6f8879dedcc63ac39d8 + version: 9.2.9.0 + sha1: 39ef88eb5e7319402b15c048f638f26e2b9c4f4c # jruby-runtime-override, if specified, will override the jruby version installed in vendor/jruby for logstash runtime only, # not for the compile-time jars From 03f9cc9f49d13a5127320110a41dc3735388856f Mon Sep 17 00:00:00 2001 From: Colin Surprenant Date: Wed, 20 Nov 2019 15:39:28 -0500 Subject: [PATCH 0278/1126] remove JRuby resolv.rb patch following fix in 9.2.9.0 Fixes #11330 --- logstash-core/lib/logstash/patches.rb | 1 - logstash-core/lib/logstash/patches/resolv.rb | 25 - .../lib/logstash/patches/resolv_9270.rb | 2903 ----------------- 3 files changed, 2929 deletions(-) delete mode 100644 logstash-core/lib/logstash/patches/resolv.rb delete mode 100644 logstash-core/lib/logstash/patches/resolv_9270.rb diff --git a/logstash-core/lib/logstash/patches.rb b/logstash-core/lib/logstash/patches.rb index a34d5d44e..283d74aa3 100644 --- a/logstash-core/lib/logstash/patches.rb +++ b/logstash-core/lib/logstash/patches.rb @@ -4,4 +4,3 @@ require "logstash/patches/cabin" require "logstash/patches/profile_require_calls" require "logstash/patches/stronger_openssl_defaults" require "logstash/patches/exception_to_json" -require "logstash/patches/resolv" diff --git a/logstash-core/lib/logstash/patches/resolv.rb b/logstash-core/lib/logstash/patches/resolv.rb deleted file mode 100644 index 2c466c465..000000000 --- a/logstash-core/lib/logstash/patches/resolv.rb +++ /dev/null @@ -1,25 +0,0 @@ -require "resolv" - -# ref: -# https://github.com/logstash-plugins/logstash-filter-dns/issues/51 -# https://github.com/jruby/jruby/pull/5722 -# -# JRuby versions starting at 9.2.0.0 have a bug in resolv.rb with a leak between the -# DNS.allocate_request_id/DNS.free_request_id methods. -# -# We are opting to load a patched full resolv.rb instead of monkey patching the -# offending methods because we do not yet know in which upcoming version of JRuby -# this will be fixed and we want to avoid potential conflicting monkey patches. -# A spec which will break on JRuby upgrade will redirect here -# to make a manual verification and eventually remove that patch here once the fix is -# made in the JRuby version of resolv.rb. - -if Gem::Version.new(JRUBY_VERSION) >= Gem::Version.new("9.2.0.0") - # save verbose level and mute the "warning: already initialized constant" - warn_level = $VERBOSE - $VERBOSE = nil - - require_relative "resolv_9270" - - $VERBOSE = warn_level -end diff --git a/logstash-core/lib/logstash/patches/resolv_9270.rb b/logstash-core/lib/logstash/patches/resolv_9270.rb deleted file mode 100644 index aff7fa5c1..000000000 --- a/logstash-core/lib/logstash/patches/resolv_9270.rb +++ /dev/null @@ -1,2903 +0,0 @@ -# frozen_string_literal: true - -require 'socket' -require 'timeout' -require 'io/wait' -require 'ipaddr' - -begin - require 'securerandom' -rescue LoadError -end - -# IMPORTANT -# -# This is a modified version of resolv.rb from JRuby 9.2.7.0 to fix a bug in -# UnconnectedUDP#sender and UnconnectedUDP#close -# see https://github.com/logstash-plugins/logstash-filter-dns/pull/52 - - -# Resolv is a thread-aware DNS resolver library written in Ruby. Resolv can -# handle multiple DNS requests concurrently without blocking the entire Ruby -# interpreter. -# -# See also resolv-replace.rb to replace the libc resolver with Resolv. -# -# Resolv can look up various DNS resources using the DNS module directly. -# -# Examples: -# -# p Resolv.getaddress "www.ruby-lang.org" -# p Resolv.getname "210.251.121.214" -# -# Resolv::DNS.open do |dns| -# ress = dns.getresources "www.ruby-lang.org", Resolv::DNS::Resource::IN::A -# p ress.map(&:address) -# ress = dns.getresources "ruby-lang.org", Resolv::DNS::Resource::IN::MX -# p ress.map { |r| [r.exchange.to_s, r.preference] } -# end -# -# -# == Bugs -# -# * NIS is not supported. -# * /etc/nsswitch.conf is not supported. - -class Resolv - - ## - # Tests whether we're running on Windows - - WINDOWS = /mswin|cygwin|mingw|bccwin/ =~ RUBY_PLATFORM || ::RbConfig::CONFIG['host_os'] =~ /mswin/ - - ## - # Looks up the first IP address for +name+. - - def self.getaddress(name) - DefaultResolver.getaddress(name) - end - - ## - # Looks up all IP address for +name+. - - def self.getaddresses(name) - DefaultResolver.getaddresses(name) - end - - ## - # Iterates over all IP addresses for +name+. - - def self.each_address(name, &block) - DefaultResolver.each_address(name, &block) - end - - ## - # Looks up the hostname of +address+. - - def self.getname(address) - DefaultResolver.getname(address) - end - - ## - # Looks up all hostnames for +address+. - - def self.getnames(address) - DefaultResolver.getnames(address) - end - - ## - # Iterates over all hostnames for +address+. - - def self.each_name(address, &proc) - DefaultResolver.each_name(address, &proc) - end - - ## - # Creates a new Resolv using +resolvers+. - - def initialize(resolvers=[Hosts.new, DNS.new]) - @resolvers = resolvers - end - - ## - # Looks up the first IP address for +name+. - - def getaddress(name) - each_address(name) {|address| return address} - raise ResolvError.new("no address for #{name}") - end - - ## - # Looks up all IP address for +name+. - - def getaddresses(name) - ret = [] - each_address(name) {|address| ret << address} - return ret - end - - ## - # Iterates over all IP addresses for +name+. - - def each_address(name) - if AddressRegex =~ name - yield name - return - end - yielded = false - @resolvers.each {|r| - r.each_address(name) {|address| - yield address.to_s - yielded = true - } - return if yielded - } - end - - ## - # Looks up the hostname of +address+. - - def getname(address) - each_name(address) {|name| return name} - raise ResolvError.new("no name for #{address}") - end - - ## - # Looks up all hostnames for +address+. - - def getnames(address) - ret = [] - each_name(address) {|name| ret << name} - return ret - end - - ## - # Iterates over all hostnames for +address+. - - def each_name(address) - yielded = false - @resolvers.each {|r| - r.each_name(address) {|name| - yield name.to_s - yielded = true - } - return if yielded - } - end - - ## - # Indicates a failure to resolve a name or address. - - class ResolvError < StandardError; end - - ## - # Indicates a timeout resolving a name or address. - - class ResolvTimeout < Timeout::Error; end - - ## - # Resolv::Hosts is a hostname resolver that uses the system hosts file. - - class Hosts - if WINDOWS - require 'win32/resolv' - DefaultFileName = Win32::Resolv.get_hosts_path - else - DefaultFileName = '/etc/hosts' - end - - ## - # Creates a new Resolv::Hosts, using +filename+ for its data source. - - def initialize(filename = DefaultFileName) - @filename = filename - @mutex = Thread::Mutex.new - @initialized = nil - end - - def lazy_initialize # :nodoc: - @mutex.synchronize { - unless @initialized - @name2addr = {} - @addr2name = {} - File.open(@filename, 'rb') {|f| - f.each {|line| - line.sub!(/#.*/, '') - addr, hostname, *aliases = line.split(/\s+/) - next unless addr - addr.untaint - hostname.untaint - @addr2name[addr] = [] unless @addr2name.include? addr - @addr2name[addr] << hostname - @addr2name[addr] += aliases - @name2addr[hostname] = [] unless @name2addr.include? hostname - @name2addr[hostname] << addr - aliases.each {|n| - n.untaint - @name2addr[n] = [] unless @name2addr.include? n - @name2addr[n] << addr - } - } - } - @name2addr.each {|name, arr| arr.reverse!} - @initialized = true - end - } - self - end - - ## - # Gets the IP address of +name+ from the hosts file. - - def getaddress(name) - each_address(name) {|address| return address} - raise ResolvError.new("#{@filename} has no name: #{name}") - end - - ## - # Gets all IP addresses for +name+ from the hosts file. - - def getaddresses(name) - ret = [] - each_address(name) {|address| ret << address} - return ret - end - - ## - # Iterates over all IP addresses for +name+ retrieved from the hosts file. - - def each_address(name, &proc) - lazy_initialize - if @name2addr.include?(name) - @name2addr[name].each(&proc) - end - end - - ## - # Gets the hostname of +address+ from the hosts file. - - def getname(address) - each_name(address) {|name| return name} - raise ResolvError.new("#{@filename} has no address: #{address}") - end - - ## - # Gets all hostnames for +address+ from the hosts file. - - def getnames(address) - ret = [] - each_name(address) {|name| ret << name} - return ret - end - - ## - # Iterates over all hostnames for +address+ retrieved from the hosts file. - - def each_name(address, &proc) - lazy_initialize - @addr2name[address]&.each(&proc) - end - end - - ## - # Resolv::DNS is a DNS stub resolver. - # - # Information taken from the following places: - # - # * STD0013 - # * RFC 1035 - # * ftp://ftp.isi.edu/in-notes/iana/assignments/dns-parameters - # * etc. - - class DNS - - ## - # Default DNS Port - - Port = 53 - - ## - # Default DNS UDP packet size - - UDPSize = 512 - - ## - # Creates a new DNS resolver. See Resolv::DNS.new for argument details. - # - # Yields the created DNS resolver to the block, if given, otherwise - # returns it. - - def self.open(*args) - dns = new(*args) - return dns unless block_given? - begin - yield dns - ensure - dns.close - end - end - - ## - # Creates a new DNS resolver. - # - # +config_info+ can be: - # - # nil:: Uses /etc/resolv.conf. - # String:: Path to a file using /etc/resolv.conf's format. - # Hash:: Must contain :nameserver, :search and :ndots keys. - # :nameserver_port can be used to specify port number of nameserver address. - # - # The value of :nameserver should be an address string or - # an array of address strings. - # - :nameserver => '8.8.8.8' - # - :nameserver => ['8.8.8.8', '8.8.4.4'] - # - # The value of :nameserver_port should be an array of - # pair of nameserver address and port number. - # - :nameserver_port => [['8.8.8.8', 53], ['8.8.4.4', 53]] - # - # Example: - # - # Resolv::DNS.new(:nameserver => ['210.251.121.21'], - # :search => ['ruby-lang.org'], - # :ndots => 1) - - def initialize(config_info=nil) - @mutex = Thread::Mutex.new - @config = Config.new(config_info) - @initialized = nil - end - - # Sets the resolver timeouts. This may be a single positive number - # or an array of positive numbers representing timeouts in seconds. - # If an array is specified, a DNS request will retry and wait for - # each successive interval in the array until a successful response - # is received. Specifying +nil+ reverts to the default timeouts: - # [ 5, second = 5 * 2 / nameserver_count, 2 * second, 4 * second ] - # - # Example: - # - # dns.timeouts = 3 - # - def timeouts=(values) - @config.timeouts = values - end - - def lazy_initialize # :nodoc: - @mutex.synchronize { - unless @initialized - @config.lazy_initialize - @initialized = true - end - } - self - end - - ## - # Closes the DNS resolver. - - def close - @mutex.synchronize { - if @initialized - @initialized = false - end - } - end - - ## - # Gets the IP address of +name+ from the DNS resolver. - # - # +name+ can be a Resolv::DNS::Name or a String. Retrieved address will - # be a Resolv::IPv4 or Resolv::IPv6 - - def getaddress(name) - each_address(name) {|address| return address} - raise ResolvError.new("DNS result has no information for #{name}") - end - - ## - # Gets all IP addresses for +name+ from the DNS resolver. - # - # +name+ can be a Resolv::DNS::Name or a String. Retrieved addresses will - # be a Resolv::IPv4 or Resolv::IPv6 - - def getaddresses(name) - ret = [] - each_address(name) {|address| ret << address} - return ret - end - - ## - # Iterates over all IP addresses for +name+ retrieved from the DNS - # resolver. - # - # +name+ can be a Resolv::DNS::Name or a String. Retrieved addresses will - # be a Resolv::IPv4 or Resolv::IPv6 - - def each_address(name) - each_resource(name, Resource::IN::A) {|resource| yield resource.address} - if use_ipv6? - each_resource(name, Resource::IN::AAAA) {|resource| yield resource.address} - end - end - - def use_ipv6? # :nodoc: - begin - list = Socket.ip_address_list - rescue NotImplementedError - return true - end - list.any? {|a| a.ipv6? && !a.ipv6_loopback? && !a.ipv6_linklocal? } - end - private :use_ipv6? - - ## - # Gets the hostname for +address+ from the DNS resolver. - # - # +address+ must be a Resolv::IPv4, Resolv::IPv6 or a String. Retrieved - # name will be a Resolv::DNS::Name. - - def getname(address) - each_name(address) {|name| return name} - raise ResolvError.new("DNS result has no information for #{address}") - end - - ## - # Gets all hostnames for +address+ from the DNS resolver. - # - # +address+ must be a Resolv::IPv4, Resolv::IPv6 or a String. Retrieved - # names will be Resolv::DNS::Name instances. - - def getnames(address) - ret = [] - each_name(address) {|name| ret << name} - return ret - end - - ## - # Iterates over all hostnames for +address+ retrieved from the DNS - # resolver. - # - # +address+ must be a Resolv::IPv4, Resolv::IPv6 or a String. Retrieved - # names will be Resolv::DNS::Name instances. - - def each_name(address) - case address - when Name - ptr = address - when IPv4::Regex - ptr = IPv4.create(address).to_name - when IPv6::Regex - ptr = IPv6.create(address).to_name - else - raise ResolvError.new("cannot interpret as address: #{address}") - end - each_resource(ptr, Resource::IN::PTR) {|resource| yield resource.name} - end - - ## - # Look up the +typeclass+ DNS resource of +name+. - # - # +name+ must be a Resolv::DNS::Name or a String. - # - # +typeclass+ should be one of the following: - # - # * Resolv::DNS::Resource::IN::A - # * Resolv::DNS::Resource::IN::AAAA - # * Resolv::DNS::Resource::IN::ANY - # * Resolv::DNS::Resource::IN::CNAME - # * Resolv::DNS::Resource::IN::HINFO - # * Resolv::DNS::Resource::IN::MINFO - # * Resolv::DNS::Resource::IN::MX - # * Resolv::DNS::Resource::IN::NS - # * Resolv::DNS::Resource::IN::PTR - # * Resolv::DNS::Resource::IN::SOA - # * Resolv::DNS::Resource::IN::TXT - # * Resolv::DNS::Resource::IN::WKS - # - # Returned resource is represented as a Resolv::DNS::Resource instance, - # i.e. Resolv::DNS::Resource::IN::A. - - def getresource(name, typeclass) - each_resource(name, typeclass) {|resource| return resource} - raise ResolvError.new("DNS result has no information for #{name}") - end - - ## - # Looks up all +typeclass+ DNS resources for +name+. See #getresource for - # argument details. - - def getresources(name, typeclass) - ret = [] - each_resource(name, typeclass) {|resource| ret << resource} - return ret - end - - ## - # Iterates over all +typeclass+ DNS resources for +name+. See - # #getresource for argument details. - - def each_resource(name, typeclass, &proc) - fetch_resource(name, typeclass) {|reply, reply_name| - extract_resources(reply, reply_name, typeclass, &proc) - } - end - - def fetch_resource(name, typeclass) - lazy_initialize - requester = make_udp_requester - senders = {} - begin - @config.resolv(name) {|candidate, tout, nameserver, port| - msg = Message.new - msg.rd = 1 - msg.add_question(candidate, typeclass) - unless sender = senders[[candidate, nameserver, port]] - sender = requester.sender(msg, candidate, nameserver, port) - next if !sender - senders[[candidate, nameserver, port]] = sender - end - reply, reply_name = requester.request(sender, tout) - case reply.rcode - when RCode::NoError - if reply.tc == 1 and not Requester::TCP === requester - requester.close - # Retry via TCP: - requester = make_tcp_requester(nameserver, port) - senders = {} - # This will use TCP for all remaining candidates (assuming the - # current candidate does not already respond successfully via - # TCP). This makes sense because we already know the full - # response will not fit in an untruncated UDP packet. - redo - else - yield(reply, reply_name) - end - return - when RCode::NXDomain - raise Config::NXDomain.new(reply_name.to_s) - else - raise Config::OtherResolvError.new(reply_name.to_s) - end - } - ensure - requester.close - end - end - - def make_udp_requester # :nodoc: - nameserver_port = @config.nameserver_port - if nameserver_port.length == 1 - Requester::ConnectedUDP.new(*nameserver_port[0]) - else - Requester::UnconnectedUDP.new(*nameserver_port) - end - end - - def make_tcp_requester(host, port) # :nodoc: - return Requester::TCP.new(host, port) - end - - def extract_resources(msg, name, typeclass) # :nodoc: - if typeclass < Resource::ANY - n0 = Name.create(name) - msg.each_resource {|n, ttl, data| - yield data if n0 == n - } - end - yielded = false - n0 = Name.create(name) - msg.each_resource {|n, ttl, data| - if n0 == n - case data - when typeclass - yield data - yielded = true - when Resource::CNAME - n0 = data.name - end - end - } - return if yielded - msg.each_resource {|n, ttl, data| - if n0 == n - case data - when typeclass - yield data - end - end - } - end - - if defined? SecureRandom - def self.random(arg) # :nodoc: - begin - SecureRandom.random_number(arg) - rescue NotImplementedError - rand(arg) - end - end - else - def self.random(arg) # :nodoc: - rand(arg) - end - end - - - def self.rangerand(range) # :nodoc: - base = range.begin - len = range.end - range.begin - if !range.exclude_end? - len += 1 - end - base + random(len) - end - - RequestID = {} # :nodoc: - RequestIDMutex = Thread::Mutex.new # :nodoc: - - def self.allocate_request_id(host, port) # :nodoc: - id = nil - RequestIDMutex.synchronize { - h = (RequestID[[host, port]] ||= {}) - begin - id = rangerand(0x0000..0xffff) - end while h[id] - h[id] = true - } - id - end - - def self.free_request_id(host, port, id) # :nodoc: - RequestIDMutex.synchronize { - key = [host, port] - if h = RequestID[key] - h.delete id - if h.empty? - RequestID.delete key - end - end - } - end - - def self.bind_random_port(udpsock, bind_host="0.0.0.0") # :nodoc: - begin - port = rangerand(1024..65535) - udpsock.bind(bind_host, port) - rescue Errno::EADDRINUSE, # POSIX - Errno::EACCES, # SunOS: See PRIV_SYS_NFS in privileges(5) - Errno::EPERM # FreeBSD: security.mac.portacl.port_high is configurable. See mac_portacl(4). - retry - end - end - - class Requester # :nodoc: - def initialize - @senders = {} - @socks = nil - end - - def request(sender, tout) - start = Process.clock_gettime(Process::CLOCK_MONOTONIC) - timelimit = start + tout - begin - sender.send - rescue Errno::EHOSTUNREACH, # multi-homed IPv6 may generate this - Errno::ENETUNREACH - raise ResolvTimeout - end - while true - before_select = Process.clock_gettime(Process::CLOCK_MONOTONIC) - timeout = timelimit - before_select - if timeout <= 0 - raise ResolvTimeout - end - if @socks.size == 1 - select_result = @socks[0].wait_readable(timeout) ? [ @socks ] : nil - else - select_result = IO.select(@socks, nil, nil, timeout) - end - if !select_result - after_select = Process.clock_gettime(Process::CLOCK_MONOTONIC) - next if after_select < timelimit - raise ResolvTimeout - end - begin - reply, from = recv_reply(select_result[0]) - rescue Errno::ECONNREFUSED, # GNU/Linux, FreeBSD - Errno::ECONNRESET # Windows - # No name server running on the server? - # Don't wait anymore. - raise ResolvTimeout - end - begin - msg = Message.decode(reply) - rescue DecodeError - next # broken DNS message ignored - end - if s = sender_for(from, msg) - break - else - # unexpected DNS message ignored - end - end - return msg, s.data - end - - def sender_for(addr, msg) - @senders[[addr,msg.id]] - end - - def close - socks = @socks - @socks = nil - socks&.each(&:close) - end - - class Sender # :nodoc: - def initialize(msg, data, sock) - @msg = msg - @data = data - @sock = sock - end - end - - class UnconnectedUDP < Requester # :nodoc: - def initialize(*nameserver_port) - super() - @nameserver_port = nameserver_port - @initialized = false - @mutex = Thread::Mutex.new - end - - def lazy_initialize - @mutex.synchronize { - next if @initialized - @initialized = true - @socks_hash = {} - @socks = [] - @nameserver_port.each {|host, port| - if host.index(':') - bind_host = "::" - af = Socket::AF_INET6 - else - bind_host = "0.0.0.0" - af = Socket::AF_INET - end - next if @socks_hash[bind_host] - begin - sock = UDPSocket.new(af) - rescue Errno::EAFNOSUPPORT - next # The kernel doesn't support the address family. - end - @socks << sock - @socks_hash[bind_host] = sock - sock.do_not_reverse_lookup = true - DNS.bind_random_port(sock, bind_host) - } - } - self - end - - def recv_reply(readable_socks) - lazy_initialize - reply, from = readable_socks[0].recvfrom(UDPSize) - return reply, [IPAddr.new(from[3]),from[1]] - end - - def sender(msg, data, host, port=Port) - lazy_initialize - sock = @socks_hash[host.index(':') ? "::" : "0.0.0.0"] - return nil if !sock - service = [IPAddr.new(host), port] - id = DNS.allocate_request_id(service[0].to_s, port) - request = msg.encode - request[0,2] = [id].pack('n') - return @senders[[service, id]] = - Sender.new(request, data, sock, host, port) - end - - def close - @mutex.synchronize { - if @initialized - super - @senders.each_key {|service, id| - DNS.free_request_id(service[0].to_s, service[1], id) - } - @initialized = false - end - } - end - - class Sender < Requester::Sender # :nodoc: - def initialize(msg, data, sock, host, port) - super(msg, data, sock) - @host = host - @port = port - end - attr_reader :data - - def send - raise "@sock is nil." if @sock.nil? - @sock.send(@msg, 0, @host, @port) - end - end - end - - class ConnectedUDP < Requester # :nodoc: - def initialize(host, port=Port) - super() - @host = host - @port = port - @mutex = Thread::Mutex.new - @initialized = false - end - - def lazy_initialize - @mutex.synchronize { - next if @initialized - @initialized = true - is_ipv6 = @host.index(':') - sock = UDPSocket.new(is_ipv6 ? Socket::AF_INET6 : Socket::AF_INET) - @socks = [sock] - sock.do_not_reverse_lookup = true - DNS.bind_random_port(sock, is_ipv6 ? "::" : "0.0.0.0") - sock.connect(@host, @port) - } - self - end - - def recv_reply(readable_socks) - lazy_initialize - reply = readable_socks[0].recv(UDPSize) - return reply, nil - end - - def sender(msg, data, host=@host, port=@port) - lazy_initialize - unless host == @host && port == @port - raise RequestError.new("host/port don't match: #{host}:#{port}") - end - id = DNS.allocate_request_id(@host, @port) - request = msg.encode - request[0,2] = [id].pack('n') - return @senders[[nil,id]] = Sender.new(request, data, @socks[0]) - end - - def close - @mutex.synchronize do - if @initialized - super - @senders.each_key {|from, id| - DNS.free_request_id(@host, @port, id) - } - @initialized = false - end - end - end - - class Sender < Requester::Sender # :nodoc: - def send - raise "@sock is nil." if @sock.nil? - @sock.send(@msg, 0) - end - attr_reader :data - end - end - - class MDNSOneShot < UnconnectedUDP # :nodoc: - def sender(msg, data, host, port=Port) - lazy_initialize - id = DNS.allocate_request_id(host, port) - request = msg.encode - request[0,2] = [id].pack('n') - sock = @socks_hash[host.index(':') ? "::" : "0.0.0.0"] - return @senders[id] = - UnconnectedUDP::Sender.new(request, data, sock, host, port) - end - - def sender_for(addr, msg) - lazy_initialize - @senders[msg.id] - end - end - - class TCP < Requester # :nodoc: - def initialize(host, port=Port) - super() - @host = host - @port = port - sock = TCPSocket.new(@host, @port) - @socks = [sock] - @senders = {} - end - - def recv_reply(readable_socks) - len = readable_socks[0].read(2).unpack('n')[0] - reply = @socks[0].read(len) - return reply, nil - end - - def sender(msg, data, host=@host, port=@port) - unless host == @host && port == @port - raise RequestError.new("host/port don't match: #{host}:#{port}") - end - id = DNS.allocate_request_id(@host, @port) - request = msg.encode - request[0,2] = [request.length, id].pack('nn') - return @senders[[nil,id]] = Sender.new(request, data, @socks[0]) - end - - class Sender < Requester::Sender # :nodoc: - def send - @sock.print(@msg) - @sock.flush - end - attr_reader :data - end - - def close - super - @senders.each_key {|from,id| - DNS.free_request_id(@host, @port, id) - } - end - end - - ## - # Indicates a problem with the DNS request. - - class RequestError < StandardError - end - end - - class Config # :nodoc: - def initialize(config_info=nil) - @mutex = Thread::Mutex.new - @config_info = config_info - @initialized = nil - @timeouts = nil - end - - def timeouts=(values) - if values - values = Array(values) - values.each do |t| - Numeric === t or raise ArgumentError, "#{t.inspect} is not numeric" - t > 0.0 or raise ArgumentError, "timeout=#{t} must be positive" - end - @timeouts = values - else - @timeouts = nil - end - end - - def Config.parse_resolv_conf(filename) - nameserver = [] - search = nil - ndots = 1 - File.open(filename, 'rb') {|f| - f.each {|line| - line.sub!(/[#;].*/, '') - keyword, *args = line.split(/\s+/) - args.each(&:untaint) - next unless keyword - case keyword - when 'nameserver' - nameserver += args - when 'domain' - next if args.empty? - search = [args[0]] - when 'search' - next if args.empty? - search = args - when 'options' - args.each {|arg| - case arg - when /\Andots:(\d+)\z/ - ndots = $1.to_i - end - } - end - } - } - return { :nameserver => nameserver, :search => search, :ndots => ndots } - end - - def Config.default_config_hash(filename="/etc/resolv.conf") - if File.exist? filename - config_hash = Config.parse_resolv_conf(filename) - else - if WINDOWS - require 'win32/resolv' - search, nameserver = Win32::Resolv.get_resolv_info - config_hash = {} - config_hash[:nameserver] = nameserver if nameserver - config_hash[:search] = [search].flatten if search - end - end - config_hash || {} - end - - def lazy_initialize - @mutex.synchronize { - unless @initialized - @nameserver_port = [] - @search = nil - @ndots = 1 - case @config_info - when nil - config_hash = Config.default_config_hash - when String - config_hash = Config.parse_resolv_conf(@config_info) - when Hash - config_hash = @config_info.dup - if String === config_hash[:nameserver] - config_hash[:nameserver] = [config_hash[:nameserver]] - end - if String === config_hash[:search] - config_hash[:search] = [config_hash[:search]] - end - else - raise ArgumentError.new("invalid resolv configuration: #{@config_info.inspect}") - end - if config_hash.include? :nameserver - @nameserver_port = config_hash[:nameserver].map {|ns| [ns, Port] } - end - if config_hash.include? :nameserver_port - @nameserver_port = config_hash[:nameserver_port].map {|ns, port| [ns, (port || Port)] } - end - @search = config_hash[:search] if config_hash.include? :search - @ndots = config_hash[:ndots] if config_hash.include? :ndots - - if @nameserver_port.empty? - @nameserver_port << ['0.0.0.0', Port] - end - if @search - @search = @search.map {|arg| Label.split(arg) } - else - hostname = Socket.gethostname - if /\./ =~ hostname - @search = [Label.split($')] - else - @search = [[]] - end - end - - if !@nameserver_port.kind_of?(Array) || - @nameserver_port.any? {|ns_port| - !(Array === ns_port) || - ns_port.length != 2 - !(String === ns_port[0]) || - !(Integer === ns_port[1]) - } - raise ArgumentError.new("invalid nameserver config: #{@nameserver_port.inspect}") - end - - if !@search.kind_of?(Array) || - !@search.all? {|ls| ls.all? {|l| Label::Str === l } } - raise ArgumentError.new("invalid search config: #{@search.inspect}") - end - - if !@ndots.kind_of?(Integer) - raise ArgumentError.new("invalid ndots config: #{@ndots.inspect}") - end - - @initialized = true - end - } - self - end - - def single? - lazy_initialize - if @nameserver_port.length == 1 - return @nameserver_port[0] - else - return nil - end - end - - def nameserver_port - @nameserver_port - end - - def generate_candidates(name) - candidates = nil - name = Name.create(name) - if name.absolute? - candidates = [name] - else - if @ndots <= name.length - 1 - candidates = [Name.new(name.to_a)] - else - candidates = [] - end - candidates.concat(@search.map {|domain| Name.new(name.to_a + domain)}) - fname = Name.create("#{name}.") - if !candidates.include?(fname) - candidates << fname - end - end - return candidates - end - - InitialTimeout = 5 - - def generate_timeouts - ts = [InitialTimeout] - ts << ts[-1] * 2 / @nameserver_port.length - ts << ts[-1] * 2 - ts << ts[-1] * 2 - return ts - end - - def resolv(name) - candidates = generate_candidates(name) - timeouts = @timeouts || generate_timeouts - begin - candidates.each {|candidate| - begin - timeouts.each {|tout| - @nameserver_port.each {|nameserver, port| - begin - yield candidate, tout, nameserver, port - rescue ResolvTimeout - end - } - } - raise ResolvError.new("DNS resolv timeout: #{name}") - rescue NXDomain - end - } - rescue ResolvError - end - end - - ## - # Indicates no such domain was found. - - class NXDomain < ResolvError - end - - ## - # Indicates some other unhandled resolver error was encountered. - - class OtherResolvError < ResolvError - end - end - - module OpCode # :nodoc: - Query = 0 - IQuery = 1 - Status = 2 - Notify = 4 - Update = 5 - end - - module RCode # :nodoc: - NoError = 0 - FormErr = 1 - ServFail = 2 - NXDomain = 3 - NotImp = 4 - Refused = 5 - YXDomain = 6 - YXRRSet = 7 - NXRRSet = 8 - NotAuth = 9 - NotZone = 10 - BADVERS = 16 - BADSIG = 16 - BADKEY = 17 - BADTIME = 18 - BADMODE = 19 - BADNAME = 20 - BADALG = 21 - end - - ## - # Indicates that the DNS response was unable to be decoded. - - class DecodeError < StandardError - end - - ## - # Indicates that the DNS request was unable to be encoded. - - class EncodeError < StandardError - end - - module Label # :nodoc: - def self.split(arg) - labels = [] - arg.scan(/[^\.]+/) {labels << Str.new($&)} - return labels - end - - class Str # :nodoc: - def initialize(string) - @string = string - # case insensivity of DNS labels doesn't apply non-ASCII characters. [RFC 4343] - # This assumes @string is given in ASCII compatible encoding. - @downcase = string.b.downcase - end - attr_reader :string, :downcase - - def to_s - return @string - end - - def inspect - return "#<#{self.class} #{self}>" - end - - def ==(other) - return self.class == other.class && @downcase == other.downcase - end - - def eql?(other) - return self == other - end - - def hash - return @downcase.hash - end - end - end - - ## - # A representation of a DNS name. - - class Name - - ## - # Creates a new DNS name from +arg+. +arg+ can be: - # - # Name:: returns +arg+. - # String:: Creates a new Name. - - def self.create(arg) - case arg - when Name - return arg - when String - return Name.new(Label.split(arg), /\.\z/ =~ arg ? true : false) - else - raise ArgumentError.new("cannot interpret as DNS name: #{arg.inspect}") - end - end - - def initialize(labels, absolute=true) # :nodoc: - labels = labels.map {|label| - case label - when String then Label::Str.new(label) - when Label::Str then label - else - raise ArgumentError, "unexpected label: #{label.inspect}" - end - } - @labels = labels - @absolute = absolute - end - - def inspect # :nodoc: - "#<#{self.class}: #{self}#{@absolute ? '.' : ''}>" - end - - ## - # True if this name is absolute. - - def absolute? - return @absolute - end - - def ==(other) # :nodoc: - return false unless Name === other - return false unless @absolute == other.absolute? - return @labels == other.to_a - end - - alias eql? == # :nodoc: - - ## - # Returns true if +other+ is a subdomain. - # - # Example: - # - # domain = Resolv::DNS::Name.create("y.z") - # p Resolv::DNS::Name.create("w.x.y.z").subdomain_of?(domain) #=> true - # p Resolv::DNS::Name.create("x.y.z").subdomain_of?(domain) #=> true - # p Resolv::DNS::Name.create("y.z").subdomain_of?(domain) #=> false - # p Resolv::DNS::Name.create("z").subdomain_of?(domain) #=> false - # p Resolv::DNS::Name.create("x.y.z.").subdomain_of?(domain) #=> false - # p Resolv::DNS::Name.create("w.z").subdomain_of?(domain) #=> false - # - - def subdomain_of?(other) - raise ArgumentError, "not a domain name: #{other.inspect}" unless Name === other - return false if @absolute != other.absolute? - other_len = other.length - return false if @labels.length <= other_len - return @labels[-other_len, other_len] == other.to_a - end - - def hash # :nodoc: - return @labels.hash ^ @absolute.hash - end - - def to_a # :nodoc: - return @labels - end - - def length # :nodoc: - return @labels.length - end - - def [](i) # :nodoc: - return @labels[i] - end - - ## - # returns the domain name as a string. - # - # The domain name doesn't have a trailing dot even if the name object is - # absolute. - # - # Example: - # - # p Resolv::DNS::Name.create("x.y.z.").to_s #=> "x.y.z" - # p Resolv::DNS::Name.create("x.y.z").to_s #=> "x.y.z" - - def to_s - return @labels.join('.') - end - end - - class Message # :nodoc: - @@identifier = -1 - - def initialize(id = (@@identifier += 1) & 0xffff) - @id = id - @qr = 0 - @opcode = 0 - @aa = 0 - @tc = 0 - @rd = 0 # recursion desired - @ra = 0 # recursion available - @rcode = 0 - @question = [] - @answer = [] - @authority = [] - @additional = [] - end - - attr_accessor :id, :qr, :opcode, :aa, :tc, :rd, :ra, :rcode - attr_reader :question, :answer, :authority, :additional - - def ==(other) - return @id == other.id && - @qr == other.qr && - @opcode == other.opcode && - @aa == other.aa && - @tc == other.tc && - @rd == other.rd && - @ra == other.ra && - @rcode == other.rcode && - @question == other.question && - @answer == other.answer && - @authority == other.authority && - @additional == other.additional - end - - def add_question(name, typeclass) - @question << [Name.create(name), typeclass] - end - - def each_question - @question.each {|name, typeclass| - yield name, typeclass - } - end - - def add_answer(name, ttl, data) - @answer << [Name.create(name), ttl, data] - end - - def each_answer - @answer.each {|name, ttl, data| - yield name, ttl, data - } - end - - def add_authority(name, ttl, data) - @authority << [Name.create(name), ttl, data] - end - - def each_authority - @authority.each {|name, ttl, data| - yield name, ttl, data - } - end - - def add_additional(name, ttl, data) - @additional << [Name.create(name), ttl, data] - end - - def each_additional - @additional.each {|name, ttl, data| - yield name, ttl, data - } - end - - def each_resource - each_answer {|name, ttl, data| yield name, ttl, data} - each_authority {|name, ttl, data| yield name, ttl, data} - each_additional {|name, ttl, data| yield name, ttl, data} - end - - def encode - return MessageEncoder.new {|msg| - msg.put_pack('nnnnnn', - @id, - (@qr & 1) << 15 | - (@opcode & 15) << 11 | - (@aa & 1) << 10 | - (@tc & 1) << 9 | - (@rd & 1) << 8 | - (@ra & 1) << 7 | - (@rcode & 15), - @question.length, - @answer.length, - @authority.length, - @additional.length) - @question.each {|q| - name, typeclass = q - msg.put_name(name) - msg.put_pack('nn', typeclass::TypeValue, typeclass::ClassValue) - } - [@answer, @authority, @additional].each {|rr| - rr.each {|r| - name, ttl, data = r - msg.put_name(name) - msg.put_pack('nnN', data.class::TypeValue, data.class::ClassValue, ttl) - msg.put_length16 {data.encode_rdata(msg)} - } - } - }.to_s - end - - class MessageEncoder # :nodoc: - def initialize - @data = ''.dup - @names = {} - yield self - end - - def to_s - return @data - end - - def put_bytes(d) - @data << d - end - - def put_pack(template, *d) - @data << d.pack(template) - end - - def put_length16 - length_index = @data.length - @data << "\0\0" - data_start = @data.length - yield - data_end = @data.length - @data[length_index, 2] = [data_end - data_start].pack("n") - end - - def put_string(d) - self.put_pack("C", d.length) - @data << d - end - - def put_string_list(ds) - ds.each {|d| - self.put_string(d) - } - end - - def put_name(d) - put_labels(d.to_a) - end - - def put_labels(d) - d.each_index {|i| - domain = d[i..-1] - if idx = @names[domain] - self.put_pack("n", 0xc000 | idx) - return - else - if @data.length < 0x4000 - @names[domain] = @data.length - end - self.put_label(d[i]) - end - } - @data << "\0" - end - - def put_label(d) - self.put_string(d.to_s) - end - end - - def Message.decode(m) - o = Message.new(0) - MessageDecoder.new(m) {|msg| - id, flag, qdcount, ancount, nscount, arcount = - msg.get_unpack('nnnnnn') - o.id = id - o.qr = (flag >> 15) & 1 - o.opcode = (flag >> 11) & 15 - o.aa = (flag >> 10) & 1 - o.tc = (flag >> 9) & 1 - o.rd = (flag >> 8) & 1 - o.ra = (flag >> 7) & 1 - o.rcode = flag & 15 - (1..qdcount).each { - name, typeclass = msg.get_question - o.add_question(name, typeclass) - } - (1..ancount).each { - name, ttl, data = msg.get_rr - o.add_answer(name, ttl, data) - } - (1..nscount).each { - name, ttl, data = msg.get_rr - o.add_authority(name, ttl, data) - } - (1..arcount).each { - name, ttl, data = msg.get_rr - o.add_additional(name, ttl, data) - } - } - return o - end - - class MessageDecoder # :nodoc: - def initialize(data) - @data = data - @index = 0 - @limit = data.bytesize - yield self - end - - def inspect - "\#<#{self.class}: #{@data.byteslice(0, @index).inspect} #{@data.byteslice(@index..-1).inspect}>" - end - - def get_length16 - len, = self.get_unpack('n') - save_limit = @limit - @limit = @index + len - d = yield(len) - if @index < @limit - raise DecodeError.new("junk exists") - elsif @limit < @index - raise DecodeError.new("limit exceeded") - end - @limit = save_limit - return d - end - - def get_bytes(len = @limit - @index) - raise DecodeError.new("limit exceeded") if @limit < @index + len - d = @data.byteslice(@index, len) - @index += len - return d - end - - def get_unpack(template) - len = 0 - template.each_byte {|byte| - byte = "%c" % byte - case byte - when ?c, ?C - len += 1 - when ?n - len += 2 - when ?N - len += 4 - else - raise StandardError.new("unsupported template: '#{byte.chr}' in '#{template}'") - end - } - raise DecodeError.new("limit exceeded") if @limit < @index + len - arr = @data.unpack("@#{@index}#{template}") - @index += len - return arr - end - - def get_string - raise DecodeError.new("limit exceeded") if @limit <= @index - len = @data.getbyte(@index) - raise DecodeError.new("limit exceeded") if @limit < @index + 1 + len - d = @data.byteslice(@index + 1, len) - @index += 1 + len - return d - end - - def get_string_list - strings = [] - while @index < @limit - strings << self.get_string - end - strings - end - - def get_name - return Name.new(self.get_labels) - end - - def get_labels - prev_index = @index - save_index = nil - d = [] - while true - raise DecodeError.new("limit exceeded") if @limit <= @index - case @data.getbyte(@index) - when 0 - @index += 1 - if save_index - @index = save_index - end - return d - when 192..255 - idx = self.get_unpack('n')[0] & 0x3fff - if prev_index <= idx - raise DecodeError.new("non-backward name pointer") - end - prev_index = idx - if !save_index - save_index = @index - end - @index = idx - else - d << self.get_label - end - end - end - - def get_label - return Label::Str.new(self.get_string) - end - - def get_question - name = self.get_name - type, klass = self.get_unpack("nn") - return name, Resource.get_class(type, klass) - end - - def get_rr - name = self.get_name - type, klass, ttl = self.get_unpack('nnN') - typeclass = Resource.get_class(type, klass) - res = self.get_length16 do - begin - typeclass.decode_rdata self - rescue => e - raise DecodeError, e.message, e.backtrace - end - end - res.instance_variable_set :@ttl, ttl - return name, ttl, res - end - end - end - - ## - # A DNS query abstract class. - - class Query - def encode_rdata(msg) # :nodoc: - raise EncodeError.new("#{self.class} is query.") - end - - def self.decode_rdata(msg) # :nodoc: - raise DecodeError.new("#{self.class} is query.") - end - end - - ## - # A DNS resource abstract class. - - class Resource < Query - - ## - # Remaining Time To Live for this Resource. - - attr_reader :ttl - - ClassHash = {} # :nodoc: - - def encode_rdata(msg) # :nodoc: - raise NotImplementedError.new - end - - def self.decode_rdata(msg) # :nodoc: - raise NotImplementedError.new - end - - def ==(other) # :nodoc: - return false unless self.class == other.class - s_ivars = self.instance_variables - s_ivars.sort! - s_ivars.delete :@ttl - o_ivars = other.instance_variables - o_ivars.sort! - o_ivars.delete :@ttl - return s_ivars == o_ivars && - s_ivars.collect {|name| self.instance_variable_get name} == - o_ivars.collect {|name| other.instance_variable_get name} - end - - def eql?(other) # :nodoc: - return self == other - end - - def hash # :nodoc: - h = 0 - vars = self.instance_variables - vars.delete :@ttl - vars.each {|name| - h ^= self.instance_variable_get(name).hash - } - return h - end - - def self.get_class(type_value, class_value) # :nodoc: - return ClassHash[[type_value, class_value]] || - Generic.create(type_value, class_value) - end - - ## - # A generic resource abstract class. - - class Generic < Resource - - ## - # Creates a new generic resource. - - def initialize(data) - @data = data - end - - ## - # Data for this generic resource. - - attr_reader :data - - def encode_rdata(msg) # :nodoc: - msg.put_bytes(data) - end - - def self.decode_rdata(msg) # :nodoc: - return self.new(msg.get_bytes) - end - - def self.create(type_value, class_value) # :nodoc: - c = Class.new(Generic) - c.const_set(:TypeValue, type_value) - c.const_set(:ClassValue, class_value) - Generic.const_set("Type#{type_value}_Class#{class_value}", c) - ClassHash[[type_value, class_value]] = c - return c - end - end - - ## - # Domain Name resource abstract class. - - class DomainName < Resource - - ## - # Creates a new DomainName from +name+. - - def initialize(name) - @name = name - end - - ## - # The name of this DomainName. - - attr_reader :name - - def encode_rdata(msg) # :nodoc: - msg.put_name(@name) - end - - def self.decode_rdata(msg) # :nodoc: - return self.new(msg.get_name) - end - end - - # Standard (class generic) RRs - - ClassValue = nil # :nodoc: - - ## - # An authoritative name server. - - class NS < DomainName - TypeValue = 2 # :nodoc: - end - - ## - # The canonical name for an alias. - - class CNAME < DomainName - TypeValue = 5 # :nodoc: - end - - ## - # Start Of Authority resource. - - class SOA < Resource - - TypeValue = 6 # :nodoc: - - ## - # Creates a new SOA record. See the attr documentation for the - # details of each argument. - - def initialize(mname, rname, serial, refresh, retry_, expire, minimum) - @mname = mname - @rname = rname - @serial = serial - @refresh = refresh - @retry = retry_ - @expire = expire - @minimum = minimum - end - - ## - # Name of the host where the master zone file for this zone resides. - - attr_reader :mname - - ## - # The person responsible for this domain name. - - attr_reader :rname - - ## - # The version number of the zone file. - - attr_reader :serial - - ## - # How often, in seconds, a secondary name server is to check for - # updates from the primary name server. - - attr_reader :refresh - - ## - # How often, in seconds, a secondary name server is to retry after a - # failure to check for a refresh. - - attr_reader :retry - - ## - # Time in seconds that a secondary name server is to use the data - # before refreshing from the primary name server. - - attr_reader :expire - - ## - # The minimum number of seconds to be used for TTL values in RRs. - - attr_reader :minimum - - def encode_rdata(msg) # :nodoc: - msg.put_name(@mname) - msg.put_name(@rname) - msg.put_pack('NNNNN', @serial, @refresh, @retry, @expire, @minimum) - end - - def self.decode_rdata(msg) # :nodoc: - mname = msg.get_name - rname = msg.get_name - serial, refresh, retry_, expire, minimum = msg.get_unpack('NNNNN') - return self.new( - mname, rname, serial, refresh, retry_, expire, minimum) - end - end - - ## - # A Pointer to another DNS name. - - class PTR < DomainName - TypeValue = 12 # :nodoc: - end - - ## - # Host Information resource. - - class HINFO < Resource - - TypeValue = 13 # :nodoc: - - ## - # Creates a new HINFO running +os+ on +cpu+. - - def initialize(cpu, os) - @cpu = cpu - @os = os - end - - ## - # CPU architecture for this resource. - - attr_reader :cpu - - ## - # Operating system for this resource. - - attr_reader :os - - def encode_rdata(msg) # :nodoc: - msg.put_string(@cpu) - msg.put_string(@os) - end - - def self.decode_rdata(msg) # :nodoc: - cpu = msg.get_string - os = msg.get_string - return self.new(cpu, os) - end - end - - ## - # Mailing list or mailbox information. - - class MINFO < Resource - - TypeValue = 14 # :nodoc: - - def initialize(rmailbx, emailbx) - @rmailbx = rmailbx - @emailbx = emailbx - end - - ## - # Domain name responsible for this mail list or mailbox. - - attr_reader :rmailbx - - ## - # Mailbox to use for error messages related to the mail list or mailbox. - - attr_reader :emailbx - - def encode_rdata(msg) # :nodoc: - msg.put_name(@rmailbx) - msg.put_name(@emailbx) - end - - def self.decode_rdata(msg) # :nodoc: - rmailbx = msg.get_string - emailbx = msg.get_string - return self.new(rmailbx, emailbx) - end - end - - ## - # Mail Exchanger resource. - - class MX < Resource - - TypeValue= 15 # :nodoc: - - ## - # Creates a new MX record with +preference+, accepting mail at - # +exchange+. - - def initialize(preference, exchange) - @preference = preference - @exchange = exchange - end - - ## - # The preference for this MX. - - attr_reader :preference - - ## - # The host of this MX. - - attr_reader :exchange - - def encode_rdata(msg) # :nodoc: - msg.put_pack('n', @preference) - msg.put_name(@exchange) - end - - def self.decode_rdata(msg) # :nodoc: - preference, = msg.get_unpack('n') - exchange = msg.get_name - return self.new(preference, exchange) - end - end - - ## - # Unstructured text resource. - - class TXT < Resource - - TypeValue = 16 # :nodoc: - - def initialize(first_string, *rest_strings) - @strings = [first_string, *rest_strings] - end - - ## - # Returns an Array of Strings for this TXT record. - - attr_reader :strings - - ## - # Returns the concatenated string from +strings+. - - def data - @strings.join("") - end - - def encode_rdata(msg) # :nodoc: - msg.put_string_list(@strings) - end - - def self.decode_rdata(msg) # :nodoc: - strings = msg.get_string_list - return self.new(*strings) - end - end - - ## - # Location resource - - class LOC < Resource - - TypeValue = 29 # :nodoc: - - def initialize(version, ssize, hprecision, vprecision, latitude, longitude, altitude) - @version = version - @ssize = Resolv::LOC::Size.create(ssize) - @hprecision = Resolv::LOC::Size.create(hprecision) - @vprecision = Resolv::LOC::Size.create(vprecision) - @latitude = Resolv::LOC::Coord.create(latitude) - @longitude = Resolv::LOC::Coord.create(longitude) - @altitude = Resolv::LOC::Alt.create(altitude) - end - - ## - # Returns the version value for this LOC record which should always be 00 - - attr_reader :version - - ## - # The spherical size of this LOC - # in meters using scientific notation as 2 integers of XeY - - attr_reader :ssize - - ## - # The horizontal precision using ssize type values - # in meters using scientific notation as 2 integers of XeY - # for precision use value/2 e.g. 2m = +/-1m - - attr_reader :hprecision - - ## - # The vertical precision using ssize type values - # in meters using scientific notation as 2 integers of XeY - # for precision use value/2 e.g. 2m = +/-1m - - attr_reader :vprecision - - ## - # The latitude for this LOC where 2**31 is the equator - # in thousandths of an arc second as an unsigned 32bit integer - - attr_reader :latitude - - ## - # The longitude for this LOC where 2**31 is the prime meridian - # in thousandths of an arc second as an unsigned 32bit integer - - attr_reader :longitude - - ## - # The altitude of the LOC above a reference sphere whose surface sits 100km below the WGS84 spheroid - # in centimeters as an unsigned 32bit integer - - attr_reader :altitude - - - def encode_rdata(msg) # :nodoc: - msg.put_bytes(@version) - msg.put_bytes(@ssize.scalar) - msg.put_bytes(@hprecision.scalar) - msg.put_bytes(@vprecision.scalar) - msg.put_bytes(@latitude.coordinates) - msg.put_bytes(@longitude.coordinates) - msg.put_bytes(@altitude.altitude) - end - - def self.decode_rdata(msg) # :nodoc: - version = msg.get_bytes(1) - ssize = msg.get_bytes(1) - hprecision = msg.get_bytes(1) - vprecision = msg.get_bytes(1) - latitude = msg.get_bytes(4) - longitude = msg.get_bytes(4) - altitude = msg.get_bytes(4) - return self.new( - version, - Resolv::LOC::Size.new(ssize), - Resolv::LOC::Size.new(hprecision), - Resolv::LOC::Size.new(vprecision), - Resolv::LOC::Coord.new(latitude,"lat"), - Resolv::LOC::Coord.new(longitude,"lon"), - Resolv::LOC::Alt.new(altitude) - ) - end - end - - ## - # A Query type requesting any RR. - - class ANY < Query - TypeValue = 255 # :nodoc: - end - - ClassInsensitiveTypes = [ # :nodoc: - NS, CNAME, SOA, PTR, HINFO, MINFO, MX, TXT, LOC, ANY - ] - - ## - # module IN contains ARPA Internet specific RRs. - - module IN - - ClassValue = 1 # :nodoc: - - ClassInsensitiveTypes.each {|s| - c = Class.new(s) - c.const_set(:TypeValue, s::TypeValue) - c.const_set(:ClassValue, ClassValue) - ClassHash[[s::TypeValue, ClassValue]] = c - self.const_set(s.name.sub(/.*::/, ''), c) - } - - ## - # IPv4 Address resource - - class A < Resource - TypeValue = 1 - ClassValue = IN::ClassValue - ClassHash[[TypeValue, ClassValue]] = self # :nodoc: - - ## - # Creates a new A for +address+. - - def initialize(address) - @address = IPv4.create(address) - end - - ## - # The Resolv::IPv4 address for this A. - - attr_reader :address - - def encode_rdata(msg) # :nodoc: - msg.put_bytes(@address.address) - end - - def self.decode_rdata(msg) # :nodoc: - return self.new(IPv4.new(msg.get_bytes(4))) - end - end - - ## - # Well Known Service resource. - - class WKS < Resource - TypeValue = 11 - ClassValue = IN::ClassValue - ClassHash[[TypeValue, ClassValue]] = self # :nodoc: - - def initialize(address, protocol, bitmap) - @address = IPv4.create(address) - @protocol = protocol - @bitmap = bitmap - end - - ## - # The host these services run on. - - attr_reader :address - - ## - # IP protocol number for these services. - - attr_reader :protocol - - ## - # A bit map of enabled services on this host. - # - # If protocol is 6 (TCP) then the 26th bit corresponds to the SMTP - # service (port 25). If this bit is set, then an SMTP server should - # be listening on TCP port 25; if zero, SMTP service is not - # supported. - - attr_reader :bitmap - - def encode_rdata(msg) # :nodoc: - msg.put_bytes(@address.address) - msg.put_pack("n", @protocol) - msg.put_bytes(@bitmap) - end - - def self.decode_rdata(msg) # :nodoc: - address = IPv4.new(msg.get_bytes(4)) - protocol, = msg.get_unpack("n") - bitmap = msg.get_bytes - return self.new(address, protocol, bitmap) - end - end - - ## - # An IPv6 address record. - - class AAAA < Resource - TypeValue = 28 - ClassValue = IN::ClassValue - ClassHash[[TypeValue, ClassValue]] = self # :nodoc: - - ## - # Creates a new AAAA for +address+. - - def initialize(address) - @address = IPv6.create(address) - end - - ## - # The Resolv::IPv6 address for this AAAA. - - attr_reader :address - - def encode_rdata(msg) # :nodoc: - msg.put_bytes(@address.address) - end - - def self.decode_rdata(msg) # :nodoc: - return self.new(IPv6.new(msg.get_bytes(16))) - end - end - - ## - # SRV resource record defined in RFC 2782 - # - # These records identify the hostname and port that a service is - # available at. - - class SRV < Resource - TypeValue = 33 - ClassValue = IN::ClassValue - ClassHash[[TypeValue, ClassValue]] = self # :nodoc: - - # Create a SRV resource record. - # - # See the documentation for #priority, #weight, #port and #target - # for +priority+, +weight+, +port and +target+ respectively. - - def initialize(priority, weight, port, target) - @priority = priority.to_int - @weight = weight.to_int - @port = port.to_int - @target = Name.create(target) - end - - # The priority of this target host. - # - # A client MUST attempt to contact the target host with the - # lowest-numbered priority it can reach; target hosts with the same - # priority SHOULD be tried in an order defined by the weight field. - # The range is 0-65535. Note that it is not widely implemented and - # should be set to zero. - - attr_reader :priority - - # A server selection mechanism. - # - # The weight field specifies a relative weight for entries with the - # same priority. Larger weights SHOULD be given a proportionately - # higher probability of being selected. The range of this number is - # 0-65535. Domain administrators SHOULD use Weight 0 when there - # isn't any server selection to do, to make the RR easier to read - # for humans (less noisy). Note that it is not widely implemented - # and should be set to zero. - - attr_reader :weight - - # The port on this target host of this service. - # - # The range is 0-65535. - - attr_reader :port - - # The domain name of the target host. - # - # A target of "." means that the service is decidedly not available - # at this domain. - - attr_reader :target - - def encode_rdata(msg) # :nodoc: - msg.put_pack("n", @priority) - msg.put_pack("n", @weight) - msg.put_pack("n", @port) - msg.put_name(@target) - end - - def self.decode_rdata(msg) # :nodoc: - priority, = msg.get_unpack("n") - weight, = msg.get_unpack("n") - port, = msg.get_unpack("n") - target = msg.get_name - return self.new(priority, weight, port, target) - end - end - end - end - end - - ## - # A Resolv::DNS IPv4 address. - - class IPv4 - - ## - # Regular expression IPv4 addresses must match. - - Regex256 = /0 - |1(?:[0-9][0-9]?)? - |2(?:[0-4][0-9]?|5[0-5]?|[6-9])? - |[3-9][0-9]?/x - Regex = /\A(#{Regex256})\.(#{Regex256})\.(#{Regex256})\.(#{Regex256})\z/ - - def self.create(arg) - case arg - when IPv4 - return arg - when Regex - if (0..255) === (a = $1.to_i) && - (0..255) === (b = $2.to_i) && - (0..255) === (c = $3.to_i) && - (0..255) === (d = $4.to_i) - return self.new([a, b, c, d].pack("CCCC")) - else - raise ArgumentError.new("IPv4 address with invalid value: " + arg) - end - else - raise ArgumentError.new("cannot interpret as IPv4 address: #{arg.inspect}") - end - end - - def initialize(address) # :nodoc: - unless address.kind_of?(String) - raise ArgumentError, 'IPv4 address must be a string' - end - unless address.length == 4 - raise ArgumentError, "IPv4 address expects 4 bytes but #{address.length} bytes" - end - @address = address - end - - ## - # A String representation of this IPv4 address. - - ## - # The raw IPv4 address as a String. - - attr_reader :address - - def to_s # :nodoc: - return sprintf("%d.%d.%d.%d", *@address.unpack("CCCC")) - end - - def inspect # :nodoc: - return "#<#{self.class} #{self}>" - end - - ## - # Turns this IPv4 address into a Resolv::DNS::Name. - - def to_name - return DNS::Name.create( - '%d.%d.%d.%d.in-addr.arpa.' % @address.unpack('CCCC').reverse) - end - - def ==(other) # :nodoc: - return @address == other.address - end - - def eql?(other) # :nodoc: - return self == other - end - - def hash # :nodoc: - return @address.hash - end - end - - ## - # A Resolv::DNS IPv6 address. - - class IPv6 - - ## - # IPv6 address format a:b:c:d:e:f:g:h - Regex_8Hex = /\A - (?:[0-9A-Fa-f]{1,4}:){7} - [0-9A-Fa-f]{1,4} - \z/x - - ## - # Compressed IPv6 address format a::b - - Regex_CompressedHex = /\A - ((?:[0-9A-Fa-f]{1,4}(?::[0-9A-Fa-f]{1,4})*)?) :: - ((?:[0-9A-Fa-f]{1,4}(?::[0-9A-Fa-f]{1,4})*)?) - \z/x - - ## - # IPv4 mapped IPv6 address format a:b:c:d:e:f:w.x.y.z - - Regex_6Hex4Dec = /\A - ((?:[0-9A-Fa-f]{1,4}:){6,6}) - (\d+)\.(\d+)\.(\d+)\.(\d+) - \z/x - - ## - # Compressed IPv4 mapped IPv6 address format a::b:w.x.y.z - - Regex_CompressedHex4Dec = /\A - ((?:[0-9A-Fa-f]{1,4}(?::[0-9A-Fa-f]{1,4})*)?) :: - ((?:[0-9A-Fa-f]{1,4}:)*) - (\d+)\.(\d+)\.(\d+)\.(\d+) - \z/x - - ## - # A composite IPv6 address Regexp. - - Regex = / - (?:#{Regex_8Hex}) | - (?:#{Regex_CompressedHex}) | - (?:#{Regex_6Hex4Dec}) | - (?:#{Regex_CompressedHex4Dec})/x - - ## - # Creates a new IPv6 address from +arg+ which may be: - # - # IPv6:: returns +arg+. - # String:: +arg+ must match one of the IPv6::Regex* constants - - def self.create(arg) - case arg - when IPv6 - return arg - when String - address = ''.b - if Regex_8Hex =~ arg - arg.scan(/[0-9A-Fa-f]+/) {|hex| address << [hex.hex].pack('n')} - elsif Regex_CompressedHex =~ arg - prefix = $1 - suffix = $2 - a1 = ''.b - a2 = ''.b - prefix.scan(/[0-9A-Fa-f]+/) {|hex| a1 << [hex.hex].pack('n')} - suffix.scan(/[0-9A-Fa-f]+/) {|hex| a2 << [hex.hex].pack('n')} - omitlen = 16 - a1.length - a2.length - address << a1 << "\0" * omitlen << a2 - elsif Regex_6Hex4Dec =~ arg - prefix, a, b, c, d = $1, $2.to_i, $3.to_i, $4.to_i, $5.to_i - if (0..255) === a && (0..255) === b && (0..255) === c && (0..255) === d - prefix.scan(/[0-9A-Fa-f]+/) {|hex| address << [hex.hex].pack('n')} - address << [a, b, c, d].pack('CCCC') - else - raise ArgumentError.new("not numeric IPv6 address: " + arg) - end - elsif Regex_CompressedHex4Dec =~ arg - prefix, suffix, a, b, c, d = $1, $2, $3.to_i, $4.to_i, $5.to_i, $6.to_i - if (0..255) === a && (0..255) === b && (0..255) === c && (0..255) === d - a1 = ''.b - a2 = ''.b - prefix.scan(/[0-9A-Fa-f]+/) {|hex| a1 << [hex.hex].pack('n')} - suffix.scan(/[0-9A-Fa-f]+/) {|hex| a2 << [hex.hex].pack('n')} - omitlen = 12 - a1.length - a2.length - address << a1 << "\0" * omitlen << a2 << [a, b, c, d].pack('CCCC') - else - raise ArgumentError.new("not numeric IPv6 address: " + arg) - end - else - raise ArgumentError.new("not numeric IPv6 address: " + arg) - end - return IPv6.new(address) - else - raise ArgumentError.new("cannot interpret as IPv6 address: #{arg.inspect}") - end - end - - def initialize(address) # :nodoc: - unless address.kind_of?(String) && address.length == 16 - raise ArgumentError.new('IPv6 address must be 16 bytes') - end - @address = address - end - - ## - # The raw IPv6 address as a String. - - attr_reader :address - - def to_s # :nodoc: - address = sprintf("%X:%X:%X:%X:%X:%X:%X:%X", *@address.unpack("nnnnnnnn")) - unless address.sub!(/(^|:)0(:0)+(:|$)/, '::') - address.sub!(/(^|:)0(:|$)/, '::') - end - return address - end - - def inspect # :nodoc: - return "#<#{self.class} #{self}>" - end - - ## - # Turns this IPv6 address into a Resolv::DNS::Name. - #-- - # ip6.arpa should be searched too. [RFC3152] - - def to_name - return DNS::Name.new( - @address.unpack("H32")[0].split(//).reverse + ['ip6', 'arpa']) - end - - def ==(other) # :nodoc: - return @address == other.address - end - - def eql?(other) # :nodoc: - return self == other - end - - def hash # :nodoc: - return @address.hash - end - end - - ## - # Resolv::MDNS is a one-shot Multicast DNS (mDNS) resolver. It blindly - # makes queries to the mDNS addresses without understanding anything about - # multicast ports. - # - # Information taken form the following places: - # - # * RFC 6762 - - class MDNS < DNS - - ## - # Default mDNS Port - - Port = 5353 - - ## - # Default IPv4 mDNS address - - AddressV4 = '224.0.0.251' - - ## - # Default IPv6 mDNS address - - AddressV6 = 'ff02::fb' - - ## - # Default mDNS addresses - - Addresses = [ - [AddressV4, Port], - [AddressV6, Port], - ] - - ## - # Creates a new one-shot Multicast DNS (mDNS) resolver. - # - # +config_info+ can be: - # - # nil:: - # Uses the default mDNS addresses - # - # Hash:: - # Must contain :nameserver or :nameserver_port like - # Resolv::DNS#initialize. - - def initialize(config_info=nil) - if config_info then - super({ nameserver_port: Addresses }.merge(config_info)) - else - super(nameserver_port: Addresses) - end - end - - ## - # Iterates over all IP addresses for +name+ retrieved from the mDNS - # resolver, provided name ends with "local". If the name does not end in - # "local" no records will be returned. - # - # +name+ can be a Resolv::DNS::Name or a String. Retrieved addresses will - # be a Resolv::IPv4 or Resolv::IPv6 - - def each_address(name) - name = Resolv::DNS::Name.create(name) - - return unless name.to_a.last.to_s == 'local' - - super(name) - end - - def make_udp_requester # :nodoc: - nameserver_port = @config.nameserver_port - Requester::MDNSOneShot.new(*nameserver_port) - end - - end - - module LOC - - ## - # A Resolv::LOC::Size - - class Size - - Regex = /^(\d+\.*\d*)[m]$/ - - ## - # Creates a new LOC::Size from +arg+ which may be: - # - # LOC::Size:: returns +arg+. - # String:: +arg+ must match the LOC::Size::Regex constant - - def self.create(arg) - case arg - when Size - return arg - when String - scalar = '' - if Regex =~ arg - scalar = [(($1.to_f*(1e2)).to_i.to_s[0].to_i*(2**4)+(($1.to_f*(1e2)).to_i.to_s.length-1))].pack("C") - else - raise ArgumentError.new("not a properly formed Size string: " + arg) - end - return Size.new(scalar) - else - raise ArgumentError.new("cannot interpret as Size: #{arg.inspect}") - end - end - - def initialize(scalar) - @scalar = scalar - end - - ## - # The raw size - - attr_reader :scalar - - def to_s # :nodoc: - s = @scalar.unpack("H2").join.to_s - return ((s[0].to_i)*(10**(s[1].to_i-2))).to_s << "m" - end - - def inspect # :nodoc: - return "#<#{self.class} #{self}>" - end - - def ==(other) # :nodoc: - return @scalar == other.scalar - end - - def eql?(other) # :nodoc: - return self == other - end - - def hash # :nodoc: - return @scalar.hash - end - - end - - ## - # A Resolv::LOC::Coord - - class Coord - - Regex = /^(\d+)\s(\d+)\s(\d+\.\d+)\s([NESW])$/ - - ## - # Creates a new LOC::Coord from +arg+ which may be: - # - # LOC::Coord:: returns +arg+. - # String:: +arg+ must match the LOC::Coord::Regex constant - - def self.create(arg) - case arg - when Coord - return arg - when String - coordinates = '' - if Regex =~ arg && $1.to_f < 180 - m = $~ - hemi = (m[4][/[NE]/]) || (m[4][/[SW]/]) ? 1 : -1 - coordinates = [ ((m[1].to_i*(36e5)) + (m[2].to_i*(6e4)) + - (m[3].to_f*(1e3))) * hemi+(2**31) ].pack("N") - orientation = m[4][/[NS]/] ? 'lat' : 'lon' - else - raise ArgumentError.new("not a properly formed Coord string: " + arg) - end - return Coord.new(coordinates,orientation) - else - raise ArgumentError.new("cannot interpret as Coord: #{arg.inspect}") - end - end - - def initialize(coordinates,orientation) - unless coordinates.kind_of?(String) - raise ArgumentError.new("Coord must be a 32bit unsigned integer in hex format: #{coordinates.inspect}") - end - unless orientation.kind_of?(String) && orientation[/^lon$|^lat$/] - raise ArgumentError.new('Coord expects orientation to be a String argument of "lat" or "lon"') - end - @coordinates = coordinates - @orientation = orientation - end - - ## - # The raw coordinates - - attr_reader :coordinates - - ## The orientation of the hemisphere as 'lat' or 'lon' - - attr_reader :orientation - - def to_s # :nodoc: - c = @coordinates.unpack("N").join.to_i - val = (c - (2**31)).abs - fracsecs = (val % 1e3).to_i.to_s - val = val / 1e3 - secs = (val % 60).to_i.to_s - val = val / 60 - mins = (val % 60).to_i.to_s - degs = (val / 60).to_i.to_s - posi = (c >= 2**31) - case posi - when true - hemi = @orientation[/^lat$/] ? "N" : "E" - else - hemi = @orientation[/^lon$/] ? "W" : "S" - end - return degs << " " << mins << " " << secs << "." << fracsecs << " " << hemi - end - - def inspect # :nodoc: - return "#<#{self.class} #{self}>" - end - - def ==(other) # :nodoc: - return @coordinates == other.coordinates - end - - def eql?(other) # :nodoc: - return self == other - end - - def hash # :nodoc: - return @coordinates.hash - end - - end - - ## - # A Resolv::LOC::Alt - - class Alt - - Regex = /^([+-]*\d+\.*\d*)[m]$/ - - ## - # Creates a new LOC::Alt from +arg+ which may be: - # - # LOC::Alt:: returns +arg+. - # String:: +arg+ must match the LOC::Alt::Regex constant - - def self.create(arg) - case arg - when Alt - return arg - when String - altitude = '' - if Regex =~ arg - altitude = [($1.to_f*(1e2))+(1e7)].pack("N") - else - raise ArgumentError.new("not a properly formed Alt string: " + arg) - end - return Alt.new(altitude) - else - raise ArgumentError.new("cannot interpret as Alt: #{arg.inspect}") - end - end - - def initialize(altitude) - @altitude = altitude - end - - ## - # The raw altitude - - attr_reader :altitude - - def to_s # :nodoc: - a = @altitude.unpack("N").join.to_i - return ((a.to_f/1e2)-1e5).to_s + "m" - end - - def inspect # :nodoc: - return "#<#{self.class} #{self}>" - end - - def ==(other) # :nodoc: - return @altitude == other.altitude - end - - def eql?(other) # :nodoc: - return self == other - end - - def hash # :nodoc: - return @altitude.hash - end - - end - - end - - ## - # Default resolver to use for Resolv class methods. - - DefaultResolver = self.new - - ## - # Replaces the resolvers in the default resolver with +new_resolvers+. This - # allows resolvers to be changed for resolv-replace. - - def DefaultResolver.replace_resolvers new_resolvers - @resolvers = new_resolvers - end - - ## - # Address Regexp to use for matching IP addresses. - - AddressRegex = /(?:#{IPv4::Regex})|(?:#{IPv6::Regex})/ - -end From 94b93af7548ff22e31421006ce2623718e94a516 Mon Sep 17 00:00:00 2001 From: Joao Duarte Date: Thu, 21 Nov 2019 11:27:39 +0000 Subject: [PATCH 0279/1126] remove leftover jruby version check in spec file Fixes #11333 --- logstash-core/spec/logstash/jruby_version_spec.rb | 15 --------------- 1 file changed, 15 deletions(-) delete mode 100644 logstash-core/spec/logstash/jruby_version_spec.rb diff --git a/logstash-core/spec/logstash/jruby_version_spec.rb b/logstash-core/spec/logstash/jruby_version_spec.rb deleted file mode 100644 index 69424fd10..000000000 --- a/logstash-core/spec/logstash/jruby_version_spec.rb +++ /dev/null @@ -1,15 +0,0 @@ -require 'spec_helper' - - -describe "JRuby Version" do - it "should break on JRuby version change" do - # This spec will break upon JRuby version change to make sure we - # verify if resolv.rb has been fixed in Jruby so we can get rid of - # lib/logstash/patches/resolv.rb. - # ref: - # https://github.com/logstash-plugins/logstash-filter-dns/issues/51 - # https://github.com/jruby/jruby/pull/5722 - expect(JRUBY_VERSION).to eq("9.2.8.0") - end -end - From 27b717938910f37a9e55b0a04f766e8f54d5ee6b Mon Sep 17 00:00:00 2001 From: Colin Surprenant Date: Thu, 21 Nov 2019 15:26:09 -0500 Subject: [PATCH 0280/1126] support remove_field on metadata and tests Fixes #11334 --- .../spec/logstash/filters/base_spec.rb | 35 +++++++++++++ .../src/main/java/org/logstash/Event.java | 12 ++++- .../src/test/java/org/logstash/EventTest.java | 28 ++++++++++ .../config/ir/compiler/CommonActionsTest.java | 52 +++++++++++++++++++ 4 files changed, 126 insertions(+), 1 deletion(-) diff --git a/logstash-core/spec/logstash/filters/base_spec.rb b/logstash-core/spec/logstash/filters/base_spec.rb index 7d6f2eb5f..34a8ac94d 100644 --- a/logstash-core/spec/logstash/filters/base_spec.rb +++ b/logstash-core/spec/logstash/filters/base_spec.rb @@ -280,6 +280,41 @@ describe LogStash::Filters::NOOP do end end + describe "remove_field within @metadata" do + config <<-CONFIG + filter { + noop { + remove_field => ["[@metadata][f1]", "[@metadata][f2]", "[@metadata][f4][f5]"] + } + } + CONFIG + + sample_one("type" => "noop", "@metadata" => {"f1" => "one", "f2" => { "f3" => "three"}, "f4" => { "f5" => "five", "f6" => "six"}, "f7" => "seven"}) do + expect(subject.include?("[@metadata][f1]")).to be_falsey + expect(subject.include?("[@metadata][f2]")).to be_falsey + expect(subject.include?("[@metadata][f4]")).to be_truthy + expect(subject.include?("[@metadata][f4][f5]")).to be_falsey + expect(subject.include?("[@metadata][f4][f6]")).to be_truthy + expect(subject.include?("[@metadata][f7]")).to be_truthy + end + end + + describe "remove_field on @metadata" do + config <<-CONFIG + filter { + noop { + remove_field => ["[@metadata]"] + } + } + CONFIG + + sample_one("type" => "noop", "@metadata" => {"f1" => "one", "f2" => { "f3" => "three"}}) do + expect(subject.include?("[@metadata]")).to be_truthy + expect(subject.include?("[@metadata][f1]")).to be_falsey + expect(subject.include?("[@metadata][f2]")).to be_falsey + end + end + describe "remove_field on array" do config <<-CONFIG filter { diff --git a/logstash-core/src/main/java/org/logstash/Event.java b/logstash-core/src/main/java/org/logstash/Event.java index 7885de87b..ea8450191 100644 --- a/logstash-core/src/main/java/org/logstash/Event.java +++ b/logstash-core/src/main/java/org/logstash/Event.java @@ -296,7 +296,17 @@ public final class Event implements Cloneable, Queueable, co.elastic.logstash.ap } public Object remove(final FieldReference field) { - return Accessors.del(data, field); + switch (field.type()) { + case FieldReference.META_PARENT: + // removal of metadata is actually emptying metadata. + final ConvertedMap old_value = ConvertedMap.newFromMap(this.metadata); + this.metadata = new ConvertedMap(); + return Javafier.deep(old_value); + case FieldReference.META_CHILD: + return Accessors.del(metadata, field); + default: + return Accessors.del(data, field); + } } @Override diff --git a/logstash-core/src/test/java/org/logstash/EventTest.java b/logstash-core/src/test/java/org/logstash/EventTest.java index d823d6dbf..d974a31ec 100644 --- a/logstash-core/src/test/java/org/logstash/EventTest.java +++ b/logstash-core/src/test/java/org/logstash/EventTest.java @@ -453,4 +453,32 @@ public final class EventTest { assertEquals(list, Arrays.asList("hello")); } + + @Test + public void removeMetadataField() { + final Event event = new Event(); + final Map metadata = new HashMap<>(); + metadata.put("foo", "bar"); + event.setField("@metadata", metadata); + + final RubyString s = (RubyString)event.remove("[@metadata][foo]"); + assertEquals(s.toString(), "bar"); + + assertFalse(event.includes("[@metadata][foo]")); + } + + @SuppressWarnings("unchecked") + @Test + public void removeMetadata() { + final Event event = new Event(); + final Map metadata = new HashMap<>(); + metadata.put("foo", "bar"); + event.setField("@metadata", metadata); + + final Map m = (Map)(event.remove("[@metadata]")); + assertEquals(m.get("foo"), "bar"); + + assertTrue(event.getMetadata().isEmpty()); + assertFalse(event.includes("[@metadata][foo]")); + } } diff --git a/logstash-core/src/test/java/org/logstash/config/ir/compiler/CommonActionsTest.java b/logstash-core/src/test/java/org/logstash/config/ir/compiler/CommonActionsTest.java index 31214c95b..1b9fce899 100644 --- a/logstash-core/src/test/java/org/logstash/config/ir/compiler/CommonActionsTest.java +++ b/logstash-core/src/test/java/org/logstash/config/ir/compiler/CommonActionsTest.java @@ -242,4 +242,56 @@ public class CommonActionsTest { Assert.assertTrue(o instanceof List); Assert.assertEquals(0, ((List) o).size()); } + + @Test + public void testRemoveFieldFromMetadata() { + // remove a field + Event e = new Event(); + String testField = "test_field"; + String testFieldRef = "[@metadata][" + testField + "]"; + String testValue = "test_value"; + e.setField(testFieldRef, testValue); + CommonActions.removeField(e, Collections.singletonList(testFieldRef)); + Assert.assertFalse(e.getMetadata().keySet().contains(testField)); + + // remove non-existent field + e = new Event(); + String testField2 = "test_field2"; + String testField2Ref = "[@metadata][" + testField2 + "]"; + e.setField(testField2Ref, testValue); + CommonActions.removeField(e, Collections.singletonList(testFieldRef)); + Assert.assertFalse(e.getMetadata().keySet().contains(testField)); + Assert.assertTrue(e.getMetadata().keySet().contains(testField2)); + + // remove multiple fields + e = new Event(); + List fields = new ArrayList<>(); + List fieldsRef = new ArrayList<>(); + for (int k = 0; k < 3; k++) { + String field = testField + k; + String fieldRef = "[@metadata][" + field + "]"; + e.setField(fieldRef, testValue); + fields.add(field); + fieldsRef.add(fieldRef); + } + e.setField(testFieldRef, testValue); + CommonActions.removeField(e, fieldsRef); + for (String field : fields) { + Assert.assertFalse(e.getMetadata().keySet().contains(field)); + } + Assert.assertTrue(e.getMetadata().keySet().contains(testField)); + + // remove dynamically-named field + e = new Event(); + String otherField = "other_field"; + String otherFieldRef = "[@metadata][" + otherField + "]"; + String otherValue = "other_value"; + e.setField(otherFieldRef, otherValue); + String derivativeField = otherValue + "_foo"; + String derivativeFieldRef = "[@metadata][" + derivativeField + "]"; + e.setField(derivativeFieldRef, otherValue); + CommonActions.removeField(e, Collections.singletonList("[@metadata][" + "%{" + otherField + "}_foo" + "]")); + Assert.assertFalse(e.getMetadata().keySet().contains(derivativeField)); + Assert.assertTrue(e.getMetadata().keySet().contains(otherField)); + } } From 17fe14c086c11d89db1f5a07d96fec43af04e31e Mon Sep 17 00:00:00 2001 From: andsel Date: Mon, 25 Nov 2019 16:56:19 +0100 Subject: [PATCH 0281/1126] Changed GemInstaller to don't blank gemspec attribute, close 11325 Fixes #11340 --- lib/pluginmanager/gem_installer.rb | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/lib/pluginmanager/gem_installer.rb b/lib/pluginmanager/gem_installer.rb index 5a770cd9d..4e2ccec51 100644 --- a/lib/pluginmanager/gem_installer.rb +++ b/lib/pluginmanager/gem_installer.rb @@ -38,7 +38,13 @@ module LogStash module PluginManager private def spec - @gem.spec + gem_spec = @gem.spec + def gem_spec.for_cache + spec = dup + spec.test_files = nil + spec + end + gem_spec end def spec_dir From b81c900b5bc8321770d0f8d2a9429029dc0bd945 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jo=C3=A3o=20Duarte?= Date: Tue, 26 Nov 2019 11:52:55 +0000 Subject: [PATCH 0282/1126] Remove license header from pipelines_info.rb This code was moved to the apache 2.0 license part of the distribution and should not have the license header any more Fixes #11345 --- logstash-core/lib/logstash/config/pipelines_info.rb | 4 ---- 1 file changed, 4 deletions(-) diff --git a/logstash-core/lib/logstash/config/pipelines_info.rb b/logstash-core/lib/logstash/config/pipelines_info.rb index 65faf2db6..58f93daa3 100644 --- a/logstash-core/lib/logstash/config/pipelines_info.rb +++ b/logstash-core/lib/logstash/config/pipelines_info.rb @@ -1,7 +1,3 @@ -# 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. -# module LogStash; module Config; class PipelinesInfo def self.format_pipelines_info(agent, metric_store, extended_performance_collection) From b7f79ac52b713ff0db226cb5ba36c5f33f63a348 Mon Sep 17 00:00:00 2001 From: lcawl Date: Mon, 25 Nov 2019 11:51:32 -0800 Subject: [PATCH 0283/1126] Fixes monitoring link Fixes #11341 --- docs/static/monitoring/monitoring-overview.asciidoc | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/docs/static/monitoring/monitoring-overview.asciidoc b/docs/static/monitoring/monitoring-overview.asciidoc index 0a4aba6cd..1c6ff5b9b 100644 --- a/docs/static/monitoring/monitoring-overview.asciidoc +++ b/docs/static/monitoring/monitoring-overview.asciidoc @@ -5,8 +5,8 @@ Use the {stack} {monitor-features} to gain insight into the health of {ls} instances running in your environment. -For an introduction to monitoring your Elastic stack, including {es} -and {kib}, see {xpack-ref}/xpack-monitoring.html[Monitoring the Elastic Stack]. +For an introduction to monitoring your Elastic stack, see +{ref}/monitor-elasticsearch-cluster.html[Monitoring a cluster]. [float] From 62cc9afa8d8cdfec7174e2c1da7abccd2d144915 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jo=C3=A3o=20Duarte?= Date: Wed, 27 Nov 2019 15:09:55 +0000 Subject: [PATCH 0284/1126] bump sinatra and rack to 2.x (#11354) --- logstash-core/logstash-core.gemspec | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/logstash-core/logstash-core.gemspec b/logstash-core/logstash-core.gemspec index 05b45491d..4d0adeb21 100644 --- a/logstash-core/logstash-core.gemspec +++ b/logstash-core/logstash-core.gemspec @@ -53,8 +53,8 @@ Gem::Specification.new do |gem| gem.add_runtime_dependency "filesize", "~> 0.2" #(MIT license) for :bytes config validator gem.add_runtime_dependency "gems", "~> 1" #(MIT license) gem.add_runtime_dependency "concurrent-ruby", "~> 1" - gem.add_runtime_dependency "rack", '~> 1', '>= 1.6.11' - gem.add_runtime_dependency "sinatra", '~> 1', '>= 1.4.6' + gem.add_runtime_dependency "rack", '~> 2' + gem.add_runtime_dependency "sinatra", '~> 2' gem.add_runtime_dependency 'puma', '~> 4' gem.add_runtime_dependency "jruby-openssl", "~> 0.10" # >= 0.9.13 Required to support TLSv1.2 gem.add_runtime_dependency "chronic_duration", "~> 0.10" From 22871cc19f7b07629b1b2f5299e34a2537608013 Mon Sep 17 00:00:00 2001 From: Karen Metts Date: Wed, 20 Nov 2019 18:53:38 -0500 Subject: [PATCH 0285/1126] Add plugin integrations to doc Fixes #11331 --- docs/index.asciidoc | 1 + 1 file changed, 1 insertion(+) diff --git a/docs/index.asciidoc b/docs/index.asciidoc index 9519e6d65..c0a072892 100644 --- a/docs/index.asciidoc +++ b/docs/index.asciidoc @@ -207,6 +207,7 @@ include::{plugins-repo-dir}/plugins/inputs.asciidoc[] include::{plugins-repo-dir}/plugins/outputs.asciidoc[] include::{plugins-repo-dir}/plugins/filters.asciidoc[] include::{plugins-repo-dir}/plugins/codecs.asciidoc[] +include::{plugins-repo-dir}/plugins/integrations.asciidoc[] // FAQ and Troubleshooting From 1431df892f108e37e2fbab777754740d191c6193 Mon Sep 17 00:00:00 2001 From: Karen Metts Date: Tue, 26 Nov 2019 11:35:38 -0500 Subject: [PATCH 0286/1126] Incorporate review comments Fixes #11331 --- docs/index.asciidoc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/index.asciidoc b/docs/index.asciidoc index c0a072892..b0b2a30b9 100644 --- a/docs/index.asciidoc +++ b/docs/index.asciidoc @@ -203,11 +203,11 @@ include::static/plugin-manager.asciidoc[] // These files do their own pass blocks +include::{plugins-repo-dir}/plugins/integrations.asciidoc[] include::{plugins-repo-dir}/plugins/inputs.asciidoc[] include::{plugins-repo-dir}/plugins/outputs.asciidoc[] include::{plugins-repo-dir}/plugins/filters.asciidoc[] include::{plugins-repo-dir}/plugins/codecs.asciidoc[] -include::{plugins-repo-dir}/plugins/integrations.asciidoc[] // FAQ and Troubleshooting From 16c085588ff3264a8b150b963f0394e1047b4364 Mon Sep 17 00:00:00 2001 From: Karol Bucek Date: Wed, 27 Nov 2019 21:45:51 +0100 Subject: [PATCH 0287/1126] Fix: do not leak ThreadContext into the system this is fairly recent - since 7.4 (added in GH-11075) there's a risk plugins would assume ThreadContext to exist or collide the 'global' constant - usually best to import where the Java class actually gets used ... Fixes #11356 --- logstash-core/lib/logstash/java_pipeline.rb | 5 +++-- logstash-core/lib/logstash/pipeline.rb | 4 ++-- 2 files changed, 5 insertions(+), 4 deletions(-) diff --git a/logstash-core/lib/logstash/java_pipeline.rb b/logstash-core/lib/logstash/java_pipeline.rb index 7ebd6b971..3a8069a0a 100644 --- a/logstash-core/lib/logstash/java_pipeline.rb +++ b/logstash-core/lib/logstash/java_pipeline.rb @@ -8,10 +8,11 @@ require "logstash/instrument/collector" require "logstash/compiler" require "logstash/config/lir_serializer" -java_import org.apache.logging.log4j.ThreadContext - module LogStash; class JavaPipeline < JavaBasePipeline include LogStash::Util::Loggable + + java_import org.apache.logging.log4j.ThreadContext + attr_reader \ :worker_threads, :events_consumed, diff --git a/logstash-core/lib/logstash/pipeline.rb b/logstash-core/lib/logstash/pipeline.rb index b6b818ea5..181c8fed1 100644 --- a/logstash-core/lib/logstash/pipeline.rb +++ b/logstash-core/lib/logstash/pipeline.rb @@ -12,11 +12,11 @@ require "logstash/instrument/collector" require "logstash/filter_delegator" require "logstash/compiler" -java_import org.apache.logging.log4j.ThreadContext - module LogStash; class BasePipeline < AbstractPipeline include LogStash::Util::Loggable + java_import org.apache.logging.log4j.ThreadContext + attr_reader :inputs, :filters, :outputs def initialize(pipeline_config, namespaced_metric = nil, agent = nil) From 6842aba9eb411af498b72e053623c23e2ee41672 Mon Sep 17 00:00:00 2001 From: Joao Duarte Date: Fri, 30 Aug 2019 18:16:39 +0100 Subject: [PATCH 0288/1126] stop installing rake and json on every bootstrap Fixes #11102 --- Gemfile.template | 2 +- build.gradle | 34 +++++++++++++++++++++------------- rakelib/artifacts.rake | 1 - rubyUtils.gradle | 13 +++++++++---- 4 files changed, 31 insertions(+), 19 deletions(-) diff --git a/Gemfile.template b/Gemfile.template index deee7206b..6f561eee4 100644 --- a/Gemfile.template +++ b/Gemfile.template @@ -6,7 +6,7 @@ gem "logstash-core", :path => "./logstash-core" gem "logstash-core-plugin-api", :path => "./logstash-core-plugin-api" gem "atomic", "~> 1" gem "builder", "~> 3" -gem "json", "~> 1.8.3" +gem "json", "~> 1" gem "paquet", "~> 0.2" gem "pleaserun", "~>0.0.28" gem "rake", "~> 12" diff --git a/build.gradle b/build.gradle index d110e7d0d..5aac74ce3 100644 --- a/build.gradle +++ b/build.gradle @@ -119,35 +119,43 @@ clean { delete "${projectDir}/build/rubyDependencies.csv" } -task bootstrap { - doLast { - rake(projectDir, buildDir, 'plugin:install-base') - } -} - def assemblyDeps = [downloadAndInstallJRuby, assemble] + subprojects.collect { it.tasks.findByName("assemble") } -task installDefaultGems(dependsOn: assemblyDeps) { +task installBundler(dependsOn: assemblyDeps) { + outputs.files file("${projectDir}/vendor/bundle/bin/bundle") + doLast { + gem(projectDir, buildDir, "bundler", "1.17.3", "${projectDir}/vendor/bundle/jruby/2.5.0") + } +} + +task bootstrap(dependsOn: installBundler) { + doLast { + setupJruby(projectDir, buildDir) + } +} + + +task installDefaultGems(dependsOn: bootstrap) { doLast { rake(projectDir, buildDir, 'plugin:install-default') } } -task installTestGems(dependsOn: assemblyDeps) { +task installTestGems(dependsOn: bootstrap) { doLast { rake(projectDir, buildDir, 'plugin:install-development-dependencies') } } -task compileGrammar(dependsOn: assemblyDeps) { +task compileGrammar(dependsOn: bootstrap) { doLast { rake(projectDir, buildDir, 'compile:grammar') } } -task assembleTarDistribution(dependsOn: assemblyDeps) { +task assembleTarDistribution(dependsOn: bootstrap) { inputs.files fileTree("${projectDir}/rakelib") inputs.files fileTree("${projectDir}/bin") inputs.files fileTree("${projectDir}/config") @@ -163,7 +171,7 @@ task assembleTarDistribution(dependsOn: assemblyDeps) { } } -task assembleOssTarDistribution(dependsOn: assemblyDeps) { +task assembleOssTarDistribution(dependsOn: bootstrap) { inputs.files fileTree("${projectDir}/rakelib") inputs.files fileTree("${projectDir}/bin") inputs.files fileTree("${projectDir}/config") @@ -177,7 +185,7 @@ task assembleOssTarDistribution(dependsOn: assemblyDeps) { } } -task assembleZipDistribution(dependsOn: assemblyDeps) { +task assembleZipDistribution(dependsOn: bootstrap) { inputs.files fileTree("${projectDir}/rakelib") inputs.files fileTree("${projectDir}/bin") inputs.files fileTree("${projectDir}/config") @@ -193,7 +201,7 @@ task assembleZipDistribution(dependsOn: assemblyDeps) { } } -task assembleOssZipDistribution(dependsOn: assemblyDeps) { +task assembleOssZipDistribution(dependsOn: bootstrap) { inputs.files fileTree("${projectDir}/rakelib") inputs.files fileTree("${projectDir}/bin") inputs.files fileTree("${projectDir}/config") diff --git a/rakelib/artifacts.rake b/rakelib/artifacts.rake index e0cf8d163..46e32ad9c 100644 --- a/rakelib/artifacts.rake +++ b/rakelib/artifacts.rake @@ -1,5 +1,4 @@ namespace "artifact" do - gem 'json', '~> 1' SNAPSHOT_BUILD = ENV["RELEASE"] != "1" VERSION_QUALIFIER = ENV["VERSION_QUALIFIER"] diff --git a/rubyUtils.gradle b/rubyUtils.gradle index bf9d2cc8f..0cecc31b6 100644 --- a/rubyUtils.gradle +++ b/rubyUtils.gradle @@ -29,6 +29,7 @@ ext { gem = this.&gem buildGem = this.&buildGem rake = this.&rake + setupJruby = this.&setupJruby generateRubySupportFilesForPlugin = this.&generateRubySupportFilesForPlugin validatePluginJar = this.&validatePluginJar versionMap = new HashMap() @@ -129,6 +130,14 @@ void rake(File projectDir, File buildDir, String task) { } } +void setupJruby(File projectDir, File buildDir) { + executeJruby projectDir, buildDir, { ScriptingContainer jruby -> + jruby.currentDirectory = projectDir + jruby.runScriptlet("require '${projectDir}/lib/bootstrap/environment'") + jruby.runScriptlet("LogStash::Bundler.invoke!") + } +} + /** * Executes Closure using a fresh JRuby environment, safely tearing it down afterwards. * @param projectDir Gradle projectDir @@ -247,10 +256,6 @@ task downloadAndInstallJRuby(dependsOn: [verifyFile, installCustomJRuby], type: includeEmptyDirs = false into "${projectDir}/vendor/jruby" - doLast { - gem(projectDir, buildDir, "rake", "12.3.1", "${projectDir}/vendor/bundle/jruby/2.5.0") - gem(projectDir, buildDir, "json", "1.8.6", "${projectDir}/vendor/bundle/jruby/2.5.0") - } } downloadAndInstallJRuby.onlyIf { customJRubyDir == "" } From 1b995d7d96944324d260fc40389b540cbc71af3d Mon Sep 17 00:00:00 2001 From: Karen Metts Date: Thu, 21 Nov 2019 21:08:02 +0000 Subject: [PATCH 0289/1126] Release notes 7.5.0 refined Fixes #11323 --- docs/static/releasenotes.asciidoc | 37 +++++++++++++++++++++++++++++++ 1 file changed, 37 insertions(+) diff --git a/docs/static/releasenotes.asciidoc b/docs/static/releasenotes.asciidoc index 3fd624769..caa58db43 100644 --- a/docs/static/releasenotes.asciidoc +++ b/docs/static/releasenotes.asciidoc @@ -3,6 +3,7 @@ This section summarizes the changes in the following releases: +* <> * <> * <> * <> @@ -21,6 +22,42 @@ This section summarizes the changes in the following releases: * <> * <> +[[logstash-7-5-0]] +=== Logstash 7.5.0 Release Notes + +* Give multiple pipelines all the settings https://github.com/elastic/logstash/pull/11076[#11076] +* Support substitutions in pipelines.yml file https://github.com/elastic/logstash/pull/11081[#11081] +* Provide log appender per pipeline https://github.com/elastic/logstash/pull/11108[#11108] +* Use 2048 bits key in OpenSSL socket specs https://github.com/elastic/logstash/pull/11115[#11115] +* Add origins of pipeline configurations https://github.com/elastic/logstash/pull/11123[#11123] +* Remove 10k character truncation from log4j2.properties https://github.com/elastic/logstash/pull/11206[#11206] +* Remove from system properties if Java runtime is less than 11 https://github.com/elastic/logstash/pull/11225[#11225] to +fix https://github.com/elastic/logstash/issues/11221[#11221] +* [DOC] Add metricbeat as a monitoring option https://github.com/elastic/logstash/issues/11190[#11190] + +==== Plugins + +*Kafka Integration* + +* Initial release of the +https://github.com/logstash-plugins/logstash-integration-kafka[Kafka +Integration Plugin], which combines previously-separate Kafka plugins and shared +dependencies into a single codebase + +*Rabbitmq Integration* + +* Initial release of the +https://github.com/logstash-plugins/logstash-integration-rabbitmq[RabbitMQ +Integration Plugin], which combines previously-separate RabbitMQ plugins and +shared dependencies into a single codebase + +*Elasticsearch Output* + +* Fixed wording and corrected option in documentation https://github.com/logstash-plugins/logstash-output-elasticsearch/pull/881[#881] https://github.com/logstash-plugins/logstash-output-elasticsearch/pull/883[#883] +* Deprecation: Added warning about connecting a default Distribution of Logstash with an OSS version of ES https://github.com/logstash-plugins/logstash-output-elasticsearch/pull/875[#875] +* Added template for connecting to ES 8.x https://github.com/logstash-plugins/logstash-output-elasticsearch/pull/871[#871] +* Added sniffing support for ES 8.x https://github.com/logstash-plugins/logstash-output-elasticsearch/pull/878[#878] + [[logstash-7-4-2]] === Logstash 7.4.2 Release Notes From ba51feea21f8d1962fe4b68ce24bd8f5b4ec149e Mon Sep 17 00:00:00 2001 From: Karol Bucek Date: Tue, 3 Dec 2019 10:44:32 +0100 Subject: [PATCH 0290/1126] Build: fix bundle bin path in bundler task follow-up on d65f78728be7e702c43cea5682b8ddc93054a231 Fixes #11381 --- build.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/build.gradle b/build.gradle index 5aac74ce3..22d217363 100644 --- a/build.gradle +++ b/build.gradle @@ -124,7 +124,7 @@ def assemblyDeps = [downloadAndInstallJRuby, assemble] + subprojects.collect { } task installBundler(dependsOn: assemblyDeps) { - outputs.files file("${projectDir}/vendor/bundle/bin/bundle") + outputs.files file("${projectDir}/vendor/bundle/jruby/2.5.0/bin/bundle") doLast { gem(projectDir, buildDir, "bundler", "1.17.3", "${projectDir}/vendor/bundle/jruby/2.5.0") } From dfa8ea719f8a3044411c132933cd238fbadd0eee Mon Sep 17 00:00:00 2001 From: Karol Bucek Date: Thu, 28 Nov 2019 21:02:36 +0100 Subject: [PATCH 0291/1126] Refactor: avoid ThreadContext retrieval + use Ruby API - thread-context isn't needed - only the runtime is really used - native Ruby types do not need to pass through Java coercion Fixes #11365 --- .../java/org/logstash/ackedqueue/AckedBatch.java | 14 ++++++++------ .../org/logstash/ackedqueue/AckedReadBatch.java | 16 +++++++--------- .../org/logstash/execution/MemoryReadBatch.java | 6 ++---- 3 files changed, 17 insertions(+), 19 deletions(-) diff --git a/logstash-core/src/main/java/org/logstash/ackedqueue/AckedBatch.java b/logstash-core/src/main/java/org/logstash/ackedqueue/AckedBatch.java index fe76bc559..07eade228 100644 --- a/logstash-core/src/main/java/org/logstash/ackedqueue/AckedBatch.java +++ b/logstash-core/src/main/java/org/logstash/ackedqueue/AckedBatch.java @@ -1,8 +1,9 @@ package org.logstash.ackedqueue; import java.io.IOException; +import org.jruby.Ruby; +import org.jruby.RubyBoolean; import org.jruby.RubyHash; -import org.jruby.runtime.ThreadContext; import org.logstash.Event; import org.logstash.ext.JrubyEventExtLibrary; @@ -15,11 +16,12 @@ public final class AckedBatch { return ackedBatch; } - public RubyHash toRubyHash(ThreadContext context) { - final RubyHash result = RubyHash.newHash(context.runtime); - this.batch.getElements().forEach(e -> result.put( - JrubyEventExtLibrary.RubyEvent.newRubyEvent(context.runtime, (Event) e), - context.tru + public RubyHash toRubyHash(final Ruby runtime) { + final RubyBoolean trueValue = runtime.getTrue(); + final RubyHash result = RubyHash.newHash(runtime); + this.batch.getElements().forEach(e -> result.fastASet( + JrubyEventExtLibrary.RubyEvent.newRubyEvent(runtime, (Event) e), + trueValue ) ); return result; diff --git a/logstash-core/src/main/java/org/logstash/ackedqueue/AckedReadBatch.java b/logstash-core/src/main/java/org/logstash/ackedqueue/AckedReadBatch.java index 599c40224..09e025b47 100644 --- a/logstash-core/src/main/java/org/logstash/ackedqueue/AckedReadBatch.java +++ b/logstash-core/src/main/java/org/logstash/ackedqueue/AckedReadBatch.java @@ -28,21 +28,20 @@ public final class AckedReadBatch implements QueueBatch { } private AckedReadBatch(final JRubyAckedQueueExt queue, final int size, final long timeout) { - ThreadContext context = RUBY.getCurrentContext(); - AckedBatch batch = null; + AckedBatch batch; try { batch = queue.readBatch(size, timeout); } catch (IOException e) { throw new IllegalStateException(e); } if (batch == null) { - originals = RubyHash.newHash(context.runtime); + originals = RubyHash.newHash(RUBY); ackedBatch = null; } else { ackedBatch = batch; - originals = ackedBatch.toRubyHash(context); + originals = ackedBatch.toRubyHash(RUBY); } - generated = RubyHash.newHash(context.runtime); + generated = RubyHash.newHash(RUBY); } @Override @@ -55,18 +54,17 @@ public final class AckedReadBatch implements QueueBatch { @SuppressWarnings({"unchecked", "rawtypes"}) @Override public RubyArray to_a() { - ThreadContext context = RUBY.getCurrentContext(); - final RubyArray result = context.runtime.newArray(filteredSize()); + final RubyArray result = RUBY.newArray(filteredSize()); for (final JrubyEventExtLibrary.RubyEvent event : (Collection) originals.keys()) { if (!MemoryReadBatch.isCancelled(event)) { - result.add(event); + result.append(event); } } for (final JrubyEventExtLibrary.RubyEvent event : (Collection) generated.keys()) { if (!MemoryReadBatch.isCancelled(event)) { - result.add(event); + result.append(event); } } return result; diff --git a/logstash-core/src/main/java/org/logstash/execution/MemoryReadBatch.java b/logstash-core/src/main/java/org/logstash/execution/MemoryReadBatch.java index c68540440..814bca75a 100644 --- a/logstash-core/src/main/java/org/logstash/execution/MemoryReadBatch.java +++ b/logstash-core/src/main/java/org/logstash/execution/MemoryReadBatch.java @@ -1,7 +1,6 @@ package org.logstash.execution; import org.jruby.RubyArray; -import org.jruby.runtime.ThreadContext; import org.jruby.runtime.builtin.IRubyObject; import org.logstash.ext.JrubyEventExtLibrary; @@ -32,11 +31,10 @@ public final class MemoryReadBatch implements QueueBatch { @Override @SuppressWarnings({"rawtypes"}) public RubyArray to_a() { - ThreadContext context = RUBY.getCurrentContext(); - final RubyArray result = context.runtime.newArray(events.size()); + final RubyArray result = RUBY.newArray(events.size()); for (final IRubyObject event : events) { if (!isCancelled(event)) { - result.add(event); + result.append(event); } } return result; From 6d776f36525d0826ca52f063ee9d149887457021 Mon Sep 17 00:00:00 2001 From: Karol Bucek Date: Wed, 27 Nov 2019 15:12:47 +0100 Subject: [PATCH 0292/1126] Changed: base-line JRUBY_OPTS to default to --dev Fixes #11355 --- bin/logstash-keystore | 2 +- bin/logstash-plugin | 2 +- bin/rspec | 2 +- bin/ruby | 2 +- 4 files changed, 4 insertions(+), 4 deletions(-) diff --git a/bin/logstash-keystore b/bin/logstash-keystore index 8e0fdc020..b1e9ac354 100755 --- a/bin/logstash-keystore +++ b/bin/logstash-keystore @@ -6,6 +6,6 @@ setup # bin/logstash-keystore is a short lived ruby script thus we can use aggressive "faster starting JRuby options" # see https://github.com/jruby/jruby/wiki/Improving-startup-time -export JRUBY_OPTS="$JRUBY_OPTS -J-XX:+TieredCompilation -J-XX:TieredStopAtLevel=1 -J-noverify -X-C -Xcompile.invokedynamic=false" +export JRUBY_OPTS="${JRUBY_OPTS---dev}" ruby_exec "${LOGSTASH_HOME}/lib/secretstore/cli.rb" "$@" diff --git a/bin/logstash-plugin b/bin/logstash-plugin index b357c749a..41921db0c 100755 --- a/bin/logstash-plugin +++ b/bin/logstash-plugin @@ -6,6 +6,6 @@ setup # bin/logstash-plugin is a short lived ruby script thus we can use aggressive "faster starting JRuby options" # see https://github.com/jruby/jruby/wiki/Improving-startup-time -export JRUBY_OPTS="$JRUBY_OPTS -J-XX:+TieredCompilation -J-XX:TieredStopAtLevel=1 -J-noverify -X-C -Xcompile.invokedynamic=false" +export JRUBY_OPTS="${JRUBY_OPTS---dev}" ruby_exec "${LOGSTASH_HOME}/lib/pluginmanager/main.rb" "$@" diff --git a/bin/rspec b/bin/rspec index b05b117c7..a0f817944 100755 --- a/bin/rspec +++ b/bin/rspec @@ -5,6 +5,6 @@ unset CDPATH setup # use faster starting JRuby options see https://github.com/jruby/jruby/wiki/Improving-startup-time -export JRUBY_OPTS="$JRUBY_OPTS -J-XX:+TieredCompilation -J-XX:TieredStopAtLevel=1" +export JRUBY_OPTS="${JRUBY_OPTS---dev}" ruby_exec "${LOGSTASH_HOME}/lib/bootstrap/rspec.rb" "$@" diff --git a/bin/ruby b/bin/ruby index 342a1e3f3..666b2ff47 100755 --- a/bin/ruby +++ b/bin/ruby @@ -12,7 +12,7 @@ # DEBUG=1 to output debugging information # use faster starting JRuby options see https://github.com/jruby/jruby/wiki/Improving-startup-time -export JRUBY_OPTS="$JRUBY_OPTS -J-XX:+TieredCompilation -J-XX:TieredStopAtLevel=1" +export JRUBY_OPTS="${JRUBY_OPTS---dev}" unset CDPATH From bd66db544adeb29b41cbc1de9361c141726d55ea Mon Sep 17 00:00:00 2001 From: Rob Bavey Date: Thu, 21 Nov 2019 13:09:47 -0500 Subject: [PATCH 0293/1126] Add UBI based docker images This commit adds support for images based on UBI7 base image Closes #11265 Fixes #11335 --- docker/Makefile | 23 +++++++++++++++++++++-- docker/templates/Dockerfile.j2 | 20 ++++++++++++++++---- rakelib/artifacts.rake | 22 +++++++++++++--------- 3 files changed, 50 insertions(+), 15 deletions(-) diff --git a/docker/Makefile b/docker/Makefile index 673043f8b..db07dac5b 100644 --- a/docker/Makefile +++ b/docker/Makefile @@ -12,7 +12,7 @@ else VERSION_TAG := $(ELASTIC_VERSION) endif -IMAGE_FLAVORS ?= oss full +IMAGE_FLAVORS ?= oss full ubi7 DEFAULT_IMAGE_FLAVOR ?= full IMAGE_TAG := $(ELASTIC_REGISTRY)/logstash/logstash @@ -20,7 +20,7 @@ HTTPD ?= logstash-docker-artifact-server FIGLET := pyfiglet -w 160 -f puffy -all: build-from-local-artifacts build-from-local-oss-artifacts public-dockerfiles +all: build-from-local-artifacts build-from-local-oss-artifacts build-from-local-ubi7-artifacts public-dockerfiles lint: venv flake8 tests @@ -48,6 +48,16 @@ build-from-local-oss-artifacts: venv dockerfile env2yaml (docker kill $(HTTPD); false); -docker kill $(HTTPD) +build-from-local-ubi7-artifacts: venv dockerfile env2yaml + docker run --rm -d --name=$(HTTPD) \ + -p 8000:8000 --expose=8000 -v $(ARTIFACTS_DIR):/mnt \ + python:3 bash -c 'cd /mnt && python3 -m http.server' + timeout 120 bash -c 'until curl -s localhost:8000 > /dev/null; do sleep 1; done' + pyfiglet -f puffy -w 160 "Building: ubi7"; \ + docker build --network=host -t $(IMAGE_TAG)-ubi7:$(VERSION_TAG) -f $(ARTIFACTS_DIR)/Dockerfile-ubi7 data/logstash || \ + (docker kill $(HTTPD); false); + -docker kill $(HTTPD) + COPY_FILES = $(ARTIFACTS_DIR)/docker/config/pipelines.yml $(ARTIFACTS_DIR)/docker/config/logstash-oss.yml $(ARTIFACTS_DIR)/docker/config/logstash-full.yml $(ARTIFACTS_DIR)/docker/config/log4j2.properties $(ARTIFACTS_DIR)/docker/pipeline/default.conf $(ARTIFACTS_DIR)/docker/bin/docker-entrypoint $(ARTIFACTS_DIR)/docker/env2yaml/env2yaml $(ARTIFACTS_DIR)/docker/config/pipelines.yml: data/logstash/config/pipelines.yml @@ -83,9 +93,18 @@ public-dockerfiles: venv templates/Dockerfile.j2 docker_paths $(COPY_FILES) -D local_artifacts='false' \ -D release='$(RELEASE)' \ templates/Dockerfile.j2 > $(ARTIFACTS_DIR)/Dockerfile-oss && \ + jinja2 \ + -D elastic_version='$(ELASTIC_VERSION)' \ + -D version_tag='$(VERSION_TAG)' \ + -D image_flavor='ubi7' \ + -D local_artifacts='false' \ + -D release='$(RELEASE)' \ + templates/Dockerfile.j2 > $(ARTIFACTS_DIR)/Dockerfile-ubi7 && \ cd $(ARTIFACTS_DIR)/docker && \ cp $(ARTIFACTS_DIR)/Dockerfile-full Dockerfile && \ tar -zcf ../logstash-$(VERSION_TAG)-docker-build-context.tar.gz Dockerfile bin config env2yaml pipeline && \ + cp $(ARTIFACTS_DIR)/Dockerfile-ubi7 Dockerfile && \ + tar -zcf ../logstash-ubi7-$(VERSION_TAG)-docker-build-context.tar.gz Dockerfile bin config env2yaml pipeline && \ cp $(ARTIFACTS_DIR)/Dockerfile-oss Dockerfile && \ tar -zcf ../logstash-oss-$(VERSION_TAG)-docker-build-context.tar.gz Dockerfile bin config env2yaml pipeline diff --git a/docker/templates/Dockerfile.j2 b/docker/templates/Dockerfile.j2 index 44e782d2e..48cb1b445 100644 --- a/docker/templates/Dockerfile.j2 +++ b/docker/templates/Dockerfile.j2 @@ -11,13 +11,21 @@ {% set tarball = 'logstash-%s.tar.gz' % elastic_version -%} {% endif -%} +{% if image_flavor == 'ubi7' -%} + {% set base_image = 'registry.access.redhat.com/ubi7/ubi-minimal:7.7' -%} + {% set package_manager = 'microdnf' -%} +{% else -%} + {% set base_image = 'centos:7' -%} + {% set package_manager = 'yum' -%} +{% endif -%} -FROM centos:7 + +FROM {{ base_image }} # Install Java and the "which" command, which is needed by Logstash's shell # scripts. -RUN yum update -y && yum install -y java-11-openjdk-devel which && \ - yum clean all +RUN {{ package_manager }} update -y && {{ package_manager }} install -y java-11-openjdk-devel which && \ + {{ package_manager }} clean all # Provide a non-root user to run the process. RUN groupadd --gid 1000 logstash && \ @@ -43,7 +51,11 @@ ENV PATH=/usr/share/logstash/bin:$PATH # Provide a minimal configuration, so that simple invocations will provide # a good experience. ADD config/pipelines.yml config/pipelines.yml -ADD config/logstash-{{ image_flavor }}.yml config/logstash.yml +{% if image_flavor == 'oss' -%} +ADD config/logstash-oss.yml config/logstash.yml +{% else -%} +ADD config/logstash-full.yml config/logstash.yml +{% endif -%} ADD config/log4j2.properties config/ ADD pipeline/default.conf pipeline/logstash.conf RUN chown --recursive logstash:root config/ pipeline/ diff --git a/rakelib/artifacts.rake b/rakelib/artifacts.rake index 46e32ad9c..eba15c3ad 100644 --- a/rakelib/artifacts.rake +++ b/rakelib/artifacts.rake @@ -181,16 +181,22 @@ namespace "artifact" do desc "Build docker image" task "docker" => ["prepare", "generate_build_metadata", "tar"] do puts("[docker] Building docker image") - build_docker(false) + build_docker end desc "Build OSS docker image" task "docker_oss" => ["prepare", "generate_build_metadata", "tar_oss"] do puts("[docker_oss] Building OSS docker image") - build_docker(true) + build_docker('oss') end - desc "Generate Dockerfile for default and oss images" + desc "Build UBI7 docker image" + task "docker_ubi7" => ["prepare", "generate_build_metadata", "tar"] do + puts("[docker_ubi7] Building UBI docker image") + build_docker('ubi7') + end + + desc "Generate Dockerfile for default, ubi7 and oss images" task "dockerfiles" => ["prepare", "generate_build_metadata"] do puts("[dockerfiles] Building Dockerfiles") build_dockerfiles @@ -210,6 +216,7 @@ namespace "artifact" do unless ENV['SKIP_DOCKER'] == "1" Rake::Task["artifact:docker"].invoke Rake::Task["artifact:docker_oss"].invoke + Rake::Task["artifact:docker_ubi7"].invoke Rake::Task["artifact:dockerfiles"].invoke end end @@ -538,18 +545,15 @@ namespace "artifact" do end end # def package - def build_docker(oss = false) + def build_docker(image = nil) env = { "ARTIFACTS_DIR" => ::File.join(Dir.pwd, "build"), "RELEASE" => ENV["RELEASE"], "VERSION_QUALIFIER" => VERSION_QUALIFIER } Dir.chdir("docker") do |dir| - if oss - system(env, "make build-from-local-oss-artifacts") - else - system(env, "make build-from-local-artifacts") - end + make_job = image.nil? ? "make build-from-local-artifacts" : "make build-from-local-#{image}-artifacts" + system(env, make_job) end end From 508a33523d3480d80da9f83b1d3673faee9a0af8 Mon Sep 17 00:00:00 2001 From: Lisa Cawley Date: Tue, 3 Dec 2019 08:59:14 -0800 Subject: [PATCH 0294/1126] [DOCS] Replaces occurrences of xpack-ref (#11366) (#11379) --- docs/static/docker.asciidoc | 2 +- docs/static/getting-started-with-logstash.asciidoc | 2 +- .../management/configuring-centralized-pipelines.asciidoc | 2 +- docs/static/setup/setting-up-xpack.asciidoc | 2 +- 4 files changed, 4 insertions(+), 4 deletions(-) diff --git a/docs/static/docker.asciidoc b/docs/static/docker.asciidoc index ce49a3e40..a05f947a6 100644 --- a/docs/static/docker.asciidoc +++ b/docs/static/docker.asciidoc @@ -9,7 +9,7 @@ https://github.com/elastic/logstash/tree/{branch}[GitHub]. These images are free to use under the Elastic license. They contain open source and free commercial features and access to paid commercial features. -{xpack-ref}/license-management.html[Start a 30-day trial] to try out all of the +{stack-ov}/license-management.html[Start a 30-day trial] to try out all of the paid commercial features. See the https://www.elastic.co/subscriptions[Subscriptions] page for information about Elastic license levels. diff --git a/docs/static/getting-started-with-logstash.asciidoc b/docs/static/getting-started-with-logstash.asciidoc index b1b6959c6..88f9ab02f 100644 --- a/docs/static/getting-started-with-logstash.asciidoc +++ b/docs/static/getting-started-with-logstash.asciidoc @@ -57,7 +57,7 @@ contains colon (:) characters. -- These packages are free to use under the Elastic license. They contain open source and free commercial features and access to paid commercial features. -{xpack-ref}/license-management.html[Start a 30-day trial] to try out all of the +{stack-ov}/license-management.html[Start a 30-day trial] to try out all of the paid commercial features. See the https://www.elastic.co/subscriptions[Subscriptions] page for information about Elastic license levels. diff --git a/docs/static/management/configuring-centralized-pipelines.asciidoc b/docs/static/management/configuring-centralized-pipelines.asciidoc index 2804ed359..57af55384 100644 --- a/docs/static/management/configuring-centralized-pipelines.asciidoc +++ b/docs/static/management/configuring-centralized-pipelines.asciidoc @@ -13,7 +13,7 @@ feature. + -- For more information, see https://www.elastic.co/subscriptions and -{xpack-ref}/license-management.html[License Management]. +{stack-ov}/license-management.html[License management]. -- . Specify diff --git a/docs/static/setup/setting-up-xpack.asciidoc b/docs/static/setup/setting-up-xpack.asciidoc index 29e3ac233..a8add39c1 100644 --- a/docs/static/setup/setting-up-xpack.asciidoc +++ b/docs/static/setup/setting-up-xpack.asciidoc @@ -7,6 +7,6 @@ monitoring, machine learning, pipeline management, and many other capabilities. By default, when you install Logstash, {xpack} is installed. If you want to try all of the {xpack} features, you can -{xpack-ref}/license-management.html[start a 30-day trial]. At the end of the +{stack-ov}/license-management.html[start a 30-day trial]. At the end of the trial period, you can purchase a subscription to keep using the full functionality of the {xpack} components. For more information, see https://www.elastic.co/subscriptions. From fdf6b1c203ad7a4496ba31ddad397f53033265bb Mon Sep 17 00:00:00 2001 From: Karen Metts Date: Tue, 3 Dec 2019 12:44:58 -0500 Subject: [PATCH 0295/1126] Add default edit_links to pages Fixes #11384 --- docs/index.asciidoc | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/docs/index.asciidoc b/docs/index.asciidoc index b0b2a30b9..cddbf5e56 100644 --- a/docs/index.asciidoc +++ b/docs/index.asciidoc @@ -211,10 +211,10 @@ include::{plugins-repo-dir}/plugins/codecs.asciidoc[] // FAQ and Troubleshooting -// :edit_url: https://github.com/elastic/logstash/edit/{branch}/docs/static/faq.asciidoc +:edit_url!: include::static/best-practice.asciidoc[] -// :edit_url: https://github.com/elastic/logstash/edit/{branch}/docs/static/troubleshooting.asciidoc +:edit_url!: include::static/troubleshooting.asciidoc[] :edit_url: From 4c57f52d8c1b54f9f4f8267efe14ac88d84eef26 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jo=C3=A3o=20Duarte?= Date: Tue, 3 Dec 2019 21:12:32 +0000 Subject: [PATCH 0296/1126] Disable flaky test "should include the http address" follow up at https://github.com/elastic/logstash/issues/11385 Fixes #11386 --- spec/support/resource_dsl_methods.rb | 1 + 1 file changed, 1 insertion(+) diff --git a/spec/support/resource_dsl_methods.rb b/spec/support/resource_dsl_methods.rb index 9d9b72755..3eb9ce8e4 100644 --- a/spec/support/resource_dsl_methods.rb +++ b/spec/support/resource_dsl_methods.rb @@ -45,6 +45,7 @@ module ResourceDSLMethods end it "should include the http address" do + skip("flaky test tracked in https://github.com/elastic/logstash/issues/11385") expect(payload["http_address"]).to eql("127.0.0.1:#{::LogStash::WebServer::DEFAULT_PORTS.first}") end From d9cd2bdce2f65d2bfd39a148503c13e0c2e5d8c5 Mon Sep 17 00:00:00 2001 From: Joao Duarte Date: Wed, 4 Dec 2019 16:23:06 +0000 Subject: [PATCH 0297/1126] setup jruby and bundler/rake before artifact rake tasks Fixes #11392 --- rakelib/vendor.rake | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/rakelib/vendor.rake b/rakelib/vendor.rake index e1848f5e3..01777a15e 100644 --- a/rakelib/vendor.rake +++ b/rakelib/vendor.rake @@ -4,7 +4,7 @@ namespace "vendor" do end task "jruby" do |task, args| - system('./gradlew downloadAndInstallJRuby') unless File.exists?(File.join("vendor", "jruby")) + system('./gradlew bootstrap') unless File.exists?(File.join("vendor", "jruby")) end # jruby namespace "force" do From f3a24217c2ed61899a3caa93f2c61c7a5989be45 Mon Sep 17 00:00:00 2001 From: Karen Metts Date: Fri, 6 Dec 2019 09:39:13 -0500 Subject: [PATCH 0298/1126] Remove ref to encrypted communications Fixes #11398 --- docs/static/monitoring/monitoring-mb.asciidoc | 2 -- 1 file changed, 2 deletions(-) diff --git a/docs/static/monitoring/monitoring-mb.asciidoc b/docs/static/monitoring/monitoring-mb.asciidoc index 2272227cb..3c401d3fb 100644 --- a/docs/static/monitoring/monitoring-mb.asciidoc +++ b/docs/static/monitoring/monitoring-mb.asciidoc @@ -110,8 +110,6 @@ To monitor multiple {ls} instances, specify a list of hosts, for example: hosts: ["http://localhost:9601","http://localhost:9602","http://localhost:9603"] ---------------------------------- -*Encrypted communications.* If you configured {ls} to use encrypted communications, you must access -it using HTTPS. For example, use a `hosts` setting like `https://localhost:9600`. // end::configure-ls-module[] // tag::remote-monitoring-user[] From 25a0ecddac9804a646aa4242fc64fafa18d65958 Mon Sep 17 00:00:00 2001 From: Joao Duarte Date: Mon, 9 Dec 2019 16:50:10 +0000 Subject: [PATCH 0299/1126] refactor list of license_types DRY up the list of license types as there were 10 places that listed the types explicitly Fixes #11407 --- x-pack/lib/license_checker/license_manager.rb | 2 -- x-pack/lib/license_checker/x_pack_info.rb | 4 ++-- x-pack/lib/monitoring/internal_pipeline_source.rb | 3 +-- x-pack/lib/x-pack/logstash_registry.rb | 2 +- x-pack/spec/config_management/elasticsearch_source_spec.rb | 5 ++--- x-pack/spec/license_checker/license_info_spec.rb | 4 ++-- x-pack/spec/modules/module_license_checker_spec.rb | 5 +++-- x-pack/spec/monitoring/internal_pipeline_source_spec.rb | 2 +- 8 files changed, 12 insertions(+), 15 deletions(-) diff --git a/x-pack/lib/license_checker/license_manager.rb b/x-pack/lib/license_checker/license_manager.rb index 076570041..d15cad421 100644 --- a/x-pack/lib/license_checker/license_manager.rb +++ b/x-pack/lib/license_checker/license_manager.rb @@ -18,8 +18,6 @@ module LogStash attr_reader :last_updated - LICENSE_TYPES = :trial, :basic, :standard, :gold, :platinum - def initialize (reader, feature, refresh_period=30, refresh_unit=TimeUnit::SECONDS) @license_reader = reader @feature = feature diff --git a/x-pack/lib/license_checker/x_pack_info.rb b/x-pack/lib/license_checker/x_pack_info.rb index e2461f56e..e2a6da25d 100644 --- a/x-pack/lib/license_checker/x_pack_info.rb +++ b/x-pack/lib/license_checker/x_pack_info.rb @@ -9,11 +9,11 @@ java_import java.util.concurrent.TimeUnit module LogStash module LicenseChecker + LICENSE_TYPES = ['trial', 'basic', 'standard', 'gold', 'platinum'] + class XPackInfo include LogStash::Util::Loggable - LICENSE_TYPES = :trial, :basic, :standard, :gold, :platinum - def initialize(license, features = nil, installed=true, failed = false) @license = license @installed = installed diff --git a/x-pack/lib/monitoring/internal_pipeline_source.rb b/x-pack/lib/monitoring/internal_pipeline_source.rb index 403617960..bbf2133d5 100644 --- a/x-pack/lib/monitoring/internal_pipeline_source.rb +++ b/x-pack/lib/monitoring/internal_pipeline_source.rb @@ -11,7 +11,6 @@ module LogStash module Monitoring include LogStash::LicenseChecker::Licensed include LogStash::Helpers::ElasticsearchOptions include LogStash::Util::Loggable - VALID_LICENSES = %w(basic trial standard gold platinum) FEATURE = 'monitoring' def initialize(pipeline_config, agent) @@ -68,7 +67,7 @@ module LogStash module Monitoring :log_level => :error, :log_message => 'Monitoring is not available: License information is currently unavailable. Please make sure you have added your production elasticsearch connection info in the xpack.monitoring.elasticsearch settings.' } - elsif !xpack_info.license_one_of?(VALID_LICENSES) + elsif !xpack_info.license_one_of?(::LogStash::LicenseChecker::LICENSE_TYPES) { :state => :error, :log_level => :error, diff --git a/x-pack/lib/x-pack/logstash_registry.rb b/x-pack/lib/x-pack/logstash_registry.rb index afa20d9e7..60e2aa45e 100644 --- a/x-pack/lib/x-pack/logstash_registry.rb +++ b/x-pack/lib/x-pack/logstash_registry.rb @@ -20,7 +20,7 @@ LogStash::PLUGIN_REGISTRY.add(:universal, "monitoring", LogStash::MonitoringExte LogStash::PLUGIN_REGISTRY.add(:universal, "config_management", LogStash::ConfigManagement::Extension) license_levels = Hash.new -license_levels.default = ["basic", "trial", "standard", "gold", "platinum"] +license_levels.default = LogStash::LicenseChecker::LICENSE_TYPES xpack_modules.each do |name| path = File.join(File.dirname(__FILE__), "..", "..", "modules", name, "configuration") diff --git a/x-pack/spec/config_management/elasticsearch_source_spec.rb b/x-pack/spec/config_management/elasticsearch_source_spec.rb index 3728639ee..20fdb64c4 100644 --- a/x-pack/spec/config_management/elasticsearch_source_spec.rb +++ b/x-pack/spec/config_management/elasticsearch_source_spec.rb @@ -336,8 +336,8 @@ describe LogStash::ConfigManagement::ElasticsearchSource do end end - - %w(standard trial standard gold platinum).each do |license_type| + # config management can be used with any license type except basic + (::LogStash::LicenseChecker::LICENSE_TYPES - ["basic"]).each do |license_type| context "With a valid #{license_type} license, it should return a pipeline" do before do @@ -356,7 +356,6 @@ describe LogStash::ConfigManagement::ElasticsearchSource do end end end - end context "with multiples `pipeline_id` configured" do diff --git a/x-pack/spec/license_checker/license_info_spec.rb b/x-pack/spec/license_checker/license_info_spec.rb index 0fdbdf176..6c0a31e97 100644 --- a/x-pack/spec/license_checker/license_info_spec.rb +++ b/x-pack/spec/license_checker/license_info_spec.rb @@ -94,14 +94,14 @@ describe LogStash::LicenseChecker::XPackInfo do let(:status) { 'expired' } it_behaves_like 'available? returns correctly', true it_behaves_like 'active? returns correctly', false - it_behaves_like 'one_of? returns correctly', %w(basic trial standard gold platinum), true + it_behaves_like 'one_of? returns correctly', LogStash::LicenseChecker::LICENSE_TYPES, true end context 'the license is active' do let(:status) { 'active' } it_behaves_like 'available? returns correctly', true it_behaves_like 'active? returns correctly', true - it_behaves_like 'one_of? returns correctly', %w(basic trial standard gold platinum), true + it_behaves_like 'one_of? returns correctly', LogStash::LicenseChecker::LICENSE_TYPES, true end end diff --git a/x-pack/spec/modules/module_license_checker_spec.rb b/x-pack/spec/modules/module_license_checker_spec.rb index b22fa2ebd..f9e6b35ff 100644 --- a/x-pack/spec/modules/module_license_checker_spec.rb +++ b/x-pack/spec/modules/module_license_checker_spec.rb @@ -8,6 +8,7 @@ require 'license_checker/x_pack_info' describe LogStash::LicenseChecker::ModuleLicenseChecker do + let(:license_types) { LogStash::LicenseChecker::LICENSE_TYPES } let(:settings) { LogStash::Runner::SYSTEM_SETTINGS } @@ -55,7 +56,7 @@ describe LogStash::LicenseChecker::ModuleLicenseChecker do end context "any license" do - let(:subject) {LogStash::LicenseChecker::ModuleLicenseChecker.new(name, ["basic", "trial", "standard", "gold", "platinum"])} + let(:subject) {LogStash::LicenseChecker::ModuleLicenseChecker.new(name, license_types)} let(:returned_license) {"basic"} let(:name) {"foo_module"} let(:settings) do @@ -103,7 +104,7 @@ describe LogStash::LicenseChecker::ModuleLicenseChecker do end context "no license" do - let(:subject) {LogStash::LicenseChecker::ModuleLicenseChecker.new(name, ["basic", "trial", "standard", "gold", "platinum"])} + let(:subject) {LogStash::LicenseChecker::ModuleLicenseChecker.new(name, license_types)} let(:name) {"foo_module"} let(:settings) do LogStash::SETTINGS.clone.tap do |settings| diff --git a/x-pack/spec/monitoring/internal_pipeline_source_spec.rb b/x-pack/spec/monitoring/internal_pipeline_source_spec.rb index 1639f188a..508ccdbb1 100644 --- a/x-pack/spec/monitoring/internal_pipeline_source_spec.rb +++ b/x-pack/spec/monitoring/internal_pipeline_source_spec.rb @@ -101,7 +101,7 @@ describe LogStash::Monitoring::InternalPipelineSource do end end - %w(basic standard trial gold platinum).each do |license_type| + LogStash::LicenseChecker::LICENSE_TYPES.each do |license_type| context "With a valid #{license_type} license" do let(:license_type) { license_type } let(:license) do From df3abef89f0b84f0ca6e19de773142e532a942b8 Mon Sep 17 00:00:00 2001 From: Joao Duarte Date: Mon, 9 Dec 2019 16:58:54 +0000 Subject: [PATCH 0300/1126] introduce enterprise license level Fixes #11407 --- x-pack/lib/config_management/elasticsearch_source.rb | 3 ++- x-pack/lib/license_checker/x_pack_info.rb | 2 +- 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/x-pack/lib/config_management/elasticsearch_source.rb b/x-pack/lib/config_management/elasticsearch_source.rb index a319c23a9..6f6263fc4 100644 --- a/x-pack/lib/config_management/elasticsearch_source.rb +++ b/x-pack/lib/config_management/elasticsearch_source.rb @@ -20,7 +20,8 @@ module LogStash class RemoteConfigError < LogStash::Error; end PIPELINE_INDEX = ".logstash" - VALID_LICENSES = %w(trial standard gold platinum) + # exclude basic + VALID_LICENSES = %w(trial standard gold platinum enterprise) FEATURE_INTERNAL = 'management' FEATURE_EXTERNAL = 'logstash' SUPPORTED_PIPELINE_SETTINGS = %w( diff --git a/x-pack/lib/license_checker/x_pack_info.rb b/x-pack/lib/license_checker/x_pack_info.rb index e2a6da25d..516af9294 100644 --- a/x-pack/lib/license_checker/x_pack_info.rb +++ b/x-pack/lib/license_checker/x_pack_info.rb @@ -9,7 +9,7 @@ java_import java.util.concurrent.TimeUnit module LogStash module LicenseChecker - LICENSE_TYPES = ['trial', 'basic', 'standard', 'gold', 'platinum'] + LICENSE_TYPES = ['trial', 'basic', 'standard', 'gold', 'platinum', 'enterprise'] class XPackInfo include LogStash::Util::Loggable From 6bf0c935674a03a00006f4ab581ac20289e08e95 Mon Sep 17 00:00:00 2001 From: Joao Duarte Date: Wed, 4 Dec 2019 10:17:37 +0000 Subject: [PATCH 0301/1126] remove use of thread.exclusive in plugin_metadata.rb Fixes #11388 --- logstash-core/lib/logstash/plugin_metadata.rb | 12 +++++------- 1 file changed, 5 insertions(+), 7 deletions(-) diff --git a/logstash-core/lib/logstash/plugin_metadata.rb b/logstash-core/lib/logstash/plugin_metadata.rb index a0bab9c99..c3c1df913 100644 --- a/logstash-core/lib/logstash/plugin_metadata.rb +++ b/logstash-core/lib/logstash/plugin_metadata.rb @@ -29,9 +29,7 @@ module LogStash class PluginMetadata include LogStash::Util::Loggable - Thread.exclusive do - @registry = ThreadSafe::Cache.new unless defined?(@registry) - end + REGISTRY = ThreadSafe::Cache.new unless defined?(REGISTRY) class << self ## @@ -42,7 +40,7 @@ module LogStash # @return [PluginMetadata]: the metadata object for the provided `plugin_id`; if no # metadata object exists, it will be created. def for_plugin(plugin_id) - @registry.compute_if_absent(plugin_id) { PluginMetadata.new } + REGISTRY.compute_if_absent(plugin_id) { PluginMetadata.new } end ## @@ -53,7 +51,7 @@ module LogStash # # @return [Boolean] def exists?(plugin_id) - @registry.key?(plugin_id) + REGISTRY.key?(plugin_id) end ## @@ -64,14 +62,14 @@ module LogStash # @return [Boolean] def delete_for_plugin(plugin_id) logger.debug("Removing metadata for plugin #{plugin_id}") - old_registry = @registry.delete(plugin_id) + old_registry = REGISTRY.delete(plugin_id) old_registry.clear unless old_registry.nil? end ## # @api private def reset! - @registry.clear + REGISTRY.clear end end From c7d786e46d2f0fb6cad44c4be0fd6d1a40450039 Mon Sep 17 00:00:00 2001 From: andsel Date: Wed, 4 Dec 2019 10:09:12 +0100 Subject: [PATCH 0302/1126] Changed the deletion of log files to use retry mechanism and avoid flaky errors on Windows builds (related to #11307) Fixes #11387 --- .../java/org/logstash/log/LogTestUtils.java | 28 ++++++++++++++++++- 1 file changed, 27 insertions(+), 1 deletion(-) diff --git a/logstash-core/src/test/java/org/logstash/log/LogTestUtils.java b/logstash-core/src/test/java/org/logstash/log/LogTestUtils.java index db76a8a60..f7bd39fbb 100644 --- a/logstash-core/src/test/java/org/logstash/log/LogTestUtils.java +++ b/logstash-core/src/test/java/org/logstash/log/LogTestUtils.java @@ -3,6 +3,7 @@ package org.logstash.log; import org.apache.logging.log4j.core.LoggerContext; import java.io.IOException; +import java.nio.file.FileSystemException; import java.nio.file.FileSystems; import java.nio.file.Files; import java.nio.file.Path; @@ -29,6 +30,31 @@ class LogTestUtils { static void deleteLogFile(String logfileName) throws IOException { Path path = FileSystems.getDefault() .getPath(System.getProperty("user.dir"), System.getProperty("ls.logs"), logfileName); - Files.deleteIfExists(path); + pollingDelete(path, 5, TimeUnit.SECONDS); + } + + static void pollingDelete(Path path, int sleep, TimeUnit timeUnit) throws IOException { + final int maxRetries = 5; + int retries = 0; + do { + try { + Files.deleteIfExists(path); + break; + } catch (FileSystemException fsex) { + System.out.println("FS access error while deleting, " + fsex.getReason() + " deleting: " + fsex.getOtherFile()); + } + + try { + Thread.sleep(timeUnit.toMillis(sleep)); + } catch (InterruptedException e) { + // follows up + Thread.currentThread().interrupt(); + break; + } + + retries++; + } while (retries < maxRetries); + + assertTrue("Exhausted 5 retries to delete the file: " + path,retries < maxRetries); } } From 8fd34b0681ee5ab629e826cd4317b827c8ac0fc2 Mon Sep 17 00:00:00 2001 From: andsel Date: Fri, 6 Dec 2019 18:22:29 +0100 Subject: [PATCH 0303/1126] Covered the read of logfile content with try-resource to avoid to keep a file descriptor open that later prohibited access to the process itself. Also added clean shutdown of LogManager before deleting log files used by log. Fixes #11399 --- .../log/DefaultDeprecationLoggerTest.java | 1 + .../java/org/logstash/log/LogTestUtils.java | 33 +++---------------- 2 files changed, 6 insertions(+), 28 deletions(-) diff --git a/logstash-core/src/test/java/org/logstash/log/DefaultDeprecationLoggerTest.java b/logstash-core/src/test/java/org/logstash/log/DefaultDeprecationLoggerTest.java index 8388bd8cb..7353eac41 100644 --- a/logstash-core/src/test/java/org/logstash/log/DefaultDeprecationLoggerTest.java +++ b/logstash-core/src/test/java/org/logstash/log/DefaultDeprecationLoggerTest.java @@ -40,6 +40,7 @@ public class DefaultDeprecationLoggerTest { @After public void tearDown() throws IOException { + LogManager.shutdown(); LogTestUtils.deleteLogFile("logstash-deprecation.log"); LogTestUtils.reloadLogConfiguration(); } diff --git a/logstash-core/src/test/java/org/logstash/log/LogTestUtils.java b/logstash-core/src/test/java/org/logstash/log/LogTestUtils.java index f7bd39fbb..2ada1992b 100644 --- a/logstash-core/src/test/java/org/logstash/log/LogTestUtils.java +++ b/logstash-core/src/test/java/org/logstash/log/LogTestUtils.java @@ -3,12 +3,12 @@ package org.logstash.log; import org.apache.logging.log4j.core.LoggerContext; import java.io.IOException; -import java.nio.file.FileSystemException; import java.nio.file.FileSystems; import java.nio.file.Files; import java.nio.file.Path; import java.util.concurrent.TimeUnit; import java.util.stream.Collectors; +import java.util.stream.Stream; import static org.junit.Assert.assertTrue; @@ -19,7 +19,9 @@ class LogTestUtils { .getPath(System.getProperty("user.dir"), System.getProperty("ls.logs"), logfileName); assertTrue("Log [" + path.toString() + "] file MUST exists", Files.exists(path)); - return Files.lines(path).collect(Collectors.joining()); + try (Stream lines = Files.lines(path)) { + return lines.collect(Collectors.joining()); + } } static void reloadLogConfiguration() { @@ -30,31 +32,6 @@ class LogTestUtils { static void deleteLogFile(String logfileName) throws IOException { Path path = FileSystems.getDefault() .getPath(System.getProperty("user.dir"), System.getProperty("ls.logs"), logfileName); - pollingDelete(path, 5, TimeUnit.SECONDS); - } - - static void pollingDelete(Path path, int sleep, TimeUnit timeUnit) throws IOException { - final int maxRetries = 5; - int retries = 0; - do { - try { - Files.deleteIfExists(path); - break; - } catch (FileSystemException fsex) { - System.out.println("FS access error while deleting, " + fsex.getReason() + " deleting: " + fsex.getOtherFile()); - } - - try { - Thread.sleep(timeUnit.toMillis(sleep)); - } catch (InterruptedException e) { - // follows up - Thread.currentThread().interrupt(); - break; - } - - retries++; - } while (retries < maxRetries); - - assertTrue("Exhausted 5 retries to delete the file: " + path,retries < maxRetries); + Files.deleteIfExists(path); } } From c69e61fd2fb6db870238f2eb75958640e5945142 Mon Sep 17 00:00:00 2001 From: Colin Surprenant Date: Fri, 6 Dec 2019 16:32:35 -0500 Subject: [PATCH 0304/1126] test codec against class name string to prevent class equivalence bug with a Delegator Fixes #11401 --- logstash-core/lib/logstash/inputs/base.rb | 7 +++-- .../spec/logstash/inputs/base_spec.rb | 28 +++++++++++++++++++ 2 files changed, 32 insertions(+), 3 deletions(-) diff --git a/logstash-core/lib/logstash/inputs/base.rb b/logstash-core/lib/logstash/inputs/base.rb index 50878ffff..f0afaca94 100644 --- a/logstash-core/lib/logstash/inputs/base.rb +++ b/logstash-core/lib/logstash/inputs/base.rb @@ -131,11 +131,12 @@ class LogStash::Inputs::Base < LogStash::Plugin require "logstash/codecs/line" require "logstash/codecs/json" require "logstash/codecs/json_lines" - case @codec - when LogStash::Codecs::Plain + + case @codec.class.name + when "LogStash::Codecs::Plain" @logger.info("Automatically switching from #{@codec.class.config_name} to line codec", :plugin => self.class.config_name) @codec = LogStash::Codecs::Line.new("charset" => @codec.charset) - when LogStash::Codecs::JSON + when "LogStash::Codecs::JSON" @logger.info("Automatically switching from #{@codec.class.config_name} to json_lines codec", :plugin => self.class.config_name) @codec = LogStash::Codecs::JSONLines.new("charset" => @codec.charset) end diff --git a/logstash-core/spec/logstash/inputs/base_spec.rb b/logstash-core/spec/logstash/inputs/base_spec.rb index a16e7ae4d..445c22104 100644 --- a/logstash-core/spec/logstash/inputs/base_spec.rb +++ b/logstash-core/spec/logstash/inputs/base_spec.rb @@ -113,4 +113,32 @@ describe "LogStash::Inputs::Base#fix_streaming_codecs" do tcp.instance_eval { fix_streaming_codecs } expect(tcp.codec.charset).to eq("CP1252") end + + it "should switch plain codec to line" do + require "logstash/inputs/tcp" + require "logstash/codecs/plain" + require "logstash/codecs/line" + + # it is important to use "codec" => "plain" here and not the LogStash::Codecs::Plain instance so that + # the config parsing wrap the codec into the delagator which was causing the codec identification bug + # per https://github.com/elastic/logstash/issues/11140 + tcp = LogStash::Inputs::Tcp.new("codec" => "plain", "port" => 0) + tcp.register + + expect(tcp.codec.class.name).to eq("LogStash::Codecs::Line") + end + + it "should switch json codec to json_lines" do + require "logstash/inputs/tcp" + require "logstash/codecs/plain" + require "logstash/codecs/line" + + # it is important to use "codec" => "json" here and not the LogStash::Codecs::Plain instance so that + # the config parsing wrap the codec into the delagator which was causing the codec identification bug + # per https://github.com/elastic/logstash/issues/11140 + tcp = LogStash::Inputs::Tcp.new("codec" => "json", "port" => 0) + tcp.register + + expect(tcp.codec.class.name).to eq("LogStash::Codecs::JSONLines") + end end From 8ccf78ab3e8b9a6109512055e1344d971144cd67 Mon Sep 17 00:00:00 2001 From: Karol Bucek Date: Thu, 12 Dec 2019 19:11:12 +0100 Subject: [PATCH 0305/1126] Fix: handle cloud-id with an empty kibana part fixes GH-10747 Fixes #11435 --- .../lib/logstash/util/cloud_setting_id.rb | 4 ++- .../logstash/util/cloud_setting_id_spec.rb | 30 +++++++++++++++++++ 2 files changed, 33 insertions(+), 1 deletion(-) diff --git a/logstash-core/lib/logstash/util/cloud_setting_id.rb b/logstash-core/lib/logstash/util/cloud_setting_id.rb index 8f1c58179..a333447a6 100644 --- a/logstash-core/lib/logstash/util/cloud_setting_id.rb +++ b/logstash-core/lib/logstash/util/cloud_setting_id.rb @@ -57,7 +57,7 @@ module LogStash module Util class CloudSettingId @elasticsearch_host, @kibana_host, *@other_identifiers = segments @elasticsearch_host, @elasticsearch_port = @elasticsearch_host.split(":") - @kibana_host, @kibana_port = @kibana_host.split(":") + @kibana_host, @kibana_port = @kibana_host.split(":") if @kibana_host @elasticsearch_port ||= cloud_port @kibana_port ||= cloud_port @other_identifiers ||= [] @@ -72,7 +72,9 @@ module LogStash module Util class CloudSettingId if @kibana_host == "undefined" raise ArgumentError.new("Cloud Id, after decoding, the kibana segment is 'undefined', literally. You may need to enable Kibana in the Cloud UI.") end + @kibana_scheme = "https" + @kibana_host ||= String.new # non-sense really to have '.my-host:443' but we're mirroring others @kibana_host.concat(cloud_host) @kibana_host.concat(":#{@kibana_port}") end diff --git a/logstash-core/spec/logstash/util/cloud_setting_id_spec.rb b/logstash-core/spec/logstash/util/cloud_setting_id_spec.rb index e46afb836..c6f09185b 100644 --- a/logstash-core/spec/logstash/util/cloud_setting_id_spec.rb +++ b/logstash-core/spec/logstash/util/cloud_setting_id_spec.rb @@ -143,4 +143,34 @@ describe LogStash::Util::CloudSettingId do expect(subject.other_identifiers).to eq(["anotherid", "andanother"]) end end + + describe "when given acceptable input (with empty kibana uuid), the accessors:" do + let(:input) { "a-test:ZWNlLmhvbWUubGFuJHRlc3Qk" } # ece.home.lan$test$ + + it '#original has a value' do + expect(subject.original).to eq(input) + end + it '#decoded has a value' do + expect(subject.decoded).to eq("ece.home.lan$test$") + end + it '#label has a value' do + expect(subject.label).to eq("a-test") + end + it '#elasticsearch_host has a value' do + expect(subject.elasticsearch_host).to eq("test.ece.home.lan:443") + end + it '#elasticsearch_scheme has a value' do + expect(subject.elasticsearch_scheme).to eq("https") + end + it '#kibana_host has a value' do + # NOTE: kibana part is not relevant -> this is how python/beats(go) code behaves + expect(subject.kibana_host).to eq(".ece.home.lan:443") + end + it '#kibana_scheme has a value' do + expect(subject.kibana_scheme).to eq("https") + end + it '#to_s has a value of #decoded' do + expect(subject.to_s).to eq(subject.decoded) + end + end end From 6ee050fda62847623ea80488fcaa510df4551d0d Mon Sep 17 00:00:00 2001 From: Karol Bucek Date: Thu, 12 Dec 2019 19:45:49 +0100 Subject: [PATCH 0306/1126] Test: a lengthy real-world cloud-id test Fixes #11435 --- .../logstash/util/cloud_setting_id_spec.rb | 26 +++++++++++++++++++ 1 file changed, 26 insertions(+) diff --git a/logstash-core/spec/logstash/util/cloud_setting_id_spec.rb b/logstash-core/spec/logstash/util/cloud_setting_id_spec.rb index c6f09185b..996eb92ba 100644 --- a/logstash-core/spec/logstash/util/cloud_setting_id_spec.rb +++ b/logstash-core/spec/logstash/util/cloud_setting_id_spec.rb @@ -173,4 +173,30 @@ describe LogStash::Util::CloudSettingId do expect(subject.to_s).to eq(subject.decoded) end end + + describe "a lengthy real-world input, the accessors:" do + let(:input) do + "ZWFzdHVzMi5henVyZS5lbGFzdGljLWNsb3VkLmNvbTo5MjQzJDQwYjM0MzExNmNmYTRlYmNiNzZjMTFlZTIzMjlmOTJkJDQzZDA5MjUyNTAyYzQxODlhMzc2ZmQwY2YyY2QwODQ4" + # eastus2.azure.elastic-cloud.com:9243$40b343116cfa4ebcb76c11ee2329f92d$43d09252502c4189a376fd0cf2cd0848 + end + + it '#original has a value' do + expect(subject.original).to eq(input) + end + it '#decoded has a value' do + expect(subject.decoded).to eq("eastus2.azure.elastic-cloud.com:9243$40b343116cfa4ebcb76c11ee2329f92d$43d09252502c4189a376fd0cf2cd0848") + end + it '#label has a value' do + expect(subject.label).to eq("") + end + it '#elasticsearch_host has a value' do + expect(subject.elasticsearch_host).to eq("40b343116cfa4ebcb76c11ee2329f92d.eastus2.azure.elastic-cloud.com:9243") + end + it '#kibana_host has a value' do + expect(subject.kibana_host).to eq("43d09252502c4189a376fd0cf2cd0848.eastus2.azure.elastic-cloud.com:9243") + end + it '#to_s has a value of #decoded' do + expect(subject.to_s).to eq(subject.decoded) + end + end end From 9d497a13f2834d168d9ff5b600201e1d12f995df Mon Sep 17 00:00:00 2001 From: Karol Bucek Date: Wed, 4 Dec 2019 16:21:26 +0100 Subject: [PATCH 0307/1126] Changed: avoid JavaObject wrapping in Ruby methods aligns the Ruby/Java returns as they happen in scripted Java e.g. as `java.lang.Thread.new` returns a JavaProxy instance there's really no reason to use JavaObject which always needs `to_java` conversion to be useful (and is considered legacy in JRuby). considered breaking change e.g. `LogStash::MemoryReadClient#read_batch` will now return a proper JavaProxy instead of the JavaObject Fixes #11391 --- logstash-core/lib/logstash/java_pipeline.rb | 6 +----- .../src/main/java/org/logstash/RubyUtil.java | 11 +++++++++++ .../logstash/ackedqueue/ext/JRubyAckedQueueExt.java | 7 ++----- .../config/ir/compiler/JavaInputDelegatorExt.java | 3 +-- .../org/logstash/execution/QueueReadClientBase.java | 11 +++-------- 5 files changed, 18 insertions(+), 20 deletions(-) diff --git a/logstash-core/lib/logstash/java_pipeline.rb b/logstash-core/lib/logstash/java_pipeline.rb index 3a8069a0a..f76bffb57 100644 --- a/logstash-core/lib/logstash/java_pipeline.rb +++ b/logstash-core/lib/logstash/java_pipeline.rb @@ -281,11 +281,7 @@ module LogStash; class JavaPipeline < JavaBasePipeline def wait_inputs @input_threads.each do |thread| - if thread.class == Java::JavaObject - thread.to_java.join - else - thread.join - end + thread.join # Thread or java.lang.Thread (both have #join) end end diff --git a/logstash-core/src/main/java/org/logstash/RubyUtil.java b/logstash-core/src/main/java/org/logstash/RubyUtil.java index 83b038b52..d760999a6 100644 --- a/logstash-core/src/main/java/org/logstash/RubyUtil.java +++ b/logstash-core/src/main/java/org/logstash/RubyUtil.java @@ -5,7 +5,9 @@ import org.jruby.RubyClass; import org.jruby.RubyModule; import org.jruby.anno.JRubyClass; import org.jruby.exceptions.RaiseException; +import org.jruby.javasupport.JavaUtil; import org.jruby.runtime.ObjectAllocator; +import org.jruby.runtime.builtin.IRubyObject; import org.logstash.ackedqueue.QueueFactoryExt; import org.logstash.ackedqueue.ext.JRubyAckedQueueExt; import org.logstash.ackedqueue.ext.JRubyWrappedAckedQueueExt; @@ -601,4 +603,13 @@ public final class RubyUtil { return clazz; } + /** + * Convert a Java object to a Ruby representative. + * @param javaObject the object to convert (might be null) + * @return a Ruby wrapper + */ + public static IRubyObject toRubyObject(Object javaObject) { + return JavaUtil.convertJavaToRuby(RUBY, javaObject); + } + } diff --git a/logstash-core/src/main/java/org/logstash/ackedqueue/ext/JRubyAckedQueueExt.java b/logstash-core/src/main/java/org/logstash/ackedqueue/ext/JRubyAckedQueueExt.java index e1f3a6eef..86afee76b 100644 --- a/logstash-core/src/main/java/org/logstash/ackedqueue/ext/JRubyAckedQueueExt.java +++ b/logstash-core/src/main/java/org/logstash/ackedqueue/ext/JRubyAckedQueueExt.java @@ -9,7 +9,6 @@ import org.jruby.RubyObject; import org.jruby.RubyString; import org.jruby.anno.JRubyClass; import org.jruby.anno.JRubyMethod; -import org.jruby.javasupport.JavaObject; import org.jruby.runtime.ThreadContext; import org.jruby.runtime.builtin.IRubyObject; import org.logstash.Event; @@ -114,16 +113,14 @@ public final class JRubyAckedQueueExt extends RubyObject { } @JRubyMethod(name = "read_batch", required = 2) - public IRubyObject ruby_read_batch(ThreadContext context, IRubyObject limit, - IRubyObject timeout) { + public IRubyObject ruby_read_batch(ThreadContext context, IRubyObject limit, IRubyObject timeout) { AckedBatch b; try { b = readBatch(RubyFixnum.num2int(limit), RubyFixnum.num2int(timeout)); } catch (IOException e) { throw RubyUtil.newRubyIOError(context.runtime, e); } - // TODO: return proper Batch object - return (b == null) ? context.nil : JavaObject.wrap(context.runtime, b); + return RubyUtil.toRubyObject(b); } public AckedBatch readBatch(int limit, long timeout) throws IOException { diff --git a/logstash-core/src/main/java/org/logstash/config/ir/compiler/JavaInputDelegatorExt.java b/logstash-core/src/main/java/org/logstash/config/ir/compiler/JavaInputDelegatorExt.java index e91367f8c..6134a69d2 100644 --- a/logstash-core/src/main/java/org/logstash/config/ir/compiler/JavaInputDelegatorExt.java +++ b/logstash-core/src/main/java/org/logstash/config/ir/compiler/JavaInputDelegatorExt.java @@ -6,7 +6,6 @@ import org.jruby.RubyClass; import org.jruby.RubyObject; import org.jruby.anno.JRubyClass; import org.jruby.anno.JRubyMethod; -import org.jruby.javasupport.JavaObject; import org.jruby.runtime.ThreadContext; import org.jruby.runtime.builtin.IRubyObject; import org.logstash.RubyUtil; @@ -66,7 +65,7 @@ public class JavaInputDelegatorExt extends RubyObject { }); t.setName(pipeline.pipelineId().asJavaString() + "_" + input.getName() + "_" + input.getId()); t.start(); - return JavaObject.wrap(context.getRuntime(), t); + return RubyUtil.toRubyObject(t); } @JRubyMethod(name = "metric=") diff --git a/logstash-core/src/main/java/org/logstash/execution/QueueReadClientBase.java b/logstash-core/src/main/java/org/logstash/execution/QueueReadClientBase.java index 951f83f8a..6b51d125d 100644 --- a/logstash-core/src/main/java/org/logstash/execution/QueueReadClientBase.java +++ b/logstash-core/src/main/java/org/logstash/execution/QueueReadClientBase.java @@ -7,8 +7,7 @@ import org.jruby.RubyNumeric; import org.jruby.RubyObject; import org.jruby.anno.JRubyClass; import org.jruby.anno.JRubyMethod; -import org.jruby.java.proxies.JavaProxy; -import org.jruby.javasupport.JavaObject; +import org.jruby.javasupport.JavaUtil; import org.jruby.runtime.ThreadContext; import org.jruby.runtime.builtin.IRubyObject; import org.logstash.RubyUtil; @@ -103,7 +102,7 @@ public abstract class QueueReadClientBase extends RubyObject implements QueueRea @JRubyMethod(name = "read_batch") public IRubyObject rubyReadBatch(final ThreadContext context) throws InterruptedException { - return JavaObject.wrap(context.runtime, readBatch()); + return RubyUtil.toRubyObject(readBatch()); } @Override @@ -148,11 +147,7 @@ public abstract class QueueReadClientBase extends RubyObject implements QueueRea * @return Extracted queue batch */ private static QueueBatch extractQueueBatch(final IRubyObject batch) { - if (batch instanceof JavaProxy) { - return (QueueBatch) ((JavaObject)batch.dataGetStruct()).getValue(); - } else { - return (QueueBatch)((JavaObject)batch).getValue(); - } + return JavaUtil.unwrapIfJavaObject(batch); } /** From fa199fe1ecea3cccde87c0d49dc27ff8105934aa Mon Sep 17 00:00:00 2001 From: Karol Bucek Date: Thu, 12 Dec 2019 20:18:39 +0100 Subject: [PATCH 0308/1126] Test: Java proxied QueueReadClient unwrapping Fixes #11391 --- .../logstash/util/wrapped_synchronous_queue_spec.rb | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/logstash-core/spec/logstash/util/wrapped_synchronous_queue_spec.rb b/logstash-core/spec/logstash/util/wrapped_synchronous_queue_spec.rb index c81e59c97..22b3098de 100644 --- a/logstash-core/spec/logstash/util/wrapped_synchronous_queue_spec.rb +++ b/logstash-core/spec/logstash/util/wrapped_synchronous_queue_spec.rb @@ -117,6 +117,16 @@ describe LogStash::WrappedSynchronousQueue do (0..2).each {|i| expect(received).to include("value-#{i}")} (3..4).each {|i| expect(received).to include("generated-#{i}")} end + + it "handles Java proxied read-batch object" do + batch = [] + 3.times { |i| batch.push(LogStash::Event.new({"message" => "value-#{i}"})) } + write_client.push_batch(batch) + + read_batch = read_client.read_batch + expect { read_client.close_batch(read_batch) }.to_not raise_error + expect { read_client.close_batch(read_batch.to_java) }.to_not raise_error + end end end end From 51de4c2674d9b5ce881967547561f0c262bbc863 Mon Sep 17 00:00:00 2001 From: Karol Bucek Date: Mon, 23 Dec 2019 19:02:40 +0100 Subject: [PATCH 0309/1126] Refactor: we're always on JRuby these days (other part of same method assume JRuby already) Fixes #11458 --- logstash-core/lib/logstash/util.rb | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/logstash-core/lib/logstash/util.rb b/logstash-core/lib/logstash/util.rb index b04192659..e966c8f7a 100644 --- a/logstash-core/lib/logstash/util.rb +++ b/logstash-core/lib/logstash/util.rb @@ -11,10 +11,8 @@ module LogStash::Util def self.set_thread_name(name) previous_name = Java::java.lang.Thread.currentThread.getName() if block_given? - if RUBY_ENGINE == "jruby" - # Keep java and ruby thread names in sync. - Java::java.lang.Thread.currentThread.setName(name) - end + # Keep java and ruby thread names in sync. + Java::java.lang.Thread.currentThread.setName(name) Thread.current[:name] = name if UNAME == "linux" From 32c306f28f1d3cb68e4318d1e65fd3f08d30525f Mon Sep 17 00:00:00 2001 From: Karol Bucek Date: Mon, 23 Dec 2019 19:03:10 +0100 Subject: [PATCH 0310/1126] Refactor: minor one sub-stitution should do Fixes #11458 --- logstash-core/lib/logstash/util.rb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/logstash-core/lib/logstash/util.rb b/logstash-core/lib/logstash/util.rb index e966c8f7a..e68ebb65a 100644 --- a/logstash-core/lib/logstash/util.rb +++ b/logstash-core/lib/logstash/util.rb @@ -46,7 +46,7 @@ module LogStash::Util def self.thread_info(thread) # When the `thread` is dead, `Thread#backtrace` returns `nil`; fall back to an empty array. backtrace = (thread.backtrace || []).map do |line| - line.gsub(LogStash::Environment::LOGSTASH_HOME, "[...]") + line.sub(LogStash::Environment::LOGSTASH_HOME, "[...]") end blocked_on = case backtrace.first From fd36783d4fdf5f89b75deef88385fee7f0df27f0 Mon Sep 17 00:00:00 2001 From: Karol Bucek Date: Mon, 23 Dec 2019 19:05:59 +0100 Subject: [PATCH 0311/1126] Fix: (move and) make get_thread_id "nil safe" necessary since native (Java) thread is kept as a weak ref so un-wrapping should deal with a potentially GCd instance resolves GH-11450 Fixes #11458 --- logstash-core/lib/logstash/util.rb | 10 +------- .../src/main/java/org/logstash/RubyUtil.java | 2 ++ .../main/java/org/logstash/util/UtilExt.java | 23 +++++++++++++++++++ 3 files changed, 26 insertions(+), 9 deletions(-) create mode 100644 logstash-core/src/main/java/org/logstash/util/UtilExt.java diff --git a/logstash-core/lib/logstash/util.rb b/logstash-core/lib/logstash/util.rb index e68ebb65a..614dcf1ea 100644 --- a/logstash-core/lib/logstash/util.rb +++ b/logstash-core/lib/logstash/util.rb @@ -35,14 +35,6 @@ module LogStash::Util Thread.current[:plugin] = plugin end - def self.get_thread_id(thread) - if RUBY_ENGINE == "jruby" - JRuby.reference(thread).native_thread.id - else - raise Exception.new("Native thread IDs aren't supported outside of JRuby") - end - end - def self.thread_info(thread) # When the `thread` is dead, `Thread#backtrace` returns `nil`; fall back to an empty array. backtrace = (thread.backtrace || []).map do |line| @@ -56,7 +48,7 @@ module LogStash::Util end { - "thread_id" => get_thread_id(thread), + "thread_id" => get_thread_id(thread), # might be nil for dead threads "name" => thread[:name], "plugin" => (thread[:plugin] ? thread[:plugin].debug_info : nil), "backtrace" => backtrace, diff --git a/logstash-core/src/main/java/org/logstash/RubyUtil.java b/logstash-core/src/main/java/org/logstash/RubyUtil.java index d760999a6..df207064f 100644 --- a/logstash-core/src/main/java/org/logstash/RubyUtil.java +++ b/logstash-core/src/main/java/org/logstash/RubyUtil.java @@ -55,6 +55,7 @@ import org.logstash.log.SlowLoggerExt; import org.logstash.plugins.HooksRegistryExt; import org.logstash.plugins.PluginFactoryExt; import org.logstash.plugins.UniversalPluginExt; +import org.logstash.util.UtilExt; import java.util.stream.Stream; @@ -308,6 +309,7 @@ public final class RubyUtil { NULL_TIMED_EXECUTION_CLASS.defineAnnotatedMethods(NullMetricExt.NullTimedExecution.class); NULL_COUNTER_CLASS.defineAnnotatedMethods(NullNamespacedMetricExt.NullCounter.class); UTIL_MODULE = LOGSTASH_MODULE.defineModuleUnder("Util"); + UTIL_MODULE.defineAnnotatedMethods(UtilExt.class); ABSTRACT_DLQ_WRITER_CLASS = UTIL_MODULE.defineClassUnder( "AbstractDeadLetterQueueWriterExt", RUBY.getObject(), ObjectAllocator.NOT_ALLOCATABLE_ALLOCATOR diff --git a/logstash-core/src/main/java/org/logstash/util/UtilExt.java b/logstash-core/src/main/java/org/logstash/util/UtilExt.java new file mode 100644 index 000000000..57bf0a310 --- /dev/null +++ b/logstash-core/src/main/java/org/logstash/util/UtilExt.java @@ -0,0 +1,23 @@ +package org.logstash.util; + +import org.jruby.RubyThread; +import org.jruby.anno.JRubyMethod; +import org.jruby.anno.JRubyModule; +import org.jruby.runtime.ThreadContext; +import org.jruby.runtime.builtin.IRubyObject; + +@JRubyModule(name = "Util") // LogStash::Util +public class UtilExt { + + @JRubyMethod(module = true) + public static IRubyObject get_thread_id(final ThreadContext context, IRubyObject self, IRubyObject thread) { + if (!(thread instanceof RubyThread)) { + throw context.runtime.newTypeError(thread, context.runtime.getThread()); + } + final Thread javaThread = ((RubyThread) thread).getNativeThread(); // weak-reference + // even if thread is dead the RubyThread instance might stick around while the Java thread + // instance already could have been garbage collected - let's return nil for dead meat : + return javaThread == null ? context.nil : context.runtime.newFixnum(javaThread.getId()); + } + +} From ded1749e7648079046e376f1e57c85606dfb3fdd Mon Sep 17 00:00:00 2001 From: Karol Bucek Date: Fri, 27 Dec 2019 12:43:23 +0100 Subject: [PATCH 0312/1126] Test: get_thread_id (native thread being gc-d) Fixes #11458 --- logstash-core/spec/logstash/util_spec.rb | 19 +++++++++++++++++++ 1 file changed, 19 insertions(+) diff --git a/logstash-core/spec/logstash/util_spec.rb b/logstash-core/spec/logstash/util_spec.rb index 3f0c23eda..201c7a0a4 100644 --- a/logstash-core/spec/logstash/util_spec.rb +++ b/logstash-core/spec/logstash/util_spec.rb @@ -67,4 +67,23 @@ describe LogStash::Util do end end end + + describe ".get_thread_id" do + it "returns native identifier" do + thread_id = LogStash::Util.get_thread_id(Thread.current) + expect( thread_id ).to be_a Integer + expect( thread_id ).to eq(java.lang.Thread.currentThread.getId) + end + + context "when a (native) thread is collected" do + let(:dead_thread) { Thread.new { 42 }.tap { |t| sleep(0.01) while t.status } } + + it "returns nil as id" do + thread = dead_thread + p thread if $VERBOSE + java.lang.System.gc + expect(LogStash::Util.get_thread_id(thread)).to be nil + end + end + end end From 97b2273b39e8203832cd995b1d9cc7b3fde653cc Mon Sep 17 00:00:00 2001 From: Karol Bucek Date: Tue, 17 Dec 2019 14:23:49 +0100 Subject: [PATCH 0313/1126] Fix: SafeURI normalize and eql? to work as expected normalize wasn't doing what was expected (URI.normalize) also make sure SafeURI can be stored in Hash (proper eql?) Fixes #11443 --- logstash-core/lib/logstash/util/safe_uri.rb | 13 ++-- .../spec/logstash/util/safe_uri_spec.rb | 63 +++++++++++++++++++ 2 files changed, 72 insertions(+), 4 deletions(-) diff --git a/logstash-core/lib/logstash/util/safe_uri.rb b/logstash-core/lib/logstash/util/safe_uri.rb index 29952a29d..63684f606 100644 --- a/logstash-core/lib/logstash/util/safe_uri.rb +++ b/logstash-core/lib/logstash/util/safe_uri.rb @@ -45,9 +45,14 @@ class LogStash::Util::SafeURI make_uri(scheme, user_info, host, port, path, query, fragment) end - def ==(other) + def hash + @uri.hash * 11 + end + + def eql?(other) other.is_a?(::LogStash::Util::SafeURI) ? @uri == other.uri : false end + alias == eql? def clone # No need to clone the URI, in java its immutable @@ -144,13 +149,13 @@ class LogStash::Util::SafeURI # Same algorithm as Ruby's URI class uses def normalize! if path && path == '' - path = '/' + update(:path, '/') end if scheme && scheme != scheme.downcase - scheme = self.scheme.downcase + update(:scheme, self.scheme.downcase) end if host && host != host.downcase - host = self.host.downcase + update(:host, self.host.downcase) end end diff --git a/logstash-core/spec/logstash/util/safe_uri_spec.rb b/logstash-core/spec/logstash/util/safe_uri_spec.rb index 478fabec3..9105d238a 100644 --- a/logstash-core/spec/logstash/util/safe_uri_spec.rb +++ b/logstash-core/spec/logstash/util/safe_uri_spec.rb @@ -17,6 +17,22 @@ module LogStash module Util end end + describe "equality" do + subject { LogStash::Util::SafeURI.new("https://localhost:9200/uri") } + + it "should eql/== to dup" do + expect(subject == subject.clone).to be true + expect(subject == subject.dup).to be true + expect(subject.eql? subject.dup).to be true + end + + it "should eql to same uri" do + uri = LogStash::Util::SafeURI.new("https://localhost:9200/uri") + expect(uri.eql? subject).to be true + expect(subject.hash).to eql uri.hash + end + end + describe "handling escapable fields" do let(:user) { "u%20" } let(:password) { "p%20ss" } @@ -72,5 +88,52 @@ module LogStash module Util end end end + + describe "normalization" do + subject { LogStash::Util::SafeURI.new("HTTPS://FOO:BaR@S11.ORG") } + + it "should normalize" do # like URI().normalize + subject.normalize! + expect(subject.to_s).to eq('https://FOO:xxxxxx@s11.org/') + end + end + + describe "writers" do + subject { LogStash::Util::SafeURI.new("http://sample.net") } + + it "should update :user" do + subject.user = 'user' + expect(subject.user).to eq('user') + expect(subject.to_s).to eq('http://user@sample.net/') + end + + it "should update :password" do + subject.user = 'user' + subject.password = 'pass' + expect(subject.password).to eq('pass') + end + + it "should update :path" do + subject.path = '/path' + expect(subject.path).to eq('/path') + expect(subject.to_s).to eq('http://sample.net/path') + + subject.path = '' + expect(subject.path).to eq('/') + expect(subject.to_s).to eq('http://sample.net/') + end + + it "should update :host" do + subject.host = '127.0.0.1' + expect(subject.host).to eq('127.0.0.1') + expect(subject.to_s).to eq('http://127.0.0.1/') + end + + it "should update :scheme" do + subject.update(:scheme, 'https') + expect(subject.scheme).to eq('https') + expect(subject.to_s).to eq('https://sample.net/') + end + end end end end From 3eb5f94f29874cb7bd2bb7bad8c7c01c5d309ab6 Mon Sep 17 00:00:00 2001 From: Rob Bavey Date: Thu, 9 Jan 2020 11:47:05 -0500 Subject: [PATCH 0314/1126] Update JrJackson and jackson deps Fixes #11478 --- versions.yml | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/versions.yml b/versions.yml index 57eda209f..e2966806f 100644 --- a/versions.yml +++ b/versions.yml @@ -21,6 +21,6 @@ jruby: # Note: this file is copied to the root of logstash-core because its gemspec needs it when # bundler evaluates the gemspec via bin/logstash # Ensure Jackson version here is kept in sync with version used by jrjackson gem -jrjackson: 0.4.10 -jackson: 2.9.9 -jackson-databind: 2.9.9.3 +jrjackson: 0.4.11 +jackson: 2.9.10 +jackson-databind: 2.9.10.1 From f06c5ef806a9ef508d17180f8b04a68894b2ddac Mon Sep 17 00:00:00 2001 From: Rob Bavey Date: Mon, 9 Dec 2019 10:37:14 -0500 Subject: [PATCH 0315/1126] Replace references to JDBC plugins with integration plugins Fixes #11406 --- lib/pluginmanager/prepare_offline_pack.rb | 2 +- rakelib/plugins-metadata.json | 16 ++++++++++------ 2 files changed, 11 insertions(+), 7 deletions(-) diff --git a/lib/pluginmanager/prepare_offline_pack.rb b/lib/pluginmanager/prepare_offline_pack.rb index 0860c3b60..45197b2b3 100644 --- a/lib/pluginmanager/prepare_offline_pack.rb +++ b/lib/pluginmanager/prepare_offline_pack.rb @@ -60,7 +60,7 @@ You need to specify at least one plugin or use a wildcard expression. Examples: bin/logstash-plugin prepare-offline-pack logstash-input-beats -bin/logstash-plugin prepare-offline-pack logstash-filter-jdbc logstash-input-beats +bin/logstash-plugin prepare-offline-pack logstash-filter-kv logstash-input-beats bin/logstash-plugin prepare-offline-pack logstash-filter-* bin/logstash-plugin prepare-offline-pack logstash-filter-* logstash-input-beats diff --git a/rakelib/plugins-metadata.json b/rakelib/plugins-metadata.json index 25fe9d24d..b8daea5aa 100644 --- a/rakelib/plugins-metadata.json +++ b/rakelib/plugins-metadata.json @@ -148,12 +148,12 @@ "skip-list": true }, "logstash-filter-jdbc_static": { - "default-plugins": true, - "skip-list": false + "default-plugins": false, + "skip-list": true }, "logstash-filter-jdbc_streaming": { - "default-plugins": true, - "skip-list": false + "default-plugins": false, + "skip-list": true }, "logstash-filter-json": { "default-plugins": true, @@ -317,8 +317,8 @@ "skip-list": true }, "logstash-input-jdbc": { - "default-plugins": true, - "skip-list": false + "default-plugins": false, + "skip-list": true }, "logstash-input-jms": { "default-plugins": true, @@ -402,6 +402,10 @@ "default-plugins": true, "skip-list": false }, + "logstash-integration-jdbc": { + "default-plugins": true, + "skip-list": false + }, "logstash-integration-kafka": { "default-plugins": true, "skip-list": false From 60a7cd1de2244f9792f1efa71e10081ff01a8b64 Mon Sep 17 00:00:00 2001 From: Rob Bavey Date: Tue, 7 Jan 2020 15:37:23 -0500 Subject: [PATCH 0316/1126] Update offline pack tests for integration plugins Fix wildcard "logstash-filter-*" test Add test for offline packaging of integaration plugins Fixes #11406 --- .../specs/cli/prepare_offline_pack_spec.rb | 22 ++++++++++++++++++- 1 file changed, 21 insertions(+), 1 deletion(-) diff --git a/qa/integration/specs/cli/prepare_offline_pack_spec.rb b/qa/integration/specs/cli/prepare_offline_pack_spec.rb index babdb0393..e691903a6 100644 --- a/qa/integration/specs/cli/prepare_offline_pack_spec.rb +++ b/qa/integration/specs/cli/prepare_offline_pack_spec.rb @@ -35,6 +35,26 @@ describe "CLI > logstash-plugin prepare-offline-pack" do end end + context "creating a pack for integration plugins" do + let(:plugin_to_pack) { "logstash-integration-jdbc" } + + + it "successfully create a pack" do + execute = @logstash_plugin.prepare_offline_pack(plugin_to_pack, temporary_zip_file) + + expect(execute.exit_code).to eq(0) + expect(execute.stderr_and_stdout).to match(/Offline package created at/) + expect(execute.stderr_and_stdout).to match(/#{temporary_zip_file}/) + + unpacked = unpack(temporary_zip_file) + expect(unpacked.plugins.collect(&:name)).to include(plugin_to_pack) + expect(unpacked.plugins.size).to eq(1) + + expect(unpacked.dependencies.size).to be > 0 + end + end + + context "create a pack from a wildcard" do let(:plugins_to_pack) { %w(logstash-filter-*) } @@ -50,7 +70,7 @@ describe "CLI > logstash-plugin prepare-offline-pack" do filters = @logstash_plugin.list(plugins_to_pack.first) .stderr_and_stdout.split("\n") .delete_if do |line| - line =~ /cext|JAVA_OPT|fatal|^WARNING|Option \w+ was deprecated/ + line =~ /cext|├──|└──|logstash-integration|JAVA_OPT|fatal|^WARNING|Option \w+ was deprecated/ end expect(unpacked.plugins.collect(&:name)).to include(*filters) From c7a4f3014528b5bc7a454eaf59f98b6e2e9f7ac4 Mon Sep 17 00:00:00 2001 From: Karol Bucek Date: Fri, 10 Jan 2020 09:25:15 +0100 Subject: [PATCH 0317/1126] Test: try to deal with (potentially) flaky spec Fixes #11483 --- logstash-core/spec/logstash/util_spec.rb | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/logstash-core/spec/logstash/util_spec.rb b/logstash-core/spec/logstash/util_spec.rb index 201c7a0a4..b86f879be 100644 --- a/logstash-core/spec/logstash/util_spec.rb +++ b/logstash-core/spec/logstash/util_spec.rb @@ -81,7 +81,8 @@ describe LogStash::Util do it "returns nil as id" do thread = dead_thread p thread if $VERBOSE - java.lang.System.gc + 2.times { java.lang.System.gc || sleep(0.01) } # we're assuming a full-gc to clear all weak-refs + # NOTE: if you notice this spec failing - remote it (a java.lang.Thread weak-ref might stick around) expect(LogStash::Util.get_thread_id(thread)).to be nil end end From fc152d3561730473608b63fef0084f82fce710fc Mon Sep 17 00:00:00 2001 From: Colin Surprenant Date: Mon, 13 Jan 2020 12:57:56 -0500 Subject: [PATCH 0318/1126] [7.6 clean backport of #11482] cache compiled datasets (#11491) --- .../logstash/config/ir/CompiledPipeline.java | 114 ++++++++++++++---- .../ir/compiler/ComputeStepSyntaxElement.java | 58 +++++---- .../config/ir/compiler/DatasetCompiler.java | 34 ++---- .../ir/compiler/DatasetCompilerTest.java | 16 +-- 4 files changed, 142 insertions(+), 80 deletions(-) diff --git a/logstash-core/src/main/java/org/logstash/config/ir/CompiledPipeline.java b/logstash-core/src/main/java/org/logstash/config/ir/CompiledPipeline.java index 612865c8f..0e955b2e7 100644 --- a/logstash-core/src/main/java/org/logstash/config/ir/CompiledPipeline.java +++ b/logstash-core/src/main/java/org/logstash/config/ir/CompiledPipeline.java @@ -3,6 +3,7 @@ package org.logstash.config.ir; import co.elastic.logstash.api.Codec; import org.apache.logging.log4j.LogManager; import org.apache.logging.log4j.Logger; +import org.jruby.RubyArray; import org.jruby.RubyHash; import org.jruby.javasupport.JavaUtil; import org.jruby.runtime.builtin.IRubyObject; @@ -34,6 +35,8 @@ import java.util.HashSet; import java.util.List; import java.util.Map; import java.util.Objects; +import java.util.concurrent.ConcurrentHashMap; +import java.util.concurrent.atomic.AtomicReference; import java.util.stream.Collectors; import java.util.stream.Stream; @@ -78,6 +81,18 @@ public final class CompiledPipeline { */ private final RubyIntegration.PluginFactory pluginFactory; + /** + * Per pipeline compiled classes cache shared across threads {@link CompiledExecution} + */ + private final Map> datasetClassCache = new ConcurrentHashMap<>(500); + + /** + * First, constructor time, compilation of the pipeline that will warm + * the {@link CompiledPipeline#datasetClassCache} in a thread safe way + * before the concurrent per worker threads {@link CompiledExecution} compilations + */ + private final AtomicReference warmedCompiledExecution = new AtomicReference<>(); + public CompiledPipeline( final PipelineIR pipelineIR, final RubyIntegration.PluginFactory pluginFactory) { @@ -96,6 +111,10 @@ public final class CompiledPipeline { inputs = setupInputs(cve); filters = setupFilters(cve); outputs = setupOutputs(cve); + + // invoke a first compilation to warm the class cache which will prevent + // redundant compilations for each subsequent worker {@link CompiledExecution} + warmedCompiledExecution.set(new CompiledPipeline.CompiledExecution()); } catch (Exception e) { throw new IllegalStateException("Unable to configure plugins: " + e.getMessage()); } @@ -119,6 +138,10 @@ public final class CompiledPipeline { * @return Compiled {@link Dataset} representation of the underlying {@link PipelineIR} topology */ public Dataset buildExecution() { + CompiledExecution result = warmedCompiledExecution.getAndSet(null); + if (result != null) { + return result.toDataset(); + } return new CompiledPipeline.CompiledExecution().toDataset(); } @@ -270,6 +293,17 @@ public final class CompiledPipeline { return outputs.containsKey(vertex.getId()); } + /** + * Returns an existing compiled dataset class implementation for the given {@code vertexId}, + * or compiles one from the provided {@code computeStepSyntaxElement}. + * @param vertexId a string uniquely identifying a {@link Vertex} within the current pipeline + * @param computeStepSyntaxElement the source from which to compile a dataset class + * @return an implementation of {@link Dataset} for the given vertex + */ + private Class getDatasetClass(final String vertexId, final ComputeStepSyntaxElement computeStepSyntaxElement) { + return datasetClassCache.computeIfAbsent(vertexId, _vid -> computeStepSyntaxElement.compile()); + } + /** * Instances of this class represent a fully compiled pipeline execution. Note that this class * has a separate lifecycle from {@link CompiledPipeline} because it holds per (worker-thread) @@ -280,13 +314,13 @@ public final class CompiledPipeline { /** * Compiled {@link IfVertex, indexed by their ID as returned by {@link Vertex#getId()}. */ - private final Map iffs = new HashMap<>(5); + private final Map iffs = new HashMap<>(50); /** * Cached {@link Dataset} compiled from {@link PluginVertex} indexed by their ID as returned * by {@link Vertex#getId()} to avoid duplicate computations. */ - private final Map plugins = new HashMap<>(5); + private final Map plugins = new HashMap<>(50); private final Dataset compiled; @@ -309,11 +343,37 @@ public final class CompiledPipeline { if (outputNodes.isEmpty()) { return Dataset.IDENTITY; } else { - return DatasetCompiler.terminalDataset(outputNodes.stream().map( + return terminalDataset(outputNodes.stream().map( leaf -> outputDataset(leaf, flatten(Collections.emptyList(), leaf)) ).collect(Collectors.toList())); } } + /** + *

Builds a terminal {@link Dataset} from the given parent {@link Dataset}s.

+ *

If the given set of parent {@link Dataset} is empty the sum is defined as the + * trivial dataset that does not invoke any computation whatsoever.

+ * {@link Dataset#compute(RubyArray, boolean, boolean)} is always + * {@link Collections#emptyList()}. + * @param parents Parent {@link Dataset} to sum and terminate + * @return Dataset representing the sum of given parent {@link Dataset} + */ + public Dataset terminalDataset(final Collection parents) { + final int count = parents.size(); + final Dataset result; + if (count > 1) { + ComputeStepSyntaxElement prepared = DatasetCompiler.terminalDataset(parents); + result = prepared.instantiate(prepared.compile()); + } else if (count == 1) { + // No need for a terminal dataset here, if there is only a single parent node we can + // call it directly. + result = parents.iterator().next(); + } else { + throw new IllegalArgumentException( + "Cannot create Terminal Dataset for an empty number of parent datasets" + ); + } + return result; + } /** * Build a {@link Dataset} representing the {@link JrubyEventExtLibrary.RubyEvent}s after @@ -326,12 +386,14 @@ public final class CompiledPipeline { final String vertexId = vertex.getId(); if (!plugins.containsKey(vertexId)) { - final ComputeStepSyntaxElement prepared = - DatasetCompiler.filterDataset(flatten(datasets, vertex), - filters.get(vertexId)); + final ComputeStepSyntaxElement prepared = DatasetCompiler.filterDataset( + flatten(datasets, vertex), + filters.get(vertexId)); + final Class clazz = getDatasetClass(vertexId, prepared); + LOGGER.debug("Compiled filter\n {} \n into \n {}", vertex, prepared); - plugins.put(vertexId, prepared.instantiate()); + plugins.put(vertexId, prepared.instantiate(clazz)); } return plugins.get(vertexId); @@ -348,13 +410,16 @@ public final class CompiledPipeline { final String vertexId = vertex.getId(); if (!plugins.containsKey(vertexId)) { - final ComputeStepSyntaxElement prepared = - DatasetCompiler.outputDataset(flatten(datasets, vertex), - outputs.get(vertexId), - outputs.size() == 1); + final ComputeStepSyntaxElement prepared = DatasetCompiler.outputDataset( + flatten(datasets, vertex), + outputs.get(vertexId), + outputs.size() == 1); + final Class clazz = getDatasetClass(vertexId, prepared); + LOGGER.debug("Compiled output\n {} \n into \n {}", vertex, prepared); - plugins.put(vertexId, prepared.instantiate()); - } + + plugins.put(vertexId, prepared.instantiate(clazz)); + } return plugins.get(vertexId); } @@ -369,24 +434,25 @@ public final class CompiledPipeline { */ private SplitDataset split(final Collection datasets, final EventCondition condition, final Vertex vertex) { - final String key = vertex.getId(); - SplitDataset conditional = iffs.get(key); + final String vertexId = vertex.getId(); + SplitDataset conditional = iffs.get(vertexId); + if (conditional == null) { final Collection dependencies = flatten(datasets, vertex); - conditional = iffs.get(key); + conditional = iffs.get(vertexId); // Check that compiling the dependencies did not already instantiate the conditional // by requiring its else branch. if (conditional == null) { - final ComputeStepSyntaxElement prepared = - DatasetCompiler.splitDataset(dependencies, condition); - LOGGER.debug( - "Compiled conditional\n {} \n into \n {}", vertex, prepared - ); - conditional = prepared.instantiate(); - iffs.put(key, conditional); - } + final ComputeStepSyntaxElement prepared = DatasetCompiler.splitDataset(dependencies, condition); + final Class clazz = getDatasetClass(vertexId, prepared); + LOGGER.debug("Compiled conditional\n {} \n into \n {}", vertex, prepared); + + conditional = prepared.instantiate(clazz); + iffs.put(vertexId, conditional); + } } + return conditional; } diff --git a/logstash-core/src/main/java/org/logstash/config/ir/compiler/ComputeStepSyntaxElement.java b/logstash-core/src/main/java/org/logstash/config/ir/compiler/ComputeStepSyntaxElement.java index 33d3b14b4..9fdc19e8b 100644 --- a/logstash-core/src/main/java/org/logstash/config/ir/compiler/ComputeStepSyntaxElement.java +++ b/logstash-core/src/main/java/org/logstash/config/ir/compiler/ComputeStepSyntaxElement.java @@ -11,6 +11,7 @@ import java.nio.file.Paths; import java.util.Arrays; import java.util.HashMap; import java.util.Map; +import java.util.concurrent.atomic.AtomicLong; import java.util.regex.Pattern; import java.util.stream.Collectors; import java.util.stream.StreamSupport; @@ -32,10 +33,9 @@ public final class ComputeStepSyntaxElement { private static final ISimpleCompiler COMPILER = new SimpleCompiler(); /** - * Cache of runtime compiled classes to prevent duplicate classes being compiled. + * Sequential counter to generate the class name */ - private static final Map, Class> CLASS_CACHE - = new HashMap<>(); + private static final AtomicLong classSeqCount = new AtomicLong(); /** * Pattern to remove redundant {@code ;} from formatted code since {@link Formatter} does not @@ -49,6 +49,8 @@ public final class ComputeStepSyntaxElement { private final Class type; + private final long classSeq; + public static ComputeStepSyntaxElement create( final Iterable methods, final ClassFields fields, final Class interfce) { @@ -60,37 +62,41 @@ public final class ComputeStepSyntaxElement { this.methods = methods; this.fields = fields; type = interfce; + classSeq = classSeqCount.incrementAndGet(); } @SuppressWarnings("unchecked") - public T instantiate() { - // We need to globally synchronize to avoid concurrency issues with the internal class - // loader and the CLASS_CACHE + public T instantiate(Class clazz) { + try { + return (T) clazz.getConstructor(Map.class).newInstance(ctorArguments()); + } catch (final NoSuchMethodException | InvocationTargetException | InstantiationException | IllegalAccessException ex) { + throw new IllegalStateException(ex); + } + } + + @SuppressWarnings("unchecked") + public Class compile() { + // We need to globally synchronize to avoid concurrency issues with the internal class loader + // Per https://github.com/elastic/logstash/pull/11482 we should review this lock. synchronized (COMPILER) { try { final Class clazz; - if (CLASS_CACHE.containsKey(this)) { - clazz = CLASS_CACHE.get(this); + final String name = String.format("CompiledDataset%d", classSeq); + final String code = generateCode(name); + if (SOURCE_DIR != null) { + final Path sourceFile = SOURCE_DIR.resolve(String.format("%s.java", name)); + Files.write(sourceFile, code.getBytes(StandardCharsets.UTF_8)); + COMPILER.cookFile(sourceFile.toFile()); } else { - final String name = String.format("CompiledDataset%d", CLASS_CACHE.size()); - final String code = generateCode(name); - if (SOURCE_DIR != null) { - final Path sourceFile = SOURCE_DIR.resolve(String.format("%s.java", name)); - Files.write(sourceFile, code.getBytes(StandardCharsets.UTF_8)); - COMPILER.cookFile(sourceFile.toFile()); - } else { - COMPILER.cook(code); - } - COMPILER.setParentClassLoader(COMPILER.getClassLoader()); - clazz = (Class) COMPILER.getClassLoader().loadClass( - String.format("org.logstash.generated.%s", name) - ); - CLASS_CACHE.put(this, clazz); + COMPILER.cook(code); } - return (T) clazz.getConstructor(Map.class).newInstance(ctorArguments()); - } catch (final CompileException | ClassNotFoundException | IOException - | NoSuchMethodException | InvocationTargetException | InstantiationException - | IllegalAccessException ex) { + COMPILER.setParentClassLoader(COMPILER.getClassLoader()); + clazz = (Class)COMPILER.getClassLoader().loadClass( + String.format("org.logstash.generated.%s", name) + ); + + return clazz; + } catch (final CompileException | ClassNotFoundException | IOException ex) { throw new IllegalStateException(ex); } } diff --git a/logstash-core/src/main/java/org/logstash/config/ir/compiler/DatasetCompiler.java b/logstash-core/src/main/java/org/logstash/config/ir/compiler/DatasetCompiler.java index 28717e983..5cd4b65cd 100644 --- a/logstash-core/src/main/java/org/logstash/config/ir/compiler/DatasetCompiler.java +++ b/logstash-core/src/main/java/org/logstash/config/ir/compiler/DatasetCompiler.java @@ -90,6 +90,7 @@ public final class DatasetCompiler { final ValueSyntaxElement outputBuffer = fields.add(new ArrayList<>()); final Closure clear = Closure.wrap(); final Closure compute; + if (parents.isEmpty()) { compute = filterBody(outputBuffer, BATCH_ARG, fields, plugin); } else { @@ -116,29 +117,16 @@ public final class DatasetCompiler { * @param parents Parent {@link Dataset} to sum and terminate * @return Dataset representing the sum of given parent {@link Dataset} */ - public static Dataset terminalDataset(final Collection parents) { - final int count = parents.size(); - final Dataset result; - if (count > 1) { - final ClassFields fields = new ClassFields(); - final Collection parentFields = - parents.stream().map(fields::add).collect(Collectors.toList()); - result = compileOutput( - Closure.wrap( - parentFields.stream().map(DatasetCompiler::computeDataset) - .toArray(MethodLevelSyntaxElement[]::new) - ).add(clearSyntax(parentFields)), Closure.EMPTY, fields - ).instantiate(); - } else if (count == 1) { - // No need for a terminal dataset here, if there is only a single parent node we can - // call it directly. - result = parents.iterator().next(); - } else { - throw new IllegalArgumentException( - "Cannot create Terminal Dataset for an empty number of parent datasets" - ); - } - return result; + public static ComputeStepSyntaxElement terminalDataset(final Collection parents) { + final ClassFields fields = new ClassFields(); + final Collection parentFields = + parents.stream().map(fields::add).collect(Collectors.toList()); + return compileOutput( + Closure.wrap( + parentFields.stream().map(DatasetCompiler::computeDataset) + .toArray(MethodLevelSyntaxElement[]::new) + ).add(clearSyntax(parentFields)), Closure.EMPTY, fields + ); } /** diff --git a/logstash-core/src/test/java/org/logstash/config/ir/compiler/DatasetCompilerTest.java b/logstash-core/src/test/java/org/logstash/config/ir/compiler/DatasetCompilerTest.java index 231245456..0978f0e43 100644 --- a/logstash-core/src/test/java/org/logstash/config/ir/compiler/DatasetCompilerTest.java +++ b/logstash-core/src/test/java/org/logstash/config/ir/compiler/DatasetCompilerTest.java @@ -20,12 +20,13 @@ public final class DatasetCompilerTest { */ @Test public void compilesOutputDataset() { + final ComputeStepSyntaxElement prepared = DatasetCompiler.outputDataset( + Collections.emptyList(), + PipelineTestUtil.buildOutput(events -> {}), + true + ); assertThat( - DatasetCompiler.outputDataset( - Collections.emptyList(), - PipelineTestUtil.buildOutput(events -> {}), - true - ).instantiate().compute(RubyUtil.RUBY.newArray(), false, false), + prepared.instantiate(prepared.compile()).compute(RubyUtil.RUBY.newArray(), false, false), nullValue() ); } @@ -33,9 +34,10 @@ public final class DatasetCompilerTest { @Test public void compilesSplitDataset() { final FieldReference key = FieldReference.from("foo"); - final SplitDataset left = DatasetCompiler.splitDataset( + final ComputeStepSyntaxElement prepared = DatasetCompiler.splitDataset( Collections.emptyList(), event -> event.getEvent().includes(key) - ).instantiate(); + ); + final SplitDataset left = prepared.instantiate(prepared.compile()); final Event trueEvent = new Event(); trueEvent.setField(key, "val"); final JrubyEventExtLibrary.RubyEvent falseEvent = From ed08e4f3620a6eb769075788205af7a4e30ace0e Mon Sep 17 00:00:00 2001 From: Karen Metts <35154725+karenzone@users.noreply.github.com> Date: Mon, 13 Jan 2020 17:02:00 -0500 Subject: [PATCH 0319/1126] [Doc] Release notes 7.5.1 (#11448) (#11495) * Created release notes for release 7.5.1 * Removed deleteable part * Updated with formatting changes and minor additions * Added more info about grok filter update * Change link format from md to asciidoc * Update docs/static/releasenotes.asciidoc Co-Authored-By: Ry Biesemeyer * Update docs/static/releasenotes.asciidoc Co-Authored-By: Ry Biesemeyer * Update docs/static/releasenotes.asciidoc Co-Authored-By: Ry Biesemeyer * Update docs/static/releasenotes.asciidoc Co-Authored-By: Ry Biesemeyer * Update docs/static/releasenotes.asciidoc Co-Authored-By: Ry Biesemeyer * Incorporate review comments --- docs/static/releasenotes.asciidoc | 74 +++++++++++++++++++++++++++++++ 1 file changed, 74 insertions(+) diff --git a/docs/static/releasenotes.asciidoc b/docs/static/releasenotes.asciidoc index caa58db43..3650cd696 100644 --- a/docs/static/releasenotes.asciidoc +++ b/docs/static/releasenotes.asciidoc @@ -3,6 +3,7 @@ This section summarizes the changes in the following releases: +* <> * <> * <> * <> @@ -22,6 +23,79 @@ This section summarizes the changes in the following releases: * <> * <> +[[logstash-7-5-1]] +=== Logstash 7.5.1 Release Notes + +* Improved usefullness of log messages when reporting full DLQ by including the relevant DLQ's path https://github.com/elastic/logstash/pull/11280[#11280] +* Fix: eliminates a crash that could occur at pipeline startup when the pipeline references a java-based plugin that had been installed via offline plugin pack https://github.com/elastic/logstash/pull/11340[#11340] +* Fix: The common `remove_field` plugin option now correctly works on `@metadata` fields https://github.com/elastic/logstash/pull/11342[#11342] +* Fix: do not leak ThreadContext into the system https://github.com/elastic/logstash/pull/11356[#11356] +* Fix: eliminates a regression introduced in 7.2.0 where streaming-oriented inputs configured with payload-oriented codecs (`plain` or `json`) would use them as-is instead of using the appropriate line-oriented codec implementation (`lines` or `json_lines`, respectively) https://github.com/elastic/logstash/pull/11401[#11401] +* Fix: handle cloud-id with an empty kibana part https://github.com/elastic/logstash/pull/11435[#11435] +* bump dependencies for patch release https://github.com/elastic/logstash/pull/11438[#11438] + + +==== Plugins + +*Dns Filter* + +* Added documentation on the `nameserver` option for relying on `/etc/resolv.conf` to configure the resolver + +*Elasticsearch Filter* + +* Loosen restrictions on Elasticsearch gem https://github.com/logstash-plugins/logstash-filter-elasticsearch/pull/120[#120] + +*Grok Filter* + +* Improved grok filter performance in multi-match scenarios. If you've noticed +some slowdown in grok and you're using many more workers than cores, this update +allows you to configure the +https://github.com/logstash-plugins/logstash-filter-grok/blob/master/docs/index.asciidoc#timeout_scope[timeout_scope +setting] to improve performance. https://github.com/logstash-plugins/logstash-filter-grok/pull/153[#153] + +*Jdbc_static Filter* + +* Fixed issue with driver verification using Java 11 https://github.com/logstash-plugins/logstash-filter-jdbc_static/pull/51[#51] + +*Jdbc_streaming Filter* + +* Fixed driver loading https://github.com/logstash-plugins/logstash-filter-jdbc_streaming/pull/35[#35] +* Added support for prepared statements https://github.com/logstash-plugins/logstash-filter-jdbc_streaming/pull/32[#32] +* Added support for `sequel_opts` to pass options to the 3rd party Sequel library. +* Added support for driver loading in JDK 9+ https://github.com/logstash-plugins/logstash-filter-jdbc_streaming/issues/25[#25] +* Added support for multiple driver jars https://github.com/logstash-plugins/logstash-filter-jdbc_streaming/issues/21[#21] + +*Elasticsearch Input* + +* Loosen restrictions on Elasticsearch gem https://github.com/logstash-plugins/logstash-input-elasticsearch/pull/110[#110] + +*Http Input* + +* Update netty and tcnative dependency https://github.com/logstash-plugins/logstash-input-http/issues/118[#118] +* Added 201 to valid response codes https://github.com/logstash-plugins/logstash-input-http/issues/114[#114] +* Documented response\_code option + +*Jdbc Input* + +* Fixed issue where paging settings in configuration were not being honored https://github.com/logstash-plugins/logstash-input-jdbc/pull/361[#361] +* Fix issue with driver loading https://github.com/logstash-plugins/logstash-input-jdbc/pull/356[#356] +* Added documentation to provide more info about jdbc driver loading https://github.com/logstash-plugins/logstash-input-jdbc/pull/352[#352] + +*Jms Input* + +* Docs: Added additional troubleshooting information https://github.com/logstash-plugins/logstash-input-jms/pull/38[#38] + +*Rabbitmq Integration* + +* Fixes issue in Output where failure to register connection recovery hooks prevented the output from starting +* Improves Input Plugin documentation to better align with upstream guidance https://github.com/logstash-plugins/logstash-integration-rabbitmq/pull/4[#4] + +*Elasticsearch Output* + +* Opened type removal logic for extension. This allows X-Pack Elasticsearch output to continue using types for special case `/_monitoring` bulk endpoint, enabling a fix for Logstash #11312. https://github.com/logstash-plugins/logstash-output-elasticsearch/pull/900[#900] +* Fixed 8.x type removal compatibility issue https://github.com/logstash-plugins/logstash-output-elasticsearch/pull/892[#892] + + [[logstash-7-5-0]] === Logstash 7.5.0 Release Notes From b846a0fdb84f1a7763beda087364fa85976183e3 Mon Sep 17 00:00:00 2001 From: Rob Bavey Date: Mon, 13 Jan 2020 09:52:36 -0500 Subject: [PATCH 0320/1126] Removes UBI7 docker code Removal of code (#11335) to generate UBI7 based docker images, as this is not being used for now Fixes #11489 --- docker/Makefile | 23 ++--------------------- docker/templates/Dockerfile.j2 | 20 ++++---------------- rakelib/artifacts.rake | 22 +++++++++------------- 3 files changed, 15 insertions(+), 50 deletions(-) diff --git a/docker/Makefile b/docker/Makefile index db07dac5b..673043f8b 100644 --- a/docker/Makefile +++ b/docker/Makefile @@ -12,7 +12,7 @@ else VERSION_TAG := $(ELASTIC_VERSION) endif -IMAGE_FLAVORS ?= oss full ubi7 +IMAGE_FLAVORS ?= oss full DEFAULT_IMAGE_FLAVOR ?= full IMAGE_TAG := $(ELASTIC_REGISTRY)/logstash/logstash @@ -20,7 +20,7 @@ HTTPD ?= logstash-docker-artifact-server FIGLET := pyfiglet -w 160 -f puffy -all: build-from-local-artifacts build-from-local-oss-artifacts build-from-local-ubi7-artifacts public-dockerfiles +all: build-from-local-artifacts build-from-local-oss-artifacts public-dockerfiles lint: venv flake8 tests @@ -48,16 +48,6 @@ build-from-local-oss-artifacts: venv dockerfile env2yaml (docker kill $(HTTPD); false); -docker kill $(HTTPD) -build-from-local-ubi7-artifacts: venv dockerfile env2yaml - docker run --rm -d --name=$(HTTPD) \ - -p 8000:8000 --expose=8000 -v $(ARTIFACTS_DIR):/mnt \ - python:3 bash -c 'cd /mnt && python3 -m http.server' - timeout 120 bash -c 'until curl -s localhost:8000 > /dev/null; do sleep 1; done' - pyfiglet -f puffy -w 160 "Building: ubi7"; \ - docker build --network=host -t $(IMAGE_TAG)-ubi7:$(VERSION_TAG) -f $(ARTIFACTS_DIR)/Dockerfile-ubi7 data/logstash || \ - (docker kill $(HTTPD); false); - -docker kill $(HTTPD) - COPY_FILES = $(ARTIFACTS_DIR)/docker/config/pipelines.yml $(ARTIFACTS_DIR)/docker/config/logstash-oss.yml $(ARTIFACTS_DIR)/docker/config/logstash-full.yml $(ARTIFACTS_DIR)/docker/config/log4j2.properties $(ARTIFACTS_DIR)/docker/pipeline/default.conf $(ARTIFACTS_DIR)/docker/bin/docker-entrypoint $(ARTIFACTS_DIR)/docker/env2yaml/env2yaml $(ARTIFACTS_DIR)/docker/config/pipelines.yml: data/logstash/config/pipelines.yml @@ -93,18 +83,9 @@ public-dockerfiles: venv templates/Dockerfile.j2 docker_paths $(COPY_FILES) -D local_artifacts='false' \ -D release='$(RELEASE)' \ templates/Dockerfile.j2 > $(ARTIFACTS_DIR)/Dockerfile-oss && \ - jinja2 \ - -D elastic_version='$(ELASTIC_VERSION)' \ - -D version_tag='$(VERSION_TAG)' \ - -D image_flavor='ubi7' \ - -D local_artifacts='false' \ - -D release='$(RELEASE)' \ - templates/Dockerfile.j2 > $(ARTIFACTS_DIR)/Dockerfile-ubi7 && \ cd $(ARTIFACTS_DIR)/docker && \ cp $(ARTIFACTS_DIR)/Dockerfile-full Dockerfile && \ tar -zcf ../logstash-$(VERSION_TAG)-docker-build-context.tar.gz Dockerfile bin config env2yaml pipeline && \ - cp $(ARTIFACTS_DIR)/Dockerfile-ubi7 Dockerfile && \ - tar -zcf ../logstash-ubi7-$(VERSION_TAG)-docker-build-context.tar.gz Dockerfile bin config env2yaml pipeline && \ cp $(ARTIFACTS_DIR)/Dockerfile-oss Dockerfile && \ tar -zcf ../logstash-oss-$(VERSION_TAG)-docker-build-context.tar.gz Dockerfile bin config env2yaml pipeline diff --git a/docker/templates/Dockerfile.j2 b/docker/templates/Dockerfile.j2 index 48cb1b445..44e782d2e 100644 --- a/docker/templates/Dockerfile.j2 +++ b/docker/templates/Dockerfile.j2 @@ -11,21 +11,13 @@ {% set tarball = 'logstash-%s.tar.gz' % elastic_version -%} {% endif -%} -{% if image_flavor == 'ubi7' -%} - {% set base_image = 'registry.access.redhat.com/ubi7/ubi-minimal:7.7' -%} - {% set package_manager = 'microdnf' -%} -{% else -%} - {% set base_image = 'centos:7' -%} - {% set package_manager = 'yum' -%} -{% endif -%} - -FROM {{ base_image }} +FROM centos:7 # Install Java and the "which" command, which is needed by Logstash's shell # scripts. -RUN {{ package_manager }} update -y && {{ package_manager }} install -y java-11-openjdk-devel which && \ - {{ package_manager }} clean all +RUN yum update -y && yum install -y java-11-openjdk-devel which && \ + yum clean all # Provide a non-root user to run the process. RUN groupadd --gid 1000 logstash && \ @@ -51,11 +43,7 @@ ENV PATH=/usr/share/logstash/bin:$PATH # Provide a minimal configuration, so that simple invocations will provide # a good experience. ADD config/pipelines.yml config/pipelines.yml -{% if image_flavor == 'oss' -%} -ADD config/logstash-oss.yml config/logstash.yml -{% else -%} -ADD config/logstash-full.yml config/logstash.yml -{% endif -%} +ADD config/logstash-{{ image_flavor }}.yml config/logstash.yml ADD config/log4j2.properties config/ ADD pipeline/default.conf pipeline/logstash.conf RUN chown --recursive logstash:root config/ pipeline/ diff --git a/rakelib/artifacts.rake b/rakelib/artifacts.rake index eba15c3ad..46e32ad9c 100644 --- a/rakelib/artifacts.rake +++ b/rakelib/artifacts.rake @@ -181,22 +181,16 @@ namespace "artifact" do desc "Build docker image" task "docker" => ["prepare", "generate_build_metadata", "tar"] do puts("[docker] Building docker image") - build_docker + build_docker(false) end desc "Build OSS docker image" task "docker_oss" => ["prepare", "generate_build_metadata", "tar_oss"] do puts("[docker_oss] Building OSS docker image") - build_docker('oss') + build_docker(true) end - desc "Build UBI7 docker image" - task "docker_ubi7" => ["prepare", "generate_build_metadata", "tar"] do - puts("[docker_ubi7] Building UBI docker image") - build_docker('ubi7') - end - - desc "Generate Dockerfile for default, ubi7 and oss images" + desc "Generate Dockerfile for default and oss images" task "dockerfiles" => ["prepare", "generate_build_metadata"] do puts("[dockerfiles] Building Dockerfiles") build_dockerfiles @@ -216,7 +210,6 @@ namespace "artifact" do unless ENV['SKIP_DOCKER'] == "1" Rake::Task["artifact:docker"].invoke Rake::Task["artifact:docker_oss"].invoke - Rake::Task["artifact:docker_ubi7"].invoke Rake::Task["artifact:dockerfiles"].invoke end end @@ -545,15 +538,18 @@ namespace "artifact" do end end # def package - def build_docker(image = nil) + def build_docker(oss = false) env = { "ARTIFACTS_DIR" => ::File.join(Dir.pwd, "build"), "RELEASE" => ENV["RELEASE"], "VERSION_QUALIFIER" => VERSION_QUALIFIER } Dir.chdir("docker") do |dir| - make_job = image.nil? ? "make build-from-local-artifacts" : "make build-from-local-#{image}-artifacts" - system(env, make_job) + if oss + system(env, "make build-from-local-oss-artifacts") + else + system(env, "make build-from-local-artifacts") + end end end From 8367abb6cdae493942ad6e9a076932bb53d48c31 Mon Sep 17 00:00:00 2001 From: andsel Date: Tue, 17 Dec 2019 10:56:48 +0100 Subject: [PATCH 0321/1126] Changed plugin factory creation to use SourceWithMedata and not destructured line and column Fixes #11456 --- logstash-core/lib/logstash/compiler.rb | 8 +- .../lib/logstash/config/config_ast.rb | 6 +- .../lib/logstash/config/pipeline_config.rb | 27 +++++++ logstash-core/lib/logstash/pipeline.rb | 8 +- .../spec/logstash/compiler/compiler_spec.rb | 18 +++++ .../spec/logstash/config/config_ast_spec.rb | 2 + .../logstash/config/pipeline_config_spec.rb | 75 ++++++++++++++++++ .../logstash/common/SourceWithMetadata.java | 16 +++- .../logstash/config/ir/CompiledPipeline.java | 17 ++--- .../logstash/config/ir/ConfigCompiler.java | 23 ++---- .../config/ir/compiler/PluginFactory.java | 29 ++++--- .../config/ir/compiler/RubyIntegration.java | 17 +++-- .../execution/AbstractPipelineExt.java | 14 ++-- .../logstash/plugins/PluginFactoryExt.java | 76 +++++++------------ .../config/ir/CompiledPipelineTest.java | 44 +++++------ .../config/ir/ConfigCompilerTest.java | 16 +++- .../config/ir/EventConditionTest.java | 8 +- .../org/logstash/config/ir/IRHelpers.java | 10 +++ .../logstash/plugins/TestPluginFactory.java | 14 ++-- 19 files changed, 283 insertions(+), 145 deletions(-) diff --git a/logstash-core/lib/logstash/compiler.rb b/logstash-core/lib/logstash/compiler.rb index 6cd68b280..d22c33936 100644 --- a/logstash-core/lib/logstash/compiler.rb +++ b/logstash-core/lib/logstash/compiler.rb @@ -6,8 +6,14 @@ java_import org.logstash.config.ir.graph.Graph module LogStash; class Compiler include ::LogStash::Util::Loggable + def self.empty_or_space(str) + str.match(/\A\s*\Z/).nil? == false + end + def self.compile_sources(sources_with_metadata, support_escapes) - graph_sections = sources_with_metadata.map do |swm| + graph_sections = sources_with_metadata.reject do |swm| + self.empty_or_space(swm.text) + end.map do |swm| self.compile_graph(swm, support_escapes) end diff --git a/logstash-core/lib/logstash/config/config_ast.rb b/logstash-core/lib/logstash/config/config_ast.rb index 1d0019616..67e88ff6e 100644 --- a/logstash-core/lib/logstash/config/config_ast.rb +++ b/logstash-core/lib/logstash/config/config_ast.rb @@ -233,12 +233,12 @@ module LogStash; module Config; module AST # If any parent is a Plugin, this must be a codec. if attributes.elements.nil? - return "plugin(#{plugin_type.inspect}, #{plugin_name.inspect}, #{source_meta.line}, #{source_meta.column})" << (plugin_type == "codec" ? "" : "\n") + return "plugin(#{plugin_type.inspect}, #{plugin_name.inspect}, line_to_source(#{source_meta.line}, #{source_meta.column}))" << (plugin_type == "codec" ? "" : "\n") else settings = attributes.recursive_select(Attribute).collect(&:compile).reject(&:empty?) attributes_code = "LogStash::Util.hash_merge_many(#{settings.map { |c| "{ #{c} }" }.join(", ")})" - return "plugin(#{plugin_type.inspect}, #{plugin_name.inspect}, #{source_meta.line}, #{source_meta.column}, #{attributes_code})" << (plugin_type == "codec" ? "" : "\n") + return "plugin(#{plugin_type.inspect}, #{plugin_name.inspect}, line_to_source(#{source_meta.line}, #{source_meta.column}), #{attributes_code})" << (plugin_type == "codec" ? "" : "\n") end end @@ -255,7 +255,7 @@ module LogStash; module Config; module AST when "codec" settings = attributes.recursive_select(Attribute).collect(&:compile).reject(&:empty?) attributes_code = "LogStash::Util.hash_merge_many(#{settings.map { |c| "{ #{c} }" }.join(", ")})" - return "plugin(#{plugin_type.inspect}, #{plugin_name.inspect}, #{source_meta.line}, #{source_meta.column}, #{attributes_code})" + return "plugin(#{plugin_type.inspect}, #{plugin_name.inspect}, line_to_source(#{source_meta.line}, #{source_meta.column}), #{attributes_code})" end end diff --git a/logstash-core/lib/logstash/config/pipeline_config.rb b/logstash-core/lib/logstash/config/pipeline_config.rb index d93b444b4..268345271 100644 --- a/logstash-core/lib/logstash/config/pipeline_config.rb +++ b/logstash-core/lib/logstash/config/pipeline_config.rb @@ -5,6 +5,8 @@ module LogStash module Config class PipelineConfig include LogStash::Util::Loggable + LineToSource = Struct.new("LineToSource", :bounds, :source) + attr_reader :source, :pipeline_id, :config_parts, :settings, :read_at def initialize(source, pipeline_id, config_parts, settings) @@ -44,5 +46,30 @@ module LogStash module Config logger.debug("Merged config") logger.debug("\n\n#{config_string}") end + + def lookup_source(global_line_number, source_column) + res = source_references.find { |line_to_source| line_to_source.bounds.include? global_line_number } + if res == nil + raise IndexError, "can't find the config segment related to line #{global_line_number}" + end + swm = res.source + SourceWithMetadata.new(swm.getProtocol(), swm.getId(), global_line_number + 1 - res.bounds.begin, source_column, swm.getText()) + end + + private + def source_references + @source_refs ||= begin + offset = 0 + source_refs = [] + config_parts.each do |config_part| + #line numbers starts from 1 in text files + lines_range = (config_part.getLine() + offset + 1..config_part.getLinesCount() + offset) + source_segment = LineToSource.new(lines_range, config_part) + source_refs << source_segment + offset += config_part.getLinesCount() + end + source_refs.freeze + end + end end end end diff --git a/logstash-core/lib/logstash/pipeline.rb b/logstash-core/lib/logstash/pipeline.rb index 181c8fed1..f182c49cd 100644 --- a/logstash-core/lib/logstash/pipeline.rb +++ b/logstash-core/lib/logstash/pipeline.rb @@ -54,6 +54,10 @@ module LogStash; class BasePipeline < AbstractPipeline end end + def line_to_source(line, column) + pipeline_config.lookup_source(line, column) + end + def reloadable? configured_as_reloadable? && reloadable_plugins? end @@ -69,8 +73,8 @@ module LogStash; class BasePipeline < AbstractPipeline private - def plugin(plugin_type, name, line, column, *args) - @plugin_factory.plugin(plugin_type, name, line, column, *args) + def plugin(plugin_type, name, source, *args) + @plugin_factory.plugin(plugin_type, name, source, *args) end def default_logging_keys(other_keys = {}) diff --git a/logstash-core/spec/logstash/compiler/compiler_spec.rb b/logstash-core/spec/logstash/compiler/compiler_spec.rb index 8e614332f..160f1c5ed 100644 --- a/logstash-core/spec/logstash/compiler/compiler_spec.rb +++ b/logstash-core/spec/logstash/compiler/compiler_spec.rb @@ -32,6 +32,24 @@ describe LogStash::Compiler do end end + describe "compile with empty source" do + subject(:source_id) { "fake_sourcefile" } + let(:source_with_metadata) { org.logstash.common.SourceWithMetadata.new(source_protocol, source_id, 0, 0, source) } + subject(:compiled) { puts "PCOMP"; described_class.compile_pipeline(source_with_metadata, settings) } + + let(:sources_with_metadata) do + [ + org.logstash.common.SourceWithMetadata.new("str", "in_plugin", 0, 0, "input { input_0 {} } "), + org.logstash.common.SourceWithMetadata.new("str", "out_plugin", 0, 0, "output { output_0 {} } "), + org.logstash.common.SourceWithMetadata.new("str", "", 0, 0, " ") + ] + end + + it "should compile only the text parts" do + described_class.compile_sources(sources_with_metadata, false) + end + end + describe "compiling to Pipeline" do subject(:source_id) { "fake_sourcefile" } let(:source_with_metadata) { org.logstash.common.SourceWithMetadata.new(source_protocol, source_id, 0, 0, source) } diff --git a/logstash-core/spec/logstash/config/config_ast_spec.rb b/logstash-core/spec/logstash/config/config_ast_spec.rb index 17d0ba61b..7e1d5edf2 100644 --- a/logstash-core/spec/logstash/config/config_ast_spec.rb +++ b/logstash-core/spec/logstash/config/config_ast_spec.rb @@ -209,6 +209,7 @@ describe LogStashConfigParser do eval(@code) end def plugin(*args);end + def line_to_source(*args);end end end context "(filters)" do @@ -262,6 +263,7 @@ describe LogStashConfigParser do eval(@code) end def plugin(*args);end + def line_to_source(*args);end end end diff --git a/logstash-core/spec/logstash/config/pipeline_config_spec.rb b/logstash-core/spec/logstash/config/pipeline_config_spec.rb index d7ed1c565..fa76e1719 100644 --- a/logstash-core/spec/logstash/config/pipeline_config_spec.rb +++ b/logstash-core/spec/logstash/config/pipeline_config_spec.rb @@ -72,4 +72,79 @@ describe LogStash::Config::PipelineConfig do end end end + + describe "source and line remapping" do + context "when pipeline is constructed from single file single line" do + let (:pipeline_conf_string) { 'input { generator1 }' } + subject { described_class.new(source, pipeline_id, [org.logstash.common.SourceWithMetadata.new("file", "/tmp/1", 0, 0, pipeline_conf_string)], settings) } + it "return the same line of the queried" do + expect(subject.lookup_source(1, 0).getLine()).to eq(1) + end + end + + context "when pipeline is constructed from single file" do + let (:pipeline_conf_string) { 'input { + generator1 + }' } + subject { described_class.new(source, pipeline_id, [org.logstash.common.SourceWithMetadata.new("file", "/tmp/1", 0, 0, pipeline_conf_string)], settings) } + + it "return the same line of the queried" do + expect(subject.lookup_source(1, 0).getLine()).to eq(1) + expect(subject.lookup_source(2, 0).getLine()).to eq(2) + end + + it "throw exception if line is out of bound" do + expect { subject.lookup_source(100, -1) }.to raise_exception(IndexError) + end + end + + context "when pipeline is constructed from multiple files" do + let (:pipeline_conf_string_part1) { 'input { + generator1 + }' } + let (:pipeline_conf_string_part2) { 'output { + stdout + }' } + let(:merged_config_parts) do + [ + org.logstash.common.SourceWithMetadata.new("file", "/tmp/input", 0, 0, pipeline_conf_string_part1), + org.logstash.common.SourceWithMetadata.new("file", "/tmp/output", 0, 0, pipeline_conf_string_part2) + ] + end + subject { described_class.new(source, pipeline_id, merged_config_parts, settings) } + + it "return the line of first segment" do + expect(subject.lookup_source(2, 0).getLine()).to eq(2) + expect(subject.lookup_source(2, 0).getId()).to eq("/tmp/input") + end + + it "return the line of second segment" do + expect(subject.lookup_source(4, 0).getLine()).to eq(1) + expect(subject.lookup_source(4, 0).getId()).to eq("/tmp/output") + end + + it "throw exception if line is out of bound" do + expect { subject.lookup_source(100, 0) }.to raise_exception(IndexError) + end + end + + context "when pipeline is constructed from multiple files and the first has trailing newline" do + let (:pipeline_conf_string_part1) { "input {\n generator1\n}\n" } + let (:pipeline_conf_string_part2) { 'output { + stdout + }' } + let(:merged_config_parts) do + [ + org.logstash.common.SourceWithMetadata.new("file", "/tmp/input", 0, 0, pipeline_conf_string_part1), + org.logstash.common.SourceWithMetadata.new("file", "/tmp/output", 0, 0, pipeline_conf_string_part2) + ] + end + subject { described_class.new(source, pipeline_id, merged_config_parts, settings) } + + it "shouldn't slide the mapping of subsequent" do + expect(subject.lookup_source(4, 0).getLine()).to eq(1) + expect(subject.lookup_source(4, 0).getId()).to eq("/tmp/output") + end + end + end end diff --git a/logstash-core/src/main/java/org/logstash/common/SourceWithMetadata.java b/logstash-core/src/main/java/org/logstash/common/SourceWithMetadata.java index 9a76ef5e5..76562a564 100644 --- a/logstash-core/src/main/java/org/logstash/common/SourceWithMetadata.java +++ b/logstash-core/src/main/java/org/logstash/common/SourceWithMetadata.java @@ -18,6 +18,7 @@ public class SourceWithMetadata implements HashableWithSource { private final Integer line; private final Integer column; private final String text; + private int linesCount; public String getProtocol() { return this.protocol; @@ -60,11 +61,13 @@ public class SourceWithMetadata implements HashableWithSource { badAttributes.add(this.getText()); } - if (!badAttributes.isEmpty()){ + if (!badAttributes.isEmpty()) { String message = "Missing attributes in SourceWithMetadata: (" + badAttributes + ") " + this.toString(); throw new IncompleteSourceWithMetadataException(message); } + + this.linesCount = text.split("\\n").length; } public SourceWithMetadata(String protocol, String id, String text) throws IncompleteSourceWithMetadataException { @@ -93,4 +96,15 @@ public class SourceWithMetadata implements HashableWithSource { private Collection hashableAttributes() { return Arrays.asList(this.getId(), this.getProtocol(), this.getLine(), this.getColumn(), this.getText()); } + + public int getLinesCount() { + return linesCount; + } + + public boolean equalsWithoutText(SourceWithMetadata other) { + return getProtocol().equals(other.getProtocol()) + && getId().equals(other.getId()) + && getLine().equals(other.getLine()) + && getColumn().equals(other.getColumn()); + } } diff --git a/logstash-core/src/main/java/org/logstash/config/ir/CompiledPipeline.java b/logstash-core/src/main/java/org/logstash/config/ir/CompiledPipeline.java index 0e955b2e7..3dea8a4f4 100644 --- a/logstash-core/src/main/java/org/logstash/config/ir/CompiledPipeline.java +++ b/logstash-core/src/main/java/org/logstash/config/ir/CompiledPipeline.java @@ -155,8 +155,7 @@ public final class CompiledPipeline { final PluginDefinition def = v.getPluginDefinition(); final SourceWithMetadata source = v.getSourceWithMetadata(); res.put(v.getId(), pluginFactory.buildOutput( - RubyUtil.RUBY.newString(def.getName()), RubyUtil.RUBY.newFixnum(source.getLine()), - RubyUtil.RUBY.newFixnum(source.getColumn()), convertArgs(def), convertJavaArgs(def, cve) + RubyUtil.RUBY.newString(def.getName()), source, convertArgs(def), convertJavaArgs(def, cve) )); }); return res; @@ -173,8 +172,7 @@ public final class CompiledPipeline { final PluginDefinition def = vertex.getPluginDefinition(); final SourceWithMetadata source = vertex.getSourceWithMetadata(); res.put(vertex.getId(), pluginFactory.buildFilter( - RubyUtil.RUBY.newString(def.getName()), RubyUtil.RUBY.newFixnum(source.getLine()), - RubyUtil.RUBY.newFixnum(source.getColumn()), convertArgs(def), convertJavaArgs(def, cve) + RubyUtil.RUBY.newString(def.getName()), source, convertArgs(def), convertJavaArgs(def, cve) )); } return res; @@ -190,8 +188,7 @@ public final class CompiledPipeline { final PluginDefinition def = v.getPluginDefinition(); final SourceWithMetadata source = v.getSourceWithMetadata(); IRubyObject o = pluginFactory.buildInput( - RubyUtil.RUBY.newString(def.getName()), RubyUtil.RUBY.newFixnum(source.getLine()), - RubyUtil.RUBY.newFixnum(source.getColumn()), convertArgs(def), convertJavaArgs(def, cve)); + RubyUtil.RUBY.newString(def.getName()), source, convertArgs(def), convertJavaArgs(def, cve)); nodes.add(o); }); return nodes; @@ -212,10 +209,11 @@ public final class CompiledPipeline { final Object toput; if (value instanceof PluginStatement) { final PluginDefinition codec = ((PluginStatement) value).getPluginDefinition(); + SourceWithMetadata source = ((PluginStatement) value).getSourceWithMetadata(); toput = pluginFactory.buildCodec( RubyUtil.RUBY.newString(codec.getName()), - Rubyfier.deep(RubyUtil.RUBY, codec.getArguments()), - codec.getArguments() + source, Rubyfier.deep(RubyUtil.RUBY, codec.getArguments()), + codec.getArguments() ); } else { toput = value; @@ -240,10 +238,11 @@ public final class CompiledPipeline { final IRubyObject toput; if (value instanceof PluginStatement) { final PluginDefinition codec = ((PluginStatement) value).getPluginDefinition(); + SourceWithMetadata source = ((PluginStatement) value).getSourceWithMetadata(); Map codecArgs = expandConfigVariables(cve, codec.getArguments()); toput = pluginFactory.buildCodec( RubyUtil.RUBY.newString(codec.getName()), - Rubyfier.deep(RubyUtil.RUBY, codec.getArguments()), + source, Rubyfier.deep(RubyUtil.RUBY, codec.getArguments()), codecArgs ); Codec javaCodec = (Codec)JavaUtil.unwrapJavaValue(toput); diff --git a/logstash-core/src/main/java/org/logstash/config/ir/ConfigCompiler.java b/logstash-core/src/main/java/org/logstash/config/ir/ConfigCompiler.java index 668563fc6..5fc2414e0 100644 --- a/logstash-core/src/main/java/org/logstash/config/ir/ConfigCompiler.java +++ b/logstash-core/src/main/java/org/logstash/config/ir/ConfigCompiler.java @@ -1,5 +1,7 @@ package org.logstash.config.ir; +import org.jruby.RubyArray; +import org.jruby.RubyClass; import org.jruby.javasupport.JavaUtil; import org.jruby.runtime.builtin.IRubyObject; import org.logstash.RubyUtil; @@ -17,28 +19,19 @@ public final class ConfigCompiler { } /** - * @param config Logstash Config String + * @param sourcesWithMetadata Logstash Config partitioned * @param supportEscapes The value of the setting {@code config.support_escapes} * @return Compiled {@link PipelineIR} - * @throws IncompleteSourceWithMetadataException On Broken Configuration */ - public static PipelineIR configToPipelineIR(final String config, final boolean supportEscapes) - throws IncompleteSourceWithMetadataException { + public static PipelineIR configToPipelineIR(final @SuppressWarnings("rawtypes") RubyArray sourcesWithMetadata, + final boolean supportEscapes) { final IRubyObject compiler = RubyUtil.RUBY.executeScript( - "require 'logstash/compiler'\nLogStash::Compiler", - "" + "require 'logstash/compiler'\nLogStash::Compiler", + "" ); final IRubyObject code = compiler.callMethod(RubyUtil.RUBY.getCurrentContext(), "compile_sources", - new IRubyObject[]{ - RubyUtil.RUBY.newArray( - JavaUtil.convertJavaToRuby( - RubyUtil.RUBY, - new SourceWithMetadata("str", "pipeline", 0, 0, config) - ) - ), - RubyUtil.RUBY.newBoolean(supportEscapes) - } + new IRubyObject[]{sourcesWithMetadata, RubyUtil.RUBY.newBoolean(supportEscapes)} ); return code.toJava(PipelineIR.class); } diff --git a/logstash-core/src/main/java/org/logstash/config/ir/compiler/PluginFactory.java b/logstash-core/src/main/java/org/logstash/config/ir/compiler/PluginFactory.java index 304a720f4..766eabc73 100644 --- a/logstash-core/src/main/java/org/logstash/config/ir/compiler/PluginFactory.java +++ b/logstash-core/src/main/java/org/logstash/config/ir/compiler/PluginFactory.java @@ -1,13 +1,13 @@ package org.logstash.config.ir.compiler; import co.elastic.logstash.api.Codec; -import org.jruby.RubyInteger; import org.jruby.RubyString; import org.jruby.runtime.builtin.IRubyObject; import co.elastic.logstash.api.Configuration; import co.elastic.logstash.api.Context; import co.elastic.logstash.api.Filter; import co.elastic.logstash.api.Input; +import org.logstash.common.SourceWithMetadata; import java.util.Map; @@ -18,9 +18,7 @@ public interface PluginFactory extends RubyIntegration.PluginFactory { Input buildInput(String name, String id, Configuration configuration, Context context); - Filter buildFilter( - String name, String id, Configuration configuration, Context context - ); + Filter buildFilter(String name, String id, Configuration configuration, Context context); final class Default implements PluginFactory { @@ -41,28 +39,27 @@ public interface PluginFactory extends RubyIntegration.PluginFactory { } @Override - public IRubyObject buildInput(final RubyString name, final RubyInteger line, final RubyInteger column, + public IRubyObject buildInput(final RubyString name, SourceWithMetadata source, final IRubyObject args, Map pluginArgs) { - return rubyFactory.buildInput(name, line, column, args, pluginArgs); + return rubyFactory.buildInput(name, source, args, pluginArgs); } @Override - public AbstractOutputDelegatorExt buildOutput(final RubyString name, final RubyInteger line, - final RubyInteger column, final IRubyObject args, - final Map pluginArgs) { - return rubyFactory.buildOutput(name, line, column, args, pluginArgs); + public AbstractOutputDelegatorExt buildOutput(final RubyString name, SourceWithMetadata source, + final IRubyObject args, final Map pluginArgs) { + return rubyFactory.buildOutput(name, source, args, pluginArgs); } @Override - public AbstractFilterDelegatorExt buildFilter(final RubyString name, final RubyInteger line, - final RubyInteger column, final IRubyObject args, - final Map pluginArgs) { - return rubyFactory.buildFilter(name, line, column, args, pluginArgs); + public AbstractFilterDelegatorExt buildFilter(final RubyString name, SourceWithMetadata source, + final IRubyObject args, final Map pluginArgs) { + return rubyFactory.buildFilter(name, source, args, pluginArgs); } @Override - public IRubyObject buildCodec(final RubyString name, final IRubyObject args, Map pluginArgs) { - return rubyFactory.buildCodec(name, args, pluginArgs); + public IRubyObject buildCodec(final RubyString name, SourceWithMetadata source, final IRubyObject args, + Map pluginArgs) { + return rubyFactory.buildCodec(name, source, args, pluginArgs); } @Override diff --git a/logstash-core/src/main/java/org/logstash/config/ir/compiler/RubyIntegration.java b/logstash-core/src/main/java/org/logstash/config/ir/compiler/RubyIntegration.java index d84059729..835da3ebd 100644 --- a/logstash-core/src/main/java/org/logstash/config/ir/compiler/RubyIntegration.java +++ b/logstash-core/src/main/java/org/logstash/config/ir/compiler/RubyIntegration.java @@ -1,9 +1,9 @@ package org.logstash.config.ir.compiler; import co.elastic.logstash.api.Codec; -import org.jruby.RubyInteger; import org.jruby.RubyString; import org.jruby.runtime.builtin.IRubyObject; +import org.logstash.common.SourceWithMetadata; import java.util.Map; @@ -21,16 +21,17 @@ public final class RubyIntegration { */ public interface PluginFactory { - IRubyObject buildInput(RubyString name, RubyInteger line, RubyInteger column, - IRubyObject args, Map pluginArgs); + IRubyObject buildInput(RubyString name, SourceWithMetadata source, + IRubyObject args, Map pluginArgs); - AbstractOutputDelegatorExt buildOutput(RubyString name, RubyInteger line, RubyInteger column, - IRubyObject args, Map pluginArgs); + AbstractOutputDelegatorExt buildOutput(RubyString name, SourceWithMetadata source, + IRubyObject args, Map pluginArgs); - AbstractFilterDelegatorExt buildFilter(RubyString name, RubyInteger line, RubyInteger column, IRubyObject args, - Map pluginArgs); + AbstractFilterDelegatorExt buildFilter(RubyString name, SourceWithMetadata source, IRubyObject args, + Map pluginArgs); - IRubyObject buildCodec(RubyString name, IRubyObject args, Map pluginArgs); + IRubyObject buildCodec(RubyString name, SourceWithMetadata source, IRubyObject args, + Map pluginArgs); Codec buildDefaultCodec(String codecName); diff --git a/logstash-core/src/main/java/org/logstash/execution/AbstractPipelineExt.java b/logstash-core/src/main/java/org/logstash/execution/AbstractPipelineExt.java index b726ff4a8..6d8b21339 100644 --- a/logstash-core/src/main/java/org/logstash/execution/AbstractPipelineExt.java +++ b/logstash-core/src/main/java/org/logstash/execution/AbstractPipelineExt.java @@ -93,6 +93,9 @@ public class AbstractPipelineExt extends RubyBasicObject { private RubyString configString; + @SuppressWarnings("rawtypes") + private RubyArray configParts; + private RubyString configHash; private IRubyObject settings; @@ -121,12 +124,13 @@ public class AbstractPipelineExt extends RubyBasicObject { public final AbstractPipelineExt initialize(final ThreadContext context, final IRubyObject pipelineConfig, final IRubyObject namespacedMetric, final IRubyObject rubyLogger) - throws NoSuchAlgorithmException, IncompleteSourceWithMetadataException { + throws NoSuchAlgorithmException { reporter = new PipelineReporterExt( context.runtime, RubyUtil.PIPELINE_REPORTER_CLASS).initialize(context, rubyLogger, this ); pipelineSettings = pipelineConfig; configString = (RubyString) pipelineSettings.callMethod(context, "config_string"); + configParts = (RubyArray) pipelineSettings.callMethod(context, "config_parts"); configHash = context.runtime.newString( Hex.encodeHexString( MessageDigest.getInstance("SHA1").digest(configString.getBytes()) @@ -153,10 +157,8 @@ public class AbstractPipelineExt extends RubyBasicObject { ); } } - lir = ConfigCompiler.configToPipelineIR( - configString.asJavaString(), - getSetting(context, "config.support_escapes").isTrue() - ); + boolean supportEscapes = getSetting(context, "config.support_escapes").isTrue(); + lir = ConfigCompiler.configToPipelineIR(configParts, supportEscapes); return this; } @@ -370,7 +372,7 @@ public class AbstractPipelineExt extends RubyBasicObject { @JRubyMethod(name = "pipeline_source_details", visibility = Visibility.PROTECTED) @SuppressWarnings("rawtypes") public RubyArray getPipelineSourceDetails(final ThreadContext context) { - RubyArray res = (RubyArray) pipelineSettings.callMethod(context, "config_parts"); + RubyArray res = configParts; List pipelineSources = new ArrayList<>(res.size()); for (IRubyObject part : res.toJavaArray()) { SourceWithMetadata sourceWithMetadata = part.toJava(SourceWithMetadata.class); diff --git a/logstash-core/src/main/java/org/logstash/plugins/PluginFactoryExt.java b/logstash-core/src/main/java/org/logstash/plugins/PluginFactoryExt.java index f570fe0d6..7f36421fa 100644 --- a/logstash-core/src/main/java/org/logstash/plugins/PluginFactoryExt.java +++ b/logstash-core/src/main/java/org/logstash/plugins/PluginFactoryExt.java @@ -12,7 +12,6 @@ import org.jruby.RubyArray; import org.jruby.RubyBasicObject; import org.jruby.RubyClass; import org.jruby.RubyHash; -import org.jruby.RubyInteger; import org.jruby.RubyString; import org.jruby.RubySymbol; import org.jruby.anno.JRubyClass; @@ -24,6 +23,7 @@ import org.logstash.RubyUtil; import org.logstash.common.AbstractDeadLetterQueueWriterExt; import org.logstash.common.DLQWriterAdapter; import org.logstash.common.NullDeadLetterQueueWriter; +import org.logstash.common.SourceWithMetadata; import org.logstash.config.ir.PipelineIR; import org.logstash.config.ir.compiler.AbstractFilterDelegatorExt; import org.logstash.config.ir.compiler.AbstractOutputDelegatorExt; @@ -115,61 +115,41 @@ public final class PluginFactoryExt { @SuppressWarnings("unchecked") @Override - public IRubyObject buildInput(final RubyString name, final RubyInteger line, final RubyInteger column, + public IRubyObject buildInput(final RubyString name, SourceWithMetadata source, final IRubyObject args, Map pluginArgs) { return plugin( - RubyUtil.RUBY.getCurrentContext(), PluginLookup.PluginType.INPUT, - name.asJavaString(), line.getIntValue(), column.getIntValue(), - (Map) args, pluginArgs - ); - } - - @JRubyMethod(required = 4) - public IRubyObject buildInput(final ThreadContext context, final IRubyObject[] args) { - return buildInput( - (RubyString) args[0], args[1].convertToInteger(), args[2].convertToInteger(), - args[3], null + RubyUtil.RUBY.getCurrentContext(), PluginLookup.PluginType.INPUT, name.asJavaString(), + source, (Map) args, pluginArgs ); } @SuppressWarnings("unchecked") @Override - public AbstractOutputDelegatorExt buildOutput(final RubyString name, final RubyInteger line, - final RubyInteger column, final IRubyObject args, - Map pluginArgs) { + public AbstractOutputDelegatorExt buildOutput(final RubyString name, SourceWithMetadata source, + final IRubyObject args, Map pluginArgs) { return (AbstractOutputDelegatorExt) plugin( - RubyUtil.RUBY.getCurrentContext(), PluginLookup.PluginType.OUTPUT, - name.asJavaString(), line.getIntValue(), column.getIntValue(), - (Map) args, pluginArgs - ); - } - - @JRubyMethod(required = 4) - public AbstractOutputDelegatorExt buildOutput(final ThreadContext context, - final IRubyObject[] args) { - return buildOutput( - (RubyString) args[0], args[1].convertToInteger(), args[2].convertToInteger(), args[3], null + RubyUtil.RUBY.getCurrentContext(), PluginLookup.PluginType.OUTPUT, name.asJavaString(), + source, (Map) args, pluginArgs ); } @SuppressWarnings("unchecked") @Override - public AbstractFilterDelegatorExt buildFilter(final RubyString name, final RubyInteger line, - final RubyInteger column, final IRubyObject args, - Map pluginArgs) { + public AbstractFilterDelegatorExt buildFilter(final RubyString name, SourceWithMetadata source, + final IRubyObject args, Map pluginArgs) { return (AbstractFilterDelegatorExt) plugin( - RubyUtil.RUBY.getCurrentContext(), PluginLookup.PluginType.FILTER, - name.asJavaString(), line.getIntValue(), column.getIntValue(), - (Map) args, pluginArgs + RubyUtil.RUBY.getCurrentContext(), PluginLookup.PluginType.FILTER, name.asJavaString(), + source, (Map) args, pluginArgs ); } @SuppressWarnings("unchecked") @Override - public IRubyObject buildCodec(final RubyString name, final IRubyObject args, Map pluginArgs) { + public IRubyObject buildCodec(final RubyString name, SourceWithMetadata source, final IRubyObject args, + Map pluginArgs) { return plugin( RubyUtil.RUBY.getCurrentContext(), PluginLookup.PluginType.CODEC, - name.asJavaString(), 0, 0, (Map) args, pluginArgs + name.asJavaString(), source, (Map) args, pluginArgs ); } @@ -177,27 +157,25 @@ public final class PluginFactoryExt { public Codec buildDefaultCodec(String codecName) { return (Codec) JavaUtil.unwrapJavaValue(plugin( RubyUtil.RUBY.getCurrentContext(), PluginLookup.PluginType.CODEC, - codecName, 0, 0, Collections.emptyMap(), Collections.emptyMap() + codecName, null, Collections.emptyMap(), Collections.emptyMap() )); } @SuppressWarnings("unchecked") - @JRubyMethod(required = 4, optional = 1) + @JRubyMethod(required = 3, optional = 1) public IRubyObject plugin(final ThreadContext context, final IRubyObject[] args) { return plugin( context, PluginLookup.PluginType.valueOf(args[0].asJavaString().toUpperCase(Locale.ENGLISH)), args[1].asJavaString(), - args[2].convertToInteger().getIntValue(), - args[3].convertToInteger().getIntValue(), - args.length > 4 ? (Map) args[4] : new HashMap<>(), + JavaUtil.unwrapIfJavaObject(args[2]), + args.length > 3 ? (Map) args[3] : new HashMap<>(), null ); } - @SuppressWarnings("unchecked") private IRubyObject plugin(final ThreadContext context, final PluginLookup.PluginType type, final String name, - final int line, final int column, final Map args, + SourceWithMetadata source, final Map args, Map pluginArgs) { final String id; final PluginLookup.PluginClass pluginClass = PluginLookup.lookup(type, name); @@ -205,17 +183,17 @@ public final class PluginFactoryExt { if (type == PluginLookup.PluginType.CODEC) { id = UUID.randomUUID().toString(); } else { - id = lir.getGraph().vertices().filter( - v -> v.getSourceWithMetadata() != null - && v.getSourceWithMetadata().getLine() == line - && v.getSourceWithMetadata().getColumn() == column - ).findFirst().map(Vertex::getId).orElse(null); + id = lir.getGraph().vertices() + .filter(v -> v.getSourceWithMetadata() != null + && v.getSourceWithMetadata().equalsWithoutText(source)) + .findFirst() + .map(Vertex::getId).orElse(null); } if (id == null) { throw context.runtime.newRaiseException( RubyUtil.CONFIGURATION_ERROR_CLASS, - String.format( - "Could not determine ID for %s/%s", type.rubyLabel().asJavaString(), name + String.format("Could not determine ID for %s/%s, source don't matched: %s", + type.rubyLabel().asJavaString(), name, source ) ); } diff --git a/logstash-core/src/test/java/org/logstash/config/ir/CompiledPipelineTest.java b/logstash-core/src/test/java/org/logstash/config/ir/CompiledPipelineTest.java index 70642c106..32f3c2ba4 100644 --- a/logstash-core/src/test/java/org/logstash/config/ir/CompiledPipelineTest.java +++ b/logstash-core/src/test/java/org/logstash/config/ir/CompiledPipelineTest.java @@ -14,7 +14,6 @@ import java.util.function.Consumer; import java.util.function.Supplier; import org.hamcrest.CoreMatchers; import org.hamcrest.MatcherAssert; -import org.jruby.RubyInteger; import org.jruby.RubyString; import org.jruby.runtime.builtin.IRubyObject; import org.junit.After; @@ -25,6 +24,7 @@ import org.logstash.ConvertedMap; import org.logstash.Event; import org.logstash.RubyUtil; import org.logstash.common.IncompleteSourceWithMetadataException; +import org.logstash.common.SourceWithMetadata; import org.logstash.config.ir.compiler.AbstractFilterDelegatorExt; import org.logstash.config.ir.compiler.AbstractOutputDelegatorExt; import org.logstash.config.ir.compiler.FilterDelegatorExt; @@ -97,7 +97,7 @@ public final class CompiledPipelineTest extends RubyEnvTestCase { @Test public void buildsTrivialPipeline() throws Exception { final PipelineIR pipelineIR = ConfigCompiler.configToPipelineIR( - "input {mockinput{}} output{mockoutput{}}", false + IRHelpers.toSourceWithMetadata("input {mockinput{}} output{mockoutput{}}"), false ); final JrubyEventExtLibrary.RubyEvent testEvent = JrubyEventExtLibrary.RubyEvent.newRubyEvent(RubyUtil.RUBY, new Event()); @@ -116,7 +116,7 @@ public final class CompiledPipelineTest extends RubyEnvTestCase { @Test public void buildsStraightPipeline() throws Exception { final PipelineIR pipelineIR = ConfigCompiler.configToPipelineIR( - "input {mockinput{}} filter { mockfilter {} mockfilter {} mockfilter {}} output{mockoutput{}}", + IRHelpers.toSourceWithMetadata("input {mockinput{}} filter { mockfilter {} mockfilter {} mockfilter {}} output{mockoutput{}}"), false ); final JrubyEventExtLibrary.RubyEvent testEvent = @@ -136,7 +136,7 @@ public final class CompiledPipelineTest extends RubyEnvTestCase { @Test public void buildsForkedPipeline() throws Exception { - final PipelineIR pipelineIR = ConfigCompiler.configToPipelineIR( + final PipelineIR pipelineIR = ConfigCompiler.configToPipelineIR(IRHelpers.toSourceWithMetadata( "input {mockinput{}} filter { " + "if [foo] != \"bar\" { " + "mockfilter {} " + @@ -144,7 +144,7 @@ public final class CompiledPipelineTest extends RubyEnvTestCase { "if [foo] != \"bar\" { " + "mockfilter {} " + "}} " + - "} output {mockoutput{} }", + "} output {mockoutput{} }"), false ); final JrubyEventExtLibrary.RubyEvent testEvent = @@ -268,9 +268,9 @@ public final class CompiledPipelineTest extends RubyEnvTestCase { new CompiledPipeline( ConfigCompiler.configToPipelineIR( - "input {mockinput{}} output { " + + IRHelpers.toSourceWithMetadata("input {mockinput{}} output { " + String.format("if \"z\" %s /z/ { ", operator) + - " mockoutput{} } }", + " mockoutput{} } }"), false ), new CompiledPipelineTest.MockPluginFactory( @@ -289,7 +289,7 @@ public final class CompiledPipelineTest extends RubyEnvTestCase { @Test public void equalityCheckOnCompositeField() throws Exception { final PipelineIR pipelineIR = ConfigCompiler.configToPipelineIR( - "input {mockinput{}} filter { if 4 == [list] { mockaddfilter {} } if 5 == [map] { mockaddfilter {} } } output {mockoutput{} }", + IRHelpers.toSourceWithMetadata("input {mockinput{}} filter { if 4 == [list] { mockaddfilter {} } if 5 == [map] { mockaddfilter {} } } output {mockoutput{} }"), false ); final Collection s = new ArrayList<>(); @@ -320,7 +320,7 @@ public final class CompiledPipelineTest extends RubyEnvTestCase { @Test public void conditionalWithNullField() throws Exception { final PipelineIR pipelineIR = ConfigCompiler.configToPipelineIR( - "input {mockinput{}} filter { if [foo] == [bar] { mockaddfilter {} } } output {mockoutput{} }", + IRHelpers.toSourceWithMetadata("input {mockinput{}} filter { if [foo] == [bar] { mockaddfilter {} } } output {mockoutput{} }"), false ); final JrubyEventExtLibrary.RubyEvent testEvent = @@ -344,7 +344,7 @@ public final class CompiledPipelineTest extends RubyEnvTestCase { @Test public void conditionalNestedMetaFieldPipeline() throws Exception { final PipelineIR pipelineIR = ConfigCompiler.configToPipelineIR( - "input {mockinput{}} filter { if [@metadata][foo][bar] { mockaddfilter {} } } output {mockoutput{} }", + IRHelpers.toSourceWithMetadata("input {mockinput{}} filter { if [@metadata][foo][bar] { mockaddfilter {} } } output {mockoutput{} }"), false ); final JrubyEventExtLibrary.RubyEvent testEvent = @@ -369,7 +369,7 @@ public final class CompiledPipelineTest extends RubyEnvTestCase { @Test public void moreThan255Parents() throws Exception { final PipelineIR pipelineIR = ConfigCompiler.configToPipelineIR( - "input {mockinput{}} filter { " + + IRHelpers.toSourceWithMetadata("input {mockinput{}} filter { " + "if [foo] != \"bar\" { " + "mockfilter {} " + "mockaddfilter {} " + @@ -377,7 +377,7 @@ public final class CompiledPipelineTest extends RubyEnvTestCase { "mockfilter {} " + Strings.repeat("} else if [foo] != \"bar\" {" + "mockfilter {} ", 300) + " } } " + - "} output {mockoutput{} }", + "} output {mockoutput{} }"), false ); final JrubyEventExtLibrary.RubyEvent testEvent = @@ -426,11 +426,11 @@ public final class CompiledPipelineTest extends RubyEnvTestCase { new CompiledPipeline( ConfigCompiler.configToPipelineIR( - "input {mockinput{}} filter { " + + IRHelpers.toSourceWithMetadata("input {mockinput{}} filter { " + String.format("if %s { ", conditional) + " mockaddfilter {} " + "} " + - "} output {mockoutput{} }", + "} output {mockoutput{} }"), false ), new CompiledPipelineTest.MockPluginFactory( @@ -476,28 +476,28 @@ public final class CompiledPipelineTest extends RubyEnvTestCase { } @Override - public IRubyObject buildInput(final RubyString name, final RubyInteger line, - final RubyInteger column, final IRubyObject args, Map pluginArgs) { + public IRubyObject buildInput(final RubyString name, SourceWithMetadata source, + final IRubyObject args, Map pluginArgs) { return setupPlugin(name, inputs); } @Override - public AbstractOutputDelegatorExt buildOutput(final RubyString name, final RubyInteger line, - final RubyInteger column, final IRubyObject args, Map pluginArgs) { + public AbstractOutputDelegatorExt buildOutput(final RubyString name, SourceWithMetadata source, + final IRubyObject args, Map pluginArgs) { return PipelineTestUtil.buildOutput(setupPlugin(name, outputs)); } @Override - public AbstractFilterDelegatorExt buildFilter(final RubyString name, final RubyInteger line, - final RubyInteger column, final IRubyObject args, - Map pluginArgs) { + public AbstractFilterDelegatorExt buildFilter(final RubyString name, SourceWithMetadata source, + final IRubyObject args, Map pluginArgs) { return new FilterDelegatorExt( RubyUtil.RUBY, RubyUtil.FILTER_DELEGATOR_CLASS) .initForTesting(setupPlugin(name, filters)); } @Override - public IRubyObject buildCodec(final RubyString name, final IRubyObject args, Map pluginArgs) { + public IRubyObject buildCodec(final RubyString name, SourceWithMetadata source, final IRubyObject args, + Map pluginArgs) { throw new IllegalStateException("No codec setup expected in this test."); } diff --git a/logstash-core/src/test/java/org/logstash/config/ir/ConfigCompilerTest.java b/logstash-core/src/test/java/org/logstash/config/ir/ConfigCompilerTest.java index 1314dd0ec..aeae84e5c 100644 --- a/logstash-core/src/test/java/org/logstash/config/ir/ConfigCompilerTest.java +++ b/logstash-core/src/test/java/org/logstash/config/ir/ConfigCompilerTest.java @@ -2,8 +2,13 @@ package org.logstash.config.ir; import java.io.ByteArrayOutputStream; import java.io.InputStream; + +import org.jruby.javasupport.JavaUtil; +import org.jruby.runtime.builtin.IRubyObject; import org.junit.Test; +import org.logstash.RubyUtil; import org.logstash.common.IncompleteSourceWithMetadataException; +import org.logstash.common.SourceWithMetadata; import org.logstash.config.ir.graph.Graph; import static org.hamcrest.CoreMatchers.is; @@ -13,8 +18,10 @@ public class ConfigCompilerTest extends RubyEnvTestCase { @Test public void testConfigToPipelineIR() throws Exception { + IRubyObject swm = JavaUtil.convertJavaToRuby( + RubyUtil.RUBY, new SourceWithMetadata("proto", "path", 1, 1, "input {stdin{}} output{stdout{}}")); final PipelineIR pipelineIR = - ConfigCompiler.configToPipelineIR("input {stdin{}} output{stdout{}}", false); + ConfigCompiler.configToPipelineIR(RubyUtil.RUBY.newArray(swm), false); assertThat(pipelineIR.getOutputPluginVertices().size(), is(1)); assertThat(pipelineIR.getFilterPluginVertices().size(), is(0)); } @@ -60,8 +67,9 @@ public class ConfigCompilerTest extends RubyEnvTestCase { assertThat(graphHash(config), is(first)); } - private static String graphHash(final String config) - throws IncompleteSourceWithMetadataException { - return ConfigCompiler.configToPipelineIR(config, false).uniqueHash(); + private static String graphHash(final String config) throws IncompleteSourceWithMetadataException { + IRubyObject swm = JavaUtil.convertJavaToRuby( + RubyUtil.RUBY, new SourceWithMetadata("proto", "path", 1, 1, config)); + return ConfigCompiler.configToPipelineIR(RubyUtil.RUBY.newArray(swm), false).uniqueHash(); } } diff --git a/logstash-core/src/test/java/org/logstash/config/ir/EventConditionTest.java b/logstash-core/src/test/java/org/logstash/config/ir/EventConditionTest.java index 0d47a4a1d..394fb0df9 100644 --- a/logstash-core/src/test/java/org/logstash/config/ir/EventConditionTest.java +++ b/logstash-core/src/test/java/org/logstash/config/ir/EventConditionTest.java @@ -55,12 +55,12 @@ public final class EventConditionTest extends RubyEnvTestCase { @SuppressWarnings("rawtypes") public void testInclusionWithFieldInField() throws Exception { final PipelineIR pipelineIR = ConfigCompiler.configToPipelineIR( - "input {mockinput{}} filter { " + + IRHelpers.toSourceWithMetadata("input {mockinput{}} filter { " + "mockfilter {} } " + "output { " + " if [left] in [right] { " + " mockoutput{}" + - " } }", + " } }"), false ); @@ -136,12 +136,12 @@ public final class EventConditionTest extends RubyEnvTestCase { private void testConditionWithConstantValue(String condition, int expectedMatches) throws Exception { final PipelineIR pipelineIR = ConfigCompiler.configToPipelineIR( - "input {mockinput{}} filter { " + + IRHelpers.toSourceWithMetadata("input {mockinput{}} filter { " + "mockfilter {} } " + "output { " + " if " + condition + " { " + " mockoutput{}" + - " } }", + " } }"), false ); diff --git a/logstash-core/src/test/java/org/logstash/config/ir/IRHelpers.java b/logstash-core/src/test/java/org/logstash/config/ir/IRHelpers.java index 8d4b1cb48..ec29b1a5f 100644 --- a/logstash-core/src/test/java/org/logstash/config/ir/IRHelpers.java +++ b/logstash-core/src/test/java/org/logstash/config/ir/IRHelpers.java @@ -1,6 +1,9 @@ package org.logstash.config.ir; import org.hamcrest.MatcherAssert; +import org.jruby.RubyArray; +import org.jruby.javasupport.JavaUtil; +import org.logstash.RubyUtil; import org.logstash.common.IncompleteSourceWithMetadataException; import org.logstash.common.SourceWithMetadata; import org.logstash.config.ir.expression.BooleanExpression; @@ -165,4 +168,11 @@ public class IRHelpers { } return out.toString(); } + + + @SuppressWarnings("rawtypes") + public static RubyArray toSourceWithMetadata(String config) throws IncompleteSourceWithMetadataException { + return RubyUtil.RUBY.newArray(JavaUtil.convertJavaToRuby( + RubyUtil.RUBY, new SourceWithMetadata("proto", "path", 1, 1, config))); + } } diff --git a/logstash-core/src/test/java/org/logstash/plugins/TestPluginFactory.java b/logstash-core/src/test/java/org/logstash/plugins/TestPluginFactory.java index 0c78ac865..b5fd7bd6e 100644 --- a/logstash-core/src/test/java/org/logstash/plugins/TestPluginFactory.java +++ b/logstash-core/src/test/java/org/logstash/plugins/TestPluginFactory.java @@ -1,9 +1,9 @@ package org.logstash.plugins; import co.elastic.logstash.api.Codec; -import org.jruby.RubyInteger; import org.jruby.RubyString; import org.jruby.runtime.builtin.IRubyObject; +import org.logstash.common.SourceWithMetadata; import org.logstash.config.ir.compiler.AbstractFilterDelegatorExt; import org.logstash.config.ir.compiler.AbstractOutputDelegatorExt; import org.logstash.config.ir.compiler.RubyIntegration; @@ -15,22 +15,26 @@ import java.util.Map; public class TestPluginFactory implements RubyIntegration.PluginFactory { @Override - public IRubyObject buildInput(RubyString name, RubyInteger line, RubyInteger column, IRubyObject args, Map pluginArgs) { + public IRubyObject buildInput(RubyString name, SourceWithMetadata source, + IRubyObject args, Map pluginArgs) { return null; } @Override - public AbstractOutputDelegatorExt buildOutput(RubyString name, RubyInteger line, RubyInteger column, IRubyObject args, Map pluginArgs) { + public AbstractOutputDelegatorExt buildOutput(RubyString name, SourceWithMetadata source, + IRubyObject args, Map pluginArgs) { return null; } @Override - public AbstractFilterDelegatorExt buildFilter(RubyString name, RubyInteger line, RubyInteger column, IRubyObject args, Map pluginArgs) { + public AbstractFilterDelegatorExt buildFilter(RubyString name, SourceWithMetadata source, + IRubyObject args, Map pluginArgs) { return null; } @Override - public IRubyObject buildCodec(RubyString name, IRubyObject args, Map pluginArgs) { + public IRubyObject buildCodec(RubyString name, SourceWithMetadata source, IRubyObject args, + Map pluginArgs) { return null; } From 3a1194edc538c4dd5debffcc509f1792a0b00f34 Mon Sep 17 00:00:00 2001 From: Karol Bucek Date: Tue, 14 Jan 2020 21:35:32 +0100 Subject: [PATCH 0322/1126] Feat: x-pack cloud id/auth for monitoring/management (#11496) resolves #11488 --- config/logstash.yml | 6 +++ ...configuration-management-settings.asciidoc | 22 ++++++-- .../settings/monitoring-settings.asciidoc | 19 +++++++ .../config_management/elasticsearch_source.rb | 13 ++++- x-pack/lib/config_management/extension.rb | 2 + x-pack/lib/helpers/elasticsearch_options.rb | 52 ++++++++++++++++--- x-pack/lib/monitoring/monitoring.rb | 19 +++++-- x-pack/lib/template.cfg.erb | 9 +++- .../elasticsearch_source_spec.rb | 37 +++++++++++++ .../spec/config_management/extension_spec.rb | 10 ++++ .../helpers/elasticsearch_options_spec.rb | 52 ++++++++++++++++++- 11 files changed, 224 insertions(+), 17 deletions(-) diff --git a/config/logstash.yml b/config/logstash.yml index 8ca9602aa..d40e00c01 100644 --- a/config/logstash.yml +++ b/config/logstash.yml @@ -224,6 +224,9 @@ #xpack.monitoring.elasticsearch.username: logstash_system #xpack.monitoring.elasticsearch.password: password #xpack.monitoring.elasticsearch.hosts: ["https://es1:9200", "https://es2:9200"] +# an alternative to hosts + username/password settings is to use cloud_id/cloud_auth +#xpack.monitoring.elasticsearch.cloud_id: monitoring_cluster_id:xxxxxxxxxx +#xpack.monitoring.elasticsearch.cloud_auth: logstash_system:password #xpack.monitoring.elasticsearch.ssl.certificate_authority: [ "/path/to/ca.crt" ] #xpack.monitoring.elasticsearch.ssl.truststore.path: path/to/file #xpack.monitoring.elasticsearch.ssl.truststore.password: password @@ -241,6 +244,9 @@ #xpack.management.elasticsearch.username: logstash_admin_user #xpack.management.elasticsearch.password: password #xpack.management.elasticsearch.hosts: ["https://es1:9200", "https://es2:9200"] +# an alternative to hosts + username/password settings is to use cloud_id/cloud_auth +#xpack.management.elasticsearch.cloud_id: management_cluster_id:xxxxxxxxxx +#xpack.management.elasticsearch.cloud_auth: logstash_admin_user:password #xpack.management.elasticsearch.ssl.certificate_authority: [ "/path/to/ca.crt" ] #xpack.management.elasticsearch.ssl.truststore.path: /path/to/file #xpack.management.elasticsearch.ssl.truststore.password: password diff --git a/docs/static/settings/configuration-management-settings.asciidoc b/docs/static/settings/configuration-management-settings.asciidoc index 14c1db3b0..1190cb643 100644 --- a/docs/static/settings/configuration-management-settings.asciidoc +++ b/docs/static/settings/configuration-management-settings.asciidoc @@ -52,9 +52,9 @@ section in your Logstash configuration, or a different one. Defaults to If your {es} cluster is protected with basic authentication, these settings provide the username and password that the Logstash instance uses to -authenticate for accessing the configuration data. The username you specify here -should have the `logstash_admin` role, which provides access to `.logstash-*` -indices for managing configurations. +authenticate for accessing the configuration data. +The username you specify here should have the `logstash_admin` role, which +provides access to `.logstash-*` indices for managing configurations. `xpack.management.elasticsearch.ssl.certificate_authority`:: @@ -78,3 +78,19 @@ the client’s certificate. `xpack.management.elasticsearch.ssl.keystore.password`:: Optional setting that provides the password to the keystore. + +`xpack.management.elasticsearch.cloud_id`:: + +If you're using {es} in {ecloud}, you should specify the identifier here. +This setting is an alternative to `xpack.management.elasticsearch.hosts`. +If `cloud_id` is configured, `xpack.management.elasticsearch.hosts` should not be used. +This {es} instance will store the Logstash pipeline configurations and metadata. + +`xpack.management.elasticsearch.cloud_auth`:: + +If you're using {es} in {ecloud}, you can set your auth credentials here. +This setting is an alternative to both `xpack.management.elasticsearch.username` +and `xpack.management.elasticsearch.password`. If `cloud_auth` is configured, +those settings should not be used. +The credentials you specify here should be for a user with the `logstash_admin` role, which +provides access to `.logstash-*` indices for managing configurations. diff --git a/docs/static/settings/monitoring-settings.asciidoc b/docs/static/settings/monitoring-settings.asciidoc index a7c882832..4309ad89d 100644 --- a/docs/static/settings/monitoring-settings.asciidoc +++ b/docs/static/settings/monitoring-settings.asciidoc @@ -80,3 +80,22 @@ the client’s certificate. `xpack.monitoring.elasticsearch.ssl.keystore.password`:: Optional settings that provide the password to the keystore. + +[[monitoring-additional-settings]] +===== Additional settings + +`xpack.monitoring.elasticsearch.cloud_id`:: + +If you're using {es} in {ecloud}, you should specify the identifier here. +This setting is an alternative to `xpack.monitoring.elasticsearch.hosts`. +If `cloud_id` is configured, `xpack.monitoring.elasticsearch.hosts` should not be used. +The {es} instances that you want to ship your Logstash metrics to. This might be +the same {es} instance specified in the `outputs` section in your Logstash +configuration, or a different one. + +`xpack.monitoring.elasticsearch.cloud_auth`:: + +If you're using {es} in {ecloud}, you can set your auth credentials here. +This setting is an alternative to both `xpack.monitoring.elasticsearch.username` +and `xpack.monitoring.elasticsearch.password`. If `cloud_auth` is configured, +those settings should not be used. diff --git a/x-pack/lib/config_management/elasticsearch_source.rb b/x-pack/lib/config_management/elasticsearch_source.rb index 6f6263fc4..6db650646 100644 --- a/x-pack/lib/config_management/elasticsearch_source.rb +++ b/x-pack/lib/config_management/elasticsearch_source.rb @@ -35,8 +35,17 @@ module LogStash def initialize(settings) super(settings) - if @settings.get("xpack.management.enabled") && !@settings.get_setting("xpack.management.elasticsearch.password").set? - raise ArgumentError.new("You must set the password using the \"xpack.management.elasticsearch.password\" in logstash.yml") + if @settings.get("xpack.management.enabled") + if @settings.get_setting("xpack.management.elasticsearch.cloud_id").set? + if !@settings.get_setting("xpack.management.elasticsearch.cloud_auth").set? + raise ArgumentError.new("You must set credentials using \"xpack.management.elasticsearch.cloud_auth\", " + + "when using \"xpack.management.elasticsearch.cloud_id\" in logstash.yml") + end + else + if !@settings.get_setting("xpack.management.elasticsearch.password").set? + raise ArgumentError.new("You must set the password using \"xpack.management.elasticsearch.password\" in logstash.yml") + end + end end @es_options = es_options_from_settings('management', settings) diff --git a/x-pack/lib/config_management/extension.rb b/x-pack/lib/config_management/extension.rb index b98aee938..34a745cbd 100644 --- a/x-pack/lib/config_management/extension.rb +++ b/x-pack/lib/config_management/extension.rb @@ -27,6 +27,8 @@ module LogStash settings.register(LogStash::Setting::NullableString.new("xpack.management.elasticsearch.username", "logstash_system")) settings.register(LogStash::Setting::NullableString.new("xpack.management.elasticsearch.password")) settings.register(LogStash::Setting::ArrayCoercible.new("xpack.management.elasticsearch.hosts", String, [ "https://localhost:9200" ] )) + settings.register(LogStash::Setting::NullableString.new("xpack.management.elasticsearch.cloud_id")) + settings.register(LogStash::Setting::NullableString.new("xpack.management.elasticsearch.cloud_auth")) settings.register(LogStash::Setting::NullableString.new("xpack.management.elasticsearch.ssl.certificate_authority")) settings.register(LogStash::Setting::NullableString.new("xpack.management.elasticsearch.ssl.truststore.path")) settings.register(LogStash::Setting::NullableString.new("xpack.management.elasticsearch.ssl.truststore.password")) diff --git a/x-pack/lib/helpers/elasticsearch_options.rb b/x-pack/lib/helpers/elasticsearch_options.rb index 0d44678bd..83fb37959 100644 --- a/x-pack/lib/helpers/elasticsearch_options.rb +++ b/x-pack/lib/helpers/elasticsearch_options.rb @@ -6,7 +6,16 @@ module LogStash module Helpers module ElasticsearchOptions extend self - ES_SETTINGS =%w(ssl.certificate_authority ssl.truststore.path ssl.keystore.path hosts username password) + ES_SETTINGS =%w( + ssl.certificate_authority + ssl.truststore.path + ssl.keystore.path + hosts + username + password + cloud_id + cloud_auth + ) # Retrieve elasticsearch options from either specific settings, or modules if the setting is not there and the # feature supports falling back to modules if the feature is not specified in logstash.yml @@ -14,14 +23,24 @@ module LogStash module Helpers only_modules_configured?(feature, settings) ? es_options_from_modules(settings) : es_options_from_settings(feature, settings) end - # Populate the Elasticsearch options from LogStashSettings file, based on the feature that is being - # used. + # Populate the Elasticsearch options from LogStashSettings file, based on the feature that is being used. + # @return Hash def es_options_from_settings(feature, settings) opts = {} - opts['hosts'] = settings.get("xpack.#{feature}.elasticsearch.hosts") - opts['user'] = settings.get("xpack.#{feature}.elasticsearch.username") - opts['password'] = settings.get("xpack.#{feature}.elasticsearch.password") + if cloud_id = settings.get("xpack.#{feature}.elasticsearch.cloud_id") + opts['cloud_id'] = cloud_id + check_cloud_id_configuration!(feature, settings) + else + opts['hosts'] = settings.get("xpack.#{feature}.elasticsearch.hosts") + end + if cloud_auth = settings.get("xpack.#{feature}.elasticsearch.cloud_auth") + opts['cloud_auth'] = cloud_auth + check_cloud_auth_configuration!(feature, settings) + else + opts['user'] = settings.get("xpack.#{feature}.elasticsearch.username") + opts['password'] = settings.get("xpack.#{feature}.elasticsearch.password") + end opts['sniffing'] = settings.get("xpack.#{feature}.elasticsearch.sniffing") opts['ssl_certificate_verification'] = settings.get("xpack.#{feature}.elasticsearch.ssl.verification_mode") == 'certificate' @@ -82,7 +101,7 @@ module LogStash module Helpers modules_configured?(settings) && !feature_configured?(feature, settings) end - # If not settings are configured, then assume that the feature has not been configured. + # If no settings are configured, then assume that the feature has not been configured. # The assumption is that with security setup, at least one setting (password or certificates) # should be configured. If security is not setup, and defaults 'just work' for monitoring, then # this will need to be reconsidered. @@ -113,4 +132,23 @@ module LogStash module Helpers # As only one module is supported in the initial rollout, use the first one found modules_array.first end + + private + + def check_cloud_id_configuration!(feature, settings) + return if !settings.set?("xpack.#{feature}.elasticsearch.hosts") + + raise ArgumentError.new("Both \"xpack.#{feature}.elasticsearch.cloud_id\" and " + + "\"xpack.#{feature}.elasticsearch.hosts\" specified, please only use one of those.") + end + + def check_cloud_auth_configuration!(feature, settings) + return if !settings.set?("xpack.#{feature}.elasticsearch.username") && + !settings.set?("xpack.#{feature}.elasticsearch.password") + + raise ArgumentError.new("Both \"xpack.#{feature}.elasticsearch.cloud_auth\" and " + + "\"xpack.#{feature}.elasticsearch.username\"/\"xpack.#{feature}.elasticsearch.password\" " + + "specified, please only use one of those.") + end + end end end \ No newline at end of file diff --git a/x-pack/lib/monitoring/monitoring.rb b/x-pack/lib/monitoring/monitoring.rb index 0975d5386..d72710b95 100644 --- a/x-pack/lib/monitoring/monitoring.rb +++ b/x-pack/lib/monitoring/monitoring.rb @@ -6,12 +6,13 @@ require "logstash/agent" require "monitoring/internal_pipeline_source" require "logstash/config/pipeline_config" require 'helpers/elasticsearch_options' -java_import java.util.concurrent.TimeUnit module LogStash class MonitoringExtension < LogStash::UniversalPlugin include LogStash::Util::Loggable + java_import java.util.concurrent.TimeUnit + class TemplateData def initialize(node_uuid, system_api_version, @@ -29,6 +30,8 @@ module LogStash @es_hosts = es_settings['hosts'] @user = es_settings['user'] @password = es_settings['password'] + @cloud_id = es_settings['cloud_id'] + @cloud_auth = es_settings['cloud_auth'] @ca_path = es_settings['cacert'] @truststore_path = es_settings['truststore'] @truststore_password = es_settings['truststore_password'] @@ -38,7 +41,7 @@ module LogStash @ssl_certificate_verification = (es_settings['verification_mode'] == 'certificate') end - attr_accessor :system_api_version, :es_hosts, :user, :password, :node_uuid + attr_accessor :system_api_version, :es_hosts, :user, :password, :node_uuid, :cloud_id, :cloud_auth attr_accessor :ca_path, :truststore_path, :truststore_password attr_accessor :keystore_path, :keystore_password, :sniffing, :ssl_certificate_verification @@ -50,6 +53,14 @@ module LogStash TimeUnit::SECONDS.convert(@collection_timeout_interval, TimeUnit::NANOSECONDS) end + def cloud_id? + !!cloud_id + end + + def cloud_auth? + !!cloud_auth && cloud_id? + end + def auth? user && password end @@ -109,7 +120,7 @@ module LogStash def monitoring_enabled?(settings) return settings.get_value("xpack.monitoring.enabled") if settings.set?("xpack.monitoring.enabled") - if settings.set?("xpack.monitoring.elasticsearch.hosts") + if settings.set?("xpack.monitoring.elasticsearch.hosts") || settings.set?("xpack.monitoring.elasticsearch.cloud_id") logger.warn("xpack.monitoring.enabled has not been defined, but found elasticsearch configuration. Please explicitly set `xpack.monitoring.enabled: true` in logstash.yml") true else @@ -174,6 +185,8 @@ module LogStash settings.register(LogStash::Setting::TimeValue.new("xpack.monitoring.collection.timeout_interval", "10m")) settings.register(LogStash::Setting::NullableString.new("xpack.monitoring.elasticsearch.username", "logstash_system")) settings.register(LogStash::Setting::NullableString.new("xpack.monitoring.elasticsearch.password")) + settings.register(LogStash::Setting::NullableString.new("xpack.monitoring.elasticsearch.cloud_id")) + settings.register(LogStash::Setting::NullableString.new("xpack.monitoring.elasticsearch.cloud_auth")) settings.register(LogStash::Setting::NullableString.new("xpack.monitoring.elasticsearch.ssl.certificate_authority")) settings.register(LogStash::Setting::NullableString.new("xpack.monitoring.elasticsearch.ssl.truststore.path")) settings.register(LogStash::Setting::NullableString.new("xpack.monitoring.elasticsearch.ssl.truststore.password")) diff --git a/x-pack/lib/template.cfg.erb b/x-pack/lib/template.cfg.erb index 7378412d2..c50a03527 100644 --- a/x-pack/lib/template.cfg.erb +++ b/x-pack/lib/template.cfg.erb @@ -12,13 +12,20 @@ input { } output { elasticsearch { + <% if cloud_id? %> + cloud_id => "<%= cloud_id %>" + <% if cloud_auth %> + cloud_auth => "<%= cloud_auth %>" + <% end %> + <% else %> hosts => <%= es_hosts %> + <% end %> bulk_path => "/_monitoring/bulk?system_id=logstash&system_api_version=<%= system_api_version %>&interval=1s" manage_template => false document_type => "%{[@metadata][document_type]}" index => "" sniffing => <%= sniffing %> - <% if auth? %> + <% if auth? && !cloud_auth? %> user => "<%= user %>" password => "<%= password %>" <% end %> diff --git a/x-pack/spec/config_management/elasticsearch_source_spec.rb b/x-pack/spec/config_management/elasticsearch_source_spec.rb index 20fdb64c4..3e204412b 100644 --- a/x-pack/spec/config_management/elasticsearch_source_spec.rb +++ b/x-pack/spec/config_management/elasticsearch_source_spec.rb @@ -103,7 +103,9 @@ describe LogStash::ConfigManagement::ElasticsearchSource do describe ".new" do before do allow_any_instance_of(described_class).to receive(:setup_license_checker) + allow_any_instance_of(described_class).to receive(:license_check) end + context "when password isn't set" do let(:settings) do { @@ -114,10 +116,45 @@ describe LogStash::ConfigManagement::ElasticsearchSource do #"xpack.management.elasticsearch.password" => elasticsearch_password, } end + it "should raise an ArgumentError" do expect { described_class.new(system_settings) }.to raise_error(ArgumentError) end end + + context "cloud settings" do + let(:cloud_name) { 'abcdefghijklmnopqrstuvxyz' } + let(:cloud_domain) { 'elastic.co' } + let(:cloud_id) { "label:#{Base64.urlsafe_encode64("#{cloud_domain}$#{cloud_name}$ignored")}" } + + let(:settings) do + { + "xpack.management.enabled" => true, + "xpack.management.pipeline.id" => "main", + "xpack.management.elasticsearch.cloud_id" => cloud_id, + "xpack.management.elasticsearch.cloud_auth" => "#{elasticsearch_username}:#{elasticsearch_password}" + } + end + + it "should not raise an ArgumentError" do + expect { described_class.new(system_settings) }.not_to raise_error + end + + context "when cloud_auth isn't set" do + let(:settings) do + { + "xpack.management.enabled" => true, + "xpack.management.pipeline.id" => "main", + "xpack.management.elasticsearch.cloud_id" => cloud_id, + #"xpack.management.elasticsearch.cloud_auth" => "#{elasticsearch_username}:#{elasticsearch_password}" + } + end + + it "should raise an ArgumentError" do + expect { described_class.new(system_settings) }.to raise_error(ArgumentError) + end + end + end end describe "#config_path" do diff --git a/x-pack/spec/config_management/extension_spec.rb b/x-pack/spec/config_management/extension_spec.rb index 1ad4e9c0c..f48731ef2 100644 --- a/x-pack/spec/config_management/extension_spec.rb +++ b/x-pack/spec/config_management/extension_spec.rb @@ -41,6 +41,16 @@ describe LogStash::ConfigManagement::Extension do "xpack.management.elasticsearch.ssl.keystore.password" => [LogStash::Setting::NullableString, nil] ) + it "has a cloud_id setting" do + name = "xpack.management.elasticsearch.cloud_id" + expect { settings.get_setting(name) }.not_to raise_error + end + + it "has a cloud_auth setting" do + name = "xpack.management.elasticsearch.cloud_auth" + expect { settings.get_setting(name) }.not_to raise_error + end + describe 'deprecated and renamed settings' do define_deprecated_and_renamed_settings( "xpack.management.elasticsearch.url" => "xpack.management.elasticsearch.hosts", diff --git a/x-pack/spec/helpers/elasticsearch_options_spec.rb b/x-pack/spec/helpers/elasticsearch_options_spec.rb index 546cea7dc..83e73b86c 100644 --- a/x-pack/spec/helpers/elasticsearch_options_spec.rb +++ b/x-pack/spec/helpers/elasticsearch_options_spec.rb @@ -15,7 +15,6 @@ shared_examples "elasticsearch options hash is populated without security" do "user" => expected_username, "password" => expected_password ) - end end @@ -109,6 +108,57 @@ describe LogStash::Helpers::ElasticsearchOptions do it_behaves_like 'elasticsearch options hash is populated without security' it_behaves_like 'elasticsearch options hash is populated with secure options' + + context 'when cloud id and auth are set' do + let(:cloud_name) { 'thebigone'} + let(:cloud_domain) { 'elastic.co'} + let(:cloud_id) { "monitoring:#{Base64.urlsafe_encode64("#{cloud_domain}$#{cloud_name}$ignored")}" } + let(:cloud_username) { 'elastic' } + let(:cloud_password) { 'passw0rd'} + let(:cloud_auth) { "#{cloud_username}:#{cloud_password}" } + let(:expected_url) { ["https://#{cloud_name}.#{cloud_domain}:443"] } + let(:settings) do + { + "xpack.monitoring.enabled" => true, + "xpack.monitoring.elasticsearch.cloud_id" => cloud_id, + "xpack.monitoring.elasticsearch.cloud_auth" => cloud_auth, + } + end + + it "creates the elasticsearch output options hash" do + es_options = test_class.es_options_from_settings_or_modules('monitoring', system_settings) + expect(es_options).to include("cloud_id" => cloud_id, "cloud_auth" => cloud_auth) + expect(es_options.keys).to_not include("hosts") + expect(es_options.keys).to_not include("username") + expect(es_options.keys).to_not include("password") + end + + context 'hosts also set' do + let(:settings) do + super.merge( + "xpack.monitoring.elasticsearch.hosts" => 'https://localhost:9200' + ) + end + + it "raises due invalid configuration" do + expect { test_class.es_options_from_settings_or_modules('monitoring', system_settings) }. + to raise_error(ArgumentError, /Both.*?cloud_id.*?and.*?hosts.*?specified/) + end + end + + context 'username also set' do + let(:settings) do + super.merge( + "xpack.monitoring.elasticsearch.username" => 'elastic' + ) + end + + it "raises due invalid configuration" do + expect { test_class.es_options_from_settings_or_modules('monitoring', system_settings) }. + to raise_error(ArgumentError, /Both.*?cloud_auth.*?and.*?username.*?specified/) + end + end + end end describe 'es_options_from_settings_or_modules' do From 1b605e30421d5aa0091fcf376e80cdcb5161b3e7 Mon Sep 17 00:00:00 2001 From: Colin Surprenant Date: Tue, 14 Jan 2020 15:46:48 -0500 Subject: [PATCH 0323/1126] start inputs only when all WorkerLoop are fully initialized (#11492) --- logstash-core/lib/logstash/java_pipeline.rb | 40 ++++++++++++++++++--- 1 file changed, 35 insertions(+), 5 deletions(-) diff --git a/logstash-core/lib/logstash/java_pipeline.rb b/logstash-core/lib/logstash/java_pipeline.rb index f76bffb57..dbc0a6441 100644 --- a/logstash-core/lib/logstash/java_pipeline.rb +++ b/logstash-core/lib/logstash/java_pipeline.rb @@ -244,18 +244,28 @@ module LogStash; class JavaPipeline < JavaBasePipeline filter_queue_client.set_batch_dimensions(batch_size, batch_delay) - pipeline_workers.times do |t| + # First launch WorkerLoop initialization in separate threads which concurrently + # compiles and initializes the worker pipelines + + worker_loops = pipeline_workers.times + .map { Thread.new { init_worker_loop } } + .map(&:value) + + fail("Some worker(s) were not correctly initialized") if worker_loops.any?{|v| v.nil?} + + # Once all WorkerLoop have been initialized run them in separate threads + + worker_loops.each_with_index do |worker_loop, t| thread = Thread.new do Util.set_thread_name("[#{pipeline_id}]>worker#{t}") ThreadContext.put("pipeline.id", pipeline_id) - org.logstash.execution.WorkerLoop.new( - lir_execution, filter_queue_client, @events_filtered, @events_consumed, - @flushRequested, @flushing, @shutdownRequested, @drain_queue).run + worker_loop.run end @worker_threads << thread end - # inputs should be started last, after all workers + # Finally inputs should be started last, after all workers have been initialized and started + begin start_inputs rescue => e @@ -466,6 +476,26 @@ module LogStash; class JavaPipeline < JavaBasePipeline private + # @return [WorkerLoop] a new WorkerLoop instance or nil upon construction exception + def init_worker_loop + begin + org.logstash.execution.WorkerLoop.new( + lir_execution, + filter_queue_client, + @events_filtered, + @events_consumed, + @flushRequested, + @flushing, + @shutdownRequested, + @drain_queue) + rescue => e + @logger.error( + "Worker loop initialization error", + default_logging_keys(:error => e.message, :exception => e.class, :stacktrace => e.backtrace.join("\n"))) + nil + end + end + def maybe_setup_out_plugins if @outputs_registered.make_true register_plugins(outputs) From 994ebf81e385abd76a4ffa9fc93ca700340b22ec Mon Sep 17 00:00:00 2001 From: Rob Bavey Date: Wed, 15 Jan 2020 09:28:58 -0500 Subject: [PATCH 0324/1126] Bump to 7.7.0 (#11505) --- README.md | 16 ++++++++-------- versions.yml | 4 ++-- 2 files changed, 10 insertions(+), 10 deletions(-) diff --git a/README.md b/README.md index ed72e329f..f2ecc12f5 100644 --- a/README.md +++ b/README.md @@ -28,14 +28,14 @@ These builds are created nightly and have undergone no formal QA, so they should | [deb-complete][] | [deb-oss][] | | [rpm-complete][] | [rpm-oss][] | -[tar-complete]: https://snapshots.elastic.co/downloads/logstash/logstash-7.6.0-SNAPSHOT.tar.gz -[zip-complete]: https://snapshots.elastic.co/downloads/logstash/logstash-7.6.0-SNAPSHOT.zip -[deb-complete]: https://snapshots.elastic.co/downloads/logstash/logstash-7.6.0-SNAPSHOT.deb -[rpm-complete]: https://snapshots.elastic.co/downloads/logstash/logstash-7.6.0-SNAPSHOT.rpm -[tar-oss]: https://snapshots.elastic.co/downloads/logstash/logstash-oss-7.6.0-SNAPSHOT.tar.gz -[zip-oss]: https://snapshots.elastic.co/downloads/logstash/logstash-oss-7.6.0-SNAPSHOT.zip -[deb-oss]: https://snapshots.elastic.co/downloads/logstash/logstash-oss-7.6.0-SNAPSHOT.deb -[rpm-oss]: https://snapshots.elastic.co/downloads/logstash/logstash-oss-7.6.0-SNAPSHOT.rpm +[tar-complete]: https://snapshots.elastic.co/downloads/logstash/logstash-7.7.0-SNAPSHOT.tar.gz +[zip-complete]: https://snapshots.elastic.co/downloads/logstash/logstash-7.7.0-SNAPSHOT.zip +[deb-complete]: https://snapshots.elastic.co/downloads/logstash/logstash-7.7.0-SNAPSHOT.deb +[rpm-complete]: https://snapshots.elastic.co/downloads/logstash/logstash-7.7.0-SNAPSHOT.rpm +[tar-oss]: https://snapshots.elastic.co/downloads/logstash/logstash-oss-7.7.0-SNAPSHOT.tar.gz +[zip-oss]: https://snapshots.elastic.co/downloads/logstash/logstash-oss-7.7.0-SNAPSHOT.zip +[deb-oss]: https://snapshots.elastic.co/downloads/logstash/logstash-oss-7.7.0-SNAPSHOT.deb +[rpm-oss]: https://snapshots.elastic.co/downloads/logstash/logstash-oss-7.7.0-SNAPSHOT.rpm ## Need Help? diff --git a/versions.yml b/versions.yml index e2966806f..9347d21e1 100644 --- a/versions.yml +++ b/versions.yml @@ -1,7 +1,7 @@ --- # alpha and beta qualifiers are now added via VERSION_QUALIFIER environment var -logstash: 7.6.0 -logstash-core: 7.6.0 +logstash: 7.7.0 +logstash-core: 7.7.0 logstash-core-plugin-api: 2.1.16 # jruby must reference a *released* version of jruby which can be downloaded from the official download url From 6f5101d60fef04bbe1d7851723ba0e5fe00e6ca8 Mon Sep 17 00:00:00 2001 From: Joao Duarte Date: Fri, 17 Jan 2020 12:28:01 +0000 Subject: [PATCH 0325/1126] pin google-java-format back to 1.1 for licensing reasons Fixes #11515 --- logstash-core/build.gradle | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/logstash-core/build.gradle b/logstash-core/build.gradle index d86742f13..a5ec6a057 100644 --- a/logstash-core/build.gradle +++ b/logstash-core/build.gradle @@ -146,9 +146,10 @@ dependencies { compile files(customJRubyDir + "/maven/jruby-complete/target/jruby-complete-${customJRubyVersion}.jar") } compile group: 'com.google.guava', name: 'guava', version: '22.0' - // Do not upgrade this, later versions require GPL licensed code in javac-shaded that is + // WARNING: DO NOT UPGRADE "google-java-format" + // later versions require GPL licensed code in javac-shaded that is // Apache2 incompatible - compile('com.google.googlejavaformat:google-java-format:1.7') { + compile('com.google.googlejavaformat:google-java-format:1.1') { exclude group: 'com.google.guava', module: 'guava' } compile 'org.javassist:javassist:3.26.0-GA' From 5a14aa8509f2cc0c170ee48b2033f6942a161128 Mon Sep 17 00:00:00 2001 From: Rob Bavey Date: Wed, 15 Jan 2020 14:11:57 -0500 Subject: [PATCH 0326/1126] Release notes for 7.5.2 Fixes #11507 --- docs/static/releasenotes.asciidoc | 23 ++++++++++++++++++++++- 1 file changed, 22 insertions(+), 1 deletion(-) diff --git a/docs/static/releasenotes.asciidoc b/docs/static/releasenotes.asciidoc index 3650cd696..b1b04ba4a 100644 --- a/docs/static/releasenotes.asciidoc +++ b/docs/static/releasenotes.asciidoc @@ -3,6 +3,7 @@ This section summarizes the changes in the following releases: +* <> * <> * <> * <> @@ -23,6 +24,26 @@ This section summarizes the changes in the following releases: * <> * <> +[[logstash-7-5-2]] +=== Logstash 7.5.2 Release Notes + +* Fix: Java Execution - Improve Logstash start-time by moving class caching from ComputeStepSyntaxElement to CompiledPipeline https://github.com/elastic/logstash/pull/11490[#11490] +* Fix: Java Execution - Avoid starting inputs when filters and output compilation is not complete, by starting only when all WorkerLoops are fully initialized https://github.com/elastic/logstash/pull/11492[#11492] +* Fix: Avoid issue with `nil` natie threads by making get_thread_id "nil safe" https://github.com/elastic/logstash/pull/11458[#11458] +* Update JrJackson and jackson dependencies https://github.com/elastic/logstash/pull/11478[#11478] + +==== Plugins + +*Beats Input* + +* Updated Netty dependencies, and removed support for CBC ciphers https://github.com/logstash-plugins/logstash-input-beats/pull/376[#376] +* Updated Jackson dependencies https://github.com/logstash-plugins/logstash-input-beats/pull/375[#375] + +*File Input* + +* Fix: Regression in `exclude` handling. Patterns are matched against the filename, not full path. + https://github.com/logstash-plugins/logstash-input-file/issues/237[#237] + [[logstash-7-5-1]] === Logstash 7.5.1 Release Notes @@ -941,4 +962,4 @@ Here are the plugin changes. - Tweaked logging statements to reduce verbosity - Fixed numerous issues relating to builds on Travis https://github.com/logstash-plugins/logstash-output-elasticsearch/pull/799[#799] * logstash-output-s3 - - Fixed issue where on restart, 0 byte files could erroneously be uploaded to s3 https://github.com/logstash-plugins/logstash-output-s3/issues/195[#195] + - Fixed issue where on restart, 0 byte files could erroneously be uploaded to s3 https://github.com/logstash-plugins/logstash-output-s3/issues/195[#195] \ No newline at end of file From 8c3ae7e157f38623801c59a1adbc1ac1b50ed706 Mon Sep 17 00:00:00 2001 From: Rob Bavey Date: Wed, 15 Jan 2020 16:32:42 -0500 Subject: [PATCH 0327/1126] Updated release notes after code review comments Fixes #11507 --- docs/static/releasenotes.asciidoc | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/docs/static/releasenotes.asciidoc b/docs/static/releasenotes.asciidoc index b1b04ba4a..93db0cf19 100644 --- a/docs/static/releasenotes.asciidoc +++ b/docs/static/releasenotes.asciidoc @@ -29,14 +29,14 @@ This section summarizes the changes in the following releases: * Fix: Java Execution - Improve Logstash start-time by moving class caching from ComputeStepSyntaxElement to CompiledPipeline https://github.com/elastic/logstash/pull/11490[#11490] * Fix: Java Execution - Avoid starting inputs when filters and output compilation is not complete, by starting only when all WorkerLoops are fully initialized https://github.com/elastic/logstash/pull/11492[#11492] -* Fix: Avoid issue with `nil` natie threads by making get_thread_id "nil safe" https://github.com/elastic/logstash/pull/11458[#11458] +* Fix: Avoid issue with `nil` native threads by making get_thread_id "nil safe" https://github.com/elastic/logstash/pull/11458[#11458] * Update JrJackson and jackson dependencies https://github.com/elastic/logstash/pull/11478[#11478] ==== Plugins *Beats Input* -* Updated Netty dependencies, and removed support for CBC ciphers https://github.com/logstash-plugins/logstash-input-beats/pull/376[#376] +* Updated Netty dependencies, and removed support for insecure CBC ciphers https://github.com/logstash-plugins/logstash-input-beats/pull/376[#376] * Updated Jackson dependencies https://github.com/logstash-plugins/logstash-input-beats/pull/375[#375] *File Input* From 7a2222046795e28cb8ec31bcc4c2c113225fd1ff Mon Sep 17 00:00:00 2001 From: andsel Date: Fri, 23 Aug 2019 17:32:45 +0200 Subject: [PATCH 0328/1126] Added plugin.id to fish tag log lines related to plugins Fixes #11078 --- config/log4j2.properties | 6 +- logstash-core/lib/logstash/java_pipeline.rb | 1 + logstash-core/lib/logstash/pipeline.rb | 1 + logstash-core/spec/logstash/pipeline_spec.rb | 16 +++++- .../config/ir/compiler/DatasetCompiler.java | 31 +++++++++-- .../ir/compiler/FilterDelegatorExt.java | 22 ++++++-- .../ir/compiler/JavaInputDelegatorExt.java | 1 + .../ir/compiler/OutputDelegatorExt.java | 7 ++- .../config/ir/CompiledPipelineTest.java | 4 +- .../ir/PluginConfigNameMethodDouble.java | 55 +++++++++++++++++++ .../fixtures/plugin_name_log_spec.yml | 18 ++++++ qa/integration/specs/plugin_name_log_spec.rb | 55 +++++++++++++++++++ 12 files changed, 202 insertions(+), 15 deletions(-) create mode 100644 logstash-core/src/test/java/org/logstash/config/ir/PluginConfigNameMethodDouble.java create mode 100644 qa/integration/fixtures/plugin_name_log_spec.yml create mode 100644 qa/integration/specs/plugin_name_log_spec.rb diff --git a/config/log4j2.properties b/config/log4j2.properties index 19ec491ba..68dd14240 100644 --- a/config/log4j2.properties +++ b/config/log4j2.properties @@ -4,7 +4,7 @@ name = LogstashPropertiesConfig appender.console.type = Console appender.console.name = plain_console appender.console.layout.type = PatternLayout -appender.console.layout.pattern = [%d{ISO8601}][%-5p][%-25c]%notEmpty{[%X{pipeline.id}]} %m%n +appender.console.layout.pattern = [%d{ISO8601}][%-5p][%-25c]%notEmpty{[%X{pipeline.id}]}%notEmpty{[%X{plugin.id}]} %m%n appender.json_console.type = Console appender.json_console.name = json_console @@ -21,7 +21,7 @@ appender.rolling.policies.time.type = TimeBasedTriggeringPolicy appender.rolling.policies.time.interval = 1 appender.rolling.policies.time.modulate = true appender.rolling.layout.type = PatternLayout -appender.rolling.layout.pattern = [%d{ISO8601}][%-5p][%-25c]%notEmpty{[%X{pipeline.id}]} %m%n +appender.rolling.layout.pattern = [%d{ISO8601}][%-5p][%-25c]%notEmpty{[%X{pipeline.id}]}%notEmpty{[%X{plugin.id}]} %m%n appender.rolling.policies.size.type = SizeBasedTriggeringPolicy appender.rolling.policies.size.size = 100MB appender.rolling.strategy.type = DefaultRolloverStrategy @@ -144,7 +144,7 @@ appender.deprecation_rolling.policies.time.type = TimeBasedTriggeringPolicy appender.deprecation_rolling.policies.time.interval = 1 appender.deprecation_rolling.policies.time.modulate = true appender.deprecation_rolling.layout.type = PatternLayout -appender.deprecation_rolling.layout.pattern = [%d{ISO8601}][%-5p][%-25c]%notEmpty{[%X{pipeline.id}]} %m%n +appender.deprecation_rolling.layout.pattern = [%d{ISO8601}][%-5p][%-25c]%notEmpty{[%X{pipeline.id}]}%notEmpty{[%X{plugin.id}]} %m%n appender.deprecation_rolling.policies.size.type = SizeBasedTriggeringPolicy appender.deprecation_rolling.policies.size.size = 100MB appender.deprecation_rolling.strategy.type = DefaultRolloverStrategy diff --git a/logstash-core/lib/logstash/java_pipeline.rb b/logstash-core/lib/logstash/java_pipeline.rb index dbc0a6441..c05f8bcf1 100644 --- a/logstash-core/lib/logstash/java_pipeline.rb +++ b/logstash-core/lib/logstash/java_pipeline.rb @@ -324,6 +324,7 @@ module LogStash; class JavaPipeline < JavaBasePipeline def inputworker(plugin) Util::set_thread_name("[#{pipeline_id}]<#{plugin.class.config_name}") ThreadContext.put("pipeline.id", pipeline_id) + ThreadContext.put("plugin.id", plugin.id) begin plugin.run(wrapped_write_client(plugin.id.to_sym)) rescue => e diff --git a/logstash-core/lib/logstash/pipeline.rb b/logstash-core/lib/logstash/pipeline.rb index f182c49cd..2c1791830 100644 --- a/logstash-core/lib/logstash/pipeline.rb +++ b/logstash-core/lib/logstash/pipeline.rb @@ -445,6 +445,7 @@ module LogStash; class Pipeline < BasePipeline def inputworker(plugin) Util::set_thread_name("[#{pipeline_id}]<#{plugin.class.config_name}") ThreadContext.put("pipeline.id", pipeline_id) + ThreadContext.put("plugin.id", plugin.id) begin plugin.run(wrapped_write_client(plugin.id.to_sym)) rescue => e diff --git a/logstash-core/spec/logstash/pipeline_spec.rb b/logstash-core/spec/logstash/pipeline_spec.rb index 12dd306e7..71b07a484 100644 --- a/logstash-core/spec/logstash/pipeline_spec.rb +++ b/logstash-core/spec/logstash/pipeline_spec.rb @@ -15,6 +15,7 @@ class DummyInput < LogStash::Inputs::Base end def run(queue) + @logger.debug("check log4j fish tagging input plugin") end def close @@ -73,7 +74,9 @@ class DummyFilter < LogStash::Filters::Base def register() end - def filter(event) end + def filter(event) + @logger.debug("check log4j fish tagging filter plugin") + end def threadsafe?() false; end @@ -243,6 +246,7 @@ describe LogStash::Pipeline do before do expect(::LogStash::Pipeline).to receive(:logger).and_return(logger) allow(logger).to receive(:debug?).and_return(true) + allow_any_instance_of(DummyFilter).to receive(:logger).and_return(logger) end it "should not receive a debug message with the compiled code" do @@ -266,8 +270,18 @@ describe LogStash::Pipeline do pipeline.filter_func([LogStash::Event.new]) pipeline.close end + + it "should log fish tagging of plugins" do + pipeline_settings_obj.set("config.debug", true) + pipeline = mock_pipeline_from_string(test_config_with_filters, pipeline_settings_obj) + expect(logger).to receive(:debug).with(/filter received/, anything) + expect(logger).to receive(:debug).with(/[dummyfilter]/) + pipeline.filter_func([LogStash::Event.new]) + pipeline.close + end end + context "when there is no command line -w N set" do it "starts one filter thread" do msg = "Defaulting pipeline worker threads to 1 because there are some filters that might not work with multiple worker threads" diff --git a/logstash-core/src/main/java/org/logstash/config/ir/compiler/DatasetCompiler.java b/logstash-core/src/main/java/org/logstash/config/ir/compiler/DatasetCompiler.java index 5cd4b65cd..d660ac7ce 100644 --- a/logstash-core/src/main/java/org/logstash/config/ir/compiler/DatasetCompiler.java +++ b/logstash-core/src/main/java/org/logstash/config/ir/compiler/DatasetCompiler.java @@ -152,7 +152,9 @@ public final class DatasetCompiler { final Closure computeSyntax; if (parents.isEmpty()) { clearSyntax = Closure.EMPTY; - computeSyntax = Closure.wrap(invokeOutput(fields.add(output), BATCH_ARG)); + computeSyntax = Closure.wrap(setPluginIdForLog4j(output), + invokeOutput(fields.add(output), BATCH_ARG), + unsetPluginIdForLog4j()); } else { final Collection parentFields = parents.stream().map(fields::add).collect(Collectors.toList()); @@ -167,8 +169,10 @@ public final class DatasetCompiler { clearSyntax = clearSyntax(parentFields); } final ValueSyntaxElement inputBuffer = fields.add(buffer); - computeSyntax = withInputBuffering( - Closure.wrap(invokeOutput(fields.add(output), inputBuffer), inlineClear), + computeSyntax = withInputBuffering(Closure.wrap( + setPluginIdForLog4j(output), + invokeOutput(fields.add(output), inputBuffer), inlineClear, + unsetPluginIdForLog4j()), parentFields, inputBuffer ); } @@ -184,12 +188,13 @@ public final class DatasetCompiler { final ValueSyntaxElement inputBuffer, final ClassFields fields, final AbstractFilterDelegatorExt plugin) { final ValueSyntaxElement filterField = fields.add(plugin); - final Closure body = Closure.wrap( + final Closure body = Closure.wrap(setPluginIdForLog4j(plugin), buffer(outputBuffer, filterField.call("multiFilter", inputBuffer)) ); if (plugin.hasFlush()) { body.add(callFilterFlush(fields, outputBuffer, filterField, !plugin.periodicFlush())); } + body.add(unsetPluginIdForLog4j()); return body; } @@ -286,6 +291,24 @@ public final class DatasetCompiler { ); } + private static MethodLevelSyntaxElement unsetPluginIdForLog4j() { + return () -> "org.apache.logging.log4j.ThreadContext.remove(\"plugin.id\")"; + } + + private static MethodLevelSyntaxElement setPluginIdForLog4j(final AbstractFilterDelegatorExt filterPlugin) { + final IRubyObject pluginId = filterPlugin.getId(); + return generateLog4jContextAssignment(pluginId); + } + + private static MethodLevelSyntaxElement setPluginIdForLog4j(final AbstractOutputDelegatorExt outputPlugin) { + final IRubyObject pluginId = outputPlugin.getId(); + return generateLog4jContextAssignment(pluginId); + } + + private static MethodLevelSyntaxElement generateLog4jContextAssignment(IRubyObject pluginId) { + return () -> "org.apache.logging.log4j.ThreadContext.put(\"plugin.id\", \"" + pluginId + "\")"; + } + private static MethodLevelSyntaxElement clear(final ValueSyntaxElement field) { return field.call("clear"); } diff --git a/logstash-core/src/main/java/org/logstash/config/ir/compiler/FilterDelegatorExt.java b/logstash-core/src/main/java/org/logstash/config/ir/compiler/FilterDelegatorExt.java index 6a39c9e06..18a44400f 100644 --- a/logstash-core/src/main/java/org/logstash/config/ir/compiler/FilterDelegatorExt.java +++ b/logstash-core/src/main/java/org/logstash/config/ir/compiler/FilterDelegatorExt.java @@ -5,17 +5,21 @@ import org.jruby.Ruby; import org.jruby.RubyArray; import org.jruby.RubyClass; import org.jruby.RubyHash; +import org.jruby.RubyObject; import org.jruby.RubyString; import org.jruby.anno.JRubyClass; import org.jruby.anno.JRubyMethod; import org.jruby.internal.runtime.methods.DynamicMethod; import org.jruby.runtime.ThreadContext; import org.jruby.runtime.builtin.IRubyObject; -import org.logstash.RubyUtil; import org.logstash.execution.WorkerLoop; import org.logstash.instrument.metrics.AbstractNamespacedMetricExt; import org.logstash.instrument.metrics.counter.LongCounter; +import java.util.UUID; + +import static org.logstash.RubyUtil.RUBY; + @JRubyClass(name = "FilterDelegator") public final class FilterDelegatorExt extends AbstractFilterDelegatorExt { @@ -44,13 +48,15 @@ public final class FilterDelegatorExt extends AbstractFilterDelegatorExt { } @VisibleForTesting - public FilterDelegatorExt initForTesting(final IRubyObject filter) { + public FilterDelegatorExt initForTesting(final IRubyObject filter, RubyObject configNameDouble) { eventMetricOut = LongCounter.DUMMY_COUNTER; eventMetricIn = LongCounter.DUMMY_COUNTER; eventMetricTime = LongCounter.DUMMY_COUNTER; this.filter = filter; filterMethod = filter.getMetaClass().searchMethod(FILTER_METHOD_NAME); flushes = filter.respondsTo("flush"); + filterClass = configNameDouble.getType(); + id = RUBY.newString(UUID.randomUUID().toString()); return this; } @@ -96,8 +102,14 @@ public final class FilterDelegatorExt extends AbstractFilterDelegatorExt { @Override @SuppressWarnings({"rawtypes"}) protected RubyArray doMultiFilter(final RubyArray batch) { - return (RubyArray) filterMethod.call( - WorkerLoop.THREAD_CONTEXT.get(), filter, filterClass, FILTER_METHOD_NAME, batch); + final IRubyObject pluginId = this.getId(); + org.apache.logging.log4j.ThreadContext.put("plugin.id", pluginId.toString()); + try { + return (RubyArray) filterMethod.call( + WorkerLoop.THREAD_CONTEXT.get(), filter, filterClass, FILTER_METHOD_NAME, batch); + } finally { + org.apache.logging.log4j.ThreadContext.remove("plugin.id"); + } } @Override @@ -112,6 +124,6 @@ public final class FilterDelegatorExt extends AbstractFilterDelegatorExt { @Override protected boolean getPeriodicFlush() { - return filter.callMethod(RubyUtil.RUBY.getCurrentContext(), "periodic_flush").isTrue(); + return filter.callMethod(RUBY.getCurrentContext(), "periodic_flush").isTrue(); } } diff --git a/logstash-core/src/main/java/org/logstash/config/ir/compiler/JavaInputDelegatorExt.java b/logstash-core/src/main/java/org/logstash/config/ir/compiler/JavaInputDelegatorExt.java index 6134a69d2..fecfc6055 100644 --- a/logstash-core/src/main/java/org/logstash/config/ir/compiler/JavaInputDelegatorExt.java +++ b/logstash-core/src/main/java/org/logstash/config/ir/compiler/JavaInputDelegatorExt.java @@ -61,6 +61,7 @@ public class JavaInputDelegatorExt extends RubyObject { } Thread t = new Thread(() -> { org.apache.logging.log4j.ThreadContext.put("pipeline.id", pipeline.pipelineId().toString()); + org.apache.logging.log4j.ThreadContext.put("plugin.id", this.getId(context).toString()); input.start(queueWriter::push); }); t.setName(pipeline.pipelineId().asJavaString() + "_" + input.getName() + "_" + input.getId()); diff --git a/logstash-core/src/main/java/org/logstash/config/ir/compiler/OutputDelegatorExt.java b/logstash-core/src/main/java/org/logstash/config/ir/compiler/OutputDelegatorExt.java index 2e6c5516c..28db76e9c 100644 --- a/logstash-core/src/main/java/org/logstash/config/ir/compiler/OutputDelegatorExt.java +++ b/logstash-core/src/main/java/org/logstash/config/ir/compiler/OutputDelegatorExt.java @@ -17,7 +17,8 @@ import org.logstash.ext.JrubyEventExtLibrary; import org.logstash.instrument.metrics.AbstractMetricExt; @JRubyClass(name = "OutputDelegator") -public final class OutputDelegatorExt extends AbstractOutputDelegatorExt { +public final class +OutputDelegatorExt extends AbstractOutputDelegatorExt { private static final long serialVersionUID = 1L; @@ -75,9 +76,13 @@ public final class OutputDelegatorExt extends AbstractOutputDelegatorExt { @Override protected void doOutput(final Collection batch) { try { + final IRubyObject pluginId = this.getId(); + org.apache.logging.log4j.ThreadContext.put("plugin.id", pluginId.toString()); strategy.multiReceive(WorkerLoop.THREAD_CONTEXT.get(), (IRubyObject) batch); } catch (final InterruptedException ex) { throw new IllegalStateException(ex); + } finally { + org.apache.logging.log4j.ThreadContext.remove("plugin.id"); } } diff --git a/logstash-core/src/test/java/org/logstash/config/ir/CompiledPipelineTest.java b/logstash-core/src/test/java/org/logstash/config/ir/CompiledPipelineTest.java index 32f3c2ba4..06af6f684 100644 --- a/logstash-core/src/test/java/org/logstash/config/ir/CompiledPipelineTest.java +++ b/logstash-core/src/test/java/org/logstash/config/ir/CompiledPipelineTest.java @@ -14,6 +14,7 @@ import java.util.function.Consumer; import java.util.function.Supplier; import org.hamcrest.CoreMatchers; import org.hamcrest.MatcherAssert; +import org.jruby.RubyObject; import org.jruby.RubyString; import org.jruby.runtime.builtin.IRubyObject; import org.junit.After; @@ -490,9 +491,10 @@ public final class CompiledPipelineTest extends RubyEnvTestCase { @Override public AbstractFilterDelegatorExt buildFilter(final RubyString name, SourceWithMetadata source, final IRubyObject args, Map pluginArgs) { + final RubyObject configNameDouble = org.logstash.config.ir.PluginConfigNameMethodDouble.create(name); return new FilterDelegatorExt( RubyUtil.RUBY, RubyUtil.FILTER_DELEGATOR_CLASS) - .initForTesting(setupPlugin(name, filters)); + .initForTesting(setupPlugin(name, filters), configNameDouble); } @Override diff --git a/logstash-core/src/test/java/org/logstash/config/ir/PluginConfigNameMethodDouble.java b/logstash-core/src/test/java/org/logstash/config/ir/PluginConfigNameMethodDouble.java new file mode 100644 index 000000000..2e9b2590b --- /dev/null +++ b/logstash-core/src/test/java/org/logstash/config/ir/PluginConfigNameMethodDouble.java @@ -0,0 +1,55 @@ +package org.logstash.config.ir; + +import org.jruby.Ruby; +import org.jruby.RubyClass; +import org.jruby.RubyObject; +import org.jruby.RubyString; +import org.jruby.anno.JRubyClass; +import org.jruby.anno.JRubyMethod; +import org.jruby.runtime.ThreadContext; +import org.jruby.runtime.builtin.IRubyObject; + +import static org.logstash.RubyUtil.RUBY; + +/** + * Fake class to double the Ruby's method config_name() + * */ +@JRubyClass(name = "PluginConfigNameMethodDouble") +public class PluginConfigNameMethodDouble extends RubyObject { + + private static final long serialVersionUID = 1L; + + static final RubyClass RUBY_META_CLASS; + private RubyString filterName; + + static { + RUBY_META_CLASS = RUBY.defineClass("PluginConfigNameMethodDouble", RUBY.getObject(), + PluginConfigNameMethodDouble::new); + RUBY_META_CLASS.defineAnnotatedMethods(org.logstash.config.ir.compiler.FakeOutClass.class); + } + + PluginConfigNameMethodDouble(final Ruby runtime, final RubyClass metaClass) { + super(runtime, metaClass); + } + + static PluginConfigNameMethodDouble create(RubyString filterName) { + final PluginConfigNameMethodDouble instance = new PluginConfigNameMethodDouble(RUBY, RUBY_META_CLASS); + instance.filterName = filterName; + return instance; + } + + @JRubyMethod + public IRubyObject name(final ThreadContext context) { + return RUBY.newString("example"); + } + + @JRubyMethod(name = "config_name") + public IRubyObject configName(final ThreadContext context, final IRubyObject recv) { + return filterName; + } + + @JRubyMethod + public IRubyObject initialize(final ThreadContext context, final IRubyObject args) { + return this; + } +} \ No newline at end of file diff --git a/qa/integration/fixtures/plugin_name_log_spec.yml b/qa/integration/fixtures/plugin_name_log_spec.yml new file mode 100644 index 000000000..f21a5d8e0 --- /dev/null +++ b/qa/integration/fixtures/plugin_name_log_spec.yml @@ -0,0 +1,18 @@ +--- +services: + - logstash +config: |- + input { + generator { + count => 4 + } + } + filter { + sleep { + id => "sleep_filter_123" + time => 1 + } + } + output { + null {} + } diff --git a/qa/integration/specs/plugin_name_log_spec.rb b/qa/integration/specs/plugin_name_log_spec.rb new file mode 100644 index 000000000..23e477bf3 --- /dev/null +++ b/qa/integration/specs/plugin_name_log_spec.rb @@ -0,0 +1,55 @@ +require_relative '../framework/fixture' +require_relative '../framework/settings' +require_relative '../services/logstash_service' +require_relative '../framework/helpers' +require "logstash/devutils/rspec/spec_helper" +require "yaml" + +describe "Test Logstash Pipeline id" do + before(:all) { + @fixture = Fixture.new(__FILE__) + # used in multiple LS tests + @ls = @fixture.get_service("logstash") + } + + after(:all) { + @fixture.teardown + } + + before(:each) { + # backup the application settings file -- logstash.yml + FileUtils.cp(@ls.application_settings_file, "#{@ls.application_settings_file}.original") + } + + after(:each) { + @ls.teardown + # restore the application settings file -- logstash.yml + FileUtils.mv("#{@ls.application_settings_file}.original", @ls.application_settings_file) + } + + let(:temp_dir) { Stud::Temporary.directory("logstash-pipelinelog-test") } + let(:config) { @fixture.config("root") } + + it "should write logs with plugin name" do + settings = { + "path.logs" => temp_dir, + "log.level" => "debug" + } + IO.write(@ls.application_settings_file, settings.to_yaml) + @ls.spawn_logstash("-w", "1" , "-e", config) + wait_logstash_process_terminate() + plainlog_file = "#{temp_dir}/logstash-plain.log" + expect(File.exists?(plainlog_file)).to be true + #We know taht sleep plugin log debug lines + expect(IO.read(plainlog_file) =~ /\[sleep_filter_123\] Sleeping {:delay=>1}/).to be > 0 + end + + @private + def wait_logstash_process_terminate + num_retries = 100 + try(num_retries) do + expect(@ls.exited?).to be(true) + end + expect(@ls.exit_code).to be(0) + end +end From d2a094629c462594d42cb2590dd23d85dc466d3f Mon Sep 17 00:00:00 2001 From: Mike Place Date: Sat, 31 Aug 2019 20:32:47 +0200 Subject: [PATCH 0329/1126] Add cluster_uuid setting to default config file, displaying it in Node stats HTTP API Fixes #11106 --- .../logstash/api/commands/default_metadata.rb | 45 +++++++++++++------ logstash-core/lib/logstash/environment.rb | 3 +- .../api/commands/default_metadata_spec.rb | 38 ++++++++++++++++ 3 files changed, 71 insertions(+), 15 deletions(-) diff --git a/logstash-core/lib/logstash/api/commands/default_metadata.rb b/logstash-core/lib/logstash/api/commands/default_metadata.rb index 4dbea76c5..3835d9b5b 100644 --- a/logstash-core/lib/logstash/api/commands/default_metadata.rb +++ b/logstash-core/lib/logstash/api/commands/default_metadata.rb @@ -7,20 +7,31 @@ module LogStash module Commands class DefaultMetadata < Commands::Base def all - {:host => host, - :version => version, - :http_address => http_address, - :id => service.agent.id, - :name => service.agent.name, - :ephemeral_id => service.agent.ephemeral_id, - :status => "green", # This is hard-coded to mirror x-pack behavior - :snapshot => ::BUILD_INFO["build_snapshot"], - :pipeline => { - :workers => LogStash::SETTINGS.get("pipeline.workers"), - :batch_size => LogStash::SETTINGS.get("pipeline.batch.size"), - :batch_delay => LogStash::SETTINGS.get("pipeline.batch.delay"), - } - } + res = {:host => host, + :version => version, + :http_address => http_address, + :id => service.agent.id, + :name => service.agent.name, + :ephemeral_id => service.agent.ephemeral_id, + :status => "green", # This is hard-coded to mirror x-pack behavior + :snapshot => ::BUILD_INFO["build_snapshot"], + :pipeline => { + :workers => LogStash::SETTINGS.get("pipeline.workers"), + :batch_size => LogStash::SETTINGS.get("pipeline.batch.size"), + :batch_delay => LogStash::SETTINGS.get("pipeline.batch.delay"), + }, + } + monitoring = {} + if enabled_xpack_monitoring? + monitoring = monitoring.merge({ + :hosts => LogStash::SETTINGS.get("xpack.monitoring.elasticsearch.hosts"), + :username => LogStash::SETTINGS.get("xpack.monitoring.elasticsearch.username") + }) + end + if LogStash::SETTINGS.set?("monitoring.cluster_uuid") + monitoring = monitoring.merge({:cluster_uuid => LogStash::SETTINGS.get("monitoring.cluster_uuid")}) + end + res.merge(monitoring.empty? ? {} : {:monitoring => monitoring}) end def host @@ -36,6 +47,12 @@ module LogStash rescue ::LogStash::Instrument::MetricStore::MetricNotFound, NoMethodError => e nil end + + private + def enabled_xpack_monitoring? + LogStash::SETTINGS.registered?("xpack.monitoring.enabled") && + LogStash::SETTINGS.get("xpack.monitoring.enabled") + end end end end diff --git a/logstash-core/lib/logstash/environment.rb b/logstash-core/lib/logstash/environment.rb index 24f00ab20..7d37d302f 100644 --- a/logstash-core/lib/logstash/environment.rb +++ b/logstash-core/lib/logstash/environment.rb @@ -71,7 +71,8 @@ module LogStash Setting::TimeValue.new("slowlog.threshold.debug", "-1"), Setting::TimeValue.new("slowlog.threshold.trace", "-1"), Setting::String.new("keystore.classname", "org.logstash.secret.store.backend.JavaKeyStore"), - Setting::String.new("keystore.file", ::File.join(::File.join(LogStash::Environment::LOGSTASH_HOME, "config"), "logstash.keystore"), false) # will be populated on + Setting::String.new("keystore.file", ::File.join(::File.join(LogStash::Environment::LOGSTASH_HOME, "config"), "logstash.keystore"), false), # will be populated on + Setting::NullableString.new("monitoring.cluster_uuid") # post_process ].each {|setting| SETTINGS.register(setting) } diff --git a/logstash-core/spec/logstash/api/commands/default_metadata_spec.rb b/logstash-core/spec/logstash/api/commands/default_metadata_spec.rb index ee5157ffb..db4a39757 100644 --- a/logstash-core/spec/logstash/api/commands/default_metadata_spec.rb +++ b/logstash-core/spec/logstash/api/commands/default_metadata_spec.rb @@ -4,6 +4,10 @@ require "spec_helper" describe LogStash::Api::Commands::DefaultMetadata do include_context "api setup" + def registerIfNot(setting) + LogStash::SETTINGS.register(setting) unless LogStash::SETTINGS.registered?(setting.name) + end + let(:report_method) { :all } subject(:report) do factory = ::LogStash::Api::CommandFactory.new(LogStash::Api::Service.new(@agent)) @@ -12,9 +16,43 @@ describe LogStash::Api::Commands::DefaultMetadata do let(:report_class) { described_class } + before :all do + registerIfNot(LogStash::Setting::Boolean.new("xpack.monitoring.enabled", false)) + registerIfNot(LogStash::Setting::ArrayCoercible.new("xpack.monitoring.elasticsearch.hosts", String, [ "http://localhost:9200" ] )) + registerIfNot(LogStash::Setting::NullableString.new("xpack.monitoring.elasticsearch.username", "logstash_TEST system")) + registerIfNot(LogStash::Setting::NullableString.new("xpack.monitoring.elasticsearch.username", "logstash_TEST system")) + end + + after :each do + LogStash::SETTINGS.set_value("xpack.monitoring.enabled", false) + end + describe "#plugins_stats_report" do let(:report_method) { :all } + # Enforce just the structure + it "check monitoring exist when cluster_uuid has been defined" do + LogStash::SETTINGS.set_value("monitoring.cluster_uuid", "cracking_cluster") + expect(report.keys).to include( + :monitoring + ) + end + + it "check monitoring exist when monitoring is enabled" do + LogStash::SETTINGS.set_value("xpack.monitoring.enabled", true) + expect(report.keys).to include( + :monitoring + ) + end + + it "check monitoring does not appear when not enabled and nor cluster_uuid is defined" do + LogStash::SETTINGS.set_value("xpack.monitoring.enabled", false) + LogStash::SETTINGS.get_setting("monitoring.cluster_uuid").reset + expect(report.keys).not_to include( + :monitoring + ) + end + it "check keys" do expect(report.keys).to include( :host, From ca89cfee75f9530ff6a20e334ee1d5cdad1f8ff9 Mon Sep 17 00:00:00 2001 From: andsel Date: Fri, 24 Jan 2020 17:14:07 +0100 Subject: [PATCH 0330/1126] Added section for monitoring.cluster_uuid Fixes #11538 --- docs/static/monitoring/monitoring-mb.asciidoc | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/docs/static/monitoring/monitoring-mb.asciidoc b/docs/static/monitoring/monitoring-mb.asciidoc index 3c401d3fb..444255aad 100644 --- a/docs/static/monitoring/monitoring-mb.asciidoc +++ b/docs/static/monitoring/monitoring-mb.asciidoc @@ -15,6 +15,7 @@ production cluster as described in <>. To collect and ship monitoring data: . <> +. <> . <> [float] @@ -36,6 +37,16 @@ Remove the `#` at the beginning of the line to enable the setting. -- +[float] +[[define-cluster__uuid]] +==== Define `cluster_uuid` (Optional) +To bind the metrics of {ls} to a specific cluster, optionally define the `monitoring.cluster_uuid` +in the configuration file (logstash.yml): + +[source,yaml] +---------------------------------- +monitoring.cluster_uuid: PRODUCTION_ES_CLUSTER_UUID +---------------------------------- [float] [[configure-metricbeat]] From 23c7f48aad01c22a1a0e3401c0dae687ab58e28c Mon Sep 17 00:00:00 2001 From: andsel Date: Fri, 24 Jan 2020 12:40:31 +0100 Subject: [PATCH 0331/1126] Updated README to document how to run single Ruby specs Fixes #11536 --- README.md | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/README.md b/README.md index f2ecc12f5..98dfd88ec 100644 --- a/README.md +++ b/README.md @@ -183,6 +183,14 @@ Most of the unit tests in Logstash are written using [rspec](http://rspec.info/) 3- To execute the complete test-suite including the integration tests run: ./gradlew check + +4- To execute a single Ruby test run: + + SPEC_OPTS="-fd -P logstash-core/spec/logstash/api/commands/default_metadata_spec.rb" ./gradlew :logstash-core:rubyTests --tests org.logstash.RSpecTests + +5- To execute single spec for integration test, run: + + ./gradlew integrationTests -PrubyIntegrationSpecs=specs/slowlog_spec.rb Sometimes you might find a change to a piece of Logstash code causes a test to hang. These can be hard to debug. From a2044fb5f15401e75758e55a040c67708c391c5a Mon Sep 17 00:00:00 2001 From: Joao Duarte Date: Sat, 25 Jan 2020 17:15:15 +0000 Subject: [PATCH 0332/1126] ensure lock template is in docker tasks Fixes #11539 --- Dockerfile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Dockerfile b/Dockerfile index ee654201d..1925810b9 100644 --- a/Dockerfile +++ b/Dockerfile @@ -29,7 +29,7 @@ ADD LICENSE.txt /opt/logstash/LICENSE.txt ADD NOTICE.TXT /opt/logstash/NOTICE.TXT ADD licenses /opt/logstash/licenses ADD CONTRIBUTORS /opt/logstash/CONTRIBUTORS -ADD Gemfile.template /opt/logstash/Gemfile.template +ADD Gemfile.template Gemfile.jruby-2.5.lock.* /opt/logstash/ ADD Rakefile /opt/logstash/Rakefile ADD build.gradle /opt/logstash/build.gradle ADD rubyUtils.gradle /opt/logstash/rubyUtils.gradle From 6a412f7afd662e59524976588a87c76877392f62 Mon Sep 17 00:00:00 2001 From: andsel Date: Thu, 16 Jan 2020 12:37:58 +0100 Subject: [PATCH 0333/1126] Added precation notice when internal monitoring collector is used. Closes #11346 Fixes #11511 --- x-pack/lib/monitoring/monitoring.rb | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/x-pack/lib/monitoring/monitoring.rb b/x-pack/lib/monitoring/monitoring.rb index d72710b95..c24dfaa88 100644 --- a/x-pack/lib/monitoring/monitoring.rb +++ b/x-pack/lib/monitoring/monitoring.rb @@ -104,6 +104,12 @@ module LogStash return unless monitoring_enabled?(runner.settings) + deprecation_logger.deprecated( + "Internal collectors option for Logstash monitoring is deprecated and targeted for removal in the next major version.\n"\ + "Please configure Metricbeat to monitor Logstash. Documentation can be found at: \n"\ + "https://www.elastic.co/guide/en/logstash/current/monitoring-with-metricbeat.html" + ) + logger.trace("registering the metrics pipeline") LogStash::SETTINGS.set("node.uuid", runner.agent.id) internal_pipeline_source = LogStash::Monitoring::InternalPipelineSource.new(setup_metrics_pipeline, runner.agent) From 5cbc9eeb475468e0d7bf6b91d83fcb224c6241ed Mon Sep 17 00:00:00 2001 From: Karen Metts Date: Fri, 10 Jan 2020 13:58:51 -0500 Subject: [PATCH 0334/1126] Add info about deprecation logger support mixin Fixes #11486 --- docs/static/include/pluginbody.asciidoc | 18 ++++++++++++++++++ 1 file changed, 18 insertions(+) diff --git a/docs/static/include/pluginbody.asciidoc b/docs/static/include/pluginbody.asciidoc index ae0d88a15..66475d822 100644 --- a/docs/static/include/pluginbody.asciidoc +++ b/docs/static/include/pluginbody.asciidoc @@ -779,6 +779,24 @@ will be discussed further in the testing section of this document. Another kind of external dependency is on jar files. This will be described in the "Add a `gemspec` file" section. +===== Deprecated features + +As a plugin evolves, an option or feature may no longer serve the +intended purpose, and the developer may want to _deprecate_ its usage. +Deprecation warns users about the option's status, so they aren't caught by +surprise when it is removed in a later release. + +{ls} 7.6 introduced a _deprecation logger_ to make handling those situations +easier. You can use the +https://github.com/logstash-plugins/logstash-mixin-deprecation_logger_support[adapter] +to ensure that your plugin can use the deprecation logger while still supporting +older versions of {ls}. See the +https://github.com/logstash-plugins/logstash-mixin-deprecation_logger_support/blob/master/README.md[readme] +for more information and for instructions on using the adapter. + +Deprecations are noted in the `logstash-deprecation.log` file in the +`log` directory. + ===== Add a Gemfile Gemfiles allow Ruby's Bundler to maintain the dependencies for your plugin. From 6a8bebffe6c60608d591d91920ff25fadd65c938 Mon Sep 17 00:00:00 2001 From: Colin Surprenant Date: Wed, 29 Jan 2020 14:05:47 -0500 Subject: [PATCH 0335/1126] add support for pipeline.ordered setting for java execution (#11552) reuse rubyArray for single element batches rename preserveBatchOrder to preserveEventOrder allow boolean and string values for the pipeline.ordered setting, reorg validation update docs yml typo Update docs/static/running-logstash-command-line.asciidoc Co-Authored-By: Karen Metts <35154725+karenzone@users.noreply.github.com> Update docs/static/running-logstash-command-line.asciidoc Co-Authored-By: Karen Metts <35154725+karenzone@users.noreply.github.com> java execution specs and spec support docs corrections per review typo close not shutdown Ruby pipeline spec --- config/logstash.yml | 9 ++ .../running-logstash-command-line.asciidoc | 14 +- docs/static/settings-file.asciidoc | 16 +++ logstash-core/lib/logstash/environment.rb | 1 + logstash-core/lib/logstash/java_pipeline.rb | 19 ++- logstash-core/lib/logstash/pipeline.rb | 9 ++ logstash-core/lib/logstash/runner.rb | 5 + logstash-core/lib/logstash/settings.rb | 23 ++++ logstash-core/locales/en.yml | 12 ++ logstash-core/spec/conditionals_spec.rb | 14 +- .../spec/logstash/filters/base_spec.rb | 11 ++ .../spec/logstash/java_pipeline_spec.rb | 130 +++++++++++++++++- logstash-core/spec/logstash/pipeline_spec.rb | 9 ++ .../spec/support/pipeline/pipeline_helpers.rb | 7 +- .../org/logstash/execution/WorkerLoop.java | 37 ++++- 15 files changed, 301 insertions(+), 15 deletions(-) diff --git a/config/logstash.yml b/config/logstash.yml index d40e00c01..3ec8577a0 100644 --- a/config/logstash.yml +++ b/config/logstash.yml @@ -57,6 +57,15 @@ # # pipeline.unsafe_shutdown: false # +# Set the pipeline event ordering. Options are "auto" (the default), "true" or "false". +# "auto" will automatically enable ordering if the 'pipeline.workers' setting +# is also set to '1'. +# "true" will enforce ordering on the pipeline and prevent logstash from starting +# if there are multiple workers. +# "false" will disable any extra processing necessary for preserving ordering. +# +pipeline.ordered: auto +# # ------------ Pipeline Configuration Settings -------------- # # Where to fetch the pipeline configuration for the main pipeline diff --git a/docs/static/running-logstash-command-line.asciidoc b/docs/static/running-logstash-command-line.asciidoc index a177ddab1..478326d23 100644 --- a/docs/static/running-logstash-command-line.asciidoc +++ b/docs/static/running-logstash-command-line.asciidoc @@ -107,6 +107,19 @@ With this command, Logstash concatenates three config files, `/tmp/one`, `/tmp/t backing up, or that the CPU is not saturated, consider increasing this number to better utilize machine processing power. The default is the number of the host's CPU cores. +*`--pipeline.ordered ORDERED`*:: + Preserves events order. Possible values are `auto` (default), `true` and `false`. + This setting + will work only when also using a single worker for the pipeline. + Note that when enabled, it may impact the performance of the filters + and ouput processing. + The `auto` option will automatically enable ordering if the + `pipeline.workers` setting is set to `1`. + Use `true` to enable ordering on the pipeline and prevent logstash + from starting if there are multiple workers. + Use `false` to disable any extra processing necessary for preserving + ordering. + *`-b, --pipeline.batch.size SIZE`*:: Size of batches the pipeline is to work in. This option defines the maximum number of events an individual worker thread will collect from inputs before attempting to execute its filters and outputs. @@ -189,4 +202,3 @@ With this command, Logstash concatenates three config files, `/tmp/one`, `/tmp/t *`-h, --help`*:: Print help - diff --git a/docs/static/settings-file.asciidoc b/docs/static/settings-file.asciidoc index 68addeaef..b3a0c56ba 100644 --- a/docs/static/settings-file.asciidoc +++ b/docs/static/settings-file.asciidoc @@ -114,6 +114,22 @@ The `logstash.yml` file includes the following settings. | (Beta) Load Java plugins in independent classloaders to isolate their dependencies. | `false` +| `pipeline.ordered` +a| +Set the pipeline event ordering.Valid options are: + +* `auto` +* `true` +* `false` + +`auto` will automatically enable ordering if the `pipeline.workers` setting is also set to `1`. +`true` will enforce ordering on the pipeline and prevent logstash from starting +if there are multiple workers. +`false` will disable the processing required to preserve order. Ordering will not be +guaranteed, but you save the processing cost of preserving order. + +| `auto` + | `path.config` | The path to the Logstash config for the main pipeline. If you specify a directory or wildcard, config files are read from the directory in alphabetical order. diff --git a/logstash-core/lib/logstash/environment.rb b/logstash-core/lib/logstash/environment.rb index 7d37d302f..8addd84cd 100644 --- a/logstash-core/lib/logstash/environment.rb +++ b/logstash-core/lib/logstash/environment.rb @@ -45,6 +45,7 @@ module LogStash Setting::Boolean.new("pipeline.reloadable", true), Setting::Boolean.new("pipeline.plugin_classloaders", false), Setting::Boolean.new("pipeline.separate_logs", false), + Setting::CoercibleString.new("pipeline.ordered", "auto", true, ["auto", "true", "false"]), Setting.new("path.plugins", Array, []), Setting::NullableString.new("interactive", nil, false), Setting::Boolean.new("config.debug", false), diff --git a/logstash-core/lib/logstash/java_pipeline.rb b/logstash-core/lib/logstash/java_pipeline.rb index c05f8bcf1..8332e6638 100644 --- a/logstash-core/lib/logstash/java_pipeline.rb +++ b/logstash-core/lib/logstash/java_pipeline.rb @@ -212,6 +212,7 @@ module LogStash; class JavaPipeline < JavaBasePipeline maybe_setup_out_plugins pipeline_workers = safe_pipeline_worker_count + @preserve_event_order = preserve_event_order?(pipeline_workers) batch_size = settings.get("pipeline.batch.size") batch_delay = settings.get("pipeline.batch.delay") @@ -488,7 +489,8 @@ module LogStash; class JavaPipeline < JavaBasePipeline @flushRequested, @flushing, @shutdownRequested, - @drain_queue) + @drain_queue, + @preserve_event_order) rescue => e @logger.error( "Worker loop initialization error", @@ -509,4 +511,19 @@ module LogStash; class JavaPipeline < JavaBasePipeline keys[:thread] ||= thread.inspect if thread keys end + + def preserve_event_order?(pipeline_workers) + case settings.get("pipeline.ordered") + when "auto" + if settings.set?("pipeline.workers") && settings.get("pipeline.workers") == 1 + @logger.warn("'pipeline.ordered' is enabled and is likely less efficient, consider disabling if preserving event order is not necessary") + return true + end + when "true" + fail("enabling the 'pipeline.ordered' setting requires the use of a single pipeline worker") if pipeline_workers > 1 + return true + end + + false + end end; end diff --git a/logstash-core/lib/logstash/pipeline.rb b/logstash-core/lib/logstash/pipeline.rb index 2c1791830..cf5fc40d9 100644 --- a/logstash-core/lib/logstash/pipeline.rb +++ b/logstash-core/lib/logstash/pipeline.rb @@ -293,6 +293,7 @@ module LogStash; class Pipeline < BasePipeline maybe_setup_out_plugins pipeline_workers = safe_pipeline_worker_count + verify_event_ordering!(pipeline_workers) batch_size = settings.get("pipeline.batch.size") batch_delay = settings.get("pipeline.batch.delay") @@ -653,4 +654,12 @@ module LogStash; class Pipeline < BasePipeline def draining_queue? @drain_queue ? !filter_queue_client.empty? : false end + + def verify_event_ordering!(pipeline_workers) + # the Ruby execution keep event order by design but when using a single worker only + if settings.get("pipeline.ordered") == "true" && pipeline_workers > 1 + fail("enabling the 'pipeline.ordered' setting requires the use of a single pipeline worker") + end + end + end; end diff --git a/logstash-core/lib/logstash/runner.rb b/logstash-core/lib/logstash/runner.rb index 24a9a68a7..0728562ab 100644 --- a/logstash-core/lib/logstash/runner.rb +++ b/logstash-core/lib/logstash/runner.rb @@ -108,6 +108,11 @@ class LogStash::Runner < Clamp::StrictCommand :attribute_name => "pipeline.workers", :default => LogStash::SETTINGS.get_default("pipeline.workers") + option "--pipeline.ordered", "ORDERED", + I18n.t("logstash.runner.flag.pipeline-ordered"), + :attribute_name => "pipeline.ordered", + :default => LogStash::SETTINGS.get_default("pipeline.ordered") + option ["--java-execution"], :flag, I18n.t("logstash.runner.flag.java-execution"), :attribute_name => "pipeline.java_execution", diff --git a/logstash-core/lib/logstash/settings.rb b/logstash-core/lib/logstash/settings.rb index c245aa6ab..5d14a2bd9 100644 --- a/logstash-core/lib/logstash/settings.rb +++ b/logstash-core/lib/logstash/settings.rb @@ -31,6 +31,7 @@ module LogStash "pipeline.reloadable", "pipeline.system", "pipeline.workers", + "pipeline.ordered", "queue.checkpoint.acks", "queue.checkpoint.interval", "queue.checkpoint.writes", @@ -464,6 +465,28 @@ module LogStash end end + # The CoercibleString allows user to enter any value which coerces to a String. + # For example for true/false booleans; if the possible_strings are ["foo", "true", "false"] + # then these options in the config file or command line will be all valid: "foo", true, false, "true", "false" + # + class CoercibleString < Coercible + def initialize(name, default=nil, strict=true, possible_strings=[], &validator_proc) + @possible_strings = possible_strings + super(name, Object, default, strict, &validator_proc) + end + + def coerce(value) + value.to_s + end + + def validate(value) + super(value) + unless @possible_strings.empty? || @possible_strings.include?(value) + raise ArgumentError.new("Invalid value \"#{value}\". Options are: #{@possible_strings.inspect}") + end + end + end + class ExistingFilePath < Setting def initialize(name, default=nil, strict=true) super(name, ::String, default, strict) do |file_path| diff --git a/logstash-core/locales/en.yml b/logstash-core/locales/en.yml index b162808df..27347484e 100644 --- a/logstash-core/locales/en.yml +++ b/logstash-core/locales/en.yml @@ -288,6 +288,18 @@ en: Sets the ID of the pipeline. pipeline-workers: |+ Sets the number of pipeline workers to run. + pipeline-ordered: |+ + Preserve events order. Possible values are `auto` (default), `true` and `false`. + This setting + will only work when also using a single worker for the pipeline. + Note that when enabled, it may impact the performance of the filters + and ouput processing. + The `auto` option will automatically enable ordering if the + `pipeline.workers` setting is set to `1`. + Use `true` to enable ordering on the pipeline and prevent logstash + from starting if there are multiple workers. + Use `false` to disable any extra processing necessary for preserving + ordering. java-execution: |+ Use Java execution engine. plugin-classloaders: |+ diff --git a/logstash-core/spec/conditionals_spec.rb b/logstash-core/spec/conditionals_spec.rb index 93473e42f..fd7f94718 100644 --- a/logstash-core/spec/conditionals_spec.rb +++ b/logstash-core/spec/conditionals_spec.rb @@ -3,7 +3,6 @@ require 'spec_helper' require 'support/pipeline/pipeline_helpers' module ConditionalFanciness - include PipelineHelpers def description return self.metadata[:description] end @@ -63,6 +62,19 @@ end describe "conditionals in filter" do extend ConditionalFanciness + extend PipelineHelpers + + let(:settings) do + # settings is used by sample_one. + # This was originally set directly in sample_one and + # pipeline.workers was also set to 1. I am preserving + # this setting here for the sake of minimizing change + # but unsure if this is actually required. + + s = LogStash::SETTINGS.clone + s.set_value("pipeline.workers", 1) + s + end describe "simple" do config <<-CONFIG diff --git a/logstash-core/spec/logstash/filters/base_spec.rb b/logstash-core/spec/logstash/filters/base_spec.rb index 34a8ac94d..6baf71d6b 100644 --- a/logstash-core/spec/logstash/filters/base_spec.rb +++ b/logstash-core/spec/logstash/filters/base_spec.rb @@ -52,6 +52,17 @@ end describe LogStash::Filters::NOOP do extend PipelineHelpers + let(:settings) do + # settings is used by sample_one. + # This was originally set directly in sample_one and + # pipeline.workers was also set to 1. I am preserving + # this setting here for the sake of minimizing change + # but unsure if this is actually required. + + s = LogStash::SETTINGS.clone + s.set_value("pipeline.workers", 1) + s + end describe "adding multiple values to one field" do config <<-CONFIG diff --git a/logstash-core/spec/logstash/java_pipeline_spec.rb b/logstash-core/spec/logstash/java_pipeline_spec.rb index 137305582..7d8592819 100644 --- a/logstash-core/spec/logstash/java_pipeline_spec.rb +++ b/logstash-core/spec/logstash/java_pipeline_spec.rb @@ -4,7 +4,6 @@ require "logstash/inputs/generator" require "logstash/filters/drop" require_relative "../support/mocks_classes" require_relative "../support/helpers" -require_relative "../logstash/pipeline_reporter_spec" # for DummyOutput class require 'support/pipeline/pipeline_helpers' require "stud/try" require 'timeout' @@ -401,6 +400,8 @@ describe LogStash::JavaPipeline do context "compiled flush function" do extend PipelineHelpers + let(:settings) { LogStash::SETTINGS.clone } + describe "flusher thread" do before(:each) do allow(LogStash::Plugin).to receive(:lookup).with("input", "dummyinput").and_return(DummyInput) @@ -448,6 +449,131 @@ describe LogStash::JavaPipeline do end end + context "batch order" do + extend PipelineHelpers + + context "with a single worker and ordering enabled" do + let(:settings) do + s = LogStash::SETTINGS.clone + s.set_value("pipeline.workers", 1) + s.set_value("pipeline.ordered", "true") + s + end + + config <<-CONFIG + filter { + if [message] =~ "\\d" { + mutate { add_tag => "digit" } + } else { + mutate { add_tag => "letter" } + } + } + CONFIG + + sample_one(["a", "1", "b", "2", "c", "3"]) do + expect(subject.map{|e| e.get("message")}).to eq(["a", "1", "b", "2", "c", "3"]) + end + end + + context "with a multiple workers and ordering enabled" do + let(:settings) do + s = LogStash::SETTINGS.clone + s.set_value("pipeline.workers", 2) + s.set_value("pipeline.ordered", "true") + s + end + let(:config) { "input { } output { }" } + let(:pipeline) { mock_java_pipeline_from_string(config, settings) } + + it "should raise error" do + expect{pipeline.run}.to raise_error(RuntimeError, /pipeline\.ordered/) + pipeline.close + end + end + + context "with an explicit single worker ordering will auto enable" do + let(:settings) do + s = LogStash::SETTINGS.clone + s.set_value("pipeline.workers", 1) + s.set_value("pipeline.ordered", "auto") + s + end + + config <<-CONFIG + filter { + if [message] =~ "\\d" { + mutate { add_tag => "digit" } + } else { + mutate { add_tag => "letter" } + } + } + CONFIG + + sample_one(["a", "1", "b", "2", "c", "3"]) do + expect(subject.map{|e| e.get("message")}).to eq(["a", "1", "b", "2", "c", "3"]) + end + end + + context "with an implicit single worker ordering will not auto enable" do + let(:settings) do + s = LogStash::SETTINGS.clone + s.set_value("pipeline.ordered", "auto") + s + end + + before(:each) do + # this is to make sure this test will be valid by having a pipeline.workers default value > 1 + # and not explicitly set. + expect(settings.get_default("pipeline.workers")).to be > 1 + expect(settings.set?("pipeline.workers")).to be_falsey + + expect(LogStash::Plugin).to receive(:lookup).with("filter", "dummyfilter").at_least(1).time.and_return(DummyFilter) + expect(LogStash::Plugin).to receive(:lookup).with(any_args).at_least(3).time.and_call_original + end + + config <<-CONFIG + filter { + # per above dummyfilter is not threadsafe hence will set the number of workers to 1 + dummyfilter { } + + if [message] =~ "\\d" { + mutate { add_tag => "digit" } + } else { + mutate { add_tag => "letter" } + } + } + CONFIG + + sample_one(["a", "1", "b", "2", "c", "3"]) do + expect(subject.map{|e| e.get("message")}).to eq(["1", "2", "3", "a", "b", "c"]) + end + end + + context "with a single worker and ordering disabled" do + let(:settings) do + s = LogStash::SETTINGS.clone + s.set_value("pipeline.workers", 1) + s.set_value("pipeline.ordered", "false") + s + end + + config <<-CONFIG + filter { + if [message] =~ "\\d" { + mutate { add_tag => "digit" } + } else { + mutate { add_tag => "letter" } + } + } + CONFIG + + sample_one(["a", "1", "b", "2", "c", "3"]) do + expect(subject.map{|e| e.get("message")}).to eq(["1", "2", "3", "a", "b", "c"]) + end + end + end + + describe "max inflight warning" do let(:config) { "input { dummyinput {} } output { dummyoutput {} }" } let(:batch_size) { 1 } @@ -489,6 +615,8 @@ describe LogStash::JavaPipeline do context "compiled filter functions" do context "new events should propagate down the filters" do extend PipelineHelpers + let(:settings) { LogStash::SETTINGS.clone } + config <<-CONFIG filter { clone { diff --git a/logstash-core/spec/logstash/pipeline_spec.rb b/logstash-core/spec/logstash/pipeline_spec.rb index 71b07a484..8a57b59cb 100644 --- a/logstash-core/spec/logstash/pipeline_spec.rb +++ b/logstash-core/spec/logstash/pipeline_spec.rb @@ -1020,4 +1020,13 @@ describe LogStash::Pipeline do end end end + + context "event ordering" do + let(:pipeline) { mock_pipeline_from_string("input { } output { }", mock_settings("pipeline.ordered" => true, "pipeline.workers" => 2)) } + + it "fail running when ordering is set to true and there are multiple workers" do + expect{pipeline.run}.to raise_error(RuntimeError, /pipeline\.ordered/) + pipeline.close + end + end end diff --git a/logstash-core/spec/support/pipeline/pipeline_helpers.rb b/logstash-core/spec/support/pipeline/pipeline_helpers.rb index a7e892189..d9afd0924 100644 --- a/logstash-core/spec/support/pipeline/pipeline_helpers.rb +++ b/logstash-core/spec/support/pipeline/pipeline_helpers.rb @@ -8,7 +8,6 @@ require "thread" java_import org.logstash.common.SourceWithMetadata module PipelineHelpers - class SpecSamplerInput < LogStash::Inputs::Base config_name "spec_sampler_input" @@ -58,9 +57,7 @@ module PipelineHelpers describe "\"#{name}\"" do let(:pipeline) do - settings = ::LogStash::SETTINGS.clone settings.set_value("queue.drain", true) - settings.set_value("pipeline.workers", 1) LogStash::JavaPipeline.new( LogStash::Config::PipelineConfig.new( LogStash::Config::Source::Local, :main, @@ -73,9 +70,9 @@ module PipelineHelpers end let(:event) do sample_event = [sample_event] unless sample_event.is_a?(Array) - next sample_event.collect do |e| + sample_event.map do |e| e = { "message" => e } if e.is_a?(String) - next LogStash::Event.new(e) + LogStash::Event.new(e) end end diff --git a/logstash-core/src/main/java/org/logstash/execution/WorkerLoop.java b/logstash-core/src/main/java/org/logstash/execution/WorkerLoop.java index c3825ddf6..7125574bb 100644 --- a/logstash-core/src/main/java/org/logstash/execution/WorkerLoop.java +++ b/logstash-core/src/main/java/org/logstash/execution/WorkerLoop.java @@ -4,6 +4,7 @@ import java.util.concurrent.atomic.AtomicBoolean; import java.util.concurrent.atomic.LongAdder; import org.apache.logging.log4j.LogManager; import org.apache.logging.log4j.Logger; +import org.jruby.RubyArray; import org.jruby.runtime.ThreadContext; import org.logstash.RubyUtil; import org.logstash.config.ir.CompiledPipeline; @@ -37,10 +38,19 @@ public final class WorkerLoop implements Runnable { private final boolean drainQueue; - public WorkerLoop(final CompiledPipeline pipeline, final QueueReadClient readClient, - final LongAdder filteredCounter, final LongAdder consumedCounter, - final AtomicBoolean flushRequested, final AtomicBoolean flushing, - final AtomicBoolean shutdownRequested, final boolean drainQueue) { + private final boolean preserveEventOrder; + + public WorkerLoop( + final CompiledPipeline pipeline, + final QueueReadClient readClient, + final LongAdder filteredCounter, + final LongAdder consumedCounter, + final AtomicBoolean flushRequested, + final AtomicBoolean flushing, + final AtomicBoolean shutdownRequested, + final boolean drainQueue, + final boolean preserveEventOrder) + { this.consumedCounter = consumedCounter; this.filteredCounter = filteredCounter; this.execution = pipeline.buildExecution(); @@ -49,6 +59,7 @@ public final class WorkerLoop implements Runnable { this.flushRequested = flushRequested; this.flushing = flushing; this.shutdownRequested = shutdownRequested; + this.preserveEventOrder = preserveEventOrder; } @Override @@ -61,7 +72,7 @@ public final class WorkerLoop implements Runnable { consumedCounter.add(batch.filteredSize()); final boolean isFlush = flushRequested.compareAndSet(true, false); readClient.startMetrics(batch); - execution.compute(batch.to_a(), isFlush, false); + compute(batch, isFlush, false); int filteredCount = batch.filteredSize(); filteredCounter.add(filteredCount); readClient.addOutputMetrics(filteredCount); @@ -75,7 +86,7 @@ public final class WorkerLoop implements Runnable { //for this we need to create a new empty batch to contain the final flushed events final QueueBatch batch = readClient.newBatch(); readClient.startMetrics(batch); - execution.compute(batch.to_a(), true, true); + compute(batch, true, true); readClient.closeBatch(batch); } catch (final Exception ex) { LOGGER.error( @@ -86,6 +97,20 @@ public final class WorkerLoop implements Runnable { } } + @SuppressWarnings("unchecked") + private void compute(final QueueBatch batch, final boolean flush, final boolean shutdown) { + if (preserveEventOrder) { + // send batch events one-by-one as single-element batches + @SuppressWarnings({"rawtypes"}) final RubyArray singleElementBatch = RubyUtil.RUBY.newArray(1); + batch.to_a().forEach((e) -> { + singleElementBatch.set(0, e); + execution.compute(singleElementBatch, flush, shutdown); + }); + } else { + execution.compute(batch.to_a(), flush, shutdown); + } + } + private boolean isDraining() { return drainQueue && !readClient.isEmpty(); } From f94f72a79e0998635594cee10e1e2e594a412969 Mon Sep 17 00:00:00 2001 From: Karen Metts Date: Mon, 6 Jan 2020 19:39:50 -0500 Subject: [PATCH 0336/1126] Add details about pipeline.workers Fixes #11474 --- docs/static/settings-file.asciidoc | 12 ++++++++---- 1 file changed, 8 insertions(+), 4 deletions(-) diff --git a/docs/static/settings-file.asciidoc b/docs/static/settings-file.asciidoc index b3a0c56ba..776e6b6b1 100644 --- a/docs/static/settings-file.asciidoc +++ b/docs/static/settings-file.asciidoc @@ -85,10 +85,14 @@ The `logstash.yml` file includes the following settings. | Use the Java execution engine. | true -| `pipeline.workers` -| The number of workers that will, in parallel, execute the filter and output stages of the pipeline. - If you find that events are backing up, or that the - CPU is not saturated, consider increasing this number to better utilize machine processing power. +| `pipeline.workers` +| The number of workers that will, in parallel, execute the filter and output +stages of the pipeline. This setting uses the +https://docs.oracle.com/javase/7/docs/api/java/lang/Runtime.html#availableProcessors()[`java.lang.Runtime.getRuntime.availableProcessors`] +value as a default if not overridden by `pipeline.workers` in `pipelines.yml` or +`pipeline.workers` from `logstash.yml`. If you have modified this setting and +see that events are backing up, or that the CPU is not saturated, consider +increasing this number to better utilize machine processing power. | Number of the host's CPU cores | `pipeline.batch.size` From 52f794695827e942ccc80a4b5c7561ae6863958a Mon Sep 17 00:00:00 2001 From: Karen Metts Date: Tue, 21 Jan 2020 17:07:03 -0500 Subject: [PATCH 0337/1126] Add deprecation notice to internal collectors for monitoring Fixes #11526 --- docs/static/monitoring/monitoring-internal.asciidoc | 4 +++- docs/static/monitoring/monitoring-overview.asciidoc | 2 +- 2 files changed, 4 insertions(+), 2 deletions(-) diff --git a/docs/static/monitoring/monitoring-internal.asciidoc b/docs/static/monitoring/monitoring-internal.asciidoc index 86bfc27ec..c58fffadb 100644 --- a/docs/static/monitoring/monitoring-internal.asciidoc +++ b/docs/static/monitoring/monitoring-internal.asciidoc @@ -2,9 +2,11 @@ [[monitoring-internal-collection]] === Collect {ls} monitoring data using internal collectors ++++ -Internal collection +Internal collection (deprecated) ++++ +deprecated[7.7.0] + Using internal collectors for {ls} {monitoring} these components: * <> diff --git a/docs/static/monitoring/monitoring-overview.asciidoc b/docs/static/monitoring/monitoring-overview.asciidoc index 1c6ff5b9b..1764aef29 100644 --- a/docs/static/monitoring/monitoring-overview.asciidoc +++ b/docs/static/monitoring/monitoring-overview.asciidoc @@ -17,7 +17,7 @@ Make sure monitoring is enabled on your {es} cluster. Then configure *one* of these methods to collect {ls} metrics: * <> -* <> +* <> include::monitoring-mb.asciidoc[] From 80cd89673df866d9b77a8ccad9fef79a86bc2141 Mon Sep 17 00:00:00 2001 From: tbotalla Date: Wed, 29 Jan 2020 15:19:09 -0300 Subject: [PATCH 0338/1126] Fix missing " on glob pattern Fixes #11551 --- docs/static/glob-support.asciidoc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/static/glob-support.asciidoc b/docs/static/glob-support.asciidoc index 7f45279e2..3e28e9cb5 100644 --- a/docs/static/glob-support.asciidoc +++ b/docs/static/glob-support.asciidoc @@ -41,7 +41,7 @@ Matches config files ending in `.conf` in the specified path. `"/var/log/*.log"`:: Matches log files ending in `.log` in the specified path. -`"/var/log/**/*.log`:: +`"/var/log/**/*.log"`:: Matches log files ending in `.log` in subdirectories under the specified path. `"/path/to/logs/{app1,app2,app3}/data.log"`:: From f12eb2f28aa769b7bc1aa4e645ed3d60e7d68a4e Mon Sep 17 00:00:00 2001 From: Joao Duarte Date: Thu, 30 Jan 2020 10:45:23 +0000 Subject: [PATCH 0339/1126] fail license report job on missing licenses Fixes #11554 --- ci/license_check.sh | 5 +++++ logstash-core/lib/logstash/dependency_report.rb | 3 ++- .../src/main/java/org/logstash/dependencies/Main.java | 2 +- 3 files changed, 8 insertions(+), 2 deletions(-) diff --git a/ci/license_check.sh b/ci/license_check.sh index f9632ecba..3bb9396ee 100755 --- a/ci/license_check.sh +++ b/ci/license_check.sh @@ -3,5 +3,10 @@ export GRADLE_OPTS="-Dorg.gradle.daemon=false -Dorg.gradle.logging.level=info -D ./gradlew installDefaultGems bin/dependencies-report --csv report.csv + +result=$? + # We want this to show on the CI server cat report.csv + +exit $result diff --git a/logstash-core/lib/logstash/dependency_report.rb b/logstash-core/lib/logstash/dependency_report.rb index 9b9493b50..6e92d2036 100644 --- a/logstash-core/lib/logstash/dependency_report.rb +++ b/logstash-core/lib/logstash/dependency_report.rb @@ -32,8 +32,9 @@ class LogStash::DependencyReport < Clamp::Command command = ["./gradlew", "generateLicenseReport", "-PlicenseReportInputCSV=#{ruby_output_path}", "-PlicenseReportOutputCSV=#{output_path}"] puts "Executing #{command}" system(*command) + if $?.exitstatus != 0 - raise "Could not run gradle java deps! Exit status #{$?.exitstatus}" + raise "generateLicenseReport failed with exit status #{$?.exitstatus}" end nil diff --git a/tools/dependencies-report/src/main/java/org/logstash/dependencies/Main.java b/tools/dependencies-report/src/main/java/org/logstash/dependencies/Main.java index a8340a0ec..cb6f0f801 100644 --- a/tools/dependencies-report/src/main/java/org/logstash/dependencies/Main.java +++ b/tools/dependencies-report/src/main/java/org/logstash/dependencies/Main.java @@ -46,7 +46,7 @@ public class Main { ); // If there were unknown results in the report, exit with a non-zero status - //System.exit(reportResult ? 0 : 1); + System.exit(reportResult ? 0 : 1); } static InputStream getResourceAsStream(String resourcePath) { From cb4369b2a9af584ba46beec6b48222db40f515aa Mon Sep 17 00:00:00 2001 From: Dan Hermann Date: Fri, 23 Aug 2019 08:56:17 -0500 Subject: [PATCH 0340/1126] Ignore versions in dependency license checker --- .../org/logstash/dependencies/Dependency.java | 16 ++--- .../dependencies/ReportGenerator.java | 28 +++++++-- .../dependencies/ReportGeneratorTest.java | 42 +++++++++++-- .../test/resources/expectedNoticeOutput.txt | 44 +++---------- .../src/test/resources/expectedOutput.txt | 13 ++-- .../resources/licenseMapping-conflicting.csv | 62 +++++++++++++++++++ .../test/resources/licenseMapping-good.csv | 5 +- .../test/resources/licenseMapping-missing.csv | 4 +- .../licenseMapping-missingNotices.csv | 2 +- .../resources/licenseMapping-missingUrls.csv | 4 +- .../resources/licenseMapping-unacceptable.csv | 7 +-- .../notices/bundler-1.16.1-NOTICE.txt | 1 - ...r-1.16.0-NOTICE.txt => bundler-NOTICE.txt} | 0 ...rxml.jackson.core!jackson-core-NOTICE.txt} | 0 ...google.errorprone!javac-shaded-NOTICE.txt} | 0 ...E.txt => commons-io!commons-io-NOTICE.txt} | 0 ...023-3-NOTICE.txt => control.js-NOTICE.txt} | 0 ...-io-2.5-NOTICE.txt => filesize-NOTICE.txt} | 0 ...thub.jk1!gradle-license-report-NOTICE.txt} | 0 ...NOTICE.txt => jar-dependencies-NOTICE.txt} | 0 .../notices/jruby-openssl-0.9.21-NOTICE.txt | 1 - ....1-NOTICE.txt => jruby-openssl-NOTICE.txt} | 0 .../notices/jruby-readline-1.1.1-NOTICE.txt | 1 - ...0-NOTICE.txt => jruby-readline-NOTICE.txt} | 0 .../notices/json-generator-NOTICE.txt | 1 + .../resources/notices/json-parser--NOTICE.txt | 1 - ...3.11-NOTICE.txt => json-parser-NOTICE.txt} | 0 .../notices/junit!junit-4.12-NOTICE.txt | 1 - ...3.12-NOTICE.txt => junit!junit-NOTICE.txt} | 0 ...s.janino!commons-compiler-3.0.8-NOTICE.txt | 1 - ...dehaus.janino!commons-compiler-NOTICE.txt} | 0 .../src/test/resources/rubyDependencies.csv | 1 + 32 files changed, 148 insertions(+), 87 deletions(-) create mode 100644 tools/dependencies-report/src/test/resources/licenseMapping-conflicting.csv delete mode 100644 tools/dependencies-report/src/test/resources/notices/bundler-1.16.1-NOTICE.txt rename tools/dependencies-report/src/test/resources/notices/{bundler-1.16.0-NOTICE.txt => bundler-NOTICE.txt} (100%) rename tools/dependencies-report/src/test/resources/notices/{com.fasterxml.jackson.core!jackson-core-2.7.3-NOTICE.txt => com.fasterxml.jackson.core!jackson-core-NOTICE.txt} (100%) rename tools/dependencies-report/src/test/resources/notices/{com.fasterxml.jackson.core!jackson-core-2.9.1-NOTICE.txt => com.google.errorprone!javac-shaded-NOTICE.txt} (100%) rename tools/dependencies-report/src/test/resources/notices/{com.fasterxml.jackson.core!jackson-core-2.9.4-NOTICE.txt => commons-io!commons-io-NOTICE.txt} (100%) rename tools/dependencies-report/src/test/resources/notices/{com.google.errorprone!javac-shaded-9-dev-r4023-3-NOTICE.txt => control.js-NOTICE.txt} (100%) rename tools/dependencies-report/src/test/resources/notices/{commons-io!commons-io-2.5-NOTICE.txt => filesize-NOTICE.txt} (100%) rename tools/dependencies-report/src/test/resources/notices/{control.js--NOTICE.txt => gradle.plugin.com.github.jk1!gradle-license-report-NOTICE.txt} (100%) rename tools/dependencies-report/src/test/resources/notices/{filesize-0.0.4-NOTICE.txt => jar-dependencies-NOTICE.txt} (100%) delete mode 100644 tools/dependencies-report/src/test/resources/notices/jruby-openssl-0.9.21-NOTICE.txt rename tools/dependencies-report/src/test/resources/notices/{gradle.plugin.com.github.jk1!gradle-license-report-0.7.1-NOTICE.txt => jruby-openssl-NOTICE.txt} (100%) delete mode 100644 tools/dependencies-report/src/test/resources/notices/jruby-readline-1.1.1-NOTICE.txt rename tools/dependencies-report/src/test/resources/notices/{jar-dependencies-0.3.10-NOTICE.txt => jruby-readline-NOTICE.txt} (100%) create mode 100644 tools/dependencies-report/src/test/resources/notices/json-generator-NOTICE.txt delete mode 100644 tools/dependencies-report/src/test/resources/notices/json-parser--NOTICE.txt rename tools/dependencies-report/src/test/resources/notices/{jar-dependencies-0.3.11-NOTICE.txt => json-parser-NOTICE.txt} (100%) delete mode 100644 tools/dependencies-report/src/test/resources/notices/junit!junit-4.12-NOTICE.txt rename tools/dependencies-report/src/test/resources/notices/{jar-dependencies-0.3.12-NOTICE.txt => junit!junit-NOTICE.txt} (100%) delete mode 100644 tools/dependencies-report/src/test/resources/notices/org.codehaus.janino!commons-compiler-3.0.8-NOTICE.txt rename tools/dependencies-report/src/test/resources/notices/{jruby-openssl-0.9.20-NOTICE.txt => org.codehaus.janino!commons-compiler-NOTICE.txt} (100%) diff --git a/tools/dependencies-report/src/main/java/org/logstash/dependencies/Dependency.java b/tools/dependencies-report/src/main/java/org/logstash/dependencies/Dependency.java index 52cee06c1..4f86329eb 100644 --- a/tools/dependencies-report/src/main/java/org/logstash/dependencies/Dependency.java +++ b/tools/dependencies-report/src/main/java/org/logstash/dependencies/Dependency.java @@ -102,17 +102,17 @@ class Dependency implements Comparable { return false; } Dependency d = (Dependency) o; - return Objects.equals(name, d.name) && Objects.equals(version, d.version); + return Objects.equals(name, d.name); } @Override public int hashCode() { - return Objects.hash(name, version); + return Objects.hash(name); } @Override public int compareTo(Dependency o) { - return (name + version).compareTo(o.name + o.version); + return (name).compareTo(o.name); } public String noticeSourcePath() { @@ -128,7 +128,7 @@ class Dependency implements Comparable { } public String noticeFilename() { - return String.format("%s-%s-NOTICE.txt", fsCompatibleName(), version != null ? version : "NOVERSION"); + return String.format("%s-NOTICE.txt", fsCompatibleName()); } public String resourceName() { @@ -151,14 +151,6 @@ class Dependency implements Comparable { } } - public Path noticePath() { - // Get the base first since this always exists, otherwise getResource will return null if its for a notice - // that doesn't exist - String noticesBase = ReportGenerator.class.getResource("/notices").getPath(); - Path path = Paths.get(noticesBase, noticeFilename()); - return path; - } - public String getName() { return name; } diff --git a/tools/dependencies-report/src/main/java/org/logstash/dependencies/ReportGenerator.java b/tools/dependencies-report/src/main/java/org/logstash/dependencies/ReportGenerator.java index 232cf157f..4aa5a784f 100644 --- a/tools/dependencies-report/src/main/java/org/logstash/dependencies/ReportGenerator.java +++ b/tools/dependencies-report/src/main/java/org/logstash/dependencies/ReportGenerator.java @@ -31,7 +31,6 @@ public class ReportGenerator { final Collection UNKNOWN_LICENSES = new ArrayList<>(); final String[] CSV_HEADERS = {"name", "version", "revision", "url", "license", "copyright"}; final Collection MISSING_NOTICE = new ArrayList<>(); - final HashMap UNUSED_DEPENDENCIES = new HashMap<>(); boolean generateReport( InputStream licenseMappingStream, @@ -159,9 +158,8 @@ public class ReportGenerator { } private void checkDependencyLicense(Map licenseMapping, List acceptableLicenses, Dependency dependency) { - String nameAndVersion = dependency.name + ":" + dependency.version; - if (licenseMapping.containsKey(nameAndVersion)) { - LicenseUrlPair pair = licenseMapping.get(nameAndVersion); + if (licenseMapping.containsKey(dependency.name)) { + LicenseUrlPair pair = licenseMapping.get(dependency.name); String[] dependencyLicenses = pair.license.split("\\|"); boolean hasAcceptableLicense = false; @@ -204,11 +202,31 @@ public class ReportGenerator { for (CSVRecord record : CSVFormat.DEFAULT.withFirstRecordAsHeader().parse(in)) { String dependencyNameAndVersion = record.get(0); if (dependencyNameAndVersion != null && !dependencyNameAndVersion.equals("")) { - licenseMapping.put(dependencyNameAndVersion, new LicenseUrlPair(record.get(2), record.get(1))); + int lastIndex = dependencyNameAndVersion.lastIndexOf(':'); + String depName = lastIndex < 0 + ? dependencyNameAndVersion + : dependencyNameAndVersion.substring(0, lastIndex); + validateAndAdd(licenseMapping, depName, new LicenseUrlPair(record.get(2), record.get(1))); } } } + private static void validateAndAdd(Map licenses, String depName, LicenseUrlPair lup) { + if (licenses.containsKey(depName)) { + LicenseUrlPair existingLicense = licenses.get(depName); + + // Because dependency versions are not treated independently, if dependencies with different versions + // have different licenses, we cannot distinguish between them + if (!existingLicense.license.equals(lup.license)) { + String err = String.format("License mapping contains duplicate dependencies '%s' with conflicting " + + "licenses '%s' and '%s'", depName, existingLicense.license, lup.license); + throw new IllegalStateException(err); + } + } else { + licenses.put(depName, lup); + } + } + } class LicenseUrlPair { diff --git a/tools/dependencies-report/src/test/java/org/logstash/dependencies/ReportGeneratorTest.java b/tools/dependencies-report/src/test/java/org/logstash/dependencies/ReportGeneratorTest.java index 266f1fd22..48027e802 100644 --- a/tools/dependencies-report/src/test/java/org/logstash/dependencies/ReportGeneratorTest.java +++ b/tools/dependencies-report/src/test/java/org/logstash/dependencies/ReportGeneratorTest.java @@ -1,5 +1,6 @@ package org.logstash.dependencies; +import org.junit.Assert; import org.junit.Before; import org.junit.Test; @@ -8,10 +9,15 @@ import java.io.InputStream; import java.io.StringWriter; import java.util.Optional; import java.util.Scanner; +import java.util.regex.Pattern; import static org.hamcrest.CoreMatchers.containsString; +import static org.hamcrest.CoreMatchers.is; import static org.hamcrest.CoreMatchers.not; -import static org.junit.Assert.*; +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertFalse; +import static org.junit.Assert.assertThat; +import static org.junit.Assert.assertTrue; import static org.logstash.dependencies.Main.ACCEPTABLE_LICENSES_PATH; public class ReportGeneratorTest { @@ -39,6 +45,8 @@ public class ReportGeneratorTest { assertTrue(result); assertEquals(normalizeEol(expectedOutput), normalizeEol(csvOutput.toString())); assertEquals(normalizeEol(expectedNoticeOutput), normalizeEol(noticeOutput.toString())); + String unusedLicenses = unusedLicenseWriter.toString(); + assertThat(unusedLicenses, containsString("41 license mappings were specified but unused")); } @Test @@ -51,6 +59,19 @@ public class ReportGeneratorTest { // listed in the output with no license, i.e., an empty license field followed by CR/LF assertTrue(csvOutput.toString().contains("commons-io:commons-io,2.5,,,,\r\n")); assertTrue(csvOutput.toString().contains("filesize,0.0.4,,,,\r\n")); + String unusedLicenses = unusedLicenseWriter.toString(); + assertThat(unusedLicenses, containsString("43 license mappings were specified but unused")); + } + + @Test + public void testReportWithConflictingLicenses() throws IOException { + try { + boolean result = runReportGenerator("/licenseMapping-conflicting.csv", csvOutput, noticeOutput, unusedLicenseWriter); + Assert.fail("Conflicting licenses should have been detected"); + } catch (IllegalStateException ex) { + assertThat(ex.getMessage(), + containsString("License mapping contains duplicate dependencies 'bundler' with conflicting licenses 'LGPL-2.0-only' and 'MIT'")); + } } @Test @@ -61,8 +82,13 @@ public class ReportGeneratorTest { // verify that the two components in the test input with unacceptable licenses are // listed in the output with no license, i.e., an empty license field followed by CR/LF - assertThat(csvOutput.toString(), containsString("com.fasterxml.jackson.core:jackson-core,2.7.3,,,,\r\n")); - assertThat(csvOutput.toString(), containsString("bundler,1.16.0,,,,\r\n")); + String csvString = csvOutput.toString(); + assertThat(csvString, containsString("com.fasterxml.jackson.core:jackson-core,2.7.3,,,,\r\n")); + + Pattern bundlerPattern = Pattern.compile(".*bundler,1\\.16\\.[0-1],,,,.*"); + assertThat(bundlerPattern.matcher(csvString).find(), is(true)); + String unusedLicenses = unusedLicenseWriter.toString(); + assertThat(unusedLicenses, containsString("43 license mappings were specified but unused")); } @Test @@ -75,6 +101,8 @@ public class ReportGeneratorTest { // listed in the output with no license, i.e., an empty license field followed by CR/LF assertTrue(csvOutput.toString().contains("org.codehaus.janino:commons-compiler,3.0.8,,,,\r\n")); assertTrue(csvOutput.toString().contains("json-parser,,,,,\r\n")); + String unusedLicenses = unusedLicenseWriter.toString(); + assertThat(unusedLicenses, containsString("43 license mappings were specified but unused")); } @Test @@ -92,6 +120,8 @@ public class ReportGeneratorTest { assertThat(noticeOutput.toString(), not(containsString("noNoticeDep"))); Optional found = rg.MISSING_NOTICE.stream().filter(d -> d.getName().equals("co.elastic:noNoticeDep") && d.getVersion().equals("0.0.1")).findFirst(); assertTrue(found.isPresent()); + String unusedLicenses = unusedLicenseWriter.toString(); + assertThat(unusedLicenses, containsString("45 license mappings were specified but unused")); } @Test @@ -105,8 +135,10 @@ public class ReportGeneratorTest { assertTrue("Unused licenses should not fail the license checker", result); - assertThat(unusedLicenseWriter.toString(), containsString("org.eclipse.core:org.eclipse.core.commands:3.6.0")); - assertThat(unusedLicenseWriter.toString(), not(containsString("junit:junit:4.12"))); + String unusedLicenses = unusedLicenseWriter.toString(); + assertThat(unusedLicenses, containsString("42 license mappings were specified but unused")); + assertThat(unusedLicenses, containsString("org.eclipse.core:org.eclipse.core.commands")); + assertThat(unusedLicenses, not(containsString("junit:junit"))); } private boolean runReportGenerator(String licenseMappingPath, StringWriter csvOutput, StringWriter noticeOutput, StringWriter unusedLicenseWriter) throws IOException { diff --git a/tools/dependencies-report/src/test/resources/expectedNoticeOutput.txt b/tools/dependencies-report/src/test/resources/expectedNoticeOutput.txt index 49d416946..64ed0605e 100644 --- a/tools/dependencies-report/src/test/resources/expectedNoticeOutput.txt +++ b/tools/dependencies-report/src/test/resources/expectedNoticeOutput.txt @@ -1,33 +1,15 @@ -========== -Notice for: bundler-1.16.0 ----------- - -TEST ========== Notice for: bundler-1.16.1 ---------- -TEST-bundler-1.16.1 - +TEST ========== Notice for: com.fasterxml.jackson.core:jackson-core-2.7.3 ---------- TEST -========== -Notice for: com.fasterxml.jackson.core:jackson-core-2.9.1 ----------- - -TEST - -========== -Notice for: com.fasterxml.jackson.core:jackson-core-2.9.4 ----------- - -TEST - ========== Notice for: com.google.errorprone:javac-shaded-9-dev-r4023-3 ---------- @@ -58,30 +40,12 @@ Notice for: gradle.plugin.com.github.jk1:gradle-license-report-0.7.1 TEST -========== -Notice for: jar-dependencies-0.3.10 ----------- - -TEST - -========== -Notice for: jar-dependencies-0.3.11 ----------- - -TEST - ========== Notice for: jar-dependencies-0.3.12 ---------- TEST -========== -Notice for: jruby-openssl-0.9.20 ----------- - -TEST - ========== Notice for: jruby-openssl-0.9.21 ---------- @@ -94,6 +58,12 @@ Notice for: jruby-readline-1.1.1 TEST +========== +Notice for: json-generator- +---------- + +json-generator notice + ========== Notice for: json-parser- ---------- diff --git a/tools/dependencies-report/src/test/resources/expectedOutput.txt b/tools/dependencies-report/src/test/resources/expectedOutput.txt index 94ac4b22c..2557edfe6 100644 --- a/tools/dependencies-report/src/test/resources/expectedOutput.txt +++ b/tools/dependencies-report/src/test/resources/expectedOutput.txt @@ -1,20 +1,15 @@ name,version,revision,url,license,copyright -bundler,1.16.0,,https://rubygems.org/gems/bundler/versions/1.16.0,UnacceptableLicense|MIT, -bundler,1.16.1,,https://rubygems.org/gems/bundler/versions/1.16.1,MIT, +bundler,1.16.1,,https://rubygems.org/gems/bundler/versions/1.16.0,UnacceptableLicense|MIT, com.fasterxml.jackson.core:jackson-core,2.7.3,,https://github.com/FasterXML/jackson-core/tree/jackson-core-2.7.3,Apache-2.0, -com.fasterxml.jackson.core:jackson-core,2.9.1,,https://github.com/FasterXML/jackson-core/tree/jackson-core-2.9.1,Apache-2.0, -com.fasterxml.jackson.core:jackson-core,2.9.4,,https://github.com/FasterXML/jackson-core/tree/jackson-core-2.9.4,Apache-2.0, com.google.errorprone:javac-shaded,9-dev-r4023-3,,http://repo1.maven.org/maven2/com/google/errorprone/javac-shaded/9-dev-r4023-3/,EPL-1.0, commons-io:commons-io,2.5,,https://commons.apache.org/proper/commons-io/index.html,Apache-2.0, control.js,,,https://github.com/zombieleet/control,MIT, filesize,0.0.4,,https://rubygems.org/gems/filesize/versions/0.0.4,MIT, gradle.plugin.com.github.jk1:gradle-license-report,0.7.1,,https://github.com/jk1/Gradle-License-Report,Apache-2.0, -jar-dependencies,0.3.10,,https://rubygems.org/gems/jar-dependencies/versions/0.3.10,Apache-2.0, -jar-dependencies,0.3.11,,https://rubygems.org/gems/jar-dependencies/versions/0.3.11,MIT, -jar-dependencies,0.3.12,,https://rubygems.org/gems/jar-dependencies/versions/0.3.12,MIT, -jruby-openssl,0.9.20,,https://rubygems.org/gems/jruby-openssl/versions/0.9.20-java,Apache-2.0, -jruby-openssl,0.9.21,,https://rubygems.org/gems/jruby-openssl/versions/0.9.21-java,Apache-2.0, +jar-dependencies,0.3.12,,https://rubygems.org/gems/jar-dependencies/versions/0.3.11,MIT, +jruby-openssl,0.9.21,,https://rubygems.org/gems/jruby-openssl/versions/0.9.20-java,Apache-2.0, jruby-readline,1.1.1,,https://rubygems.org/gems/jruby-readline/versions/1.1.1-java,Apache-2.0, +json-generator,,,https://github.com/flori/json,Ruby, json-parser,,,https://rubygems.org/gems/json-parser/versions/0.0.1,Apache-2.0, junit:junit,4.12,,https://github.com/junit-team/junit4,Apache-2.0, org.codehaus.janino:commons-compiler,3.0.8,,https://github.com/janino-compiler/janino,BSD-3-Clause-Attribution, diff --git a/tools/dependencies-report/src/test/resources/licenseMapping-conflicting.csv b/tools/dependencies-report/src/test/resources/licenseMapping-conflicting.csv new file mode 100644 index 000000000..d94844c31 --- /dev/null +++ b/tools/dependencies-report/src/test/resources/licenseMapping-conflicting.csv @@ -0,0 +1,62 @@ +dependency,dependencyUrl,licenseOverride +"webrick:1.3.1",,BSD-2-Clause-FreeBSD +"bundler:1.16.0",https://rubygems.org/gems/bundler/versions/1.16.0,LGPL-2.0-only +"webhdfs:0.8.0",,Apache-2.0 +"avl_tree:1.2.1",,BSD-2-Clause-FreeBSD +"filesize:0.0.4",https://rubygems.org/gems/filesize/versions/0.0.4,MIT +"filewatch:0.9.0",,MIT +"gelfd:0.2.0",,Apache-2.0 +"gmetric:0.1.3",,MIT +"UNKNOWNgzip:1.0",,UNKNOWN +"UNKNOWNjls-grok:0.11.4",,UNKNOWN +"jls-lumberjack:0.0.26",,Apache-2.0 +"march_hare:3.1.1",,MIT +"method_source:0.8.2",,MIT +"metriks:0.9.9.8",,MIT +"numerizer:0.1.1",,MIT +"rspec-sequencing:0.1.0",,Apache-2.0 +"rubyzip:1.2.1",,BSD-2-Clause-FreeBSD +"snappy-jars:1.1.0.1.2",,Apache-2.0 +"snmp:1.2.0",,MIT +"stud:0.0.23",,Apache-2.0 +"com.google.googlejavaformat:google-java-format:1.1",,Apache-2.0 +"com.google.guava:guava:19.0",,Apache-2.0 +"org.apache.logging.log4j:log4j-api:2.9.1",,Apache-2.0 +"org.apache.logging.log4j:log4j-core:2.9.1",,Apache-2.0 +"org.apache.logging.log4j:log4j-slf4j-impl:2.9.1",,Apache-2.0 +"org.codehaus.janino:commons-compiler:3.0.8",https://github.com/janino-compiler/janino,BSD-3-Clause-Attribution +"org.codehaus.janino:janino:3.0.8",,BSD-3-Clause-Attribution +"com.fasterxml.jackson.dataformat:jackson-dataformat-cbor:2.9.5",,Apache-2.0 +"org.jruby:jruby-complete:9.1.13.0",,EPL-2.0|Ruby +"org.slf4j:slf4j-api:1.7.25",,MIT +"org.eclipse.core:org.eclipse.core.commands:3.6.0",,EPL-1.0 +"org.eclipse.core:org.eclipse.core.contenttype:3.4.100",,EPL-1.0 +"org.eclipse.core:org.eclipse.core.expressions:3.4.300",,EPL-1.0 +"org.eclipse.core:org.eclipse.core.filesystem:1.3.100",,EPL-1.0 +"org.eclipse.core:org.eclipse.core.jobs:3.5.100",,EPL-1.0 +"org.eclipse.core:org.eclipse.core.resources:3.7.100",,EPL-1.0 +"org.eclipse.core:org.eclipse.core.runtime:3.7.0",,EPL-1.0 +"org.eclipse.equinox:org.eclipse.equinox.app:1.3.100",,EPL-1.0 +"org.eclipse.equinox:org.eclipse.equinox.common:3.6.0",,EPL-1.0 +"org.eclipse.equinox:org.eclipse.equinox.preferences:3.4.1",,EPL-1.0 +"org.eclipse.equinox:org.eclipse.equinox.registry:3.5.101",,EPL-1.0 +"org.eclipse.jdt:org.eclipse.jdt.core:3.10.0",,EPL-1.0 +"org.eclipse.osgi:org.eclipse.osgi:3.7.1",,EPL-1.0 +"org.eclipse.text:org.eclipse.text:3.5.101",,EPL-1.0 +"bundler:1.16.1",https://rubygems.org/gems/bundler/versions/1.16.1,MIT +"com.fasterxml.jackson.core:jackson-core:2.7.3",https://github.com/FasterXML/jackson-core/tree/jackson-core-2.7.3,LGPL-2.0-only +"com.fasterxml.jackson.core:jackson-core:2.9.1",https://github.com/FasterXML/jackson-core/tree/jackson-core-2.9.1,Apache-2.0 +"com.fasterxml.jackson.core:jackson-core:2.9.4",https://github.com/FasterXML/jackson-core/tree/jackson-core-2.9.4,Apache-2.0 +"com.google.errorprone:javac-shaded:9-dev-r4023-3",http://repo1.maven.org/maven2/com/google/errorprone/javac-shaded/9-dev-r4023-3/,EPL-1.0 +"commons-io:commons-io:2.5",https://commons.apache.org/proper/commons-io/index.html,Apache-2.0 +"control.js:",https://github.com/zombieleet/control,MIT +"gradle.plugin.com.github.jk1:gradle-license-report:0.7.1",https://github.com/jk1/Gradle-License-Report,Apache-2.0 +"jar-dependencies:0.3.10",https://rubygems.org/gems/jar-dependencies/versions/0.3.10,Apache-2.0 +"jar-dependencies:0.3.11",https://rubygems.org/gems/jar-dependencies/versions/0.3.11,MIT +"jar-dependencies:0.3.12",https://rubygems.org/gems/jar-dependencies/versions/0.3.12,MIT +"jruby-openssl:0.9.20",https://rubygems.org/gems/jruby-openssl/versions/0.9.20-java,Apache-2.0 +"jruby-openssl:0.9.21",https://rubygems.org/gems/jruby-openssl/versions/0.9.21-java,Apache-2.0 +"jruby-readline:1.1.1",https://rubygems.org/gems/jruby-readline/versions/1.1.1-java,Apache-2.0 +"json-parser:",https://rubygems.org/gems/json-parser/versions/0.0.1,Apache-2.0 +"junit:junit:4.12",https://github.com/junit-team/junit4,Apache-2.0 +"json-generator",https://github.com/flori/json,Ruby diff --git a/tools/dependencies-report/src/test/resources/licenseMapping-good.csv b/tools/dependencies-report/src/test/resources/licenseMapping-good.csv index 3320d55eb..b3cf57c4d 100644 --- a/tools/dependencies-report/src/test/resources/licenseMapping-good.csv +++ b/tools/dependencies-report/src/test/resources/licenseMapping-good.csv @@ -43,7 +43,6 @@ dependency,dependencyUrl,licenseOverride "org.eclipse.jdt:org.eclipse.jdt.core:3.10.0",,EPL-1.0 "org.eclipse.osgi:org.eclipse.osgi:3.7.1",,EPL-1.0 "org.eclipse.text:org.eclipse.text:3.5.101",,EPL-1.0 -"bundler:1.16.1",https://rubygems.org/gems/bundler/versions/1.16.1,MIT "com.fasterxml.jackson.core:jackson-core:2.7.3",https://github.com/FasterXML/jackson-core/tree/jackson-core-2.7.3,Apache-2.0 "com.fasterxml.jackson.core:jackson-core:2.9.1",https://github.com/FasterXML/jackson-core/tree/jackson-core-2.9.1,Apache-2.0 "com.fasterxml.jackson.core:jackson-core:2.9.4",https://github.com/FasterXML/jackson-core/tree/jackson-core-2.9.4,Apache-2.0 @@ -51,11 +50,11 @@ dependency,dependencyUrl,licenseOverride "commons-io:commons-io:2.5",https://commons.apache.org/proper/commons-io/index.html,Apache-2.0 "control.js:",https://github.com/zombieleet/control,MIT "gradle.plugin.com.github.jk1:gradle-license-report:0.7.1",https://github.com/jk1/Gradle-License-Report,Apache-2.0 -"jar-dependencies:0.3.10",https://rubygems.org/gems/jar-dependencies/versions/0.3.10,Apache-2.0 "jar-dependencies:0.3.11",https://rubygems.org/gems/jar-dependencies/versions/0.3.11,MIT "jar-dependencies:0.3.12",https://rubygems.org/gems/jar-dependencies/versions/0.3.12,MIT "jruby-openssl:0.9.20",https://rubygems.org/gems/jruby-openssl/versions/0.9.20-java,Apache-2.0 "jruby-openssl:0.9.21",https://rubygems.org/gems/jruby-openssl/versions/0.9.21-java,Apache-2.0 "jruby-readline:1.1.1",https://rubygems.org/gems/jruby-readline/versions/1.1.1-java,Apache-2.0 "json-parser:",https://rubygems.org/gems/json-parser/versions/0.0.1,Apache-2.0 -"junit:junit:4.12",https://github.com/junit-team/junit4,Apache-2.0 \ No newline at end of file +"junit:junit:4.12",https://github.com/junit-team/junit4,Apache-2.0 +"json-generator",https://github.com/flori/json,Ruby diff --git a/tools/dependencies-report/src/test/resources/licenseMapping-missing.csv b/tools/dependencies-report/src/test/resources/licenseMapping-missing.csv index 931c385c6..a31a46863 100644 --- a/tools/dependencies-report/src/test/resources/licenseMapping-missing.csv +++ b/tools/dependencies-report/src/test/resources/licenseMapping-missing.csv @@ -51,11 +51,11 @@ dependency,dependencyUrl,licenseOverride "commons-io:commons-io:2.5",https://commons.apache.org/proper/commons-io/index.html, "control.js:",https://github.com/zombieleet/control,MIT "gradle.plugin.com.github.jk1:gradle-license-report:0.7.1",https://github.com/jk1/Gradle-License-Report,Apache-2.0 -"jar-dependencies:0.3.10",https://rubygems.org/gems/jar-dependencies/versions/0.3.10,Apache-2.0 "jar-dependencies:0.3.11",https://rubygems.org/gems/jar-dependencies/versions/0.3.11,MIT "jar-dependencies:0.3.12",https://rubygems.org/gems/jar-dependencies/versions/0.3.12,MIT "jruby-openssl:0.9.20",https://rubygems.org/gems/jruby-openssl/versions/0.9.20-java,Apache-2.0 "jruby-openssl:0.9.21",https://rubygems.org/gems/jruby-openssl/versions/0.9.21-java,Apache-2.0 "jruby-readline:1.1.1",https://rubygems.org/gems/jruby-readline/versions/1.1.1-java,Apache-2.0 "json-parser:",https://rubygems.org/gems/json-parser/versions/0.0.1,Apache-2.0 -"junit:junit:4.12",https://github.com/junit-team/junit4,Apache-2.0 \ No newline at end of file +"junit:junit:4.12",https://github.com/junit-team/junit4,Apache-2.0 +"json-generator",https://github.com/flori/json,Ruby diff --git a/tools/dependencies-report/src/test/resources/licenseMapping-missingNotices.csv b/tools/dependencies-report/src/test/resources/licenseMapping-missingNotices.csv index f99b4bca8..c4c53d411 100644 --- a/tools/dependencies-report/src/test/resources/licenseMapping-missingNotices.csv +++ b/tools/dependencies-report/src/test/resources/licenseMapping-missingNotices.csv @@ -52,7 +52,6 @@ dependency,dependencyUrl,licenseOverride "commons-io:commons-io:2.5",https://commons.apache.org/proper/commons-io/index.html,Apache-2.0 "control.js:",https://github.com/zombieleet/control,MIT "gradle.plugin.com.github.jk1:gradle-license-report:0.7.1",https://github.com/jk1/Gradle-License-Report,Apache-2.0 -"jar-dependencies:0.3.10",https://rubygems.org/gems/jar-dependencies/versions/0.3.10,Apache-2.0 "jar-dependencies:0.3.11",https://rubygems.org/gems/jar-dependencies/versions/0.3.11,MIT "jar-dependencies:0.3.12",https://rubygems.org/gems/jar-dependencies/versions/0.3.12,MIT "jruby-openssl:0.9.20",https://rubygems.org/gems/jruby-openssl/versions/0.9.20-java,Apache-2.0 @@ -61,3 +60,4 @@ dependency,dependencyUrl,licenseOverride "json-parser:",https://rubygems.org/gems/json-parser/versions/0.0.1,Apache-2.0 "junit:junit:4.12",https://github.com/junit-team/junit4,Apache-2.0 "junit:junit:4.12",https://github.com/junit-team/junit4,Apache-2.0 +"json-generator",https://github.com/flori/json,Ruby diff --git a/tools/dependencies-report/src/test/resources/licenseMapping-missingUrls.csv b/tools/dependencies-report/src/test/resources/licenseMapping-missingUrls.csv index 16171e54c..5e6fe4a3c 100644 --- a/tools/dependencies-report/src/test/resources/licenseMapping-missingUrls.csv +++ b/tools/dependencies-report/src/test/resources/licenseMapping-missingUrls.csv @@ -51,11 +51,11 @@ dependency,dependencyUrl,licenseOverride "commons-io:commons-io:2.5",https://commons.apache.org/proper/commons-io/index.html,Apache-2.0 "control.js:",https://github.com/zombieleet/control,MIT "gradle.plugin.com.github.jk1:gradle-license-report:0.7.1",https://github.com/jk1/Gradle-License-Report,Apache-2.0 -"jar-dependencies:0.3.10",https://rubygems.org/gems/jar-dependencies/versions/0.3.10,Apache-2.0 "jar-dependencies:0.3.11",https://rubygems.org/gems/jar-dependencies/versions/0.3.11,MIT "jar-dependencies:0.3.12",https://rubygems.org/gems/jar-dependencies/versions/0.3.12,MIT "jruby-openssl:0.9.20",https://rubygems.org/gems/jruby-openssl/versions/0.9.20-java,Apache-2.0 "jruby-openssl:0.9.21",https://rubygems.org/gems/jruby-openssl/versions/0.9.21-java,Apache-2.0 "jruby-readline:1.1.1",https://rubygems.org/gems/jruby-readline/versions/1.1.1-java,Apache-2.0 "json-parser:",,Apache-2.0 -"junit:junit:4.12",https://github.com/junit-team/junit4,Apache-2.0 \ No newline at end of file +"junit:junit:4.12",https://github.com/junit-team/junit4,Apache-2.0 +"json-generator",https://github.com/flori/json,Ruby diff --git a/tools/dependencies-report/src/test/resources/licenseMapping-unacceptable.csv b/tools/dependencies-report/src/test/resources/licenseMapping-unacceptable.csv index e0fff0c03..e9a06cbbf 100644 --- a/tools/dependencies-report/src/test/resources/licenseMapping-unacceptable.csv +++ b/tools/dependencies-report/src/test/resources/licenseMapping-unacceptable.csv @@ -43,19 +43,16 @@ dependency,dependencyUrl,licenseOverride "org.eclipse.jdt:org.eclipse.jdt.core:3.10.0",,EPL-1.0 "org.eclipse.osgi:org.eclipse.osgi:3.7.1",,EPL-1.0 "org.eclipse.text:org.eclipse.text:3.5.101",,EPL-1.0 -"bundler:1.16.1",https://rubygems.org/gems/bundler/versions/1.16.1,MIT "com.fasterxml.jackson.core:jackson-core:2.7.3",https://github.com/FasterXML/jackson-core/tree/jackson-core-2.7.3,LGPL-2.0-only -"com.fasterxml.jackson.core:jackson-core:2.9.1",https://github.com/FasterXML/jackson-core/tree/jackson-core-2.9.1,Apache-2.0 -"com.fasterxml.jackson.core:jackson-core:2.9.4",https://github.com/FasterXML/jackson-core/tree/jackson-core-2.9.4,Apache-2.0 "com.google.errorprone:javac-shaded:9-dev-r4023-3",http://repo1.maven.org/maven2/com/google/errorprone/javac-shaded/9-dev-r4023-3/,EPL-1.0 "commons-io:commons-io:2.5",https://commons.apache.org/proper/commons-io/index.html,Apache-2.0 "control.js:",https://github.com/zombieleet/control,MIT "gradle.plugin.com.github.jk1:gradle-license-report:0.7.1",https://github.com/jk1/Gradle-License-Report,Apache-2.0 -"jar-dependencies:0.3.10",https://rubygems.org/gems/jar-dependencies/versions/0.3.10,Apache-2.0 "jar-dependencies:0.3.11",https://rubygems.org/gems/jar-dependencies/versions/0.3.11,MIT "jar-dependencies:0.3.12",https://rubygems.org/gems/jar-dependencies/versions/0.3.12,MIT "jruby-openssl:0.9.20",https://rubygems.org/gems/jruby-openssl/versions/0.9.20-java,Apache-2.0 "jruby-openssl:0.9.21",https://rubygems.org/gems/jruby-openssl/versions/0.9.21-java,Apache-2.0 "jruby-readline:1.1.1",https://rubygems.org/gems/jruby-readline/versions/1.1.1-java,Apache-2.0 "json-parser:",https://rubygems.org/gems/json-parser/versions/0.0.1,Apache-2.0 -"junit:junit:4.12",https://github.com/junit-team/junit4,Apache-2.0 \ No newline at end of file +"junit:junit:4.12",https://github.com/junit-team/junit4,Apache-2.0 +"json-generator",https://github.com/flori/json,Ruby diff --git a/tools/dependencies-report/src/test/resources/notices/bundler-1.16.1-NOTICE.txt b/tools/dependencies-report/src/test/resources/notices/bundler-1.16.1-NOTICE.txt deleted file mode 100644 index 2ce57e3db..000000000 --- a/tools/dependencies-report/src/test/resources/notices/bundler-1.16.1-NOTICE.txt +++ /dev/null @@ -1 +0,0 @@ -TEST-bundler-1.16.1 diff --git a/tools/dependencies-report/src/test/resources/notices/bundler-1.16.0-NOTICE.txt b/tools/dependencies-report/src/test/resources/notices/bundler-NOTICE.txt similarity index 100% rename from tools/dependencies-report/src/test/resources/notices/bundler-1.16.0-NOTICE.txt rename to tools/dependencies-report/src/test/resources/notices/bundler-NOTICE.txt diff --git a/tools/dependencies-report/src/test/resources/notices/com.fasterxml.jackson.core!jackson-core-2.7.3-NOTICE.txt b/tools/dependencies-report/src/test/resources/notices/com.fasterxml.jackson.core!jackson-core-NOTICE.txt similarity index 100% rename from tools/dependencies-report/src/test/resources/notices/com.fasterxml.jackson.core!jackson-core-2.7.3-NOTICE.txt rename to tools/dependencies-report/src/test/resources/notices/com.fasterxml.jackson.core!jackson-core-NOTICE.txt diff --git a/tools/dependencies-report/src/test/resources/notices/com.fasterxml.jackson.core!jackson-core-2.9.1-NOTICE.txt b/tools/dependencies-report/src/test/resources/notices/com.google.errorprone!javac-shaded-NOTICE.txt similarity index 100% rename from tools/dependencies-report/src/test/resources/notices/com.fasterxml.jackson.core!jackson-core-2.9.1-NOTICE.txt rename to tools/dependencies-report/src/test/resources/notices/com.google.errorprone!javac-shaded-NOTICE.txt diff --git a/tools/dependencies-report/src/test/resources/notices/com.fasterxml.jackson.core!jackson-core-2.9.4-NOTICE.txt b/tools/dependencies-report/src/test/resources/notices/commons-io!commons-io-NOTICE.txt similarity index 100% rename from tools/dependencies-report/src/test/resources/notices/com.fasterxml.jackson.core!jackson-core-2.9.4-NOTICE.txt rename to tools/dependencies-report/src/test/resources/notices/commons-io!commons-io-NOTICE.txt diff --git a/tools/dependencies-report/src/test/resources/notices/com.google.errorprone!javac-shaded-9-dev-r4023-3-NOTICE.txt b/tools/dependencies-report/src/test/resources/notices/control.js-NOTICE.txt similarity index 100% rename from tools/dependencies-report/src/test/resources/notices/com.google.errorprone!javac-shaded-9-dev-r4023-3-NOTICE.txt rename to tools/dependencies-report/src/test/resources/notices/control.js-NOTICE.txt diff --git a/tools/dependencies-report/src/test/resources/notices/commons-io!commons-io-2.5-NOTICE.txt b/tools/dependencies-report/src/test/resources/notices/filesize-NOTICE.txt similarity index 100% rename from tools/dependencies-report/src/test/resources/notices/commons-io!commons-io-2.5-NOTICE.txt rename to tools/dependencies-report/src/test/resources/notices/filesize-NOTICE.txt diff --git a/tools/dependencies-report/src/test/resources/notices/control.js--NOTICE.txt b/tools/dependencies-report/src/test/resources/notices/gradle.plugin.com.github.jk1!gradle-license-report-NOTICE.txt similarity index 100% rename from tools/dependencies-report/src/test/resources/notices/control.js--NOTICE.txt rename to tools/dependencies-report/src/test/resources/notices/gradle.plugin.com.github.jk1!gradle-license-report-NOTICE.txt diff --git a/tools/dependencies-report/src/test/resources/notices/filesize-0.0.4-NOTICE.txt b/tools/dependencies-report/src/test/resources/notices/jar-dependencies-NOTICE.txt similarity index 100% rename from tools/dependencies-report/src/test/resources/notices/filesize-0.0.4-NOTICE.txt rename to tools/dependencies-report/src/test/resources/notices/jar-dependencies-NOTICE.txt diff --git a/tools/dependencies-report/src/test/resources/notices/jruby-openssl-0.9.21-NOTICE.txt b/tools/dependencies-report/src/test/resources/notices/jruby-openssl-0.9.21-NOTICE.txt deleted file mode 100644 index 2a02d41ce..000000000 --- a/tools/dependencies-report/src/test/resources/notices/jruby-openssl-0.9.21-NOTICE.txt +++ /dev/null @@ -1 +0,0 @@ -TEST diff --git a/tools/dependencies-report/src/test/resources/notices/gradle.plugin.com.github.jk1!gradle-license-report-0.7.1-NOTICE.txt b/tools/dependencies-report/src/test/resources/notices/jruby-openssl-NOTICE.txt similarity index 100% rename from tools/dependencies-report/src/test/resources/notices/gradle.plugin.com.github.jk1!gradle-license-report-0.7.1-NOTICE.txt rename to tools/dependencies-report/src/test/resources/notices/jruby-openssl-NOTICE.txt diff --git a/tools/dependencies-report/src/test/resources/notices/jruby-readline-1.1.1-NOTICE.txt b/tools/dependencies-report/src/test/resources/notices/jruby-readline-1.1.1-NOTICE.txt deleted file mode 100644 index 2a02d41ce..000000000 --- a/tools/dependencies-report/src/test/resources/notices/jruby-readline-1.1.1-NOTICE.txt +++ /dev/null @@ -1 +0,0 @@ -TEST diff --git a/tools/dependencies-report/src/test/resources/notices/jar-dependencies-0.3.10-NOTICE.txt b/tools/dependencies-report/src/test/resources/notices/jruby-readline-NOTICE.txt similarity index 100% rename from tools/dependencies-report/src/test/resources/notices/jar-dependencies-0.3.10-NOTICE.txt rename to tools/dependencies-report/src/test/resources/notices/jruby-readline-NOTICE.txt diff --git a/tools/dependencies-report/src/test/resources/notices/json-generator-NOTICE.txt b/tools/dependencies-report/src/test/resources/notices/json-generator-NOTICE.txt new file mode 100644 index 000000000..567d94fbb --- /dev/null +++ b/tools/dependencies-report/src/test/resources/notices/json-generator-NOTICE.txt @@ -0,0 +1 @@ +json-generator notice diff --git a/tools/dependencies-report/src/test/resources/notices/json-parser--NOTICE.txt b/tools/dependencies-report/src/test/resources/notices/json-parser--NOTICE.txt deleted file mode 100644 index 2a02d41ce..000000000 --- a/tools/dependencies-report/src/test/resources/notices/json-parser--NOTICE.txt +++ /dev/null @@ -1 +0,0 @@ -TEST diff --git a/tools/dependencies-report/src/test/resources/notices/jar-dependencies-0.3.11-NOTICE.txt b/tools/dependencies-report/src/test/resources/notices/json-parser-NOTICE.txt similarity index 100% rename from tools/dependencies-report/src/test/resources/notices/jar-dependencies-0.3.11-NOTICE.txt rename to tools/dependencies-report/src/test/resources/notices/json-parser-NOTICE.txt diff --git a/tools/dependencies-report/src/test/resources/notices/junit!junit-4.12-NOTICE.txt b/tools/dependencies-report/src/test/resources/notices/junit!junit-4.12-NOTICE.txt deleted file mode 100644 index 2a02d41ce..000000000 --- a/tools/dependencies-report/src/test/resources/notices/junit!junit-4.12-NOTICE.txt +++ /dev/null @@ -1 +0,0 @@ -TEST diff --git a/tools/dependencies-report/src/test/resources/notices/jar-dependencies-0.3.12-NOTICE.txt b/tools/dependencies-report/src/test/resources/notices/junit!junit-NOTICE.txt similarity index 100% rename from tools/dependencies-report/src/test/resources/notices/jar-dependencies-0.3.12-NOTICE.txt rename to tools/dependencies-report/src/test/resources/notices/junit!junit-NOTICE.txt diff --git a/tools/dependencies-report/src/test/resources/notices/org.codehaus.janino!commons-compiler-3.0.8-NOTICE.txt b/tools/dependencies-report/src/test/resources/notices/org.codehaus.janino!commons-compiler-3.0.8-NOTICE.txt deleted file mode 100644 index 2a02d41ce..000000000 --- a/tools/dependencies-report/src/test/resources/notices/org.codehaus.janino!commons-compiler-3.0.8-NOTICE.txt +++ /dev/null @@ -1 +0,0 @@ -TEST diff --git a/tools/dependencies-report/src/test/resources/notices/jruby-openssl-0.9.20-NOTICE.txt b/tools/dependencies-report/src/test/resources/notices/org.codehaus.janino!commons-compiler-NOTICE.txt similarity index 100% rename from tools/dependencies-report/src/test/resources/notices/jruby-openssl-0.9.20-NOTICE.txt rename to tools/dependencies-report/src/test/resources/notices/org.codehaus.janino!commons-compiler-NOTICE.txt diff --git a/tools/dependencies-report/src/test/resources/rubyDependencies.csv b/tools/dependencies-report/src/test/resources/rubyDependencies.csv index a73b5e35c..1ac0913d9 100644 --- a/tools/dependencies-report/src/test/resources/rubyDependencies.csv +++ b/tools/dependencies-report/src/test/resources/rubyDependencies.csv @@ -11,4 +11,5 @@ jruby-readline,1.1.1,https://github.com/jruby/jruby,EPL-1.0|GPL-2.0|LGPL-2.1 com.fasterxml.jackson.core:jackson-core,2.7.3,https://github.com/FasterXML/jackson-core,Apache-2.0 com.fasterxml.jackson.core:jackson-core,2.9.1,https://github.com/FasterXML/jackson-core,Apache-2.0 control.js,,,MIT +json-generator,,https://github.com/flori/json,Ruby json-parser,,https://github.com/flori/json,Ruby From 03ec7923081820e635933cab5e03f99ec86a7a15 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jo=C3=A3o=20Duarte?= Date: Fri, 31 Jan 2020 12:43:01 +0000 Subject: [PATCH 0341/1126] update licenses for 7.x (backport of #11549) --- NOTICE.TXT | 14692 ---------------- .../lib/logstash/dependency_report.rb | 6 + logstash-core/logstash-core.gemspec | 1 + .../src/main/resources/licenseMapping.csv | 328 +- .../src/main/resources/notices/a.txt | 57 + ....3.8-NOTICE.txt => addressable-NOTICE.txt} | 0 .../main/resources/notices/asm-6.0-NOTICE.txt | 27 - ...ic-1.1.99-NOTICE.txt => atomic-NOTICE.txt} | 0 ...e-1.2.1-NOTICE.txt => avl_tree-NOTICE.txt} | 0 .../main/resources/notices/avro-NOTICE.txt | 6 + ....0-NOTICE.txt => awesome_print-NOTICE.txt} | 0 .../notices/aws-eventstream-NOTICE.txt | 2 + ...2.11.111-NOTICE.txt => aws-sdk-NOTICE.txt} | 0 ...111-NOTICE.txt => aws-sdk-core-NOTICE.txt} | 0 ...OTICE.txt => aws-sdk-resources-NOTICE.txt} | 0 ....67.0-NOTICE.txt => aws-sdk-v1-NOTICE.txt} | 0 ...-1.0.3-NOTICE.txt => aws-sigv4-NOTICE.txt} | 0 ...ns-NOTICE.txt => back_pressure-NOTICE.txt} | 4 +- .../notices/backports-3.11.3-NOTICE.txt | 20 - ...ta-2.4.3-NOTICE.txt => bindata-NOTICE.txt} | 0 ...tok-0.2.0-NOTICE.txt => buftok-NOTICE.txt} | 0 ...er-3.2.3-NOTICE.txt => builder-NOTICE.txt} | 0 ...r-1.9.10-NOTICE.txt => bundler-NOTICE.txt} | 0 ...abin-0.9.0-NOTICE.txt => cabin-NOTICE.txt} | 0 ...NOTICE.txt => chronic_duration-NOTICE.txt} | 0 ...lamp-0.6.5-NOTICE.txt => clamp-NOTICE.txt} | 0 ...ay-1.1.2-NOTICE.txt => coderay-NOTICE.txt} | 0 ...ckson.core!jackson-annotations-NOTICE.txt} | 0 ...rxml.jackson.core!jackson-core-NOTICE.txt} | 0 ....jackson.core!jackson-databind-NOTICE.txt} | 0 ...format!jackson-dataformat-cbor-NOTICE.txt} | 0 ...ule!jackson-module-afterburner-NOTICE.txt} | 0 ...om.google.code.findbugs!jsr305-NOTICE.txt} | 0 ...rprone!error_prone_annotations-NOTICE.txt} | 0 ...ejavaformat!google-java-format-NOTICE.txt} | 0 ....txt => com.google.guava!guava-NOTICE.txt} | 0 ...ogle.j2objc!j2objc-annotations-NOTICE.txt} | 0 ...ommons-codec!commons-codec-1.11-NOTICE.txt | 220 - ...=> commons-codec!commons-codec-NOTICE.txt} | 0 ...ommons-logging!commons-logging-NOTICE.txt} | 0 ...-NOTICE.txt => concurrent-ruby-NOTICE.txt} | 0 .../resources/notices/controls.js-NOTICE.txt | 1 - ...rack-0.4.3-NOTICE.txt => dalli-NOTICE.txt} | 2 +- .../resources/notices/diff-lcs-1.3-NOTICE.txt | 19 - ...0417-NOTICE.txt => domain_name-NOTICE.txt} | 0 ...env-2.5.0-NOTICE.txt => dotenv-NOTICE.txt} | 0 .../{edn-1.1.1-NOTICE.txt => edn-NOTICE.txt} | 0 ....5-NOTICE.txt => elasticsearch-NOTICE.txt} | 0 ...OTICE.txt => elasticsearch-api-NOTICE.txt} | 0 ...txt => elasticsearch-transport-NOTICE.txt} | 0 ...0.0.10-NOTICE.txt => equalizer-NOTICE.txt} | 0 ...ay-0.9.2-NOTICE.txt => faraday-NOTICE.txt} | 0 .../{ffi-1.9.25-NOTICE.txt => ffi-NOTICE.txt} | 0 ...e-0.0.4-NOTICE.txt => filesize-NOTICE.txt} | 0 .../notices/filewatch-0.9.0-NOTICE.txt | 3 - .../resources/notices/ftw-0.0.48-NOTICE.txt | 3 - .../resources/notices/gelf-3.0.0-NOTICE.txt | 22 - ...lfd-0.2.0-NOTICE.txt => gelfd2-NOTICE.txt} | 3 - ...{gems-0.8.3-NOTICE.txt => gems-NOTICE.txt} | 0 ...-0.9.0-NOTICE.txt => gene_pool-NOTICE.txt} | 2 +- .../notices/gmetric-0.1.3-NOTICE.txt | 3 - ...thub.jk1!gradle-license-report-NOTICE.txt} | 0 .../notices/gserver-0.0.1-NOTICE.txt | 58 - ...es-1.3.0-NOTICE.txt => hitimes-NOTICE.txt} | 0 ...{http-0.9.9-NOTICE.txt => http-NOTICE.txt} | 0 ....0.3-NOTICE.txt => http-cookie-NOTICE.txt} | 0 ...1-NOTICE.txt => http-form_data-NOTICE.txt} | 0 ...0-NOTICE.txt => http_parser.rb-NOTICE.txt} | 0 ...{i18n-0.6.9-NOTICE.txt => i18n-NOTICE.txt} | 0 ...ist-1.0.0-NOTICE.txt => insist-NOTICE.txt} | 0 .../notices/invokebinder-1.7-NOTICE.txt | 15 - ...NOTICE.txt => jar-dependencies-NOTICE.txt} | 0 ...{jay-yydebug-NOTICE.txt => jay-NOTICE.txt} | 0 .../notices/jcodings-1.0.18-NOTICE.txt | 19 - .../notices/jdbc-derby-10.12.1.1-NOTICE.txt | 203 - .../resources/notices/jffi-1.2.16-NOTICE.txt | 27 - .../notices/jitescript-0.4.1-NOTICE.txt | 179 - .../resources/notices/jline2-2.1.1-NOTICE.txt | 36 - ...-0.11.5-NOTICE.txt => jls-grok-NOTICE.txt} | 0 ...6-NOTICE.txt => jls-lumberjack-NOTICE.txt} | 0 ...h-1.4.0-NOTICE.txt => jmespath-NOTICE.txt} | 0 ...r-unixsocket-NOTICE.txt => jnr-NOTICE.txt} | 0 .../notices/jnr-constants-0.9.9-NOTICE.txt | 27 - .../notices/jnr-enxio-0.16-NOTICE.txt | 13 - .../notices/jnr-ffi-2.1.7-NOTICE.txt | 27 - .../notices/jnr-netdb-1.1.6-NOTICE.txt | 13 - .../notices/jnr-posix-3.0.41-NOTICE.txt | 2488 --- .../resources/notices/jnr-x86asm-NOTICE.txt | 25 - .../{joda-time-NOTICE.txt => joda-NOTICE.txt} | 0 .../main/resources/notices/joni-NOTICE.txt | 23 - ...-0.4.6-NOTICE.txt => jrjackson-NOTICE.txt} | 0 .../notices/jruby-9.1.14.0-NOTICE.txt | 342 - .../{bytelist-NOTICE.txt => jruby-NOTICE.txt} | 1348 +- ...-1.1.0-NOTICE.txt => jruby-jms-NOTICE.txt} | 2 +- ....1-NOTICE.txt => jruby-openssl-NOTICE.txt} | 0 .../notices/jruby-readline-NOTICE.txt | 32 - ...ICE.txt => jruby-stdin-channel-NOTICE.txt} | 0 .../resources/notices/json-1.8.6-NOTICE.txt | 3 - ...n-generator-NOTICE.txt => json-NOTICE.txt} | 0 .../main/resources/notices/jzlib-NOTICE.txt | 27 - ...-1.1.0-NOTICE.txt => lru_redux-NOTICE.txt} | 0 ...{mail-2.6.6-NOTICE.txt => mail-NOTICE.txt} | 0 ...-0.6.4-NOTICE.txt => manticore-NOTICE.txt} | 0 ...3.1.1-NOTICE.txt => march_hare-NOTICE.txt} | 0 ...0.4.2-NOTICE.txt => memoizable-NOTICE.txt} | 0 ....2-NOTICE.txt => method_source-NOTICE.txt} | 0 ...-0.9.9.8-NOTICE.txt => metriks-NOTICE.txt} | 0 ...2.6.2-NOTICE.txt => mime-types-NOTICE.txt} | 0 ...ar-0.6.1-NOTICE.txt => minitar-NOTICE.txt} | 0 ...ck-1.2.4-NOTICE.txt => msgpack-NOTICE.txt} | 0 ....13.1-NOTICE.txt => multi_json-NOTICE.txt} | 0 ...0-NOTICE.txt => multipart-post-NOTICE.txt} | 0 ....1.6-NOTICE.txt => murmurhash3-NOTICE.txt} | 0 ...-0.99.8-NOTICE.txt => mustache-NOTICE.txt} | 0 ...3.7.0-NOTICE.txt => mustermann-NOTICE.txt} | 9 +- .../main/resources/notices/nailgun-NOTICE.txt | 5 - ...ght-1.1.0-NOTICE.txt => naught-NOTICE.txt} | 0 ...uncycastle-NOTICE.txt => nio4r-NOTICE.txt} | 7 +- ...i-1.8.4-NOTICE.txt => nokogiri-NOTICE.txt} | 0 ...-0.1.1-NOTICE.txt => numerizer-NOTICE.txt} | 0 ...TICE.txt => openssl_pkcs8_pure-NOTICE.txt} | 0 ...apache.logging.log4j!log4j-api-NOTICE.txt} | 0 ...pache.logging.log4j!log4j-core-NOTICE.txt} | 0 ...logging.log4j!log4j-slf4j-impl-NOTICE.txt} | 0 ...dehaus.janino!commons-compiler-NOTICE.txt} | 0 ... => org.codehaus.janino!janino-NOTICE.txt} | 0 ...ojo!animal-sniffer-annotations-NOTICE.txt} | 0 ...core!org.eclipse.core.commands-NOTICE.txt} | 0 ...e!org.eclipse.core.contenttype-NOTICE.txt} | 0 ...e!org.eclipse.core.expressions-NOTICE.txt} | 0 ...re!org.eclipse.core.filesystem-NOTICE.txt} | 0 ...pse.core!org.eclipse.core.jobs-NOTICE.txt} | 0 ...ore!org.eclipse.core.resources-NOTICE.txt} | 0 ....core!org.eclipse.core.runtime-NOTICE.txt} | 0 ...quinox!org.eclipse.equinox.app-NOTICE.txt} | 0 ...nox!org.eclipse.equinox.common-NOTICE.txt} | 0 ...rg.eclipse.equinox.preferences-NOTICE.txt} | 0 ...x!org.eclipse.equinox.registry-NOTICE.txt} | 0 ...lipse.jdt!org.eclipse.jdt.core-NOTICE.txt} | 0 ....eclipse.osgi!org.eclipse.osgi-NOTICE.txt} | 0 ....eclipse.text!org.eclipse.text-NOTICE.txt} | 0 .../org.javassist!javassist-NOTICE.txt | 3 + ...xt => org.jruby!jruby-complete-NOTICE.txt} | 0 .../org.reflections!reflections-NOTICE.txt | 15 + ...ICE.txt => org.slf4j!slf4j-api-NOTICE.txt} | 0 ...uet-0.2.1-NOTICE.txt => paquet-NOTICE.txt} | 0 ...0.0.30-NOTICE.txt => pleaserun-NOTICE.txt} | 0 ...t-0.3.5-NOTICE.txt => polyglot-NOTICE.txt} | 0 .../notices/poseidon-0.0.5-NOTICE.txt | 22 - .../resources/notices/prototype.js-NOTICE.txt | 1 - .../{pry-0.10.4-NOTICE.txt => pry-NOTICE.txt} | 0 .../resources/notices/psych-2.2.4-NOTICE.txt | 7 - ....6-NOTICE.txt => public_suffix-NOTICE.txt} | 0 ...puma-2.16.0-NOTICE.txt => puma-NOTICE.txt} | 0 .../main/resources/notices/racc-NOTICE.txt | 8 - ...{rack-1.6.6-NOTICE.txt => rack-NOTICE.txt} | 0 ...-NOTICE.txt => rack-protection-NOTICE.txt} | 0 ...rake-10.4.2-NOTICE.txt => rake-NOTICE.txt} | 0 ...edis-3.3.5-NOTICE.txt => redis-NOTICE.txt} | 0 .../notices/rspec-core-3.7.1-NOTICE.txt | 26 - .../rspec-expectations-3.7.0-NOTICE.txt | 25 - .../notices/rspec-mocks-3.7.0-NOTICE.txt | 25 - .../notices/rspec-sequencing-0.1.0-NOTICE.txt | 202 - .../notices/rspec-support-3.7.1-NOTICE.txt | 20 - .../notices/rspec-wait-0.0.9-NOTICE.txt | 22 - ...NOTICE.txt => ruby-progressbar-NOTICE.txt} | 0 ...ip-1.2.1-NOTICE.txt => rubyzip-NOTICE.txt} | 0 ...-NOTICE.txt => rufus-scheduler-NOTICE.txt} | 0 .../notices/safe_yaml-1.0.4-NOTICE.txt | 22 - ...-NOTICE.txt => semantic_logger-NOTICE.txt} | 2 +- ...el-5.11.0-NOTICE.txt => sequel-NOTICE.txt} | 0 ...3.1-NOTICE.txt => simple_oauth-NOTICE.txt} | 0 ...ra-1.4.8-NOTICE.txt => sinatra-NOTICE.txt} | 0 .../resources/notices/slop-3.6.0-NOTICE.txt | 20 - ...py-0.0.12-NOTICE.txt => snappy-NOTICE.txt} | 0 ....1.2-NOTICE.txt => snappy-jars-NOTICE.txt} | 0 ...{snmp-1.2.0-NOTICE.txt => snmp-NOTICE.txt} | 0 ...poon-0.0.6-NOTICE.txt => spoon-NOTICE.txt} | 0 ...stud-0.0.23-NOTICE.txt => stud-NOTICE.txt} | 0 ....3.6-NOTICE.txt => thread_safe-NOTICE.txt} | 0 ...{tilt-2.0.8-NOTICE.txt => tilt-NOTICE.txt} | 0 .../notices/timecop-0.9.1-NOTICE.txt | 22 - ...p-1.4.15-NOTICE.txt => treetop-NOTICE.txt} | 0 ...r-5.15.0-NOTICE.txt => twitter-NOTICE.txt} | 0 ...nfo-1.2.5-NOTICE.txt => tzinfo-NOTICE.txt} | 0 ...18.5-NOTICE.txt => tzinfo-data-NOTICE.txt} | 0 .../{unf-0.1.4-NOTICE.txt => unf-NOTICE.txt} | 0 .../notices/unsafe-fences-1.0-NOTICE.txt | 202 - ...fs-0.8.0-NOTICE.txt => webhdfs-NOTICE.txt} | 0 .../notices/webmock-1.21.0-NOTICE.txt | 20 - .../notices/webrick-1.3.1-NOTICE.txt | 22 - ...1.1.5-NOTICE.txt => xml-simple-NOTICE.txt} | 0 192 files changed, 906 insertions(+), 20129 deletions(-) delete mode 100644 NOTICE.TXT create mode 100644 tools/dependencies-report/src/main/resources/notices/a.txt rename tools/dependencies-report/src/main/resources/notices/{addressable-2.3.8-NOTICE.txt => addressable-NOTICE.txt} (100%) delete mode 100644 tools/dependencies-report/src/main/resources/notices/asm-6.0-NOTICE.txt rename tools/dependencies-report/src/main/resources/notices/{atomic-1.1.99-NOTICE.txt => atomic-NOTICE.txt} (100%) rename tools/dependencies-report/src/main/resources/notices/{avl_tree-1.2.1-NOTICE.txt => avl_tree-NOTICE.txt} (100%) create mode 100644 tools/dependencies-report/src/main/resources/notices/avro-NOTICE.txt rename tools/dependencies-report/src/main/resources/notices/{awesome_print-1.7.0-NOTICE.txt => awesome_print-NOTICE.txt} (100%) create mode 100644 tools/dependencies-report/src/main/resources/notices/aws-eventstream-NOTICE.txt rename tools/dependencies-report/src/main/resources/notices/{aws-sdk-2.11.111-NOTICE.txt => aws-sdk-NOTICE.txt} (100%) rename tools/dependencies-report/src/main/resources/notices/{aws-sdk-core-2.11.111-NOTICE.txt => aws-sdk-core-NOTICE.txt} (100%) rename tools/dependencies-report/src/main/resources/notices/{aws-sdk-resources-2.11.111-NOTICE.txt => aws-sdk-resources-NOTICE.txt} (100%) rename tools/dependencies-report/src/main/resources/notices/{aws-sdk-v1-1.67.0-NOTICE.txt => aws-sdk-v1-NOTICE.txt} (100%) rename tools/dependencies-report/src/main/resources/notices/{aws-sigv4-1.0.3-NOTICE.txt => aws-sigv4-NOTICE.txt} (100%) rename tools/dependencies-report/src/main/resources/notices/{options-NOTICE.txt => back_pressure-NOTICE.txt} (74%) delete mode 100644 tools/dependencies-report/src/main/resources/notices/backports-3.11.3-NOTICE.txt rename tools/dependencies-report/src/main/resources/notices/{bindata-2.4.3-NOTICE.txt => bindata-NOTICE.txt} (100%) rename tools/dependencies-report/src/main/resources/notices/{buftok-0.2.0-NOTICE.txt => buftok-NOTICE.txt} (100%) rename tools/dependencies-report/src/main/resources/notices/{builder-3.2.3-NOTICE.txt => builder-NOTICE.txt} (100%) rename tools/dependencies-report/src/main/resources/notices/{bundler-1.9.10-NOTICE.txt => bundler-NOTICE.txt} (100%) rename tools/dependencies-report/src/main/resources/notices/{cabin-0.9.0-NOTICE.txt => cabin-NOTICE.txt} (100%) rename tools/dependencies-report/src/main/resources/notices/{chronic_duration-0.10.6-NOTICE.txt => chronic_duration-NOTICE.txt} (100%) rename tools/dependencies-report/src/main/resources/notices/{clamp-0.6.5-NOTICE.txt => clamp-NOTICE.txt} (100%) rename tools/dependencies-report/src/main/resources/notices/{coderay-1.1.2-NOTICE.txt => coderay-NOTICE.txt} (100%) rename tools/dependencies-report/src/main/resources/notices/{com.fasterxml.jackson.core!jackson-annotations-2.9.5-NOTICE.txt => com.fasterxml.jackson.core!jackson-annotations-NOTICE.txt} (100%) rename tools/dependencies-report/src/main/resources/notices/{com.fasterxml.jackson.core!jackson-core-2.9.5-NOTICE.txt => com.fasterxml.jackson.core!jackson-core-NOTICE.txt} (100%) rename tools/dependencies-report/src/main/resources/notices/{com.fasterxml.jackson.core!jackson-databind-2.9.5-NOTICE.txt => com.fasterxml.jackson.core!jackson-databind-NOTICE.txt} (100%) rename tools/dependencies-report/src/main/resources/notices/{com.fasterxml.jackson.dataformat!jackson-dataformat-cbor-2.9.5-NOTICE.txt => com.fasterxml.jackson.dataformat!jackson-dataformat-cbor-NOTICE.txt} (100%) rename tools/dependencies-report/src/main/resources/notices/{com.fasterxml.jackson.module!jackson-module-afterburner-2.9.5-NOTICE.txt => com.fasterxml.jackson.module!jackson-module-afterburner-NOTICE.txt} (100%) rename tools/dependencies-report/src/main/resources/notices/{com.google.code.findbugs!jsr305-1.3.9-NOTICE.txt => com.google.code.findbugs!jsr305-NOTICE.txt} (100%) rename tools/dependencies-report/src/main/resources/notices/{com.google.errorprone!error_prone_annotations-2.0.18-NOTICE.txt => com.google.errorprone!error_prone_annotations-NOTICE.txt} (100%) rename tools/dependencies-report/src/main/resources/notices/{com.google.googlejavaformat!google-java-format-1.1-NOTICE.txt => com.google.googlejavaformat!google-java-format-NOTICE.txt} (100%) rename tools/dependencies-report/src/main/resources/notices/{com.google.guava!guava-22.0-NOTICE.txt => com.google.guava!guava-NOTICE.txt} (100%) rename tools/dependencies-report/src/main/resources/notices/{com.google.j2objc!j2objc-annotations-1.1-NOTICE.txt => com.google.j2objc!j2objc-annotations-NOTICE.txt} (100%) delete mode 100644 tools/dependencies-report/src/main/resources/notices/commons-codec!commons-codec-1.11-NOTICE.txt rename tools/dependencies-report/src/main/resources/notices/{commons-codec!commons-codec-1.10.0-NOTICE.txt => commons-codec!commons-codec-NOTICE.txt} (100%) rename tools/dependencies-report/src/main/resources/notices/{commons-logging!commons-logging-1.2.0-NOTICE.txt => commons-logging!commons-logging-NOTICE.txt} (100%) rename tools/dependencies-report/src/main/resources/notices/{concurrent-ruby-1.0.5-NOTICE.txt => concurrent-ruby-NOTICE.txt} (100%) delete mode 100644 tools/dependencies-report/src/main/resources/notices/controls.js-NOTICE.txt rename tools/dependencies-report/src/main/resources/notices/{crack-0.4.3-NOTICE.txt => dalli-NOTICE.txt} (95%) delete mode 100644 tools/dependencies-report/src/main/resources/notices/diff-lcs-1.3-NOTICE.txt rename tools/dependencies-report/src/main/resources/notices/{domain_name-0.5.20180417-NOTICE.txt => domain_name-NOTICE.txt} (100%) rename tools/dependencies-report/src/main/resources/notices/{dotenv-2.5.0-NOTICE.txt => dotenv-NOTICE.txt} (100%) rename tools/dependencies-report/src/main/resources/notices/{edn-1.1.1-NOTICE.txt => edn-NOTICE.txt} (100%) rename tools/dependencies-report/src/main/resources/notices/{elasticsearch-5.0.5-NOTICE.txt => elasticsearch-NOTICE.txt} (100%) rename tools/dependencies-report/src/main/resources/notices/{elasticsearch-api-5.0.5-NOTICE.txt => elasticsearch-api-NOTICE.txt} (100%) rename tools/dependencies-report/src/main/resources/notices/{elasticsearch-transport-5.0.5-NOTICE.txt => elasticsearch-transport-NOTICE.txt} (100%) rename tools/dependencies-report/src/main/resources/notices/{equalizer-0.0.10-NOTICE.txt => equalizer-NOTICE.txt} (100%) rename tools/dependencies-report/src/main/resources/notices/{faraday-0.9.2-NOTICE.txt => faraday-NOTICE.txt} (100%) rename tools/dependencies-report/src/main/resources/notices/{ffi-1.9.25-NOTICE.txt => ffi-NOTICE.txt} (100%) rename tools/dependencies-report/src/main/resources/notices/{filesize-0.0.4-NOTICE.txt => filesize-NOTICE.txt} (100%) delete mode 100644 tools/dependencies-report/src/main/resources/notices/filewatch-0.9.0-NOTICE.txt delete mode 100644 tools/dependencies-report/src/main/resources/notices/ftw-0.0.48-NOTICE.txt delete mode 100644 tools/dependencies-report/src/main/resources/notices/gelf-3.0.0-NOTICE.txt rename tools/dependencies-report/src/main/resources/notices/{gelfd-0.2.0-NOTICE.txt => gelfd2-NOTICE.txt} (90%) rename tools/dependencies-report/src/main/resources/notices/{gems-0.8.3-NOTICE.txt => gems-NOTICE.txt} (100%) rename tools/dependencies-report/src/main/resources/notices/{childprocess-0.9.0-NOTICE.txt => gene_pool-NOTICE.txt} (96%) delete mode 100644 tools/dependencies-report/src/main/resources/notices/gmetric-0.1.3-NOTICE.txt rename tools/dependencies-report/src/main/resources/notices/{gradle.plugin.com.github.jk1!gradle-license-report-0.7.1-NOTICE.txt => gradle.plugin.com.github.jk1!gradle-license-report-NOTICE.txt} (100%) delete mode 100644 tools/dependencies-report/src/main/resources/notices/gserver-0.0.1-NOTICE.txt rename tools/dependencies-report/src/main/resources/notices/{hitimes-1.3.0-NOTICE.txt => hitimes-NOTICE.txt} (100%) rename tools/dependencies-report/src/main/resources/notices/{http-0.9.9-NOTICE.txt => http-NOTICE.txt} (100%) rename tools/dependencies-report/src/main/resources/notices/{http-cookie-1.0.3-NOTICE.txt => http-cookie-NOTICE.txt} (100%) rename tools/dependencies-report/src/main/resources/notices/{http-form_data-1.0.1-NOTICE.txt => http-form_data-NOTICE.txt} (100%) rename tools/dependencies-report/src/main/resources/notices/{http_parser.rb-0.6.0-NOTICE.txt => http_parser.rb-NOTICE.txt} (100%) rename tools/dependencies-report/src/main/resources/notices/{i18n-0.6.9-NOTICE.txt => i18n-NOTICE.txt} (100%) rename tools/dependencies-report/src/main/resources/notices/{insist-1.0.0-NOTICE.txt => insist-NOTICE.txt} (100%) delete mode 100644 tools/dependencies-report/src/main/resources/notices/invokebinder-1.7-NOTICE.txt rename tools/dependencies-report/src/main/resources/notices/{jar-dependencies-0.3.12-NOTICE.txt => jar-dependencies-NOTICE.txt} (100%) rename tools/dependencies-report/src/main/resources/notices/{jay-yydebug-NOTICE.txt => jay-NOTICE.txt} (100%) delete mode 100644 tools/dependencies-report/src/main/resources/notices/jcodings-1.0.18-NOTICE.txt delete mode 100644 tools/dependencies-report/src/main/resources/notices/jdbc-derby-10.12.1.1-NOTICE.txt delete mode 100644 tools/dependencies-report/src/main/resources/notices/jffi-1.2.16-NOTICE.txt delete mode 100644 tools/dependencies-report/src/main/resources/notices/jitescript-0.4.1-NOTICE.txt delete mode 100644 tools/dependencies-report/src/main/resources/notices/jline2-2.1.1-NOTICE.txt rename tools/dependencies-report/src/main/resources/notices/{jls-grok-0.11.5-NOTICE.txt => jls-grok-NOTICE.txt} (100%) rename tools/dependencies-report/src/main/resources/notices/{jls-lumberjack-0.0.26-NOTICE.txt => jls-lumberjack-NOTICE.txt} (100%) rename tools/dependencies-report/src/main/resources/notices/{jmespath-1.4.0-NOTICE.txt => jmespath-NOTICE.txt} (100%) rename tools/dependencies-report/src/main/resources/notices/{jnr-unixsocket-NOTICE.txt => jnr-NOTICE.txt} (100%) delete mode 100644 tools/dependencies-report/src/main/resources/notices/jnr-constants-0.9.9-NOTICE.txt delete mode 100644 tools/dependencies-report/src/main/resources/notices/jnr-enxio-0.16-NOTICE.txt delete mode 100644 tools/dependencies-report/src/main/resources/notices/jnr-ffi-2.1.7-NOTICE.txt delete mode 100644 tools/dependencies-report/src/main/resources/notices/jnr-netdb-1.1.6-NOTICE.txt delete mode 100644 tools/dependencies-report/src/main/resources/notices/jnr-posix-3.0.41-NOTICE.txt delete mode 100644 tools/dependencies-report/src/main/resources/notices/jnr-x86asm-NOTICE.txt rename tools/dependencies-report/src/main/resources/notices/{joda-time-NOTICE.txt => joda-NOTICE.txt} (100%) delete mode 100644 tools/dependencies-report/src/main/resources/notices/joni-NOTICE.txt rename tools/dependencies-report/src/main/resources/notices/{jrjackson-0.4.6-NOTICE.txt => jrjackson-NOTICE.txt} (100%) delete mode 100644 tools/dependencies-report/src/main/resources/notices/jruby-9.1.14.0-NOTICE.txt rename tools/dependencies-report/src/main/resources/notices/{bytelist-NOTICE.txt => jruby-NOTICE.txt} (72%) rename tools/dependencies-report/src/main/resources/notices/{rumbster-1.1.0-NOTICE.txt => jruby-jms-NOTICE.txt} (87%) rename tools/dependencies-report/src/main/resources/notices/{jruby-openssl-0.10.1-NOTICE.txt => jruby-openssl-NOTICE.txt} (100%) delete mode 100644 tools/dependencies-report/src/main/resources/notices/jruby-readline-NOTICE.txt rename tools/dependencies-report/src/main/resources/notices/{jruby-stdin-channel-0.2.0-NOTICE.txt => jruby-stdin-channel-NOTICE.txt} (100%) delete mode 100644 tools/dependencies-report/src/main/resources/notices/json-1.8.6-NOTICE.txt rename tools/dependencies-report/src/main/resources/notices/{json-generator-NOTICE.txt => json-NOTICE.txt} (100%) delete mode 100644 tools/dependencies-report/src/main/resources/notices/jzlib-NOTICE.txt rename tools/dependencies-report/src/main/resources/notices/{lru_redux-1.1.0-NOTICE.txt => lru_redux-NOTICE.txt} (100%) rename tools/dependencies-report/src/main/resources/notices/{mail-2.6.6-NOTICE.txt => mail-NOTICE.txt} (100%) rename tools/dependencies-report/src/main/resources/notices/{manticore-0.6.4-NOTICE.txt => manticore-NOTICE.txt} (100%) rename tools/dependencies-report/src/main/resources/notices/{march_hare-3.1.1-NOTICE.txt => march_hare-NOTICE.txt} (100%) rename tools/dependencies-report/src/main/resources/notices/{memoizable-0.4.2-NOTICE.txt => memoizable-NOTICE.txt} (100%) rename tools/dependencies-report/src/main/resources/notices/{method_source-0.8.2-NOTICE.txt => method_source-NOTICE.txt} (100%) rename tools/dependencies-report/src/main/resources/notices/{metriks-0.9.9.8-NOTICE.txt => metriks-NOTICE.txt} (100%) rename tools/dependencies-report/src/main/resources/notices/{mime-types-2.6.2-NOTICE.txt => mime-types-NOTICE.txt} (100%) rename tools/dependencies-report/src/main/resources/notices/{minitar-0.6.1-NOTICE.txt => minitar-NOTICE.txt} (100%) rename tools/dependencies-report/src/main/resources/notices/{msgpack-1.2.4-NOTICE.txt => msgpack-NOTICE.txt} (100%) rename tools/dependencies-report/src/main/resources/notices/{multi_json-1.13.1-NOTICE.txt => multi_json-NOTICE.txt} (100%) rename tools/dependencies-report/src/main/resources/notices/{multipart-post-2.0.0-NOTICE.txt => multipart-post-NOTICE.txt} (100%) rename tools/dependencies-report/src/main/resources/notices/{murmurhash3-0.1.6-NOTICE.txt => murmurhash3-NOTICE.txt} (100%) rename tools/dependencies-report/src/main/resources/notices/{mustache-0.99.8-NOTICE.txt => mustache-NOTICE.txt} (100%) rename tools/dependencies-report/src/main/resources/notices/{rspec-3.7.0-NOTICE.txt => mustermann-NOTICE.txt} (76%) delete mode 100644 tools/dependencies-report/src/main/resources/notices/nailgun-NOTICE.txt rename tools/dependencies-report/src/main/resources/notices/{naught-1.1.0-NOTICE.txt => naught-NOTICE.txt} (100%) rename tools/dependencies-report/src/main/resources/notices/{bouncycastle-NOTICE.txt => nio4r-NOTICE.txt} (89%) rename tools/dependencies-report/src/main/resources/notices/{nokogiri-1.8.4-NOTICE.txt => nokogiri-NOTICE.txt} (100%) rename tools/dependencies-report/src/main/resources/notices/{numerizer-0.1.1-NOTICE.txt => numerizer-NOTICE.txt} (100%) rename tools/dependencies-report/src/main/resources/notices/{openssl_pkcs8_pure-0.0.0.2-NOTICE.txt => openssl_pkcs8_pure-NOTICE.txt} (100%) rename tools/dependencies-report/src/main/resources/notices/{org.apache.logging.log4j!log4j-api-2.9.1-NOTICE.txt => org.apache.logging.log4j!log4j-api-NOTICE.txt} (100%) rename tools/dependencies-report/src/main/resources/notices/{org.apache.logging.log4j!log4j-core-2.9.1-NOTICE.txt => org.apache.logging.log4j!log4j-core-NOTICE.txt} (100%) rename tools/dependencies-report/src/main/resources/notices/{org.apache.logging.log4j!log4j-slf4j-impl-2.9.1-NOTICE.txt => org.apache.logging.log4j!log4j-slf4j-impl-NOTICE.txt} (100%) rename tools/dependencies-report/src/main/resources/notices/{org.codehaus.janino!commons-compiler-3.0.8-NOTICE.txt => org.codehaus.janino!commons-compiler-NOTICE.txt} (100%) rename tools/dependencies-report/src/main/resources/notices/{org.codehaus.janino!janino-3.0.8-NOTICE.txt => org.codehaus.janino!janino-NOTICE.txt} (100%) rename tools/dependencies-report/src/main/resources/notices/{org.codehaus.mojo!animal-sniffer-annotations-1.14-NOTICE.txt => org.codehaus.mojo!animal-sniffer-annotations-NOTICE.txt} (100%) rename tools/dependencies-report/src/main/resources/notices/{org.eclipse.core!org.eclipse.core.commands-3.6.0-NOTICE.txt => org.eclipse.core!org.eclipse.core.commands-NOTICE.txt} (100%) rename tools/dependencies-report/src/main/resources/notices/{org.eclipse.core!org.eclipse.core.contenttype-3.4.100-NOTICE.txt => org.eclipse.core!org.eclipse.core.contenttype-NOTICE.txt} (100%) rename tools/dependencies-report/src/main/resources/notices/{org.eclipse.core!org.eclipse.core.expressions-3.4.300-NOTICE.txt => org.eclipse.core!org.eclipse.core.expressions-NOTICE.txt} (100%) rename tools/dependencies-report/src/main/resources/notices/{org.eclipse.core!org.eclipse.core.filesystem-1.3.100-NOTICE.txt => org.eclipse.core!org.eclipse.core.filesystem-NOTICE.txt} (100%) rename tools/dependencies-report/src/main/resources/notices/{org.eclipse.core!org.eclipse.core.jobs-3.5.100-NOTICE.txt => org.eclipse.core!org.eclipse.core.jobs-NOTICE.txt} (100%) rename tools/dependencies-report/src/main/resources/notices/{org.eclipse.core!org.eclipse.core.resources-3.7.100-NOTICE.txt => org.eclipse.core!org.eclipse.core.resources-NOTICE.txt} (100%) rename tools/dependencies-report/src/main/resources/notices/{org.eclipse.core!org.eclipse.core.runtime-3.7.0-NOTICE.txt => org.eclipse.core!org.eclipse.core.runtime-NOTICE.txt} (100%) rename tools/dependencies-report/src/main/resources/notices/{org.eclipse.equinox!org.eclipse.equinox.app-1.3.100-NOTICE.txt => org.eclipse.equinox!org.eclipse.equinox.app-NOTICE.txt} (100%) rename tools/dependencies-report/src/main/resources/notices/{org.eclipse.equinox!org.eclipse.equinox.common-3.6.0-NOTICE.txt => org.eclipse.equinox!org.eclipse.equinox.common-NOTICE.txt} (100%) rename tools/dependencies-report/src/main/resources/notices/{org.eclipse.equinox!org.eclipse.equinox.preferences-3.4.1-NOTICE.txt => org.eclipse.equinox!org.eclipse.equinox.preferences-NOTICE.txt} (100%) rename tools/dependencies-report/src/main/resources/notices/{org.eclipse.equinox!org.eclipse.equinox.registry-3.5.101-NOTICE.txt => org.eclipse.equinox!org.eclipse.equinox.registry-NOTICE.txt} (100%) rename tools/dependencies-report/src/main/resources/notices/{org.eclipse.jdt!org.eclipse.jdt.core-3.10.0-NOTICE.txt => org.eclipse.jdt!org.eclipse.jdt.core-NOTICE.txt} (100%) rename tools/dependencies-report/src/main/resources/notices/{org.eclipse.osgi!org.eclipse.osgi-3.7.1-NOTICE.txt => org.eclipse.osgi!org.eclipse.osgi-NOTICE.txt} (100%) rename tools/dependencies-report/src/main/resources/notices/{org.eclipse.text!org.eclipse.text-3.5.101-NOTICE.txt => org.eclipse.text!org.eclipse.text-NOTICE.txt} (100%) create mode 100644 tools/dependencies-report/src/main/resources/notices/org.javassist!javassist-NOTICE.txt rename tools/dependencies-report/src/main/resources/notices/{org.jruby!jruby-complete-9.1.13.0-NOTICE.txt => org.jruby!jruby-complete-NOTICE.txt} (100%) create mode 100644 tools/dependencies-report/src/main/resources/notices/org.reflections!reflections-NOTICE.txt rename tools/dependencies-report/src/main/resources/notices/{org.slf4j!slf4j-api-1.7.25-NOTICE.txt => org.slf4j!slf4j-api-NOTICE.txt} (100%) rename tools/dependencies-report/src/main/resources/notices/{paquet-0.2.1-NOTICE.txt => paquet-NOTICE.txt} (100%) rename tools/dependencies-report/src/main/resources/notices/{pleaserun-0.0.30-NOTICE.txt => pleaserun-NOTICE.txt} (100%) rename tools/dependencies-report/src/main/resources/notices/{polyglot-0.3.5-NOTICE.txt => polyglot-NOTICE.txt} (100%) delete mode 100644 tools/dependencies-report/src/main/resources/notices/poseidon-0.0.5-NOTICE.txt delete mode 100644 tools/dependencies-report/src/main/resources/notices/prototype.js-NOTICE.txt rename tools/dependencies-report/src/main/resources/notices/{pry-0.10.4-NOTICE.txt => pry-NOTICE.txt} (100%) delete mode 100644 tools/dependencies-report/src/main/resources/notices/psych-2.2.4-NOTICE.txt rename tools/dependencies-report/src/main/resources/notices/{public_suffix-1.4.6-NOTICE.txt => public_suffix-NOTICE.txt} (100%) rename tools/dependencies-report/src/main/resources/notices/{puma-2.16.0-NOTICE.txt => puma-NOTICE.txt} (100%) delete mode 100644 tools/dependencies-report/src/main/resources/notices/racc-NOTICE.txt rename tools/dependencies-report/src/main/resources/notices/{rack-1.6.6-NOTICE.txt => rack-NOTICE.txt} (100%) rename tools/dependencies-report/src/main/resources/notices/{rack-protection-1.5.5-NOTICE.txt => rack-protection-NOTICE.txt} (100%) rename tools/dependencies-report/src/main/resources/notices/{rake-10.4.2-NOTICE.txt => rake-NOTICE.txt} (100%) rename tools/dependencies-report/src/main/resources/notices/{redis-3.3.5-NOTICE.txt => redis-NOTICE.txt} (100%) delete mode 100644 tools/dependencies-report/src/main/resources/notices/rspec-core-3.7.1-NOTICE.txt delete mode 100644 tools/dependencies-report/src/main/resources/notices/rspec-expectations-3.7.0-NOTICE.txt delete mode 100644 tools/dependencies-report/src/main/resources/notices/rspec-mocks-3.7.0-NOTICE.txt delete mode 100644 tools/dependencies-report/src/main/resources/notices/rspec-sequencing-0.1.0-NOTICE.txt delete mode 100644 tools/dependencies-report/src/main/resources/notices/rspec-support-3.7.1-NOTICE.txt delete mode 100644 tools/dependencies-report/src/main/resources/notices/rspec-wait-0.0.9-NOTICE.txt rename tools/dependencies-report/src/main/resources/notices/{ruby-progressbar-1.8.3-NOTICE.txt => ruby-progressbar-NOTICE.txt} (100%) rename tools/dependencies-report/src/main/resources/notices/{rubyzip-1.2.1-NOTICE.txt => rubyzip-NOTICE.txt} (100%) rename tools/dependencies-report/src/main/resources/notices/{rufus-scheduler-3.0.9-NOTICE.txt => rufus-scheduler-NOTICE.txt} (100%) delete mode 100644 tools/dependencies-report/src/main/resources/notices/safe_yaml-1.0.4-NOTICE.txt rename tools/dependencies-report/src/main/resources/notices/{snakeyaml-1.18-NOTICE.txt => semantic_logger-NOTICE.txt} (90%) rename tools/dependencies-report/src/main/resources/notices/{sequel-5.11.0-NOTICE.txt => sequel-NOTICE.txt} (100%) rename tools/dependencies-report/src/main/resources/notices/{simple_oauth-0.3.1-NOTICE.txt => simple_oauth-NOTICE.txt} (100%) rename tools/dependencies-report/src/main/resources/notices/{sinatra-1.4.8-NOTICE.txt => sinatra-NOTICE.txt} (100%) delete mode 100644 tools/dependencies-report/src/main/resources/notices/slop-3.6.0-NOTICE.txt rename tools/dependencies-report/src/main/resources/notices/{snappy-0.0.12-NOTICE.txt => snappy-NOTICE.txt} (100%) rename tools/dependencies-report/src/main/resources/notices/{snappy-jars-1.1.0.1.2-NOTICE.txt => snappy-jars-NOTICE.txt} (100%) rename tools/dependencies-report/src/main/resources/notices/{snmp-1.2.0-NOTICE.txt => snmp-NOTICE.txt} (100%) rename tools/dependencies-report/src/main/resources/notices/{spoon-0.0.6-NOTICE.txt => spoon-NOTICE.txt} (100%) rename tools/dependencies-report/src/main/resources/notices/{stud-0.0.23-NOTICE.txt => stud-NOTICE.txt} (100%) rename tools/dependencies-report/src/main/resources/notices/{thread_safe-0.3.6-NOTICE.txt => thread_safe-NOTICE.txt} (100%) rename tools/dependencies-report/src/main/resources/notices/{tilt-2.0.8-NOTICE.txt => tilt-NOTICE.txt} (100%) delete mode 100644 tools/dependencies-report/src/main/resources/notices/timecop-0.9.1-NOTICE.txt rename tools/dependencies-report/src/main/resources/notices/{treetop-1.4.15-NOTICE.txt => treetop-NOTICE.txt} (100%) rename tools/dependencies-report/src/main/resources/notices/{twitter-5.15.0-NOTICE.txt => twitter-NOTICE.txt} (100%) rename tools/dependencies-report/src/main/resources/notices/{tzinfo-1.2.5-NOTICE.txt => tzinfo-NOTICE.txt} (100%) rename tools/dependencies-report/src/main/resources/notices/{tzinfo-data-1.2018.5-NOTICE.txt => tzinfo-data-NOTICE.txt} (100%) rename tools/dependencies-report/src/main/resources/notices/{unf-0.1.4-NOTICE.txt => unf-NOTICE.txt} (100%) delete mode 100644 tools/dependencies-report/src/main/resources/notices/unsafe-fences-1.0-NOTICE.txt rename tools/dependencies-report/src/main/resources/notices/{webhdfs-0.8.0-NOTICE.txt => webhdfs-NOTICE.txt} (100%) delete mode 100644 tools/dependencies-report/src/main/resources/notices/webmock-1.21.0-NOTICE.txt delete mode 100644 tools/dependencies-report/src/main/resources/notices/webrick-1.3.1-NOTICE.txt rename tools/dependencies-report/src/main/resources/notices/{xml-simple-1.1.5-NOTICE.txt => xml-simple-NOTICE.txt} (100%) diff --git a/NOTICE.TXT b/NOTICE.TXT deleted file mode 100644 index 6289b9e8e..000000000 --- a/NOTICE.TXT +++ /dev/null @@ -1,14692 +0,0 @@ -Logstash -Copyright 2012-2018 Elasticsearch - -This product includes software developed by The Apache Software Foundation (http://www.apache.org/). - -========================================================================== -Third party libraries bundled by the Logstash project: - --------------------------------------------------- -Library: addressable v2.3.8 -Url: https://github.com/sporkmonger/addressable -License: Apache-2.0 - -Copyright © Bob Aman - - Apache License - Version 2.0, January 2004 - http://www.apache.org/licenses/ - -TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION - -1. Definitions. - - "License" shall mean the terms and conditions for use, reproduction, - and distribution as defined by Sections 1 through 9 of this document. - - "Licensor" shall mean the copyright owner or entity authorized by - the copyright owner that is granting the License. - - "Legal Entity" shall mean the union of the acting entity and all - other entities that control, are controlled by, or are under common - control with that entity. For the purposes of this definition, - "control" means (i) the power, direct or indirect, to cause the - direction or management of such entity, whether by contract or - otherwise, or (ii) ownership of fifty percent (50%) or more of the - outstanding shares, or (iii) beneficial ownership of such entity. - - "You" (or "Your") shall mean an individual or Legal Entity - exercising permissions granted by this License. - - "Source" form shall mean the preferred form for making modifications, - including but not limited to software source code, documentation - source, and configuration files. - - "Object" form shall mean any form resulting from mechanical - transformation or translation of a Source form, including but - not limited to compiled object code, generated documentation, - and conversions to other media types. - - "Work" shall mean the work of authorship, whether in Source or - Object form, made available under the License, as indicated by a - copyright notice that is included in or attached to the work - (an example is provided in the Appendix below). - - "Derivative Works" shall mean any work, whether in Source or Object - form, that is based on (or derived from) the Work and for which the - editorial revisions, annotations, elaborations, or other modifications - represent, as a whole, an original work of authorship. For the purposes - of this License, Derivative Works shall not include works that remain - separable from, or merely link (or bind by name) to the interfaces of, - the Work and Derivative Works thereof. - - "Contribution" shall mean any work of authorship, including - the original version of the Work and any modifications or additions - to that Work or Derivative Works thereof, that is intentionally - submitted to Licensor for inclusion in the Work by the copyright owner - or by an individual or Legal Entity authorized to submit on behalf of - the copyright owner. For the purposes of this definition, "submitted" - means any form of electronic, verbal, or written communication sent - to the Licensor or its representatives, including but not limited to - communication on electronic mailing lists, source code control systems, - and issue tracking systems that are managed by, or on behalf of, the - Licensor for the purpose of discussing and improving the Work, but - excluding communication that is conspicuously marked or otherwise - designated in writing by the copyright owner as "Not a Contribution." - - "Contributor" shall mean Licensor and any individual or Legal Entity - on behalf of whom a Contribution has been received by Licensor and - subsequently incorporated within the Work. - -2. Grant of Copyright License. Subject to the terms and conditions of - this License, each Contributor hereby grants to You a perpetual, - worldwide, non-exclusive, no-charge, royalty-free, irrevocable - copyright license to reproduce, prepare Derivative Works of, - publicly display, publicly perform, sublicense, and distribute the - Work and such Derivative Works in Source or Object form. - -3. Grant of Patent License. Subject to the terms and conditions of - this License, each Contributor hereby grants to You a perpetual, - worldwide, non-exclusive, no-charge, royalty-free, irrevocable - (except as stated in this section) patent license to make, have made, - use, offer to sell, sell, import, and otherwise transfer the Work, - where such license applies only to those patent claims licensable - by such Contributor that are necessarily infringed by their - Contribution(s) alone or by combination of their Contribution(s) - with the Work to which such Contribution(s) was submitted. If You - institute patent litigation against any entity (including a - cross-claim or counterclaim in a lawsuit) alleging that the Work - or a Contribution incorporated within the Work constitutes direct - or contributory patent infringement, then any patent licenses - granted to You under this License for that Work shall terminate - as of the date such litigation is filed. - -4. Redistribution. You may reproduce and distribute copies of the - Work or Derivative Works thereof in any medium, with or without - modifications, and in Source or Object form, provided that You - meet the following conditions: - - (a) You must give any other recipients of the Work or - Derivative Works a copy of this License; and - - (b) You must cause any modified files to carry prominent notices - stating that You changed the files; and - - (c) You must retain, in the Source form of any Derivative Works - that You distribute, all copyright, patent, trademark, and - attribution notices from the Source form of the Work, - excluding those notices that do not pertain to any part of - the Derivative Works; and - - (d) If the Work includes a "NOTICE" text file as part of its - distribution, then any Derivative Works that You distribute must - include a readable copy of the attribution notices contained - within such NOTICE file, excluding those notices that do not - pertain to any part of the Derivative Works, in at least one - of the following places: within a NOTICE text file distributed - as part of the Derivative Works; within the Source form or - documentation, if provided along with the Derivative Works; or, - within a display generated by the Derivative Works, if and - wherever such third-party notices normally appear. The contents - of the NOTICE file are for informational purposes only and - do not modify the License. You may add Your own attribution - notices within Derivative Works that You distribute, alongside - or as an addendum to the NOTICE text from the Work, provided - that such additional attribution notices cannot be construed - as modifying the License. - - You may add Your own copyright statement to Your modifications and - may provide additional or different license terms and conditions - for use, reproduction, or distribution of Your modifications, or - for any such Derivative Works as a whole, provided Your use, - reproduction, and distribution of the Work otherwise complies with - the conditions stated in this License. - -5. Submission of Contributions. Unless You explicitly state otherwise, - any Contribution intentionally submitted for inclusion in the Work - by You to the Licensor shall be under the terms and conditions of - this License, without any additional terms or conditions. - Notwithstanding the above, nothing herein shall supersede or modify - the terms of any separate license agreement you may have executed - with Licensor regarding such Contributions. - -6. Trademarks. This License does not grant permission to use the trade - names, trademarks, service marks, or product names of the Licensor, - except as required for reasonable and customary use in describing the - origin of the Work and reproducing the content of the NOTICE file. - -7. Disclaimer of Warranty. Unless required by applicable law or - agreed to in writing, Licensor provides the Work (and each - Contributor provides its Contributions) on an "AS IS" BASIS, - WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or - implied, including, without limitation, any warranties or conditions - of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A - PARTICULAR PURPOSE. You are solely responsible for determining the - appropriateness of using or redistributing the Work and assume any - risks associated with Your exercise of permissions under this License. - -8. Limitation of Liability. In no event and under no legal theory, - whether in tort (including negligence), contract, or otherwise, - unless required by applicable law (such as deliberate and grossly - negligent acts) or agreed to in writing, shall any Contributor be - liable to You for damages, including any direct, indirect, special, - incidental, or consequential damages of any character arising as a - result of this License or out of the use or inability to use the - Work (including but not limited to damages for loss of goodwill, - work stoppage, computer failure or malfunction, or any and all - other commercial damages or losses), even if such Contributor - has been advised of the possibility of such damages. - -9. Accepting Warranty or Additional Liability. While redistributing - the Work or Derivative Works thereof, You may choose to offer, - and charge a fee for, acceptance of support, warranty, indemnity, - or other liability obligations and/or rights consistent with this - License. However, in accepting such obligations, You may act only - on Your own behalf and on Your sole responsibility, not on behalf - of any other Contributor, and only if You agree to indemnify, - defend, and hold each Contributor harmless for any liability - incurred by, or claims asserted against, such Contributor by reason - of your accepting any such warranty or additional liability. - -END OF TERMS AND CONDITIONS - -APPENDIX: How to apply the Apache License to your work. - - To apply the Apache License to your work, attach the following - boilerplate notice, with the fields enclosed by brackets "[]" - replaced with your own identifying information. (Don't include - the brackets!) The text should be enclosed in the appropriate - comment syntax for the file format. We also recommend that a - file or class name and description of purpose be included on the - same "printed page" as the copyright notice for easier - identification within third-party archives. - -Copyright [yyyy] [name of copyright owner] - -Licensed 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. - --------------------------------------------------- -Library: asm v6.0 -Url: http://asm.objectweb.org -License: BSD-3-Clause - -ASM: a very small and fast Java bytecode manipulation framework -Copyright (c) 2000-2011 INRIA, France Telecom -All rights reserved. - -Redistribution and use in source and binary forms, with or without -modification, are permitted provided that the following conditions -are met: -1. Redistributions of source code must retain the above copyright - notice, this list of conditions and the following disclaimer. -2. Redistributions in binary form must reproduce the above copyright - notice, this list of conditions and the following disclaimer in the - documentation and/or other materials provided with the distribution. -3. Neither the name of the copyright holders nor the names of its - contributors may be used to endorse or promote products derived from - this software without specific prior written permission. - -THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" -AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE -IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE -ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE -LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR -CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF -SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS -INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN -CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) -ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF -THE POSSIBILITY OF SUCH DAMAGE. - --------------------------------------------------- -Library: atomic v1.1.99 -Url: http://github.com/ruby-concurrency/atomic -License: Apache-2.0 - -Apache License - -Version 2.0, January 2004 - -http://www.apache.org/licenses/ - -TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION - -1. Definitions. - -"License" shall mean the terms and conditions for use, reproduction, and distribution as -defined by Sections 1 through 9 of this document. - -"Licensor" shall mean the copyright owner or entity authorized by the copyright owner that -is granting the License. - -"Legal Entity" shall mean the union of the acting entity and all other entities that -control, are controlled by, or are under common control with that entity. For the purposes -of this definition, "control" means (i) the power, direct or indirect, to cause the -direction or management of such entity, whether by contract or otherwise, or (ii) ownership -of fifty percent (50%) or more of the outstanding shares, or (iii) beneficial ownership of -such entity. - -"You" (or "Your") shall mean an individual or Legal Entity exercising permissions granted by -this License. - -"Source" form shall mean the preferred form for making modifications, including but not -limited to software source code, documentation source, and configuration files. - -"Object" form shall mean any form resulting from mechanical transformation or translation of -a Source form, including but not limited to compiled object code, generated documentation, -and conversions to other media types. - -"Work" shall mean the work of authorship, whether in Source or Object form, made available -under the License, as indicated by a copyright notice that is included in or attached to the -work (an example is provided in the Appendix below). - -"Derivative Works" shall mean any work, whether in Source or Object form, that is based on -(or derived from) the Work and for which the editorial revisions, annotations, elaborations, -or other modifications represent, as a whole, an original work of authorship. For the -purposes of this License, Derivative Works shall not include works that remain separable -from, or merely link (or bind by name) to the interfaces of, the Work and Derivative Works -thereof. - -"Contribution" shall mean any work of authorship, including the original version of the Work -and any modifications or additions to that Work or Derivative Works thereof, that is -intentionally submitted to Licensor for inclusion in the Work by the copyright owner or by -an individual or Legal Entity authorized to submit on behalf of the copyright owner. For the -purposes of this definition, "submitted" means any form of electronic, verbal, or written -communication sent to the Licensor or its representatives, including but not limited to -communication on electronic mailing lists, source code control systems, and issue tracking -systems that are managed by, or on behalf of, the Licensor for the purpose of discussing and -improving the Work, but excluding communication that is conspicuously marked or otherwise -designated in writing by the copyright owner as "Not a Contribution." - -"Contributor" shall mean Licensor and any individual or Legal Entity on behalf of whom a -Contribution has been received by Licensor and subsequently incorporated within the Work. - -2. Grant of Copyright License. Subject to the terms and conditions of this License, each -Contributor hereby grants to You a perpetual, worldwide, non-exclusive, no-charge, -royalty-free, irrevocable copyright license to reproduce, prepare Derivative Works of, -publicly display, publicly perform, sublicense, and distribute the Work and such Derivative -Works in Source or Object form. - -3. Grant of Patent License. Subject to the terms and conditions of this License, each -Contributor hereby grants to You a perpetual, worldwide, non-exclusive, no-charge, -royalty-free, irrevocable (except as stated in this section) patent license to make, have -made, use, offer to sell, sell, import, and otherwise transfer the Work, where such license -applies only to those patent claims licensable by such Contributor that are necessarily -infringed by their Contribution(s) alone or by combination of their Contribution(s) with the -Work to which such Contribution(s) was submitted. If You institute patent litigation against -any entity (including a cross-claim or counterclaim in a lawsuit) alleging that the Work or -a Contribution incorporated within the Work constitutes direct or contributory patent -infringement, then any patent licenses granted to You under this License for that Work shall -terminate as of the date such litigation is filed. - -4. Redistribution. You may reproduce and distribute copies of the Work or Derivative Works -thereof in any medium, with or without modifications, and in Source or Object form, provided -that You meet the following conditions: - -You must give any other recipients of the Work or Derivative Works a copy of this License; -and - -You must cause any modified files to carry prominent notices stating that You changed the -files; and - -You must retain, in the Source form of any Derivative Works that You distribute, all -copyright, patent, trademark, and attribution notices from the Source form of the Work, -excluding those notices that do not pertain to any part of the Derivative Works; and - -If the Work includes a "NOTICE" text file as part of its distribution, then any Derivative -Works that You distribute must include a readable copy of the attribution notices contained -within such NOTICE file, excluding those notices that do not pertain to any part of the -Derivative Works, in at least one of the following places: within a NOTICE text file -distributed as part of the Derivative Works; within the Source form or documentation, if -provided along with the Derivative Works; or, within a display generated by the Derivative -Works, if and wherever such third-party notices normally appear. The contents of the NOTICE -file are for informational purposes only and do not modify the License. You may add Your own -attribution notices within Derivative Works that You distribute, alongside or as an addendum -to the NOTICE text from the Work, provided that such additional attribution notices cannot -be construed as modifying the License. You may add Your own copyright statement to Your -modifications and may provide additional or different license terms and conditions for use, -reproduction, or distribution of Your modifications, or for any such Derivative Works as a -whole, provided Your use, reproduction, and distribution of the Work otherwise complies with -the conditions stated in this License. - -5. Submission of Contributions. Unless You explicitly state otherwise, any Contribution -intentionally submitted for inclusion in the Work by You to the Licensor shall be under the -terms and conditions of this License, without any additional terms or conditions. -Notwithstanding the above, nothing herein shall supersede or modify the terms of any -separate license agreement you may have executed with Licensor regarding such Contributions. - -6. Trademarks. This License does not grant permission to use the trade names, trademarks, -service marks, or product names of the Licensor, except as required for reasonable and -customary use in describing the origin of the Work and reproducing the content of the NOTICE -file. - -7. Disclaimer of Warranty. Unless required by applicable law or agreed to in writing, -Licensor provides the Work (and each Contributor provides its Contributions) on an "AS IS" -BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied, including, -without limitation, any warranties or conditions of TITLE, NON-INFRINGEMENT, -MERCHANTABILITY, or FITNESS FOR A PARTICULAR PURPOSE. You are solely responsible for -determining the appropriateness of using or redistributing the Work and assume any risks -associated with Your exercise of permissions under this License. - -8. Limitation of Liability. In no event and under no legal theory, whether in tort -(including negligence), contract, or otherwise, unless required by applicable law (such as -deliberate and grossly negligent acts) or agreed to in writing, shall any Contributor be -liable to You for damages, including any direct, indirect, special, incidental, or -consequential damages of any character arising as a result of this License or out of the use -or inability to use the Work (including but not limited to damages for loss of goodwill, -work stoppage, computer failure or malfunction, or any and all other commercial damages or -losses), even if such Contributor has been advised of the possibility of such damages. - -9. Accepting Warranty or Additional Liability. While redistributing the Work or Derivative -Works thereof, You may choose to offer, and charge a fee for, acceptance of support, -warranty, indemnity, or other liability obligations and/or rights consistent with this -License. However, in accepting such obligations, You may act only on Your own behalf and on -Your sole responsibility, not on behalf of any other Contributor, and only if You agree to -indemnify, defend, and hold each Contributor harmless for any liability incurred by, or -claims asserted against, such Contributor by reason of your accepting any such warranty or -additional liability. - -END OF TERMS AND CONDITIONS - --------------------------------------------------- -Library: avl_tree v1.2.1 -Url: https://github.com/nahi/avl_tree -License: BSD-2-Clause-FreeBSD - -Copyright (c) 2012, Hiroshi Nakamura -All rights reserved. - -Redistribution and use in source and binary forms, with or without -modification, are permitted provided that the following conditions are -met: - -1. Redistributions of source code must retain the above copyright -notice, this list of conditions and the following disclaimer. - -2. Redistributions in binary form must reproduce the above copyright -notice, this list of conditions and the following disclaimer in the -documentation and/or other materials provided with the distribution. - -THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS -"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT -LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR -A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT -HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, -SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT -LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, -DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY -THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE -OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - --------------------------------------------------- -Library: awesome_print v1.8.0 -Url: https://github.com/awesome-print/awesome_print -License: MIT - -Copyright (c) 2010-2013 Michael Dvorkin -http://www.dvorkin.net -%w(mike dvorkin.net) * "@" || "twitter.com/mid" - -Permission is hereby granted, free of charge, to any person obtaining -a copy of this software and associated documentation files (the -"Software"), to deal in the Software without restriction, including -without limitation the rights to use, copy, modify, merge, publish, -distribute, sublicense, and/or sell copies of the Software, and to -permit persons to whom the Software is furnished to do so, subject to -the following conditions: - -The above copyright notice and this permission notice shall be -included in all copies or substantial portions of the Software. - -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, -EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF -MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND -NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE -LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION -OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION -WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. - --------------------------------------------------- -Library: aws-sdk-core v2.11.37 -Url: http://github.com/aws/aws-sdk-ruby -License: Apache-2.0 - -copyright 2013. amazon web services, inc. all rights reserved. - - Apache License - Version 2.0, January 2004 - http://www.apache.org/licenses/ - - TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION - - 1. Definitions. - - "License" shall mean the terms and conditions for use, reproduction, - and distribution as defined by Sections 1 through 9 of this document. - - "Licensor" shall mean the copyright owner or entity authorized by - the copyright owner that is granting the License. - - "Legal Entity" shall mean the union of the acting entity and all - other entities that control, are controlled by, or are under common - control with that entity. For the purposes of this definition, - "control" means (i) the power, direct or indirect, to cause the - direction or management of such entity, whether by contract or - otherwise, or (ii) ownership of fifty percent (50%) or more of the - outstanding shares, or (iii) beneficial ownership of such entity. - - "You" (or "Your") shall mean an individual or Legal Entity - exercising permissions granted by this License. - - "Source" form shall mean the preferred form for making modifications, - including but not limited to software source code, documentation - source, and configuration files. - - "Object" form shall mean any form resulting from mechanical - transformation or translation of a Source form, including but - not limited to compiled object code, generated documentation, - and conversions to other media types. - - "Work" shall mean the work of authorship, whether in Source or - Object form, made available under the License, as indicated by a - copyright notice that is included in or attached to the work - (an example is provided in the Appendix below). - - "Derivative Works" shall mean any work, whether in Source or Object - form, that is based on (or derived from) the Work and for which the - editorial revisions, annotations, elaborations, or other modifications - represent, as a whole, an original work of authorship. For the purposes - of this License, Derivative Works shall not include works that remain - separable from, or merely link (or bind by name) to the interfaces of, - the Work and Derivative Works thereof. - - "Contribution" shall mean any work of authorship, including - the original version of the Work and any modifications or additions - to that Work or Derivative Works thereof, that is intentionally - submitted to Licensor for inclusion in the Work by the copyright owner - or by an individual or Legal Entity authorized to submit on behalf of - the copyright owner. For the purposes of this definition, "submitted" - means any form of electronic, verbal, or written communication sent - to the Licensor or its representatives, including but not limited to - communication on electronic mailing lists, source code control systems, - and issue tracking systems that are managed by, or on behalf of, the - Licensor for the purpose of discussing and improving the Work, but - excluding communication that is conspicuously marked or otherwise - designated in writing by the copyright owner as "Not a Contribution." - - "Contributor" shall mean Licensor and any individual or Legal Entity - on behalf of whom a Contribution has been received by Licensor and - subsequently incorporated within the Work. - - 2. Grant of Copyright License. Subject to the terms and conditions of - this License, each Contributor hereby grants to You a perpetual, - worldwide, non-exclusive, no-charge, royalty-free, irrevocable - copyright license to reproduce, prepare Derivative Works of, - publicly display, publicly perform, sublicense, and distribute the - Work and such Derivative Works in Source or Object form. - - 3. Grant of Patent License. Subject to the terms and conditions of - this License, each Contributor hereby grants to You a perpetual, - worldwide, non-exclusive, no-charge, royalty-free, irrevocable - (except as stated in this section) patent license to make, have made, - use, offer to sell, sell, import, and otherwise transfer the Work, - where such license applies only to those patent claims licensable - by such Contributor that are necessarily infringed by their - Contribution(s) alone or by combination of their Contribution(s) - with the Work to which such Contribution(s) was submitted. If You - institute patent litigation against any entity (including a - cross-claim or counterclaim in a lawsuit) alleging that the Work - or a Contribution incorporated within the Work constitutes direct - or contributory patent infringement, then any patent licenses - granted to You under this License for that Work shall terminate - as of the date such litigation is filed. - - 4. Redistribution. You may reproduce and distribute copies of the - Work or Derivative Works thereof in any medium, with or without - modifications, and in Source or Object form, provided that You - meet the following conditions: - - (a) You must give any other recipients of the Work or - Derivative Works a copy of this License; and - - (b) You must cause any modified files to carry prominent notices - stating that You changed the files; and - - (c) You must retain, in the Source form of any Derivative Works - that You distribute, all copyright, patent, trademark, and - attribution notices from the Source form of the Work, - excluding those notices that do not pertain to any part of - the Derivative Works; and - - (d) If the Work includes a "NOTICE" text file as part of its - distribution, then any Derivative Works that You distribute must - include a readable copy of the attribution notices contained - within such NOTICE file, excluding those notices that do not - pertain to any part of the Derivative Works, in at least one - of the following places: within a NOTICE text file distributed - as part of the Derivative Works; within the Source form or - documentation, if provided along with the Derivative Works; or, - within a display generated by the Derivative Works, if and - wherever such third-party notices normally appear. The contents - of the NOTICE file are for informational purposes only and - do not modify the License. You may add Your own attribution - notices within Derivative Works that You distribute, alongside - or as an addendum to the NOTICE text from the Work, provided - that such additional attribution notices cannot be construed - as modifying the License. - - You may add Your own copyright statement to Your modifications and - may provide additional or different license terms and conditions - for use, reproduction, or distribution of Your modifications, or - for any such Derivative Works as a whole, provided Your use, - reproduction, and distribution of the Work otherwise complies with - the conditions stated in this License. - - 5. Submission of Contributions. Unless You explicitly state otherwise, - any Contribution intentionally submitted for inclusion in the Work - by You to the Licensor shall be under the terms and conditions of - this License, without any additional terms or conditions. - Notwithstanding the above, nothing herein shall supersede or modify - the terms of any separate license agreement you may have executed - with Licensor regarding such Contributions. - - 6. Trademarks. This License does not grant permission to use the trade - names, trademarks, service marks, or product names of the Licensor, - except as required for reasonable and customary use in describing the - origin of the Work and reproducing the content of the NOTICE file. - - 7. Disclaimer of Warranty. Unless required by applicable law or - agreed to in writing, Licensor provides the Work (and each - Contributor provides its Contributions) on an "AS IS" BASIS, - WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or - implied, including, without limitation, any warranties or conditions - of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A - PARTICULAR PURPOSE. You are solely responsible for determining the - appropriateness of using or redistributing the Work and assume any - risks associated with Your exercise of permissions under this License. - - 8. Limitation of Liability. In no event and under no legal theory, - whether in tort (including negligence), contract, or otherwise, - unless required by applicable law (such as deliberate and grossly - negligent acts) or agreed to in writing, shall any Contributor be - liable to You for damages, including any direct, indirect, special, - incidental, or consequential damages of any character arising as a - result of this License or out of the use or inability to use the - Work (including but not limited to damages for loss of goodwill, - work stoppage, computer failure or malfunction, or any and all - other commercial damages or losses), even if such Contributor - has been advised of the possibility of such damages. - - 9. Accepting Warranty or Additional Liability. While redistributing - the Work or Derivative Works thereof, You may choose to offer, - and charge a fee for, acceptance of support, warranty, indemnity, - or other liability obligations and/or rights consistent with this - License. However, in accepting such obligations, You may act only - on Your own behalf and on Your sole responsibility, not on behalf - of any other Contributor, and only if You agree to indemnify, - defend, and hold each Contributor harmless for any liability - incurred by, or claims asserted against, such Contributor by reason - of your accepting any such warranty or additional liability. - - END OF TERMS AND CONDITIONS - - APPENDIX: How to apply the Apache License to your work. - - To apply the Apache License to your work, attach the following - boilerplate notice, with the fields enclosed by brackets "[]" - replaced with your own identifying information. (Don't include - the brackets!) The text should be enclosed in the appropriate - comment syntax for the file format. We also recommend that a - file or class name and description of purpose be included on the - same "printed page" as the copyright notice for easier - identification within third-party archives. - - Copyright [yyyy] [name of copyright owner] - - Licensed 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. - --------------------------------------------------- -Library: aws-sdk-resources v2.11.37 -Url: http://github.com/aws/aws-sdk-ruby -License: Apache-2.0 - -copyright 2013. amazon web services, inc. all rights reserved. - - Apache License - Version 2.0, January 2004 - http://www.apache.org/licenses/ - - TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION - - 1. Definitions. - - "License" shall mean the terms and conditions for use, reproduction, - and distribution as defined by Sections 1 through 9 of this document. - - "Licensor" shall mean the copyright owner or entity authorized by - the copyright owner that is granting the License. - - "Legal Entity" shall mean the union of the acting entity and all - other entities that control, are controlled by, or are under common - control with that entity. For the purposes of this definition, - "control" means (i) the power, direct or indirect, to cause the - direction or management of such entity, whether by contract or - otherwise, or (ii) ownership of fifty percent (50%) or more of the - outstanding shares, or (iii) beneficial ownership of such entity. - - "You" (or "Your") shall mean an individual or Legal Entity - exercising permissions granted by this License. - - "Source" form shall mean the preferred form for making modifications, - including but not limited to software source code, documentation - source, and configuration files. - - "Object" form shall mean any form resulting from mechanical - transformation or translation of a Source form, including but - not limited to compiled object code, generated documentation, - and conversions to other media types. - - "Work" shall mean the work of authorship, whether in Source or - Object form, made available under the License, as indicated by a - copyright notice that is included in or attached to the work - (an example is provided in the Appendix below). - - "Derivative Works" shall mean any work, whether in Source or Object - form, that is based on (or derived from) the Work and for which the - editorial revisions, annotations, elaborations, or other modifications - represent, as a whole, an original work of authorship. For the purposes - of this License, Derivative Works shall not include works that remain - separable from, or merely link (or bind by name) to the interfaces of, - the Work and Derivative Works thereof. - - "Contribution" shall mean any work of authorship, including - the original version of the Work and any modifications or additions - to that Work or Derivative Works thereof, that is intentionally - submitted to Licensor for inclusion in the Work by the copyright owner - or by an individual or Legal Entity authorized to submit on behalf of - the copyright owner. For the purposes of this definition, "submitted" - means any form of electronic, verbal, or written communication sent - to the Licensor or its representatives, including but not limited to - communication on electronic mailing lists, source code control systems, - and issue tracking systems that are managed by, or on behalf of, the - Licensor for the purpose of discussing and improving the Work, but - excluding communication that is conspicuously marked or otherwise - designated in writing by the copyright owner as "Not a Contribution." - - "Contributor" shall mean Licensor and any individual or Legal Entity - on behalf of whom a Contribution has been received by Licensor and - subsequently incorporated within the Work. - - 2. Grant of Copyright License. Subject to the terms and conditions of - this License, each Contributor hereby grants to You a perpetual, - worldwide, non-exclusive, no-charge, royalty-free, irrevocable - copyright license to reproduce, prepare Derivative Works of, - publicly display, publicly perform, sublicense, and distribute the - Work and such Derivative Works in Source or Object form. - - 3. Grant of Patent License. Subject to the terms and conditions of - this License, each Contributor hereby grants to You a perpetual, - worldwide, non-exclusive, no-charge, royalty-free, irrevocable - (except as stated in this section) patent license to make, have made, - use, offer to sell, sell, import, and otherwise transfer the Work, - where such license applies only to those patent claims licensable - by such Contributor that are necessarily infringed by their - Contribution(s) alone or by combination of their Contribution(s) - with the Work to which such Contribution(s) was submitted. If You - institute patent litigation against any entity (including a - cross-claim or counterclaim in a lawsuit) alleging that the Work - or a Contribution incorporated within the Work constitutes direct - or contributory patent infringement, then any patent licenses - granted to You under this License for that Work shall terminate - as of the date such litigation is filed. - - 4. Redistribution. You may reproduce and distribute copies of the - Work or Derivative Works thereof in any medium, with or without - modifications, and in Source or Object form, provided that You - meet the following conditions: - - (a) You must give any other recipients of the Work or - Derivative Works a copy of this License; and - - (b) You must cause any modified files to carry prominent notices - stating that You changed the files; and - - (c) You must retain, in the Source form of any Derivative Works - that You distribute, all copyright, patent, trademark, and - attribution notices from the Source form of the Work, - excluding those notices that do not pertain to any part of - the Derivative Works; and - - (d) If the Work includes a "NOTICE" text file as part of its - distribution, then any Derivative Works that You distribute must - include a readable copy of the attribution notices contained - within such NOTICE file, excluding those notices that do not - pertain to any part of the Derivative Works, in at least one - of the following places: within a NOTICE text file distributed - as part of the Derivative Works; within the Source form or - documentation, if provided along with the Derivative Works; or, - within a display generated by the Derivative Works, if and - wherever such third-party notices normally appear. The contents - of the NOTICE file are for informational purposes only and - do not modify the License. You may add Your own attribution - notices within Derivative Works that You distribute, alongside - or as an addendum to the NOTICE text from the Work, provided - that such additional attribution notices cannot be construed - as modifying the License. - - You may add Your own copyright statement to Your modifications and - may provide additional or different license terms and conditions - for use, reproduction, or distribution of Your modifications, or - for any such Derivative Works as a whole, provided Your use, - reproduction, and distribution of the Work otherwise complies with - the conditions stated in this License. - - 5. Submission of Contributions. Unless You explicitly state otherwise, - any Contribution intentionally submitted for inclusion in the Work - by You to the Licensor shall be under the terms and conditions of - this License, without any additional terms or conditions. - Notwithstanding the above, nothing herein shall supersede or modify - the terms of any separate license agreement you may have executed - with Licensor regarding such Contributions. - - 6. Trademarks. This License does not grant permission to use the trade - names, trademarks, service marks, or product names of the Licensor, - except as required for reasonable and customary use in describing the - origin of the Work and reproducing the content of the NOTICE file. - - 7. Disclaimer of Warranty. Unless required by applicable law or - agreed to in writing, Licensor provides the Work (and each - Contributor provides its Contributions) on an "AS IS" BASIS, - WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or - implied, including, without limitation, any warranties or conditions - of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A - PARTICULAR PURPOSE. You are solely responsible for determining the - appropriateness of using or redistributing the Work and assume any - risks associated with Your exercise of permissions under this License. - - 8. Limitation of Liability. In no event and under no legal theory, - whether in tort (including negligence), contract, or otherwise, - unless required by applicable law (such as deliberate and grossly - negligent acts) or agreed to in writing, shall any Contributor be - liable to You for damages, including any direct, indirect, special, - incidental, or consequential damages of any character arising as a - result of this License or out of the use or inability to use the - Work (including but not limited to damages for loss of goodwill, - work stoppage, computer failure or malfunction, or any and all - other commercial damages or losses), even if such Contributor - has been advised of the possibility of such damages. - - 9. Accepting Warranty or Additional Liability. While redistributing - the Work or Derivative Works thereof, You may choose to offer, - and charge a fee for, acceptance of support, warranty, indemnity, - or other liability obligations and/or rights consistent with this - License. However, in accepting such obligations, You may act only - on Your own behalf and on Your sole responsibility, not on behalf - of any other Contributor, and only if You agree to indemnify, - defend, and hold each Contributor harmless for any liability - incurred by, or claims asserted against, such Contributor by reason - of your accepting any such warranty or additional liability. - - END OF TERMS AND CONDITIONS - - APPENDIX: How to apply the Apache License to your work. - - To apply the Apache License to your work, attach the following - boilerplate notice, with the fields enclosed by brackets "[]" - replaced with your own identifying information. (Don't include - the brackets!) The text should be enclosed in the appropriate - comment syntax for the file format. We also recommend that a - file or class name and description of purpose be included on the - same "printed page" as the copyright notice for easier - identification within third-party archives. - - Copyright [yyyy] [name of copyright owner] - - Licensed 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. - --------------------------------------------------- -Library: aws-sdk-v1 v1.67.0 -Url: http://aws.amazon.com/sdkforruby -License: Apache-2.0 - -Copyright 2011-2015 Amazon.com, Inc. or its affiliates. All Rights Reserved. - -Licensed under the Apache License, Version 2.0 (the "License"). You -may not use this file except in compliance with the License. A copy of -the License is located at - - http://aws.amazon.com/apache2.0/ - -or in the "license" file accompanying this file. This file 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. - --------------------------------------------------- -Library: aws-sdk v2.11.37 -Url: http://github.com/aws/aws-sdk-ruby -License: Apache-2.0 - -copyright 2013. amazon web services, inc. all rights reserved. - - Apache License - Version 2.0, January 2004 - http://www.apache.org/licenses/ - - TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION - - 1. Definitions. - - "License" shall mean the terms and conditions for use, reproduction, - and distribution as defined by Sections 1 through 9 of this document. - - "Licensor" shall mean the copyright owner or entity authorized by - the copyright owner that is granting the License. - - "Legal Entity" shall mean the union of the acting entity and all - other entities that control, are controlled by, or are under common - control with that entity. For the purposes of this definition, - "control" means (i) the power, direct or indirect, to cause the - direction or management of such entity, whether by contract or - otherwise, or (ii) ownership of fifty percent (50%) or more of the - outstanding shares, or (iii) beneficial ownership of such entity. - - "You" (or "Your") shall mean an individual or Legal Entity - exercising permissions granted by this License. - - "Source" form shall mean the preferred form for making modifications, - including but not limited to software source code, documentation - source, and configuration files. - - "Object" form shall mean any form resulting from mechanical - transformation or translation of a Source form, including but - not limited to compiled object code, generated documentation, - and conversions to other media types. - - "Work" shall mean the work of authorship, whether in Source or - Object form, made available under the License, as indicated by a - copyright notice that is included in or attached to the work - (an example is provided in the Appendix below). - - "Derivative Works" shall mean any work, whether in Source or Object - form, that is based on (or derived from) the Work and for which the - editorial revisions, annotations, elaborations, or other modifications - represent, as a whole, an original work of authorship. For the purposes - of this License, Derivative Works shall not include works that remain - separable from, or merely link (or bind by name) to the interfaces of, - the Work and Derivative Works thereof. - - "Contribution" shall mean any work of authorship, including - the original version of the Work and any modifications or additions - to that Work or Derivative Works thereof, that is intentionally - submitted to Licensor for inclusion in the Work by the copyright owner - or by an individual or Legal Entity authorized to submit on behalf of - the copyright owner. For the purposes of this definition, "submitted" - means any form of electronic, verbal, or written communication sent - to the Licensor or its representatives, including but not limited to - communication on electronic mailing lists, source code control systems, - and issue tracking systems that are managed by, or on behalf of, the - Licensor for the purpose of discussing and improving the Work, but - excluding communication that is conspicuously marked or otherwise - designated in writing by the copyright owner as "Not a Contribution." - - "Contributor" shall mean Licensor and any individual or Legal Entity - on behalf of whom a Contribution has been received by Licensor and - subsequently incorporated within the Work. - - 2. Grant of Copyright License. Subject to the terms and conditions of - this License, each Contributor hereby grants to You a perpetual, - worldwide, non-exclusive, no-charge, royalty-free, irrevocable - copyright license to reproduce, prepare Derivative Works of, - publicly display, publicly perform, sublicense, and distribute the - Work and such Derivative Works in Source or Object form. - - 3. Grant of Patent License. Subject to the terms and conditions of - this License, each Contributor hereby grants to You a perpetual, - worldwide, non-exclusive, no-charge, royalty-free, irrevocable - (except as stated in this section) patent license to make, have made, - use, offer to sell, sell, import, and otherwise transfer the Work, - where such license applies only to those patent claims licensable - by such Contributor that are necessarily infringed by their - Contribution(s) alone or by combination of their Contribution(s) - with the Work to which such Contribution(s) was submitted. If You - institute patent litigation against any entity (including a - cross-claim or counterclaim in a lawsuit) alleging that the Work - or a Contribution incorporated within the Work constitutes direct - or contributory patent infringement, then any patent licenses - granted to You under this License for that Work shall terminate - as of the date such litigation is filed. - - 4. Redistribution. You may reproduce and distribute copies of the - Work or Derivative Works thereof in any medium, with or without - modifications, and in Source or Object form, provided that You - meet the following conditions: - - (a) You must give any other recipients of the Work or - Derivative Works a copy of this License; and - - (b) You must cause any modified files to carry prominent notices - stating that You changed the files; and - - (c) You must retain, in the Source form of any Derivative Works - that You distribute, all copyright, patent, trademark, and - attribution notices from the Source form of the Work, - excluding those notices that do not pertain to any part of - the Derivative Works; and - - (d) If the Work includes a "NOTICE" text file as part of its - distribution, then any Derivative Works that You distribute must - include a readable copy of the attribution notices contained - within such NOTICE file, excluding those notices that do not - pertain to any part of the Derivative Works, in at least one - of the following places: within a NOTICE text file distributed - as part of the Derivative Works; within the Source form or - documentation, if provided along with the Derivative Works; or, - within a display generated by the Derivative Works, if and - wherever such third-party notices normally appear. The contents - of the NOTICE file are for informational purposes only and - do not modify the License. You may add Your own attribution - notices within Derivative Works that You distribute, alongside - or as an addendum to the NOTICE text from the Work, provided - that such additional attribution notices cannot be construed - as modifying the License. - - You may add Your own copyright statement to Your modifications and - may provide additional or different license terms and conditions - for use, reproduction, or distribution of Your modifications, or - for any such Derivative Works as a whole, provided Your use, - reproduction, and distribution of the Work otherwise complies with - the conditions stated in this License. - - 5. Submission of Contributions. Unless You explicitly state otherwise, - any Contribution intentionally submitted for inclusion in the Work - by You to the Licensor shall be under the terms and conditions of - this License, without any additional terms or conditions. - Notwithstanding the above, nothing herein shall supersede or modify - the terms of any separate license agreement you may have executed - with Licensor regarding such Contributions. - - 6. Trademarks. This License does not grant permission to use the trade - names, trademarks, service marks, or product names of the Licensor, - except as required for reasonable and customary use in describing the - origin of the Work and reproducing the content of the NOTICE file. - - 7. Disclaimer of Warranty. Unless required by applicable law or - agreed to in writing, Licensor provides the Work (and each - Contributor provides its Contributions) on an "AS IS" BASIS, - WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or - implied, including, without limitation, any warranties or conditions - of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A - PARTICULAR PURPOSE. You are solely responsible for determining the - appropriateness of using or redistributing the Work and assume any - risks associated with Your exercise of permissions under this License. - - 8. Limitation of Liability. In no event and under no legal theory, - whether in tort (including negligence), contract, or otherwise, - unless required by applicable law (such as deliberate and grossly - negligent acts) or agreed to in writing, shall any Contributor be - liable to You for damages, including any direct, indirect, special, - incidental, or consequential damages of any character arising as a - result of this License or out of the use or inability to use the - Work (including but not limited to damages for loss of goodwill, - work stoppage, computer failure or malfunction, or any and all - other commercial damages or losses), even if such Contributor - has been advised of the possibility of such damages. - - 9. Accepting Warranty or Additional Liability. While redistributing - the Work or Derivative Works thereof, You may choose to offer, - and charge a fee for, acceptance of support, warranty, indemnity, - or other liability obligations and/or rights consistent with this - License. However, in accepting such obligations, You may act only - on Your own behalf and on Your sole responsibility, not on behalf - of any other Contributor, and only if You agree to indemnify, - defend, and hold each Contributor harmless for any liability - incurred by, or claims asserted against, such Contributor by reason - of your accepting any such warranty or additional liability. - - END OF TERMS AND CONDITIONS - - APPENDIX: How to apply the Apache License to your work. - - To apply the Apache License to your work, attach the following - boilerplate notice, with the fields enclosed by brackets "[]" - replaced with your own identifying information. (Don't include - the brackets!) The text should be enclosed in the appropriate - comment syntax for the file format. We also recommend that a - file or class name and description of purpose be included on the - same "printed page" as the copyright notice for easier - identification within third-party archives. - - Copyright [yyyy] [name of copyright owner] - - Licensed 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. - --------------------------------------------------- -Library: aws-sigv4 v1.0.2 -Url: http://github.com/aws/aws-sdk-ruby -License: Apache-2.0 - -copyright 2013. amazon web services, inc. all rights reserved. - - Apache License - Version 2.0, January 2004 - http://www.apache.org/licenses/ - - TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION - - 1. Definitions. - - "License" shall mean the terms and conditions for use, reproduction, - and distribution as defined by Sections 1 through 9 of this document. - - "Licensor" shall mean the copyright owner or entity authorized by - the copyright owner that is granting the License. - - "Legal Entity" shall mean the union of the acting entity and all - other entities that control, are controlled by, or are under common - control with that entity. For the purposes of this definition, - "control" means (i) the power, direct or indirect, to cause the - direction or management of such entity, whether by contract or - otherwise, or (ii) ownership of fifty percent (50%) or more of the - outstanding shares, or (iii) beneficial ownership of such entity. - - "You" (or "Your") shall mean an individual or Legal Entity - exercising permissions granted by this License. - - "Source" form shall mean the preferred form for making modifications, - including but not limited to software source code, documentation - source, and configuration files. - - "Object" form shall mean any form resulting from mechanical - transformation or translation of a Source form, including but - not limited to compiled object code, generated documentation, - and conversions to other media types. - - "Work" shall mean the work of authorship, whether in Source or - Object form, made available under the License, as indicated by a - copyright notice that is included in or attached to the work - (an example is provided in the Appendix below). - - "Derivative Works" shall mean any work, whether in Source or Object - form, that is based on (or derived from) the Work and for which the - editorial revisions, annotations, elaborations, or other modifications - represent, as a whole, an original work of authorship. For the purposes - of this License, Derivative Works shall not include works that remain - separable from, or merely link (or bind by name) to the interfaces of, - the Work and Derivative Works thereof. - - "Contribution" shall mean any work of authorship, including - the original version of the Work and any modifications or additions - to that Work or Derivative Works thereof, that is intentionally - submitted to Licensor for inclusion in the Work by the copyright owner - or by an individual or Legal Entity authorized to submit on behalf of - the copyright owner. For the purposes of this definition, "submitted" - means any form of electronic, verbal, or written communication sent - to the Licensor or its representatives, including but not limited to - communication on electronic mailing lists, source code control systems, - and issue tracking systems that are managed by, or on behalf of, the - Licensor for the purpose of discussing and improving the Work, but - excluding communication that is conspicuously marked or otherwise - designated in writing by the copyright owner as "Not a Contribution." - - "Contributor" shall mean Licensor and any individual or Legal Entity - on behalf of whom a Contribution has been received by Licensor and - subsequently incorporated within the Work. - - 2. Grant of Copyright License. Subject to the terms and conditions of - this License, each Contributor hereby grants to You a perpetual, - worldwide, non-exclusive, no-charge, royalty-free, irrevocable - copyright license to reproduce, prepare Derivative Works of, - publicly display, publicly perform, sublicense, and distribute the - Work and such Derivative Works in Source or Object form. - - 3. Grant of Patent License. Subject to the terms and conditions of - this License, each Contributor hereby grants to You a perpetual, - worldwide, non-exclusive, no-charge, royalty-free, irrevocable - (except as stated in this section) patent license to make, have made, - use, offer to sell, sell, import, and otherwise transfer the Work, - where such license applies only to those patent claims licensable - by such Contributor that are necessarily infringed by their - Contribution(s) alone or by combination of their Contribution(s) - with the Work to which such Contribution(s) was submitted. If You - institute patent litigation against any entity (including a - cross-claim or counterclaim in a lawsuit) alleging that the Work - or a Contribution incorporated within the Work constitutes direct - or contributory patent infringement, then any patent licenses - granted to You under this License for that Work shall terminate - as of the date such litigation is filed. - - 4. Redistribution. You may reproduce and distribute copies of the - Work or Derivative Works thereof in any medium, with or without - modifications, and in Source or Object form, provided that You - meet the following conditions: - - (a) You must give any other recipients of the Work or - Derivative Works a copy of this License; and - - (b) You must cause any modified files to carry prominent notices - stating that You changed the files; and - - (c) You must retain, in the Source form of any Derivative Works - that You distribute, all copyright, patent, trademark, and - attribution notices from the Source form of the Work, - excluding those notices that do not pertain to any part of - the Derivative Works; and - - (d) If the Work includes a "NOTICE" text file as part of its - distribution, then any Derivative Works that You distribute must - include a readable copy of the attribution notices contained - within such NOTICE file, excluding those notices that do not - pertain to any part of the Derivative Works, in at least one - of the following places: within a NOTICE text file distributed - as part of the Derivative Works; within the Source form or - documentation, if provided along with the Derivative Works; or, - within a display generated by the Derivative Works, if and - wherever such third-party notices normally appear. The contents - of the NOTICE file are for informational purposes only and - do not modify the License. You may add Your own attribution - notices within Derivative Works that You distribute, alongside - or as an addendum to the NOTICE text from the Work, provided - that such additional attribution notices cannot be construed - as modifying the License. - - You may add Your own copyright statement to Your modifications and - may provide additional or different license terms and conditions - for use, reproduction, or distribution of Your modifications, or - for any such Derivative Works as a whole, provided Your use, - reproduction, and distribution of the Work otherwise complies with - the conditions stated in this License. - - 5. Submission of Contributions. Unless You explicitly state otherwise, - any Contribution intentionally submitted for inclusion in the Work - by You to the Licensor shall be under the terms and conditions of - this License, without any additional terms or conditions. - Notwithstanding the above, nothing herein shall supersede or modify - the terms of any separate license agreement you may have executed - with Licensor regarding such Contributions. - - 6. Trademarks. This License does not grant permission to use the trade - names, trademarks, service marks, or product names of the Licensor, - except as required for reasonable and customary use in describing the - origin of the Work and reproducing the content of the NOTICE file. - - 7. Disclaimer of Warranty. Unless required by applicable law or - agreed to in writing, Licensor provides the Work (and each - Contributor provides its Contributions) on an "AS IS" BASIS, - WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or - implied, including, without limitation, any warranties or conditions - of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A - PARTICULAR PURPOSE. You are solely responsible for determining the - appropriateness of using or redistributing the Work and assume any - risks associated with Your exercise of permissions under this License. - - 8. Limitation of Liability. In no event and under no legal theory, - whether in tort (including negligence), contract, or otherwise, - unless required by applicable law (such as deliberate and grossly - negligent acts) or agreed to in writing, shall any Contributor be - liable to You for damages, including any direct, indirect, special, - incidental, or consequential damages of any character arising as a - result of this License or out of the use or inability to use the - Work (including but not limited to damages for loss of goodwill, - work stoppage, computer failure or malfunction, or any and all - other commercial damages or losses), even if such Contributor - has been advised of the possibility of such damages. - - 9. Accepting Warranty or Additional Liability. While redistributing - the Work or Derivative Works thereof, You may choose to offer, - and charge a fee for, acceptance of support, warranty, indemnity, - or other liability obligations and/or rights consistent with this - License. However, in accepting such obligations, You may act only - on Your own behalf and on Your sole responsibility, not on behalf - of any other Contributor, and only if You agree to indemnify, - defend, and hold each Contributor harmless for any liability - incurred by, or claims asserted against, such Contributor by reason - of your accepting any such warranty or additional liability. - - END OF TERMS AND CONDITIONS - - APPENDIX: How to apply the Apache License to your work. - - To apply the Apache License to your work, attach the following - boilerplate notice, with the fields enclosed by brackets "[]" - replaced with your own identifying information. (Don't include - the brackets!) The text should be enclosed in the appropriate - comment syntax for the file format. We also recommend that a - file or class name and description of purpose be included on the - same "printed page" as the copyright notice for easier - identification within third-party archives. - - Copyright [yyyy] [name of copyright owner] - - Licensed 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. - --------------------------------------------------- -Library: backports v3.11.3 -Url: http://github.com/marcandre/backports -License: MIT - -Copyright (c) 2009 Marc-Andre Lafortune - -Permission is hereby granted, free of charge, to any person obtaining -a copy of this software and associated documentation files (the -"Software"), to deal in the Software without restriction, including -without limitation the rights to use, copy, modify, merge, publish, -distribute, sublicense, and/or sell copies of the Software, and to -permit persons to whom the Software is furnished to do so, subject to -the following conditions: - -The above copyright notice and this permission notice shall be -included in all copies or substantial portions of the Software. - -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, -EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF -MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND -NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE -LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION -OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION -WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. - --------------------------------------------------- -Library: bindata v2.4.3 -Url: http://github.com/dmendel/bindata -License: BSD-2-Clause - -Copyright (C) 2007-2012 Dion Mendel. All rights reserved. - -Redistribution and use in source and binary forms, with or without -modification, are permitted provided that the following conditions -are met: -1. Redistributions of source code must retain the above copyright -notice, this list of conditions and the following disclaimer. -2. Redistributions in binary form must reproduce the above copyright -notice, this list of conditions and the following disclaimer in the -documentation and/or other materials provided with the distribution. - -THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND -ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE -IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE -ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE -FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL -DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS -OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) -HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT -LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY -OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF -SUCH DAMAGE. - --------------------------------------------------- -Library: bouncycastle v -Url: https://www.bouncycastle.org -License: MIT - -Copyright (c) 2000 - 2018 The Legion of the Bouncy Castle Inc. (https://www.bouncycastle.org) - -Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: - -The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. - -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. - --------------------------------------------------- -Library: buftok v0.2.0 -Url: https://github.com/sferik/buftok -License: MIT OR Ruby|BSD-2-Clause - -Copyright (c) 2006-2013 Tony Arcieri, Martin Emde, Erik Michaels-Ober. Distributed under the [Ruby license][license]. [license]: http://www.ruby-lang.org/en/LICENSE.txt - -Ruby is copyrighted free software by Yukihiro Matsumoto . -You can redistribute it and/or modify it under either the terms of the -2-clause BSDL (see the file BSDL), or the conditions below: - - 1. You may make and give away verbatim copies of the source form of the - software without restriction, provided that you duplicate all of the - original copyright notices and associated disclaimers. - - 2. You may modify your copy of the software in any way, provided that - you do at least ONE of the following: - - a) place your modifications in the Public Domain or otherwise - make them Freely Available, such as by posting said - modifications to Usenet or an equivalent medium, or by allowing - the author to include your modifications in the software. - - b) use the modified software only within your corporation or - organization. - - c) give non-standard binaries non-standard names, with - instructions on where to get the original software distribution. - - d) make other distribution arrangements with the author. - - 3. You may distribute the software in object code or binary form, - provided that you do at least ONE of the following: - - a) distribute the binaries and library files of the software, - together with instructions (in the manual page or equivalent) - on where to get the original distribution. - - b) accompany the distribution with the machine-readable source of - the software. - - c) give non-standard binaries non-standard names, with - instructions on where to get the original software distribution. - - d) make other distribution arrangements with the author. - - 4. You may modify and include the part of the software into any other - software (possibly commercial). But some files in the distribution - are not written by the author, so that they are not under these terms. - - For the list of those files and their copying conditions, see the - file LEGAL. - - 5. The scripts and library files supplied as input to or produced as - output from the software do not automatically fall under the - copyright of the software, but belong to whomever generated them, - and may be sold commercially, and may be aggregated with this - software. - - 6. THIS SOFTWARE IS PROVIDED "AS IS" AND WITHOUT ANY EXPRESS OR - IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED - WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR - PURPOSE. - --------------------------------------------------- -Library: builder v3.2.3 -Url: http://onestepback.org -License: MIT - -Copyright (c) 2003-2012 Jim Weirich (jim.weirich@gmail.com) - -Permission is hereby granted, free of charge, to any person obtaining -a copy of this software and associated documentation files (the -"Software"), to deal in the Software without restriction, including -without limitation the rights to use, copy, modify, merge, publish, -distribute, sublicense, and/or sell copies of the Software, and to -permit persons to whom the Software is furnished to do so, subject to -the following conditions: - -The above copyright notice and this permission notice shall be -included in all copies or substantial portions of the Software. - -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, -EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF -MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND -NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE -LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION -OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION -WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. - --------------------------------------------------- -Library: bundler v1.9.10 -Url: https://bundler.io/ -License: MIT - -Portions copyright (c) 2010 Andre Arko -Portions copyright (c) 2009 Engine Yard - -MIT License - -Permission is hereby granted, free of charge, to any person obtaining -a copy of this software and associated documentation files (the -"Software"), to deal in the Software without restriction, including -without limitation the rights to use, copy, modify, merge, publish, -distribute, sublicense, and/or sell copies of the Software, and to -permit persons to whom the Software is furnished to do so, subject to -the following conditions: - -The above copyright notice and this permission notice shall be -included in all copies or substantial portions of the Software. - -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, -EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF -MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND -NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE -LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION -OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION -WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. - --------------------------------------------------- -Library: bytelist v -Url: http://github.com/jruby/bytelist -License: EPL-1.0 - -JRuby is Copyright (c) 2007-2013 The JRuby project, and is released -under a tri EPL/GPL/LGPL license. You can use it, redistribute it -and/or modify it under the terms of the: - - Eclipse Public License version 1.0 - GNU General Public License version 2 - GNU Lesser General Public License version 2.1 - -The complete text of the Eclipse Public License is as follows: - - Eclipse Public License - v 1.0 - - THE ACCOMPANYING PROGRAM IS PROVIDED UNDER THE TERMS OF THIS ECLIPSE - PUBLIC LICENSE ("AGREEMENT"). ANY USE, REPRODUCTION OR DISTRIBUTION - OF THE PROGRAM CONSTITUTES RECIPIENT'S ACCEPTANCE OF THIS AGREEMENT. - - 1. DEFINITIONS - - "Contribution" means: - - a) in the case of the initial Contributor, the initial code and - documentation distributed under this Agreement, and - - b) in the case of each subsequent Contributor: - - i) changes to the Program, and - - ii) additions to the Program; - where such changes and/or additions to the Program - originate from and are distributed by that particular - Contributor. A Contribution 'originates' from a - Contributor if it was added to the Program by such - Contributor itself or anyone acting on such - Contributor's behalf. Contributions do not include - additions to the Program which: (i) are separate modules - of software distributed in conjunction with the Program - under their own license agreement, and (ii) are not - derivative works of the Program. - - "Contributor" means any person or entity that distributes the Program. - - "Licensed Patents" mean patent claims licensable by a Contributor - which are necessarily infringed by the use or sale of its - Contribution alone or when combined with the Program. - - "Program" means the Contributions distributed in accordance with - this Agreement. - - "Recipient" means anyone who receives the Program under this - Agreement, including all Contributors. - - 2. GRANT OF RIGHTS - - a) Subject to the terms of this Agreement, each Contributor - hereby grants Recipient a non-exclusive, worldwide, - royalty-free copyright license to reproduce, prepare - derivative works of, publicly display, publicly perform, - distribute and sublicense the Contribution of such - Contributor, if any, and such derivative works, in source - code and object code form. - - b) Subject to the terms of this Agreement, each Contributor - hereby grants Recipient a non-exclusive, worldwide, - royalty-free patent license under Licensed Patents to make, - use, sell, offer to sell, import and otherwise transfer the - Contribution of such Contributor, if any, in source code and - object code form. This patent license shall apply to the - combination of the Contribution and the Program if, at the - time the Contribution is added by the Contributor, such - addition of the Contribution causes such combination to be - covered by the Licensed Patents. The patent license shall not - apply to any other combinations which include the - Contribution. No hardware per se is licensed hereunder. - - c) Recipient understands that although each Contributor grants - the licenses to its Contributions set forth herein, no - assurances are provided by any Contributor that the Program - does not infringe the patent or other intellectual property - rights of any other entity. Each Contributor disclaims any - liability to Recipient for claims brought by any other entity - based on infringement of intellectual property rights or - otherwise. As a condition to exercising the rights and - licenses granted hereunder, each Recipient hereby assumes - sole responsibility to secure any other intellectual property - rights needed, if any. For example, if a third party patent - license is required to allow Recipient to distribute the - Program, it is Recipient's responsibility to acquire that - license before distributing the Program. - - d) Each Contributor represents that to its knowledge it has - sufficient copyright rights in its Contribution, if any, to - grant the copyright license set forth in this Agreement. - - 3. REQUIREMENTS - - A Contributor may choose to distribute the Program in object code - form under its own license agreement, provided that: - - a) it complies with the terms and conditions of this Agreement; and - - b) its license agreement: - - i) effectively disclaims on behalf of all Contributors all - warranties and conditions, express and implied, including - warranties or conditions of title and non-infringement, - and implied warranties or conditions of merchantability - and fitness for a particular purpose; - - ii) effectively excludes on behalf of all Contributors all - liability for damages, including direct, indirect, - special, incidental and consequential damages, such as - lost profits; - - iii) states that any provisions which differ from this - Agreement are offered by that Contributor alone and not - by any other party; and - - iv) states that source code for the Program is available - from such Contributor, and informs licensees how to - obtain it in a reasonable manner on or through a medium - customarily used for software exchange. - - When the Program is made available in source code form: - - a) it must be made available under this Agreement; and - - b) a copy of this Agreement must be included with each copy of - the Program. - - Contributors may not remove or alter any copyright notices contained - within the Program. - - Each Contributor must identify itself as the originator of its - Contribution, if any, in a manner that reasonably allows subsequent - Recipients to identify the originator of the Contribution. - - 4. COMMERCIAL DISTRIBUTION - - Commercial distributors of software may accept certain - responsibilities with respect to end users, business partners and - the like. While this license is intended to facilitate the - commercial use of the Program, the Contributor who includes the - Program in a commercial product offering should do so in a manner - which does not create potential liability for other Contributors. - Therefore, if a Contributor includes the Program in a commercial - product offering, such Contributor ("Commercial Contributor") hereby - agrees to defend and indemnify every other Contributor ("Indemnified - Contributor") against any losses, damages and costs (collectively - "Losses") arising from claims, lawsuits and other legal actions - brought by a third party against the Indemnified Contributor to the - extent caused by the acts or omissions of such Commercial - Contributor in connection with its distribution of the Program in a - commercial product offering. The obligations in this section do not - apply to any claims or Losses relating to any actual or alleged - intellectual property infringement. In order to qualify, an - Indemnified Contributor must: a) promptly notify the Commercial - Contributor in writing of such claim, and b) allow the Commercial - Contributor to control, and cooperate with the Commercial - Contributor in, the defense and any related settlement negotiations. - The Indemnified Contributor may participate in any such claim at its - own expense. - - For example, a Contributor might include the Program in a commercial - product offering, Product X. That Contributor is then a Commercial - Contributor. If that Commercial Contributor then makes performance - claims, or offers warranties related to Product X, those performance - claims and warranties are such Commercial Contributor's - responsibility alone. Under this section, the Commercial Contributor - would have to defend claims against the other Contributors related - to those performance claims and warranties, and if a court requires - any other Contributor to pay any damages as a result, the Commercial - Contributor must pay those damages. - - 5. NO WARRANTY - - EXCEPT AS EXPRESSLY SET FORTH IN THIS AGREEMENT, THE PROGRAM IS - PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF - ANY KIND, EITHER EXPRESS OR IMPLIED INCLUDING, WITHOUT LIMITATION, - ANY WARRANTIES OR CONDITIONS OF TITLE, NON-INFRINGEMENT, - MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE. Each Recipient - is solely responsible for determining the appropriateness of using - and distributing the Program and assumes all risks associated with - its exercise of rights under this Agreement , including but not - limited to the risks and costs of program errors, compliance with - applicable laws, damage to or loss of data, programs or equipment, - and unavailability or interruption of operations. - - 6. DISCLAIMER OF LIABILITY - - EXCEPT AS EXPRESSLY SET FORTH IN THIS AGREEMENT, NEITHER RECIPIENT - NOR ANY CONTRIBUTORS SHALL HAVE ANY LIABILITY FOR ANY DIRECT, - INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES - (INCLUDING WITHOUT LIMITATION LOST PROFITS), HOWEVER CAUSED AND ON - ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR - TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF - THE USE OR DISTRIBUTION OF THE PROGRAM OR THE EXERCISE OF ANY RIGHTS - GRANTED HEREUNDER, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH - DAMAGES. - - 7. GENERAL - - If any provision of this Agreement is invalid or unenforceable under - applicable law, it shall not affect the validity or enforceability - of the remainder of the terms of this Agreement, and without further - action by the parties hereto, such provision shall be reformed to - the minimum extent necessary to make such provision valid and - enforceable. - - If Recipient institutes patent litigation against any entity - (including a cross-claim or counterclaim in a lawsuit) alleging that - the Program itself (excluding combinations of the Program with other - software or hardware) infringes such Recipient's patent(s), then - such Recipient's rights granted under Section 2(b) shall terminate - as of the date such litigation is filed. - - All Recipient's rights under this Agreement shall terminate if it - fails to comply with any of the material terms or conditions of this - Agreement and does not cure such failure in a reasonable period of - time after becoming aware of such noncompliance. If all Recipient's - rights under this Agreement terminate, Recipient agrees to cease use - and distribution of the Program as soon as reasonably practicable. - However, Recipient's obligations under this Agreement and any - licenses granted by Recipient relating to the Program shall continue - and survive. - - Everyone is permitted to copy and distribute copies of this - Agreement, but in order to avoid inconsistency the Agreement is - copyrighted and may only be modified in the following manner. The - Agreement Steward reserves the right to publish new versions - (including revisions) of this Agreement from time to time. No one - other than the Agreement Steward has the right to modify this - Agreement. The Eclipse Foundation is the initial Agreement Steward. - The Eclipse Foundation may assign the responsibility to serve as the - Agreement Steward to a suitable separate entity. Each new version of - the Agreement will be given a distinguishing version number. The - Program (including Contributions) may always be distributed subject - to the version of the Agreement under which it was received. In - addition, after a new version of the Agreement is published, - Contributor may elect to distribute the Program (including its - Contributions) under the new version. Except as expressly stated in - Sections 2(a) and 2(b) above, Recipient receives no rights or - licenses to the intellectual property of any Contributor under this - Agreement, whether expressly, by implication, estoppel or otherwise. - All rights in the Program not expressly granted under this Agreement - are reserved. - - This Agreement is governed by the laws of the State of New York and - the intellectual property laws of the United States of America. No - party to this Agreement will bring a legal action under this - Agreement more than one year after the cause of action arose. Each - party waives its rights to a jury trial in any resulting litigation. - -The complete text of the Common Public License is as follows: - - Common Public License - v 1.0 - - THE ACCOMPANYING PROGRAM IS PROVIDED UNDER THE TERMS OF THIS COMMON - PUBLIC LICENSE ("AGREEMENT"). ANY USE, REPRODUCTION OR DISTRIBUTION OF - THE PROGRAM CONSTITUTES RECIPIENT'S ACCEPTANCE OF THIS AGREEMENT. - - 1. DEFINITIONS - - "Contribution" means: - - a) in the case of the initial Contributor, the initial code and - documentation distributed under this Agreement, and - - b) in the case of each subsequent Contributor: - - i) changes to the Program, and - - ii) additions to the Program; - - where such changes and/or additions to the Program originate - from and are distributed by that particular Contributor. A - Contribution 'originates' from a Contributor if it was added to the - Program by such Contributor itself or anyone acting on such - Contributor's behalf. Contributions do not include additions to the - Program which: (i) are separate modules of software distributed in - conjunction with the Program under their own license agreement, - and (ii) are not derivative works of the Program. - - "Contributor" means any person or entity that distributes the Program. - - "Licensed Patents " mean patent claims licensable by a Contributor - which are necessarily infringed by the use or sale of its Contribution - alone or when combined with the Program. - - "Program" means the Contributions distributed in accordance with this Agreement. - - "Recipient" means anyone who receives the Program under this - Agreement, including all Contributors. - - 2. GRANT OF RIGHTS - - a) Subject to the terms of this Agreement, each Contributor - hereby grants Recipient a non-exclusive, worldwide, royalty-free - copyright license to reproduce, prepare derivative works of, publicly - display, publicly perform, distribute and sublicense the Contribution - of such Contributor, if any, and such derivative works, in source code - and object code form. - - b) Subject to the terms of this Agreement, each Contributor - hereby grants Recipient a non-exclusive, worldwide, royalty-free - patent license under Licensed Patents to make, use, sell, offer to - sell, import and otherwise transfer the Contribution of such - Contributor, if any, in source code and object code form. This patent - license shall apply to the combination of the Contribution and the - Program if, at the time the Contribution is added by the Contributor, - such addition of the Contribution causes such combination to be - covered by the Licensed Patents. The patent license shall not apply to - any other combinations which include the Contribution. No hardware per - se is licensed hereunder. - - c) Recipient understands that although each Contributor grants - the licenses to its Contributions set forth herein, no assurances are - provided by any Contributor that the Program does not infringe the - patent or other intellectual property rights of any other entity. Each - Contributor disclaims any liability to Recipient for claims brought by - any other entity based on infringement of intellectual property rights - or otherwise. As a condition to exercising the rights and licenses - granted hereunder, each Recipient hereby assumes sole responsibility - to secure any other intellectual property rights needed, if any. For - example, if a third party patent license is required to allow - Recipient to distribute the Program, it is Recipient's responsibility - to acquire that license before distributing the Program. - - d) Each Contributor represents that to its knowledge it has - sufficient copyright rights in its Contribution, if any, to grant the - copyright license set forth in this Agreement. - - 3. REQUIREMENTS - - A Contributor may choose to distribute the Program in object code form - under its own license agreement, provided that: - - a) it complies with the terms and conditions of this Agreement; - and - - b) its license agreement: - - i) effectively disclaims on behalf of all Contributors all - warranties and conditions, express and implied, including warranties - or conditions of title and non-infringement, and implied warranties or - conditions of merchantability and fitness for a particular purpose; - - ii) effectively excludes on behalf of all Contributors all - liability for damages, including direct, indirect, special, incidental - and consequential damages, such as lost profits; - - iii) states that any provisions which differ from this Agreement - are offered by that Contributor alone and not by any other party; and - - iv) states that source code for the Program is available from - such Contributor, and informs licensees how to obtain it in a - reasonable manner on or through a medium customarily used for software - exchange. - - When the Program is made available in source code form: - - a) it must be made available under this Agreement; and - - b) a copy of this Agreement must be included with each copy of - the Program. - - Contributors may not remove or alter any copyright notices contained - within the Program. - - Each Contributor must identify itself as the originator of its - Contribution, if any, in a manner that reasonably allows subsequent - Recipients to identify the originator of the Contribution. - - 4. COMMERCIAL DISTRIBUTION - - Commercial distributors of software may accept certain - responsibilities with respect to end users, business partners and the - like. While this license is intended to facilitate the commercial use - of the Program, the Contributor who includes the Program in a - commercial product offering should do so in a manner which does not - create potential liability for other Contributors. Therefore, if a - Contributor includes the Program in a commercial product offering, - such Contributor ("Commercial Contributor") hereby agrees to defend - and indemnify every other Contributor ("Indemnified Contributor") - against any losses, damages and costs (collectively "Losses") arising - from claims, lawsuits and other legal actions brought by a third party - against the Indemnified Contributor to the extent caused by the acts - or omissions of such Commercial Contributor in connection with its - distribution of the Program in a commercial product offering. The - obligations in this section do not apply to any claims or Losses - relating to any actual or alleged intellectual property - infringement. In order to qualify, an Indemnified Contributor must: a) - promptly notify the Commercial Contributor in writing of such claim, - and b) allow the Commercial Contributor to control, and cooperate with - the Commercial Contributor in, the defense and any related settlement - negotiations. The Indemnified Contributor may participate in any such - claim at its own expense. - - For example, a Contributor might include the Program in a commercial - product offering, Product X. That Contributor is then a Commercial - Contributor. If that Commercial Contributor then makes performance - claims, or offers warranties related to Product X, those performance - claims and warranties are such Commercial Contributor's responsibility - alone. Under this section, the Commercial Contributor would have to - defend claims against the other Contributors related to those - performance claims and warranties, and if a court requires any other - Contributor to pay any damages as a result, the Commercial Contributor - must pay those damages. - - 5. NO WARRANTY - - EXCEPT AS EXPRESSLY SET FORTH IN THIS AGREEMENT, THE PROGRAM IS - PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - KIND, EITHER EXPRESS OR IMPLIED INCLUDING, WITHOUT LIMITATION, ANY - WARRANTIES OR CONDITIONS OF TITLE, NON-INFRINGEMENT, MERCHANTABILITY - OR FITNESS FOR A PARTICULAR PURPOSE. Each Recipient is solely - responsible for determining the appropriateness of using and - distributing the Program and assumes all risks associated with its - exercise of rights under this Agreement, including but not limited to - the risks and costs of program errors, compliance with applicable - laws, damage to or loss of data, programs or equipment, and - unavailability or interruption of operations. - - 6. DISCLAIMER OF LIABILITY - - EXCEPT AS EXPRESSLY SET FORTH IN THIS AGREEMENT, NEITHER RECIPIENT NOR - ANY CONTRIBUTORS SHALL HAVE ANY LIABILITY FOR ANY DIRECT, INDIRECT, - INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING - WITHOUT LIMITATION LOST PROFITS), HOWEVER CAUSED AND ON ANY THEORY OF - LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING - NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OR - DISTRIBUTION OF THE PROGRAM OR THE EXERCISE OF ANY RIGHTS GRANTED - HEREUNDER, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGES. - - 7. GENERAL - - If any provision of this Agreement is invalid or unenforceable under - applicable law, it shall not affect the validity or enforceability of - the remainder of the terms of this Agreement, and without further - action by the parties hereto, such provision shall be reformed to the - minimum extent necessary to make such provision valid and enforceable. - - If Recipient institutes patent litigation against a Contributor with - respect to a patent applicable to software (including a cross-claim or - counterclaim in a lawsuit), then any patent licenses granted by that - Contributor to such Recipient under this Agreement shall terminate as - of the date such litigation is filed. In addition, if Recipient - institutes patent litigation against any entity (including a - cross-claim or counterclaim in a lawsuit) alleging that the Program - itself (excluding combinations of the Program with other software or - hardware) infringes such Recipient's patent(s), then such Recipient's - rights granted under Section 2(b) shall terminate as of the date such - litigation is filed. - - All Recipient's rights under this Agreement shall terminate if it - fails to comply with any of the material terms or conditions of this - Agreement and does not cure such failure in a reasonable period of - time after becoming aware of such noncompliance. If all Recipient's - rights under this Agreement terminate, Recipient agrees to cease use - and distribution of the Program as soon as reasonably - practicable. However, Recipient's obligations under this Agreement and - any licenses granted by Recipient relating to the Program shall - continue and survive. - - Everyone is permitted to copy and distribute copies of this Agreement, - but in order to avoid inconsistency the Agreement is copyrighted and - may only be modified in the following manner. The Agreement Steward - reserves the right to publish new versions (including revisions) of - this Agreement from time to time. No one other than the Agreement - Steward has the right to modify this Agreement. IBM is the initial - Agreement Steward. IBM may assign the responsibility to serve as the - Agreement Steward to a suitable separate entity. Each new version of - the Agreement will be given a distinguishing version number. The - Program (including Contributions) may always be distributed subject to - the version of the Agreement under which it was received. In addition, - after a new version of the Agreement is published, Contributor may - elect to distribute the Program (including its Contributions) under - the new version. Except as expressly stated in Sections 2(a) and 2(b) - above, Recipient receives no rights or licenses to the intellectual - property of any Contributor under this Agreement, whether expressly, - by implication, estoppel or otherwise. All rights in the Program not - expressly granted under this Agreement are reserved. - - This Agreement is governed by the laws of the State of New York and - the intellectual property laws of the United States of America. No - party to this Agreement will bring a legal action under this Agreement - more than one year after the cause of action arose. Each party waives - its rights to a jury trial in any resulting litigation. - -The complete text of the GNU General Public License v2 is as follows: - - GNU GENERAL PUBLIC LICENSE - Version 2, June 1991 - - Copyright (C) 1989, 1991 Free Software Foundation, Inc. - 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - Everyone is permitted to copy and distribute verbatim copies - of this license document, but changing it is not allowed. - - Preamble - - The licenses for most software are designed to take away your - freedom to share and change it. By contrast, the GNU General Public - License is intended to guarantee your freedom to share and change free - software--to make sure the software is free for all its users. This - General Public License applies to most of the Free Software - Foundation's software and to any other program whose authors commit to - using it. (Some other Free Software Foundation software is covered by - the GNU Library General Public License instead.) You can apply it to - your programs, too. - - When we speak of free software, we are referring to freedom, not - price. Our General Public Licenses are designed to make sure that you - have the freedom to distribute copies of free software (and charge for - this service if you wish), that you receive source code or can get it - if you want it, that you can change the software or use pieces of it - in new free programs; and that you know you can do these things. - - To protect your rights, we need to make restrictions that forbid - anyone to deny you these rights or to ask you to surrender the rights. - These restrictions translate to certain responsibilities for you if you - distribute copies of the software, or if you modify it. - - For example, if you distribute copies of such a program, whether - gratis or for a fee, you must give the recipients all the rights that - you have. You must make sure that they, too, receive or can get the - source code. And you must show them these terms so they know their - rights. - - We protect your rights with two steps: (1) copyright the software, and - (2) offer you this license which gives you legal permission to copy, - distribute and/or modify the software. - - Also, for each author's protection and ours, we want to make certain - that everyone understands that there is no warranty for this free - software. If the software is modified by someone else and passed on, we - want its recipients to know that what they have is not the original, so - that any problems introduced by others will not reflect on the original - authors' reputations. - - Finally, any free program is threatened constantly by software - patents. We wish to avoid the danger that redistributors of a free - program will individually obtain patent licenses, in effect making the - program proprietary. To prevent this, we have made it clear that any - patent must be licensed for everyone's free use or not licensed at all. - - The precise terms and conditions for copying, distribution and - modification follow. - - GNU GENERAL PUBLIC LICENSE - TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION - - 0. This License applies to any program or other work which contains - a notice placed by the copyright holder saying it may be distributed - under the terms of this General Public License. The "Program", below, - refers to any such program or work, and a "work based on the Program" - means either the Program or any derivative work under copyright law: - that is to say, a work containing the Program or a portion of it, - either verbatim or with modifications and/or translated into another - language. (Hereinafter, translation is included without limitation in - the term "modification".) Each licensee is addressed as "you". - - Activities other than copying, distribution and modification are not - covered by this License; they are outside its scope. The act of - running the Program is not restricted, and the output from the Program - is covered only if its contents constitute a work based on the - Program (independent of having been made by running the Program). - Whether that is true depends on what the Program does. - - 1. You may copy and distribute verbatim copies of the Program's - source code as you receive it, in any medium, provided that you - conspicuously and appropriately publish on each copy an appropriate - copyright notice and disclaimer of warranty; keep intact all the - notices that refer to this License and to the absence of any warranty; - and give any other recipients of the Program a copy of this License - along with the Program. - - You may charge a fee for the physical act of transferring a copy, and - you may at your option offer warranty protection in exchange for a fee. - - 2. You may modify your copy or copies of the Program or any portion - of it, thus forming a work based on the Program, and copy and - distribute such modifications or work under the terms of Section 1 - above, provided that you also meet all of these conditions: - - a) You must cause the modified files to carry prominent notices - stating that you changed the files and the date of any change. - - b) You must cause any work that you distribute or publish, that in - whole or in part contains or is derived from the Program or any - part thereof, to be licensed as a whole at no charge to all third - parties under the terms of this License. - - c) If the modified program normally reads commands interactively - when run, you must cause it, when started running for such - interactive use in the most ordinary way, to print or display an - announcement including an appropriate copyright notice and a - notice that there is no warranty (or else, saying that you provide - a warranty) and that users may redistribute the program under - these conditions, and telling the user how to view a copy of this - License. (Exception: if the Program itself is interactive but - does not normally print such an announcement, your work based on - the Program is not required to print an announcement.) - - These requirements apply to the modified work as a whole. If - identifiable sections of that work are not derived from the Program, - and can be reasonably considered independent and separate works in - themselves, then this License, and its terms, do not apply to those - sections when you distribute them as separate works. But when you - distribute the same sections as part of a whole which is a work based - on the Program, the distribution of the whole must be on the terms of - this License, whose permissions for other licensees extend to the - entire whole, and thus to each and every part regardless of who wrote it. - - Thus, it is not the intent of this section to claim rights or contest - your rights to work written entirely by you; rather, the intent is to - exercise the right to control the distribution of derivative or - collective works based on the Program. - - In addition, mere aggregation of another work not based on the Program - with the Program (or with a work based on the Program) on a volume of - a storage or distribution medium does not bring the other work under - the scope of this License. - - 3. You may copy and distribute the Program (or a work based on it, - under Section 2) in object code or executable form under the terms of - Sections 1 and 2 above provided that you also do one of the following: - - a) Accompany it with the complete corresponding machine-readable - source code, which must be distributed under the terms of Sections - 1 and 2 above on a medium customarily used for software interchange; or, - - b) Accompany it with a written offer, valid for at least three - years, to give any third party, for a charge no more than your - cost of physically performing source distribution, a complete - machine-readable copy of the corresponding source code, to be - distributed under the terms of Sections 1 and 2 above on a medium - customarily used for software interchange; or, - - c) Accompany it with the information you received as to the offer - to distribute corresponding source code. (This alternative is - allowed only for noncommercial distribution and only if you - received the program in object code or executable form with such - an offer, in accord with Subsection b above.) - - The source code for a work means the preferred form of the work for - making modifications to it. For an executable work, complete source - code means all the source code for all modules it contains, plus any - associated interface definition files, plus the scripts used to - control compilation and installation of the executable. However, as a - special exception, the source code distributed need not include - anything that is normally distributed (in either source or binary - form) with the major components (compiler, kernel, and so on) of the - operating system on which the executable runs, unless that component - itself accompanies the executable. - - If distribution of executable or object code is made by offering - access to copy from a designated place, then offering equivalent - access to copy the source code from the same place counts as - distribution of the source code, even though third parties are not - compelled to copy the source along with the object code. - - 4. You may not copy, modify, sublicense, or distribute the Program - except as expressly provided under this License. Any attempt - otherwise to copy, modify, sublicense or distribute the Program is - void, and will automatically terminate your rights under this License. - However, parties who have received copies, or rights, from you under - this License will not have their licenses terminated so long as such - parties remain in full compliance. - - 5. You are not required to accept this License, since you have not - signed it. However, nothing else grants you permission to modify or - distribute the Program or its derivative works. These actions are - prohibited by law if you do not accept this License. Therefore, by - modifying or distributing the Program (or any work based on the - Program), you indicate your acceptance of this License to do so, and - all its terms and conditions for copying, distributing or modifying - the Program or works based on it. - - 6. Each time you redistribute the Program (or any work based on the - Program), the recipient automatically receives a license from the - original licensor to copy, distribute or modify the Program subject to - these terms and conditions. You may not impose any further - restrictions on the recipients' exercise of the rights granted herein. - You are not responsible for enforcing compliance by third parties to - this License. - - 7. If, as a consequence of a court judgment or allegation of patent - infringement or for any other reason (not limited to patent issues), - conditions are imposed on you (whether by court order, agreement or - otherwise) that contradict the conditions of this License, they do not - excuse you from the conditions of this License. If you cannot - distribute so as to satisfy simultaneously your obligations under this - License and any other pertinent obligations, then as a consequence you - may not distribute the Program at all. For example, if a patent - license would not permit royalty-free redistribution of the Program by - all those who receive copies directly or indirectly through you, then - the only way you could satisfy both it and this License would be to - refrain entirely from distribution of the Program. - - If any portion of this section is held invalid or unenforceable under - any particular circumstance, the balance of the section is intended to - apply and the section as a whole is intended to apply in other - circumstances. - - It is not the purpose of this section to induce you to infringe any - patents or other property right claims or to contest validity of any - such claims; this section has the sole purpose of protecting the - integrity of the free software distribution system, which is - implemented by public license practices. Many people have made - generous contributions to the wide range of software distributed - through that system in reliance on consistent application of that - system; it is up to the author/donor to decide if he or she is willing - to distribute software through any other system and a licensee cannot - impose that choice. - - This section is intended to make thoroughly clear what is believed to - be a consequence of the rest of this License. - - 8. If the distribution and/or use of the Program is restricted in - certain countries either by patents or by copyrighted interfaces, the - original copyright holder who places the Program under this License - may add an explicit geographical distribution limitation excluding - those countries, so that distribution is permitted only in or among - countries not thus excluded. In such case, this License incorporates - the limitation as if written in the body of this License. - - 9. The Free Software Foundation may publish revised and/or new versions - of the General Public License from time to time. Such new versions will - be similar in spirit to the present version, but may differ in detail to - address new problems or concerns. - - Each version is given a distinguishing version number. If the Program - specifies a version number of this License which applies to it and "any - later version", you have the option of following the terms and conditions - either of that version or of any later version published by the Free - Software Foundation. If the Program does not specify a version number of - this License, you may choose any version ever published by the Free Software - Foundation. - - 10. If you wish to incorporate parts of the Program into other free - programs whose distribution conditions are different, write to the author - to ask for permission. For software which is copyrighted by the Free - Software Foundation, write to the Free Software Foundation; we sometimes - make exceptions for this. Our decision will be guided by the two goals - of preserving the free status of all derivatives of our free software and - of promoting the sharing and reuse of software generally. - - NO WARRANTY - - 11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY - FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN - OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES - PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED - OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF - MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS - TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE - PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING, - REPAIR OR CORRECTION. - - 12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING - WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR - REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, - INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING - OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED - TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY - YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER - PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE - POSSIBILITY OF SUCH DAMAGES. - - END OF TERMS AND CONDITIONS - -The complete text of the GNU Lesser General Public License 2.1 is as follows: - - GNU LESSER GENERAL PUBLIC LICENSE - Version 2.1, February 1999 - - Copyright (C) 1991, 1999 Free Software Foundation, Inc. - 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - Everyone is permitted to copy and distribute verbatim copies - of this license document, but changing it is not allowed. - - [This is the first released version of the Lesser GPL. It also counts - as the successor of the GNU Library Public License, version 2, hence - the version number 2.1.] - - Preamble - - The licenses for most software are designed to take away your - freedom to share and change it. By contrast, the GNU General Public - Licenses are intended to guarantee your freedom to share and change - free software--to make sure the software is free for all its users. - - This license, the Lesser General Public License, applies to some - specially designated software packages--typically libraries--of the - Free Software Foundation and other authors who decide to use it. You - can use it too, but we suggest you first think carefully about whether - this license or the ordinary General Public License is the better - strategy to use in any particular case, based on the explanations below. - - When we speak of free software, we are referring to freedom of use, - not price. Our General Public Licenses are designed to make sure that - you have the freedom to distribute copies of free software (and charge - for this service if you wish); that you receive source code or can get - it if you want it; that you can change the software and use pieces of - it in new free programs; and that you are informed that you can do - these things. - - To protect your rights, we need to make restrictions that forbid - distributors to deny you these rights or to ask you to surrender these - rights. These restrictions translate to certain responsibilities for - you if you distribute copies of the library or if you modify it. - - For example, if you distribute copies of the library, whether gratis - or for a fee, you must give the recipients all the rights that we gave - you. You must make sure that they, too, receive or can get the source - code. If you link other code with the library, you must provide - complete object files to the recipients, so that they can relink them - with the library after making changes to the library and recompiling - it. And you must show them these terms so they know their rights. - - We protect your rights with a two-step method: (1) we copyright the - library, and (2) we offer you this license, which gives you legal - permission to copy, distribute and/or modify the library. - - To protect each distributor, we want to make it very clear that - there is no warranty for the free library. Also, if the library is - modified by someone else and passed on, the recipients should know - that what they have is not the original version, so that the original - author's reputation will not be affected by problems that might be - introduced by others. - - Finally, software patents pose a constant threat to the existence of - any free program. We wish to make sure that a company cannot - effectively restrict the users of a free program by obtaining a - restrictive license from a patent holder. Therefore, we insist that - any patent license obtained for a version of the library must be - consistent with the full freedom of use specified in this license. - - Most GNU software, including some libraries, is covered by the - ordinary GNU General Public License. This license, the GNU Lesser - General Public License, applies to certain designated libraries, and - is quite different from the ordinary General Public License. We use - this license for certain libraries in order to permit linking those - libraries into non-free programs. - - When a program is linked with a library, whether statically or using - a shared library, the combination of the two is legally speaking a - combined work, a derivative of the original library. The ordinary - General Public License therefore permits such linking only if the - entire combination fits its criteria of freedom. The Lesser General - Public License permits more lax criteria for linking other code with - the library. - - We call this license the "Lesser" General Public License because it - does Less to protect the user's freedom than the ordinary General - Public License. It also provides other free software developers Less - of an advantage over competing non-free programs. These disadvantages - are the reason we use the ordinary General Public License for many - libraries. However, the Lesser license provides advantages in certain - special circumstances. - - For example, on rare occasions, there may be a special need to - encourage the widest possible use of a certain library, so that it becomes - a de-facto standard. To achieve this, non-free programs must be - allowed to use the library. A more frequent case is that a free - library does the same job as widely used non-free libraries. In this - case, there is little to gain by limiting the free library to free - software only, so we use the Lesser General Public License. - - In other cases, permission to use a particular library in non-free - programs enables a greater number of people to use a large body of - free software. For example, permission to use the GNU C Library in - non-free programs enables many more people to use the whole GNU - operating system, as well as its variant, the GNU/Linux operating - system. - - Although the Lesser General Public License is Less protective of the - users' freedom, it does ensure that the user of a program that is - linked with the Library has the freedom and the wherewithal to run - that program using a modified version of the Library. - - The precise terms and conditions for copying, distribution and - modification follow. Pay close attention to the difference between a - "work based on the library" and a "work that uses the library". The - former contains code derived from the library, whereas the latter must - be combined with the library in order to run. - - GNU LESSER GENERAL PUBLIC LICENSE - TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION - - 0. This License Agreement applies to any software library or other - program which contains a notice placed by the copyright holder or - other authorized party saying it may be distributed under the terms of - this Lesser General Public License (also called "this License"). - Each licensee is addressed as "you". - - A "library" means a collection of software functions and/or data - prepared so as to be conveniently linked with application programs - (which use some of those functions and data) to form executables. - - The "Library", below, refers to any such software library or work - which has been distributed under these terms. A "work based on the - Library" means either the Library or any derivative work under - copyright law: that is to say, a work containing the Library or a - portion of it, either verbatim or with modifications and/or translated - straightforwardly into another language. (Hereinafter, translation is - included without limitation in the term "modification".) - - "Source code" for a work means the preferred form of the work for - making modifications to it. For a library, complete source code means - all the source code for all modules it contains, plus any associated - interface definition files, plus the scripts used to control compilation - and installation of the library. - - Activities other than copying, distribution and modification are not - covered by this License; they are outside its scope. The act of - running a program using the Library is not restricted, and output from - such a program is covered only if its contents constitute a work based - on the Library (independent of the use of the Library in a tool for - writing it). Whether that is true depends on what the Library does - and what the program that uses the Library does. - - 1. You may copy and distribute verbatim copies of the Library's - complete source code as you receive it, in any medium, provided that - you conspicuously and appropriately publish on each copy an - appropriate copyright notice and disclaimer of warranty; keep intact - all the notices that refer to this License and to the absence of any - warranty; and distribute a copy of this License along with the - Library. - - You may charge a fee for the physical act of transferring a copy, - and you may at your option offer warranty protection in exchange for a - fee. - - 2. You may modify your copy or copies of the Library or any portion - of it, thus forming a work based on the Library, and copy and - distribute such modifications or work under the terms of Section 1 - above, provided that you also meet all of these conditions: - - a) The modified work must itself be a software library. - - b) You must cause the files modified to carry prominent notices - stating that you changed the files and the date of any change. - - c) You must cause the whole of the work to be licensed at no - charge to all third parties under the terms of this License. - - d) If a facility in the modified Library refers to a function or a - table of data to be supplied by an application program that uses - the facility, other than as an argument passed when the facility - is invoked, then you must make a good faith effort to ensure that, - in the event an application does not supply such function or - table, the facility still operates, and performs whatever part of - its purpose remains meaningful. - - (For example, a function in a library to compute square roots has - a purpose that is entirely well-defined independent of the - application. Therefore, Subsection 2d requires that any - application-supplied function or table used by this function must - be optional: if the application does not supply it, the square - root function must still compute square roots.) - - These requirements apply to the modified work as a whole. If - identifiable sections of that work are not derived from the Library, - and can be reasonably considered independent and separate works in - themselves, then this License, and its terms, do not apply to those - sections when you distribute them as separate works. But when you - distribute the same sections as part of a whole which is a work based - on the Library, the distribution of the whole must be on the terms of - this License, whose permissions for other licensees extend to the - entire whole, and thus to each and every part regardless of who wrote - it. - - Thus, it is not the intent of this section to claim rights or contest - your rights to work written entirely by you; rather, the intent is to - exercise the right to control the distribution of derivative or - collective works based on the Library. - - In addition, mere aggregation of another work not based on the Library - with the Library (or with a work based on the Library) on a volume of - a storage or distribution medium does not bring the other work under - the scope of this License. - - 3. You may opt to apply the terms of the ordinary GNU General Public - License instead of this License to a given copy of the Library. To do - this, you must alter all the notices that refer to this License, so - that they refer to the ordinary GNU General Public License, version 2, - instead of to this License. (If a newer version than version 2 of the - ordinary GNU General Public License has appeared, then you can specify - that version instead if you wish.) Do not make any other change in - these notices. - - Once this change is made in a given copy, it is irreversible for - that copy, so the ordinary GNU General Public License applies to all - subsequent copies and derivative works made from that copy. - - This option is useful when you wish to copy part of the code of - the Library into a program that is not a library. - - 4. You may copy and distribute the Library (or a portion or - derivative of it, under Section 2) in object code or executable form - under the terms of Sections 1 and 2 above provided that you accompany - it with the complete corresponding machine-readable source code, which - must be distributed under the terms of Sections 1 and 2 above on a - medium customarily used for software interchange. - - If distribution of object code is made by offering access to copy - from a designated place, then offering equivalent access to copy the - source code from the same place satisfies the requirement to - distribute the source code, even though third parties are not - compelled to copy the source along with the object code. - - 5. A program that contains no derivative of any portion of the - Library, but is designed to work with the Library by being compiled or - linked with it, is called a "work that uses the Library". Such a - work, in isolation, is not a derivative work of the Library, and - therefore falls outside the scope of this License. - - However, linking a "work that uses the Library" with the Library - creates an executable that is a derivative of the Library (because it - contains portions of the Library), rather than a "work that uses the - library". The executable is therefore covered by this License. - Section 6 states terms for distribution of such executables. - - When a "work that uses the Library" uses material from a header file - that is part of the Library, the object code for the work may be a - derivative work of the Library even though the source code is not. - Whether this is true is especially significant if the work can be - linked without the Library, or if the work is itself a library. The - threshold for this to be true is not precisely defined by law. - - If such an object file uses only numerical parameters, data - structure layouts and accessors, and small macros and small inline - functions (ten lines or less in length), then the use of the object - file is unrestricted, regardless of whether it is legally a derivative - work. (Executables containing this object code plus portions of the - Library will still fall under Section 6.) - - Otherwise, if the work is a derivative of the Library, you may - distribute the object code for the work under the terms of Section 6. - Any executables containing that work also fall under Section 6, - whether or not they are linked directly with the Library itself. - - 6. As an exception to the Sections above, you may also combine or - link a "work that uses the Library" with the Library to produce a - work containing portions of the Library, and distribute that work - under terms of your choice, provided that the terms permit - modification of the work for the customer's own use and reverse - engineering for debugging such modifications. - - You must give prominent notice with each copy of the work that the - Library is used in it and that the Library and its use are covered by - this License. You must supply a copy of this License. If the work - during execution displays copyright notices, you must include the - copyright notice for the Library among them, as well as a reference - directing the user to the copy of this License. Also, you must do one - of these things: - - a) Accompany the work with the complete corresponding - machine-readable source code for the Library including whatever - changes were used in the work (which must be distributed under - Sections 1 and 2 above); and, if the work is an executable linked - with the Library, with the complete machine-readable "work that - uses the Library", as object code and/or source code, so that the - user can modify the Library and then relink to produce a modified - executable containing the modified Library. (It is understood - that the user who changes the contents of definitions files in the - Library will not necessarily be able to recompile the application - to use the modified definitions.) - - b) Use a suitable shared library mechanism for linking with the - Library. A suitable mechanism is one that (1) uses at run time a - copy of the library already present on the user's computer system, - rather than copying library functions into the executable, and (2) - will operate properly with a modified version of the library, if - the user installs one, as long as the modified version is - interface-compatible with the version that the work was made with. - - c) Accompany the work with a written offer, valid for at - least three years, to give the same user the materials - specified in Subsection 6a, above, for a charge no more - than the cost of performing this distribution. - - d) If distribution of the work is made by offering access to copy - from a designated place, offer equivalent access to copy the above - specified materials from the same place. - - e) Verify that the user has already received a copy of these - materials or that you have already sent this user a copy. - - For an executable, the required form of the "work that uses the - Library" must include any data and utility programs needed for - reproducing the executable from it. However, as a special exception, - the materials to be distributed need not include anything that is - normally distributed (in either source or binary form) with the major - components (compiler, kernel, and so on) of the operating system on - which the executable runs, unless that component itself accompanies - the executable. - - It may happen that this requirement contradicts the license - restrictions of other proprietary libraries that do not normally - accompany the operating system. Such a contradiction means you cannot - use both them and the Library together in an executable that you - distribute. - - 7. You may place library facilities that are a work based on the - Library side-by-side in a single library together with other library - facilities not covered by this License, and distribute such a combined - library, provided that the separate distribution of the work based on - the Library and of the other library facilities is otherwise - permitted, and provided that you do these two things: - - a) Accompany the combined library with a copy of the same work - based on the Library, uncombined with any other library - facilities. This must be distributed under the terms of the - Sections above. - - b) Give prominent notice with the combined library of the fact - that part of it is a work based on the Library, and explaining - where to find the accompanying uncombined form of the same work. - - 8. You may not copy, modify, sublicense, link with, or distribute - the Library except as expressly provided under this License. Any - attempt otherwise to copy, modify, sublicense, link with, or - distribute the Library is void, and will automatically terminate your - rights under this License. However, parties who have received copies, - or rights, from you under this License will not have their licenses - terminated so long as such parties remain in full compliance. - - 9. You are not required to accept this License, since you have not - signed it. However, nothing else grants you permission to modify or - distribute the Library or its derivative works. These actions are - prohibited by law if you do not accept this License. Therefore, by - modifying or distributing the Library (or any work based on the - Library), you indicate your acceptance of this License to do so, and - all its terms and conditions for copying, distributing or modifying - the Library or works based on it. - - 10. Each time you redistribute the Library (or any work based on the - Library), the recipient automatically receives a license from the - original licensor to copy, distribute, link with or modify the Library - subject to these terms and conditions. You may not impose any further - restrictions on the recipients' exercise of the rights granted herein. - You are not responsible for enforcing compliance by third parties with - this License. - - 11. If, as a consequence of a court judgment or allegation of patent - infringement or for any other reason (not limited to patent issues), - conditions are imposed on you (whether by court order, agreement or - otherwise) that contradict the conditions of this License, they do not - excuse you from the conditions of this License. If you cannot - distribute so as to satisfy simultaneously your obligations under this - License and any other pertinent obligations, then as a consequence you - may not distribute the Library at all. For example, if a patent - license would not permit royalty-free redistribution of the Library by - all those who receive copies directly or indirectly through you, then - the only way you could satisfy both it and this License would be to - refrain entirely from distribution of the Library. - - If any portion of this section is held invalid or unenforceable under any - particular circumstance, the balance of the section is intended to apply, - and the section as a whole is intended to apply in other circumstances. - - It is not the purpose of this section to induce you to infringe any - patents or other property right claims or to contest validity of any - such claims; this section has the sole purpose of protecting the - integrity of the free software distribution system which is - implemented by public license practices. Many people have made - generous contributions to the wide range of software distributed - through that system in reliance on consistent application of that - system; it is up to the author/donor to decide if he or she is willing - to distribute software through any other system and a licensee cannot - impose that choice. - - This section is intended to make thoroughly clear what is believed to - be a consequence of the rest of this License. - - 12. If the distribution and/or use of the Library is restricted in - certain countries either by patents or by copyrighted interfaces, the - original copyright holder who places the Library under this License may add - an explicit geographical distribution limitation excluding those countries, - so that distribution is permitted only in or among countries not thus - excluded. In such case, this License incorporates the limitation as if - written in the body of this License. - - 13. The Free Software Foundation may publish revised and/or new - versions of the Lesser General Public License from time to time. - Such new versions will be similar in spirit to the present version, - but may differ in detail to address new problems or concerns. - - Each version is given a distinguishing version number. If the Library - specifies a version number of this License which applies to it and - "any later version", you have the option of following the terms and - conditions either of that version or of any later version published by - the Free Software Foundation. If the Library does not specify a - license version number, you may choose any version ever published by - the Free Software Foundation. - - 14. If you wish to incorporate parts of the Library into other free - programs whose distribution conditions are incompatible with these, - write to the author to ask for permission. For software which is - copyrighted by the Free Software Foundation, write to the Free - Software Foundation; we sometimes make exceptions for this. Our - decision will be guided by the two goals of preserving the free status - of all derivatives of our free software and of promoting the sharing - and reuse of software generally. - - NO WARRANTY - - 15. BECAUSE THE LIBRARY IS LICENSED FREE OF CHARGE, THERE IS NO - WARRANTY FOR THE LIBRARY, TO THE EXTENT PERMITTED BY APPLICABLE LAW. - EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR - OTHER PARTIES PROVIDE THE LIBRARY "AS IS" WITHOUT WARRANTY OF ANY - KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE - IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR - PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE - LIBRARY IS WITH YOU. SHOULD THE LIBRARY PROVE DEFECTIVE, YOU ASSUME - THE COST OF ALL NECESSARY SERVICING, REPAIR OR CORRECTION. - - 16. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN - WRITING WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY - AND/OR REDISTRIBUTE THE LIBRARY AS PERMITTED ABOVE, BE LIABLE TO YOU - FOR DAMAGES, INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR - CONSEQUENTIAL DAMAGES ARISING OUT OF THE USE OR INABILITY TO USE THE - LIBRARY (INCLUDING BUT NOT LIMITED TO LOSS OF DATA OR DATA BEING - RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD PARTIES OR A - FAILURE OF THE LIBRARY TO OPERATE WITH ANY OTHER SOFTWARE), EVEN IF - SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH - DAMAGES. - - END OF TERMS AND CONDITIONS - - How to Apply These Terms to Your New Libraries - - If you develop a new library, and you want it to be of the greatest - possible use to the public, we recommend making it free software that - everyone can redistribute and change. You can do so by permitting - redistribution under these terms (or, alternatively, under the terms of the - ordinary General Public License). - - To apply these terms, attach the following notices to the library. It is - safest to attach them to the start of each source file to most effectively - convey the exclusion of warranty; and each file should have at least the - "copyright" line and a pointer to where the full notice is found. - - - Copyright (C) - - This library is free software; you can redistribute it and/or - modify it under the terms of the GNU Lesser General Public - License as published by the Free Software Foundation; either - version 2.1 of the License, or (at your option) any later version. - - This library is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - Lesser General Public License for more details. - - You should have received a copy of the GNU Lesser General Public - License along with this library; if not, write to the Free Software - Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - - Also add information on how to contact you by electronic and paper mail. - - You should also get your employer (if you work as a programmer) or your - school, if any, to sign a "copyright disclaimer" for the library, if - necessary. Here is a sample; alter the names: - - Yoyodyne, Inc., hereby disclaims all copyright interest in the - library `Frob' (a library for tweaking knobs) written by James Random Hacker. - - , 1 April 1990 - Ty Coon, President of Vice - - That's all there is to it! - -The following licenses cover code other than JRuby which is included with JRuby. - -Licenses listed below include: - -* GNU General Public License version 3 -* Apache 2.0 License -* BSD License -* Apache Software License Version 1.1 -* MIT License - -The complete text of the GNU General Public License version 3 is as follows: - - GNU GENERAL PUBLIC LICENSE - Version 3, 29 June 2007 - - Copyright (C) 2007 Free Software Foundation, Inc. - Everyone is permitted to copy and distribute verbatim copies - of this license document, but changing it is not allowed. - - Preamble - - The GNU General Public License is a free, copyleft license for - software and other kinds of works. - - The licenses for most software and other practical works are designed - to take away your freedom to share and change the works. By contrast, - the GNU General Public License is intended to guarantee your freedom to - share and change all versions of a program--to make sure it remains free - software for all its users. We, the Free Software Foundation, use the - GNU General Public License for most of our software; it applies also to - any other work released this way by its authors. You can apply it to - your programs, too. - - When we speak of free software, we are referring to freedom, not - price. Our General Public Licenses are designed to make sure that you - have the freedom to distribute copies of free software (and charge for - them if you wish), that you receive source code or can get it if you - want it, that you can change the software or use pieces of it in new - free programs, and that you know you can do these things. - - To protect your rights, we need to prevent others from denying you - these rights or asking you to surrender the rights. Therefore, you have - certain responsibilities if you distribute copies of the software, or if - you modify it: responsibilities to respect the freedom of others. - - For example, if you distribute copies of such a program, whether - gratis or for a fee, you must pass on to the recipients the same - freedoms that you received. You must make sure that they, too, receive - or can get the source code. And you must show them these terms so they - know their rights. - - Developers that use the GNU GPL protect your rights with two steps: - (1) assert copyright on the software, and (2) offer you this License - giving you legal permission to copy, distribute and/or modify it. - - For the developers' and authors' protection, the GPL clearly explains - that there is no warranty for this free software. For both users' and - authors' sake, the GPL requires that modified versions be marked as - changed, so that their problems will not be attributed erroneously to - authors of previous versions. - - Some devices are designed to deny users access to install or run - modified versions of the software inside them, although the manufacturer - can do so. This is fundamentally incompatible with the aim of - protecting users' freedom to change the software. The systematic - pattern of such abuse occurs in the area of products for individuals to - use, which is precisely where it is most unacceptable. Therefore, we - have designed this version of the GPL to prohibit the practice for those - products. If such problems arise substantially in other domains, we - stand ready to extend this provision to those domains in future versions - of the GPL, as needed to protect the freedom of users. - - Finally, every program is threatened constantly by software patents. - States should not allow patents to restrict development and use of - software on general-purpose computers, but in those that do, we wish to - avoid the special danger that patents applied to a free program could - make it effectively proprietary. To prevent this, the GPL assures that - patents cannot be used to render the program non-free. - - The precise terms and conditions for copying, distribution and - modification follow. - - TERMS AND CONDITIONS - - 0. Definitions. - - "This License" refers to version 3 of the GNU General Public License. - - "Copyright" also means copyright-like laws that apply to other kinds of - works, such as semiconductor masks. - - "The Program" refers to any copyrightable work licensed under this - License. Each licensee is addressed as "you". "Licensees" and - "recipients" may be individuals or organizations. - - To "modify" a work means to copy from or adapt all or part of the work - in a fashion requiring copyright permission, other than the making of an - exact copy. The resulting work is called a "modified version" of the - earlier work or a work "based on" the earlier work. - - A "covered work" means either the unmodified Program or a work based - on the Program. - - To "propagate" a work means to do anything with it that, without - permission, would make you directly or secondarily liable for - infringement under applicable copyright law, except executing it on a - computer or modifying a private copy. Propagation includes copying, - distribution (with or without modification), making available to the - public, and in some countries other activities as well. - - To "convey" a work means any kind of propagation that enables other - parties to make or receive copies. Mere interaction with a user through - a computer network, with no transfer of a copy, is not conveying. - - An interactive user interface displays "Appropriate Legal Notices" - to the extent that it includes a convenient and prominently visible - feature that (1) displays an appropriate copyright notice, and (2) - tells the user that there is no warranty for the work (except to the - extent that warranties are provided), that licensees may convey the - work under this License, and how to view a copy of this License. If - the interface presents a list of user commands or options, such as a - menu, a prominent item in the list meets this criterion. - - 1. Source Code. - - The "source code" for a work means the preferred form of the work - for making modifications to it. "Object code" means any non-source - form of a work. - - A "Standard Interface" means an interface that either is an official - standard defined by a recognized standards body, or, in the case of - interfaces specified for a particular programming language, one that - is widely used among developers working in that language. - - The "System Libraries" of an executable work include anything, other - than the work as a whole, that (a) is included in the normal form of - packaging a Major Component, but which is not part of that Major - Component, and (b) serves only to enable use of the work with that - Major Component, or to implement a Standard Interface for which an - implementation is available to the public in source code form. A - "Major Component", in this context, means a major essential component - (kernel, window system, and so on) of the specific operating system - (if any) on which the executable work runs, or a compiler used to - produce the work, or an object code interpreter used to run it. - - The "Corresponding Source" for a work in object code form means all - the source code needed to generate, install, and (for an executable - work) run the object code and to modify the work, including scripts to - control those activities. However, it does not include the work's - System Libraries, or general-purpose tools or generally available free - programs which are used unmodified in performing those activities but - which are not part of the work. For example, Corresponding Source - includes interface definition files associated with source files for - the work, and the source code for shared libraries and dynamically - linked subprograms that the work is specifically designed to require, - such as by intimate data communication or control flow between those - subprograms and other parts of the work. - - The Corresponding Source need not include anything that users - can regenerate automatically from other parts of the Corresponding - Source. - - The Corresponding Source for a work in source code form is that - same work. - - 2. Basic Permissions. - - All rights granted under this License are granted for the term of - copyright on the Program, and are irrevocable provided the stated - conditions are met. This License explicitly affirms your unlimited - permission to run the unmodified Program. The output from running a - covered work is covered by this License only if the output, given its - content, constitutes a covered work. This License acknowledges your - rights of fair use or other equivalent, as provided by copyright law. - - You may make, run and propagate covered works that you do not - convey, without conditions so long as your license otherwise remains - in force. You may convey covered works to others for the sole purpose - of having them make modifications exclusively for you, or provide you - with facilities for running those works, provided that you comply with - the terms of this License in conveying all material for which you do - not control copyright. Those thus making or running the covered works - for you must do so exclusively on your behalf, under your direction - and control, on terms that prohibit them from making any copies of - your copyrighted material outside their relationship with you. - - Conveying under any other circumstances is permitted solely under - the conditions stated below. Sublicensing is not allowed; section 10 - makes it unnecessary. - - 3. Protecting Users' Legal Rights From Anti-Circumvention Law. - - No covered work shall be deemed part of an effective technological - measure under any applicable law fulfilling obligations under article - 11 of the WIPO copyright treaty adopted on 20 December 1996, or - similar laws prohibiting or restricting circumvention of such - measures. - - When you convey a covered work, you waive any legal power to forbid - circumvention of technological measures to the extent such circumvention - is effected by exercising rights under this License with respect to - the covered work, and you disclaim any intention to limit operation or - modification of the work as a means of enforcing, against the work's - users, your or third parties' legal rights to forbid circumvention of - technological measures. - - 4. Conveying Verbatim Copies. - - You may convey verbatim copies of the Program's source code as you - receive it, in any medium, provided that you conspicuously and - appropriately publish on each copy an appropriate copyright notice; - keep intact all notices stating that this License and any - non-permissive terms added in accord with section 7 apply to the code; - keep intact all notices of the absence of any warranty; and give all - recipients a copy of this License along with the Program. - - You may charge any price or no price for each copy that you convey, - and you may offer support or warranty protection for a fee. - - 5. Conveying Modified Source Versions. - - You may convey a work based on the Program, or the modifications to - produce it from the Program, in the form of source code under the - terms of section 4, provided that you also meet all of these conditions: - - a) The work must carry prominent notices stating that you modified - it, and giving a relevant date. - - b) The work must carry prominent notices stating that it is - released under this License and any conditions added under section - 7. This requirement modifies the requirement in section 4 to - "keep intact all notices". - - c) You must license the entire work, as a whole, under this - License to anyone who comes into possession of a copy. This - License will therefore apply, along with any applicable section 7 - additional terms, to the whole of the work, and all its parts, - regardless of how they are packaged. This License gives no - permission to license the work in any other way, but it does not - invalidate such permission if you have separately received it. - - d) If the work has interactive user interfaces, each must display - Appropriate Legal Notices; however, if the Program has interactive - interfaces that do not display Appropriate Legal Notices, your - work need not make them do so. - - A compilation of a covered work with other separate and independent - works, which are not by their nature extensions of the covered work, - and which are not combined with it such as to form a larger program, - in or on a volume of a storage or distribution medium, is called an - "aggregate" if the compilation and its resulting copyright are not - used to limit the access or legal rights of the compilation's users - beyond what the individual works permit. Inclusion of a covered work - in an aggregate does not cause this License to apply to the other - parts of the aggregate. - - 6. Conveying Non-Source Forms. - - You may convey a covered work in object code form under the terms - of sections 4 and 5, provided that you also convey the - machine-readable Corresponding Source under the terms of this License, - in one of these ways: - - a) Convey the object code in, or embodied in, a physical product - (including a physical distribution medium), accompanied by the - Corresponding Source fixed on a durable physical medium - customarily used for software interchange. - - b) Convey the object code in, or embodied in, a physical product - (including a physical distribution medium), accompanied by a - written offer, valid for at least three years and valid for as - long as you offer spare parts or customer support for that product - model, to give anyone who possesses the object code either (1) a - copy of the Corresponding Source for all the software in the - product that is covered by this License, on a durable physical - medium customarily used for software interchange, for a price no - more than your reasonable cost of physically performing this - conveying of source, or (2) access to copy the - Corresponding Source from a network server at no charge. - - c) Convey individual copies of the object code with a copy of the - written offer to provide the Corresponding Source. This - alternative is allowed only occasionally and noncommercially, and - only if you received the object code with such an offer, in accord - with subsection 6b. - - d) Convey the object code by offering access from a designated - place (gratis or for a charge), and offer equivalent access to the - Corresponding Source in the same way through the same place at no - further charge. You need not require recipients to copy the - Corresponding Source along with the object code. If the place to - copy the object code is a network server, the Corresponding Source - may be on a different server (operated by you or a third party) - that supports equivalent copying facilities, provided you maintain - clear directions next to the object code saying where to find the - Corresponding Source. Regardless of what server hosts the - Corresponding Source, you remain obligated to ensure that it is - available for as long as needed to satisfy these requirements. - - e) Convey the object code using peer-to-peer transmission, provided - you inform other peers where the object code and Corresponding - Source of the work are being offered to the general public at no - charge under subsection 6d. - - A separable portion of the object code, whose source code is excluded - from the Corresponding Source as a System Library, need not be - included in conveying the object code work. - - A "User Product" is either (1) a "consumer product", which means any - tangible personal property which is normally used for personal, family, - or household purposes, or (2) anything designed or sold for incorporation - into a dwelling. In determining whether a product is a consumer product, - doubtful cases shall be resolved in favor of coverage. For a particular - product received by a particular user, "normally used" refers to a - typical or common use of that class of product, regardless of the status - of the particular user or of the way in which the particular user - actually uses, or expects or is expected to use, the product. A product - is a consumer product regardless of whether the product has substantial - commercial, industrial or non-consumer uses, unless such uses represent - the only significant mode of use of the product. - - "Installation Information" for a User Product means any methods, - procedures, authorization keys, or other information required to install - and execute modified versions of a covered work in that User Product from - a modified version of its Corresponding Source. The information must - suffice to ensure that the continued functioning of the modified object - code is in no case prevented or interfered with solely because - modification has been made. - - If you convey an object code work under this section in, or with, or - specifically for use in, a User Product, and the conveying occurs as - part of a transaction in which the right of possession and use of the - User Product is transferred to the recipient in perpetuity or for a - fixed term (regardless of how the transaction is characterized), the - Corresponding Source conveyed under this section must be accompanied - by the Installation Information. But this requirement does not apply - if neither you nor any third party retains the ability to install - modified object code on the User Product (for example, the work has - been installed in ROM). - - The requirement to provide Installation Information does not include a - requirement to continue to provide support service, warranty, or updates - for a work that has been modified or installed by the recipient, or for - the User Product in which it has been modified or installed. Access to a - network may be denied when the modification itself materially and - adversely affects the operation of the network or violates the rules and - protocols for communication across the network. - - Corresponding Source conveyed, and Installation Information provided, - in accord with this section must be in a format that is publicly - documented (and with an implementation available to the public in - source code form), and must require no special password or key for - unpacking, reading or copying. - - 7. Additional Terms. - - "Additional permissions" are terms that supplement the terms of this - License by making exceptions from one or more of its conditions. - Additional permissions that are applicable to the entire Program shall - be treated as though they were included in this License, to the extent - that they are valid under applicable law. If additional permissions - apply only to part of the Program, that part may be used separately - under those permissions, but the entire Program remains governed by - this License without regard to the additional permissions. - - When you convey a copy of a covered work, you may at your option - remove any additional permissions from that copy, or from any part of - it. (Additional permissions may be written to require their own - removal in certain cases when you modify the work.) You may place - additional permissions on material, added by you to a covered work, - for which you have or can give appropriate copyright permission. - - Notwithstanding any other provision of this License, for material you - add to a covered work, you may (if authorized by the copyright holders of - that material) supplement the terms of this License with terms: - - a) Disclaiming warranty or limiting liability differently from the - terms of sections 15 and 16 of this License; or - - b) Requiring preservation of specified reasonable legal notices or - author attributions in that material or in the Appropriate Legal - Notices displayed by works containing it; or - - c) Prohibiting misrepresentation of the origin of that material, or - requiring that modified versions of such material be marked in - reasonable ways as different from the original version; or - - d) Limiting the use for publicity purposes of names of licensors or - authors of the material; or - - e) Declining to grant rights under trademark law for use of some - trade names, trademarks, or service marks; or - - f) Requiring indemnification of licensors and authors of that - material by anyone who conveys the material (or modified versions of - it) with contractual assumptions of liability to the recipient, for - any liability that these contractual assumptions directly impose on - those licensors and authors. - - All other non-permissive additional terms are considered "further - restrictions" within the meaning of section 10. If the Program as you - received it, or any part of it, contains a notice stating that it is - governed by this License along with a term that is a further - restriction, you may remove that term. If a license document contains - a further restriction but permits relicensing or conveying under this - License, you may add to a covered work material governed by the terms - of that license document, provided that the further restriction does - not survive such relicensing or conveying. - - If you add terms to a covered work in accord with this section, you - must place, in the relevant source files, a statement of the - additional terms that apply to those files, or a notice indicating - where to find the applicable terms. - - Additional terms, permissive or non-permissive, may be stated in the - form of a separately written license, or stated as exceptions; - the above requirements apply either way. - - 8. Termination. - - You may not propagate or modify a covered work except as expressly - provided under this License. Any attempt otherwise to propagate or - modify it is void, and will automatically terminate your rights under - this License (including any patent licenses granted under the third - paragraph of section 11). - - However, if you cease all violation of this License, then your - license from a particular copyright holder is reinstated (a) - provisionally, unless and until the copyright holder explicitly and - finally terminates your license, and (b) permanently, if the copyright - holder fails to notify you of the violation by some reasonable means - prior to 60 days after the cessation. - - Moreover, your license from a particular copyright holder is - reinstated permanently if the copyright holder notifies you of the - violation by some reasonable means, this is the first time you have - received notice of violation of this License (for any work) from that - copyright holder, and you cure the violation prior to 30 days after - your receipt of the notice. - - Termination of your rights under this section does not terminate the - licenses of parties who have received copies or rights from you under - this License. If your rights have been terminated and not permanently - reinstated, you do not qualify to receive new licenses for the same - material under section 10. - - 9. Acceptance Not Required for Having Copies. - - You are not required to accept this License in order to receive or - run a copy of the Program. Ancillary propagation of a covered work - occurring solely as a consequence of using peer-to-peer transmission - to receive a copy likewise does not require acceptance. However, - nothing other than this License grants you permission to propagate or - modify any covered work. These actions infringe copyright if you do - not accept this License. Therefore, by modifying or propagating a - covered work, you indicate your acceptance of this License to do so. - - 10. Automatic Licensing of Downstream Recipients. - - Each time you convey a covered work, the recipient automatically - receives a license from the original licensors, to run, modify and - propagate that work, subject to this License. You are not responsible - for enforcing compliance by third parties with this License. - - An "entity transaction" is a transaction transferring control of an - organization, or substantially all assets of one, or subdividing an - organization, or merging organizations. If propagation of a covered - work results from an entity transaction, each party to that - transaction who receives a copy of the work also receives whatever - licenses to the work the party's predecessor in interest had or could - give under the previous paragraph, plus a right to possession of the - Corresponding Source of the work from the predecessor in interest, if - the predecessor has it or can get it with reasonable efforts. - - You may not impose any further restrictions on the exercise of the - rights granted or affirmed under this License. For example, you may - not impose a license fee, royalty, or other charge for exercise of - rights granted under this License, and you may not initiate litigation - (including a cross-claim or counterclaim in a lawsuit) alleging that - any patent claim is infringed by making, using, selling, offering for - sale, or importing the Program or any portion of it. - - 11. Patents. - - A "contributor" is a copyright holder who authorizes use under this - License of the Program or a work on which the Program is based. The - work thus licensed is called the contributor's "contributor version". - - A contributor's "essential patent claims" are all patent claims - owned or controlled by the contributor, whether already acquired or - hereafter acquired, that would be infringed by some manner, permitted - by this License, of making, using, or selling its contributor version, - but do not include claims that would be infringed only as a - consequence of further modification of the contributor version. For - purposes of this definition, "control" includes the right to grant - patent sublicenses in a manner consistent with the requirements of - this License. - - Each contributor grants you a non-exclusive, worldwide, royalty-free - patent license under the contributor's essential patent claims, to - make, use, sell, offer for sale, import and otherwise run, modify and - propagate the contents of its contributor version. - - In the following three paragraphs, a "patent license" is any express - agreement or commitment, however denominated, not to enforce a patent - (such as an express permission to practice a patent or covenant not to - sue for patent infringement). To "grant" such a patent license to a - party means to make such an agreement or commitment not to enforce a - patent against the party. - - If you convey a covered work, knowingly relying on a patent license, - and the Corresponding Source of the work is not available for anyone - to copy, free of charge and under the terms of this License, through a - publicly available network server or other readily accessible means, - then you must either (1) cause the Corresponding Source to be so - available, or (2) arrange to deprive yourself of the benefit of the - patent license for this particular work, or (3) arrange, in a manner - consistent with the requirements of this License, to extend the patent - license to downstream recipients. "Knowingly relying" means you have - actual knowledge that, but for the patent license, your conveying the - covered work in a country, or your recipient's use of the covered work - in a country, would infringe one or more identifiable patents in that - country that you have reason to believe are valid. - - If, pursuant to or in connection with a single transaction or - arrangement, you convey, or propagate by procuring conveyance of, a - covered work, and grant a patent license to some of the parties - receiving the covered work authorizing them to use, propagate, modify - or convey a specific copy of the covered work, then the patent license - you grant is automatically extended to all recipients of the covered - work and works based on it. - - A patent license is "discriminatory" if it does not include within - the scope of its coverage, prohibits the exercise of, or is - conditioned on the non-exercise of one or more of the rights that are - specifically granted under this License. You may not convey a covered - work if you are a party to an arrangement with a third party that is - in the business of distributing software, under which you make payment - to the third party based on the extent of your activity of conveying - the work, and under which the third party grants, to any of the - parties who would receive the covered work from you, a discriminatory - patent license (a) in connection with copies of the covered work - conveyed by you (or copies made from those copies), or (b) primarily - for and in connection with specific products or compilations that - contain the covered work, unless you entered into that arrangement, - or that patent license was granted, prior to 28 March 2007. - - Nothing in this License shall be construed as excluding or limiting - any implied license or other defenses to infringement that may - otherwise be available to you under applicable patent law. - - 12. No Surrender of Others' Freedom. - - If conditions are imposed on you (whether by court order, agreement or - otherwise) that contradict the conditions of this License, they do not - excuse you from the conditions of this License. If you cannot convey a - covered work so as to satisfy simultaneously your obligations under this - License and any other pertinent obligations, then as a consequence you may - not convey it at all. For example, if you agree to terms that obligate you - to collect a royalty for further conveying from those to whom you convey - the Program, the only way you could satisfy both those terms and this - License would be to refrain entirely from conveying the Program. - - 13. Use with the GNU Affero General Public License. - - Notwithstanding any other provision of this License, you have - permission to link or combine any covered work with a work licensed - under version 3 of the GNU Affero General Public License into a single - combined work, and to convey the resulting work. The terms of this - License will continue to apply to the part which is the covered work, - but the special requirements of the GNU Affero General Public License, - section 13, concerning interaction through a network will apply to the - combination as such. - - 14. Revised Versions of this License. - - The Free Software Foundation may publish revised and/or new versions of - the GNU General Public License from time to time. Such new versions will - be similar in spirit to the present version, but may differ in detail to - address new problems or concerns. - - Each version is given a distinguishing version number. If the - Program specifies that a certain numbered version of the GNU General - Public License "or any later version" applies to it, you have the - option of following the terms and conditions either of that numbered - version or of any later version published by the Free Software - Foundation. If the Program does not specify a version number of the - GNU General Public License, you may choose any version ever published - by the Free Software Foundation. - - If the Program specifies that a proxy can decide which future - versions of the GNU General Public License can be used, that proxy's - public statement of acceptance of a version permanently authorizes you - to choose that version for the Program. - - Later license versions may give you additional or different - permissions. However, no additional obligations are imposed on any - author or copyright holder as a result of your choosing to follow a - later version. - - 15. Disclaimer of Warranty. - - THERE IS NO WARRANTY FOR THE PROGRAM, TO THE EXTENT PERMITTED BY - APPLICABLE LAW. EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT - HOLDERS AND/OR OTHER PARTIES PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY - OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, - THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR - PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE PROGRAM - IS WITH YOU. SHOULD THE PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF - ALL NECESSARY SERVICING, REPAIR OR CORRECTION. - - 16. Limitation of Liability. - - IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING - WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MODIFIES AND/OR CONVEYS - THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY - GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE - USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED TO LOSS OF - DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD - PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER PROGRAMS), - EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF - SUCH DAMAGES. - - 17. Interpretation of Sections 15 and 16. - - If the disclaimer of warranty and limitation of liability provided - above cannot be given local legal effect according to their terms, - reviewing courts shall apply local law that most closely approximates - an absolute waiver of all civil liability in connection with the - Program, unless a warranty or assumption of liability accompanies a - copy of the Program in return for a fee. - - END OF TERMS AND CONDITIONS - - How to Apply These Terms to Your New Programs - - If you develop a new program, and you want it to be of the greatest - possible use to the public, the best way to achieve this is to make it - free software which everyone can redistribute and change under these terms. - - To do so, attach the following notices to the program. It is safest - to attach them to the start of each source file to most effectively - state the exclusion of warranty; and each file should have at least - the "copyright" line and a pointer to where the full notice is found. - - - Copyright (C) - - This program is free software: you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation, either version 3 of the License, or - (at your option) any later version. - - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program. If not, see . - - Also add information on how to contact you by electronic and paper mail. - - If the program does terminal interaction, make it output a short - notice like this when it starts in an interactive mode: - - Copyright (C) - This program comes with ABSOLUTELY NO WARRANTY; for details type `show w'. - This is free software, and you are welcome to redistribute it - under certain conditions; type `show c' for details. - - The hypothetical commands `show w' and `show c' should show the appropriate - parts of the General Public License. Of course, your program's commands - might be different; for a GUI interface, you would use an "about box". - - You should also get your employer (if you work as a programmer) or school, - if any, to sign a "copyright disclaimer" for the program, if necessary. - For more information on this, and how to apply and follow the GNU GPL, see - . - - The GNU General Public License does not permit incorporating your program - into proprietary programs. If your program is a subroutine library, you - may consider it more useful to permit linking proprietary applications with - the library. If this is what you want to do, use the GNU Lesser General - Public License instead of this License. But first, please read - . - -The complete text of the Apache 2.0 License is as follows: - - Apache License - Version 2.0, January 2004 - http://www.apache.org/licenses/ - - TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION - - 1. Definitions. - - "License" shall mean the terms and conditions for use, reproduction, - and distribution as defined by Sections 1 through 9 of this document. - - "Licensor" shall mean the copyright owner or entity authorized by - the copyright owner that is granting the License. - - "Legal Entity" shall mean the union of the acting entity and all - other entities that control, are controlled by, or are under common - control with that entity. For the purposes of this definition, - "control" means (i) the power, direct or indirect, to cause the - direction or management of such entity, whether by contract or - otherwise, or (ii) ownership of fifty percent (50%) or more of the - outstanding shares, or (iii) beneficial ownership of such entity. - - "You" (or "Your") shall mean an individual or Legal Entity - exercising permissions granted by this License. - - "Source" form shall mean the preferred form for making modifications, - including but not limited to software source code, documentation - source, and configuration files. - - "Object" form shall mean any form resulting from mechanical - transformation or translation of a Source form, including but - not limited to compiled object code, generated documentation, - and conversions to other media types. - - "Work" shall mean the work of authorship, whether in Source or - Object form, made available under the License, as indicated by a - copyright notice that is included in or attached to the work - (an example is provided in the Appendix below). - - "Derivative Works" shall mean any work, whether in Source or Object - form, that is based on (or derived from) the Work and for which the - editorial revisions, annotations, elaborations, or other modifications - represent, as a whole, an original work of authorship. For the purposes - of this License, Derivative Works shall not include works that remain - separable from, or merely link (or bind by name) to the interfaces of, - the Work and Derivative Works thereof. - - "Contribution" shall mean any work of authorship, including - the original version of the Work and any modifications or additions - to that Work or Derivative Works thereof, that is intentionally - submitted to Licensor for inclusion in the Work by the copyright owner - or by an individual or Legal Entity authorized to submit on behalf of - the copyright owner. For the purposes of this definition, "submitted" - means any form of electronic, verbal, or written communication sent - to the Licensor or its representatives, including but not limited to - communication on electronic mailing lists, source code control systems, - and issue tracking systems that are managed by, or on behalf of, the - Licensor for the purpose of discussing and improving the Work, but - excluding communication that is conspicuously marked or otherwise - designated in writing by the copyright owner as "Not a Contribution." - - "Contributor" shall mean Licensor and any individual or Legal Entity - on behalf of whom a Contribution has been received by Licensor and - subsequently incorporated within the Work. - - 2. Grant of Copyright License. Subject to the terms and conditions of - this License, each Contributor hereby grants to You a perpetual, - worldwide, non-exclusive, no-charge, royalty-free, irrevocable - copyright license to reproduce, prepare Derivative Works of, - publicly display, publicly perform, sublicense, and distribute the - Work and such Derivative Works in Source or Object form. - - 3. Grant of Patent License. Subject to the terms and conditions of - this License, each Contributor hereby grants to You a perpetual, - worldwide, non-exclusive, no-charge, royalty-free, irrevocable - (except as stated in this section) patent license to make, have made, - use, offer to sell, sell, import, and otherwise transfer the Work, - where such license applies only to those patent claims licensable - by such Contributor that are necessarily infringed by their - Contribution(s) alone or by combination of their Contribution(s) - with the Work to which such Contribution(s) was submitted. If You - institute patent litigation against any entity (including a - cross-claim or counterclaim in a lawsuit) alleging that the Work - or a Contribution incorporated within the Work constitutes direct - or contributory patent infringement, then any patent licenses - granted to You under this License for that Work shall terminate - as of the date such litigation is filed. - - 4. Redistribution. You may reproduce and distribute copies of the - Work or Derivative Works thereof in any medium, with or without - modifications, and in Source or Object form, provided that You - meet the following conditions: - - (a) You must give any other recipients of the Work or - Derivative Works a copy of this License; and - - (b) You must cause any modified files to carry prominent notices - stating that You changed the files; and - - (c) You must retain, in the Source form of any Derivative Works - that You distribute, all copyright, patent, trademark, and - attribution notices from the Source form of the Work, - excluding those notices that do not pertain to any part of - the Derivative Works; and - - (d) If the Work includes a "NOTICE" text file as part of its - distribution, then any Derivative Works that You distribute must - include a readable copy of the attribution notices contained - within such NOTICE file, excluding those notices that do not - pertain to any part of the Derivative Works, in at least one - of the following places: within a NOTICE text file distributed - as part of the Derivative Works; within the Source form or - documentation, if provided along with the Derivative Works; or, - within a display generated by the Derivative Works, if and - wherever such third-party notices normally appear. The contents - of the NOTICE file are for informational purposes only and - do not modify the License. You may add Your own attribution - notices within Derivative Works that You distribute, alongside - or as an addendum to the NOTICE text from the Work, provided - that such additional attribution notices cannot be construed - as modifying the License. - - You may add Your own copyright statement to Your modifications and - may provide additional or different license terms and conditions - for use, reproduction, or distribution of Your modifications, or - for any such Derivative Works as a whole, provided Your use, - reproduction, and distribution of the Work otherwise complies with - the conditions stated in this License. - - 5. Submission of Contributions. Unless You explicitly state otherwise, - any Contribution intentionally submitted for inclusion in the Work - by You to the Licensor shall be under the terms and conditions of - this License, without any additional terms or conditions. - Notwithstanding the above, nothing herein shall supersede or modify - the terms of any separate license agreement you may have executed - with Licensor regarding such Contributions. - - 6. Trademarks. This License does not grant permission to use the trade - names, trademarks, service marks, or product names of the Licensor, - except as required for reasonable and customary use in describing the - origin of the Work and reproducing the content of the NOTICE file. - - 7. Disclaimer of Warranty. Unless required by applicable law or - agreed to in writing, Licensor provides the Work (and each - Contributor provides its Contributions) on an "AS IS" BASIS, - WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or - implied, including, without limitation, any warranties or conditions - of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A - PARTICULAR PURPOSE. You are solely responsible for determining the - appropriateness of using or redistributing the Work and assume any - risks associated with Your exercise of permissions under this License. - - 8. Limitation of Liability. In no event and under no legal theory, - whether in tort (including negligence), contract, or otherwise, - unless required by applicable law (such as deliberate and grossly - negligent acts) or agreed to in writing, shall any Contributor be - liable to You for damages, including any direct, indirect, special, - incidental, or consequential damages of any character arising as a - result of this License or out of the use or inability to use the - Work (including but not limited to damages for loss of goodwill, - work stoppage, computer failure or malfunction, or any and all - other commercial damages or losses), even if such Contributor - has been advised of the possibility of such damages. - - 9. Accepting Warranty or Additional Liability. While redistributing - the Work or Derivative Works thereof, You may choose to offer, - and charge a fee for, acceptance of support, warranty, indemnity, - or other liability obligations and/or rights consistent with this - License. However, in accepting such obligations, You may act only - on Your own behalf and on Your sole responsibility, not on behalf - of any other Contributor, and only if You agree to indemnify, - defend, and hold each Contributor harmless for any liability - incurred by, or claims asserted against, such Contributor by reason - of your accepting any such warranty or additional liability. - - END OF TERMS AND CONDITIONS - - APPENDIX: How to apply the Apache License to your work. - - To apply the Apache License to your work, attach the following - boilerplate notice, with the fields enclosed by brackets "[]" - replaced with your own identifying information. (Don't include - the brackets!) The text should be enclosed in the appropriate - comment syntax for the file format. We also recommend that a - file or class name and description of purpose be included on the - same "printed page" as the copyright notice for easier - identification within third-party archives. - - Copyright [yyyy] [name of copyright owner] - - Licensed 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. - -The complete text of the BSD license can be is as follows: - - Copyright (c) The Regents of the University of California. - All rights reserved. - - Redistribution and use in source and binary forms, with or without - modification, are permitted provided that the following conditions - are met: - 1. Redistributions of source code must retain the above copyright - notice, this list of conditions and the following disclaimer. - 2. Redistributions in binary form must reproduce the above copyright - notice, this list of conditions and the following disclaimer in the - documentation and/or other materials provided with the distribution. - 3. Neither the name of the University nor the names of its contributors - may be used to endorse or promote products derived from this software - without specific prior written permission. - - THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND - ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE - ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE - FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL - DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS - OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) - HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT - LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY - OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF - SUCH DAMAGE. - -The complete text of the Apache Software License Version 1.1 is as follows: - - /* - * ================================================================ - * The Apache Software License, Version 1.1 - * ================================================================ - * - * Copyright (C) 2000-2002 The Apache Software Foundation. All - * rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following - * conditions are met: - * - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in - * the documentation and/or other materials provided with the - * distribution. - * - * 3. The end-user documentation included with the redistribution, if - * any, must include the following acknowledgment: "This product - * includes software developed by the Apache Software Foundation - * (http://www.apache.org/)." Alternately, this acknowledgment may - * appear in the software itself, if and wherever such third-party - * acknowledgments normally appear. - * - * 4. The names "Ant" and "Apache Software Foundation" must not be - * used to endorse or promote products derived from this software - * without prior written permission. For written permission, please - * contact apache@apache.org. - * - * 5. Products derived from this software may not be called "Apache", - * nor may "Apache" appear in their name, without prior written - * permission of the Apache Software Foundation. - * - * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED - * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES - * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE - * DISCLAIMED. IN NO EVENT SHALL THE APACHE SOFTWARE FOUNDATION - * OR ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT - * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, - * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON - * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR - * TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT - * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY - * OF SUCH DAMAGE. - * - * This software consists of voluntary contributions made by many - * individuals on behalf of the Apache Software Foundation. For more - * information on the Apache Software Foundation, please see - * . - * - */ - -The complete text of the MIT license is as follows: - - Permission is hereby granted, free of charge, to any person - obtaining a copy of this software and associated documentation - files (the “Software”), to deal in the Software without - restriction, including without limitation the rights to use, - copy, modify, merge, publish, distribute, sublicense, and/or sell - copies of the Software, and to permit persons to whom the - Software is furnished to do so, subject to the following - conditions: - - The above copyright notice and this permission notice shall be - included in all copies or substantial portions of the Software. - - THE SOFTWARE IS PROVIDED “AS IS”, WITHOUT WARRANTY OF ANY KIND, - EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES - OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND - NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT - HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, - WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING - FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR - OTHER DEALINGS IN THE SOFTWARE. - -The complete text of the Eclipse Public License v1.0 is as follows: - - Eclipse Public License - v 1.0 - - THE ACCOMPANYING PROGRAM IS PROVIDED UNDER THE TERMS OF THIS ECLIPSE PUBLIC - LICENSE ("AGREEMENT"). ANY USE, REPRODUCTION OR DISTRIBUTION OF THE PROGRAM - CONSTITUTES RECIPIENT’S ACCEPTANCE OF THIS AGREEMENT. - - 1. DEFINITIONS - - "Contribution" means: - - a) in the case of the initial Contributor, the initial code and documentation - distributed under this Agreement, and - b) in the case of each subsequent Contributor: - - i) changes to the Program, and - - ii) additions to the Program; - - where such changes and/or additions to the Program originate from and are - distributed by that particular Contributor. A Contribution 'originates' from a - Contributor if it was added to the Program by such Contributor itself or anyone - acting on such Contributor’s behalf. Contributions do not include additions to - the Program which: (i) are separate modules of software distributed in - conjunction with the Program under their own license agreement, and (ii) are not - derivative works of the Program. - - "Contributor" means any person or entity that distributes the Program. - - "Licensed Patents " mean patent claims licensable by a Contributor which are - necessarily infringed by the use or sale of its Contribution alone or when - combined with the Program. - - "Program" means the Contributions distributed in accordance with this Agreement. - - "Recipient" means anyone who receives the Program under this Agreement, - including all Contributors. - - 2. GRANT OF RIGHTS - - a) Subject to the terms of this Agreement, each Contributor hereby grants - Recipient a non-exclusive, worldwide, royalty-free copyright license to - reproduce, prepare derivative works of, publicly display, publicly perform, - distribute and sublicense the Contribution of such Contributor, if any, and such - derivative works, in source code and object code form. - - b) Subject to the terms of this Agreement, each Contributor hereby grants - Recipient a non-exclusive, worldwide, royalty-free patent license under Licensed - Patents to make, use, sell, offer to sell, import and otherwise transfer the - Contribution of such Contributor, if any, in source code and object code form. - This patent license shall apply to the combination of the Contribution and the - Program if, at the time the Contribution is added by the Contributor, such - addition of the Contribution causes such combination to be covered by the - Licensed Patents. The patent license shall not apply to any other combinations - which include the Contribution. No hardware per se is licensed hereunder. - - c) Recipient understands that although each Contributor grants the licenses to - its Contributions set forth herein, no assurances are provided by any - Contributor that the Program does not infringe the patent or other intellectual - property rights of any other entity. Each Contributor disclaims any liability to - Recipient for claims brought by any other entity based on infringement of - intellectual property rights or otherwise. As a condition to exercising the - rights and licenses granted hereunder, each Recipient hereby assumes sole - responsibility to secure any other intellectual property rights needed, if any. - For example, if a third party patent license is required to allow Recipient to - distribute the Program, it is Recipient’s responsibility to acquire that license - before distributing the Program. - - d) Each Contributor represents that to its knowledge it has sufficient copyright - rights in its Contribution, if any, to grant the copyright license set forth in - this Agreement. - - 3. REQUIREMENTS - - A Contributor may choose to distribute the Program in object code form under its - own license agreement, provided that: - - a) it complies with the terms and conditions of this Agreement; and - - b) its license agreement: - - i) effectively disclaims on behalf of all Contributors all warranties and - conditions, express and implied, including warranties or conditions of title and - non-infringement, and implied warranties or conditions of merchantability and - fitness for a particular purpose; - - ii) effectively excludes on behalf of all Contributors all liability for - damages, including direct, indirect, special, incidental and consequential - damages, such as lost profits; - - iii) states that any provisions which differ from this Agreement are offered by - that Contributor alone and not by any other party; and - - iv) states that source code for the Program is available from such Contributor, - and informs licensees how to obtain it in a reasonable manner on or through a - medium customarily used for software exchange. - - When the Program is made available in source code form: - - a) it must be made available under this Agreement; and - b) a copy of this Agreement must be included with each copy of the Program. - - Contributors may not remove or alter any copyright notices contained within the - Program. - - Each Contributor must identify itself as the originator of its Contribution, if - any, in a manner that reasonably allows subsequent Recipients to identify the - originator of the Contribution. - - 4. COMMERCIAL DISTRIBUTION - - Commercial distributors of software may accept certain responsibilities with - respect to end users, business partners and the like. While this license is - intended to facilitate the commercial use of the Program, the Contributor who - includes the Program in a commercial product offering should do so in a manner - which does not create potential liability for other Contributors. Therefore, if - a Contributor includes the Program in a commercial product offering, such - Contributor ("Commercial Contributor") hereby agrees to defend and indemnify - every other Contributor ("Indemnified Contributor") against any losses, damages - and costs (collectively "Losses") arising from claims, lawsuits and other legal - actions brought by a third party against the Indemnified Contributor to the - extent caused by the acts or omissions of such Commercial Contributor in - connection with its distribution of the Program in a commercial product - offering. The obligations in this section do not apply to any claims or Losses - relating to any actual or alleged intellectual property infringement. In order - to qualify, an Indemnified Contributor must: a) promptly notify the Commercial - Contributor in writing of such claim, and b) allow the Commercial Contributor to - control, and cooperate with the Commercial Contributor in, the defense and any - related settlement negotiations. The Indemnified Contributor may participate in - any such claim at its own expense. - - For example, a Contributor might include the Program in a commercial product - offering, Product X. That Contributor is then a Commercial Contributor. If that - Commercial Contributor then makes performance claims, or offers warranties - related to Product X, those performance claims and warranties are such - Commercial Contributor’s responsibility alone. Under this section, the - Commercial Contributor would have to defend claims against the other - Contributors related to those performance claims and warranties, and if a court - requires any other Contributor to pay any damages as a result, the Commercial - Contributor must pay those damages. - - 5. NO WARRANTY - - EXCEPT AS EXPRESSLY SET FORTH IN THIS AGREEMENT, THE PROGRAM IS PROVIDED ON AN - "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, EITHER EXPRESS OR - IMPLIED INCLUDING, WITHOUT LIMITATION, ANY WARRANTIES OR CONDITIONS OF TITLE, - NON-INFRINGEMENT, MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE. Each - Recipient is solely responsible for determining the appropriateness of using and - distributing the Program and assumes all risks associated with its exercise of - rights under this Agreement , including but not limited to the risks and costs - of program errors, compliance with applicable laws, damage to or loss of data, - programs or equipment, and unavailability or interruption of operations. - - 6. DISCLAIMER OF LIABILITY - - EXCEPT AS EXPRESSLY SET FORTH IN THIS AGREEMENT, NEITHER RECIPIENT NOR ANY - CONTRIBUTORS SHALL HAVE ANY LIABILITY FOR ANY DIRECT, INDIRECT, INCIDENTAL, - SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING WITHOUT LIMITATION LOST - PROFITS), HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, - STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY - OUT OF THE USE OR DISTRIBUTION OF THE PROGRAM OR THE EXERCISE OF ANY RIGHTS - GRANTED HEREUNDER, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGES. - - 7. GENERAL - - If any provision of this Agreement is invalid or unenforceable under applicable - law, it shall not affect the validity or enforceability of the remainder of the - terms of this Agreement, and without further action by the parties hereto, such - provision shall be reformed to the minimum extent necessary to make such - provision valid and enforceable. - - If Recipient institutes patent litigation against any entity (including a - cross-claim or counterclaim in a lawsuit) alleging that the Program itself - (excluding combinations of the Program with other software or hardware) - infringes such Recipient’s patent(s), then such Recipient’s rights granted under - Section 2(b) shall terminate as of the date such litigation is filed. - - All Recipient’s rights under this Agreement shall terminate if it fails to - comply with any of the material terms or conditions of this Agreement and does - not cure such failure in a reasonable period of time after becoming aware of - such noncompliance. If all Recipient’s rights under this Agreement terminate, - Recipient agrees to cease use and distribution of the Program as soon as - reasonably practicable. However, Recipient’s obligations under this Agreement - and any licenses granted by Recipient relating to the Program shall continue and - survive. - - Everyone is permitted to copy and distribute copies of this Agreement, but in - order to avoid inconsistency the Agreement is copyrighted and may only be - modified in the following manner. The Agreement Steward reserves the right to - publish new versions (including revisions) of this Agreement from time to time. - No one other than the Agreement Steward has the right to modify this Agreement. - The Eclipse Foundation is the initial Agreement Steward. The Eclipse Foundation - may assign the responsibility to serve as the Agreement Steward to a suitable - separate entity. Each new version of the Agreement will be given a - distinguishing version number. The Program (including Contributions) may always - be distributed subject to the version of the Agreement under which it was - received. In addition, after a new version of the Agreement is published, - Contributor may elect to distribute the Program (including its Contributions) - under the new version. Except as expressly stated in Sections 2(a) and 2(b) - above, Recipient receives no rights or licenses to the intellectual property of - any Contributor under this Agreement, whether expressly, by implication, - estoppel or otherwise. All rights in the Program not expressly granted under - this Agreement are reserved. - - This Agreement is governed by the laws of the State of New York and the - intellectual property laws of the United States of America. No party to this - Agreement will bring a legal action under this Agreement more than one year - after the cause of action arose. Each party waives its rights to a jury trial in - any resulting litigation. - --------------------------------------------------- -Library: cabin v0.9.0 -Url: https://github.com/jordansissel/ruby-cabin -License: Apache-2.0 - -Copyright 2011 Jordan Sissel - -Licensed 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. - - --------------------------------------------------- -Library: childprocess v0.9.0 -Url: http://github.com/enkessler/childprocess -License: MIT - -Copyright (c) 2010-2015 Jari Bakken - -Permission is hereby granted, free of charge, to any person obtaining -a copy of this software and associated documentation files (the -"Software"), to deal in the Software without restriction, including -without limitation the rights to use, copy, modify, merge, publish, -distribute, sublicense, and/or sell copies of the Software, and to -permit persons to whom the Software is furnished to do so, subject to -the following conditions: - -The above copyright notice and this permission notice shall be -included in all copies or substantial portions of the Software. - -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, -EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF -MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND -NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE -LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION -OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION -WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. - --------------------------------------------------- -Library: chronic_duration v0.10.6 -Url: https://github.com/hpoydar/chronic_duration -License: MIT - -Copyright (c) Henry Poydar - -Permission is hereby granted, free of charge, to any person -obtaining a copy of this software and associated documentation -files (the "Software"), to deal in the Software without -restriction, including without limitation the rights to use, -copy, modify, merge, publish, distribute, sublicense, and/or sell -copies of the Software, and to permit persons to whom the -Software is furnished to do so, subject to the following -conditions: - -The above copyright notice and this permission notice shall be -included in all copies or substantial portions of the Software. - -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, -EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES -OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND -NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT -HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, -WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING -FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR -OTHER DEALINGS IN THE SOFTWARE. - --------------------------------------------------- -Library: clamp v0.6.5 -Url: http://github.com/mdub/clamp -License: MIT - -Copyright (c) 2010 Mike Williams - -Permission is hereby granted, free of charge, to any person obtaining -a copy of this software and associated documentation files (the -"Software"), to deal in the Software without restriction, including -without limitation the rights to use, copy, modify, merge, publish, -distribute, sublicense, and/or sell copies of the Software, and to -permit persons to whom the Software is furnished to do so, subject to -the following conditions: - -The above copyright notice and this permission notice shall be -included in all copies or substantial portions of the Software. - -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, -EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF -MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND -NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE -LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION -OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION -WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. - --------------------------------------------------- -Library: coderay v1.1.2 -Url: http://coderay.rubychan.de -License: MIT - -Copyright (C) 2005-2012 Kornelius Kalnbach (@murphy_karasu) - -http://coderay.rubychan.de/ - -Permission is hereby granted, free of charge, to any person obtaining -a copy of this software and associated documentation files (the -"Software"), to deal in the Software without restriction, including -without limitation the rights to use, copy, modify, merge, publish, -distribute, sublicense, and/or sell copies of the Software, and to -permit persons to whom the Software is furnished to do so, subject to -the following conditions: - -The above copyright notice and this permission notice shall be -included in all copies or substantial portions of the Software. - -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, -EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF -MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND -NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE -LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION -OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION -WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. - --------------------------------------------------- -Library: jackson-annotations v2.9.5 -Url: https://github.com/FasterXML/jackson-annotations -License: Apache-2.0 - -This copy of Jackson JSON processor annotations is licensed under the -Apache (Software) License, version 2.0 ("the License"). -See the License for details about distribution rights, and the -specific rights regarding derivate works. - -You may obtain a copy of the License at: - -http://www.apache.org/licenses/LICENSE-2.0 - - - - Apache License - Version 2.0, January 2004 - http://www.apache.org/licenses/ - - TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION - - 1. Definitions. - - "License" shall mean the terms and conditions for use, reproduction, - and distribution as defined by Sections 1 through 9 of this document. - - "Licensor" shall mean the copyright owner or entity authorized by - the copyright owner that is granting the License. - - "Legal Entity" shall mean the union of the acting entity and all - other entities that control, are controlled by, or are under common - control with that entity. For the purposes of this definition, - "control" means (i) the power, direct or indirect, to cause the - direction or management of such entity, whether by contract or - otherwise, or (ii) ownership of fifty percent (50%) or more of the - outstanding shares, or (iii) beneficial ownership of such entity. - - "You" (or "Your") shall mean an individual or Legal Entity - exercising permissions granted by this License. - - "Source" form shall mean the preferred form for making modifications, - including but not limited to software source code, documentation - source, and configuration files. - - "Object" form shall mean any form resulting from mechanical - transformation or translation of a Source form, including but - not limited to compiled object code, generated documentation, - and conversions to other media types. - - "Work" shall mean the work of authorship, whether in Source or - Object form, made available under the License, as indicated by a - copyright notice that is included in or attached to the work - (an example is provided in the Appendix below). - - "Derivative Works" shall mean any work, whether in Source or Object - form, that is based on (or derived from) the Work and for which the - editorial revisions, annotations, elaborations, or other modifications - represent, as a whole, an original work of authorship. For the purposes - of this License, Derivative Works shall not include works that remain - separable from, or merely link (or bind by name) to the interfaces of, - the Work and Derivative Works thereof. - - "Contribution" shall mean any work of authorship, including - the original version of the Work and any modifications or additions - to that Work or Derivative Works thereof, that is intentionally - submitted to Licensor for inclusion in the Work by the copyright owner - or by an individual or Legal Entity authorized to submit on behalf of - the copyright owner. For the purposes of this definition, "submitted" - means any form of electronic, verbal, or written communication sent - to the Licensor or its representatives, including but not limited to - communication on electronic mailing lists, source code control systems, - and issue tracking systems that are managed by, or on behalf of, the - Licensor for the purpose of discussing and improving the Work, but - excluding communication that is conspicuously marked or otherwise - designated in writing by the copyright owner as "Not a Contribution." - - "Contributor" shall mean Licensor and any individual or Legal Entity - on behalf of whom a Contribution has been received by Licensor and - subsequently incorporated within the Work. - - 2. Grant of Copyright License. Subject to the terms and conditions of - this License, each Contributor hereby grants to You a perpetual, - worldwide, non-exclusive, no-charge, royalty-free, irrevocable - copyright license to reproduce, prepare Derivative Works of, - publicly display, publicly perform, sublicense, and distribute the - Work and such Derivative Works in Source or Object form. - - 3. Grant of Patent License. Subject to the terms and conditions of - this License, each Contributor hereby grants to You a perpetual, - worldwide, non-exclusive, no-charge, royalty-free, irrevocable - (except as stated in this section) patent license to make, have made, - use, offer to sell, sell, import, and otherwise transfer the Work, - where such license applies only to those patent claims licensable - by such Contributor that are necessarily infringed by their - Contribution(s) alone or by combination of their Contribution(s) - with the Work to which such Contribution(s) was submitted. If You - institute patent litigation against any entity (including a - cross-claim or counterclaim in a lawsuit) alleging that the Work - or a Contribution incorporated within the Work constitutes direct - or contributory patent infringement, then any patent licenses - granted to You under this License for that Work shall terminate - as of the date such litigation is filed. - - 4. Redistribution. You may reproduce and distribute copies of the - Work or Derivative Works thereof in any medium, with or without - modifications, and in Source or Object form, provided that You - meet the following conditions: - - (a) You must give any other recipients of the Work or - Derivative Works a copy of this License; and - - (b) You must cause any modified files to carry prominent notices - stating that You changed the files; and - - (c) You must retain, in the Source form of any Derivative Works - that You distribute, all copyright, patent, trademark, and - attribution notices from the Source form of the Work, - excluding those notices that do not pertain to any part of - the Derivative Works; and - - (d) If the Work includes a "NOTICE" text file as part of its - distribution, then any Derivative Works that You distribute must - include a readable copy of the attribution notices contained - within such NOTICE file, excluding those notices that do not - pertain to any part of the Derivative Works, in at least one - of the following places: within a NOTICE text file distributed - as part of the Derivative Works; within the Source form or - documentation, if provided along with the Derivative Works; or, - within a display generated by the Derivative Works, if and - wherever such third-party notices normally appear. The contents - of the NOTICE file are for informational purposes only and - do not modify the License. You may add Your own attribution - notices within Derivative Works that You distribute, alongside - or as an addendum to the NOTICE text from the Work, provided - that such additional attribution notices cannot be construed - as modifying the License. - - You may add Your own copyright statement to Your modifications and - may provide additional or different license terms and conditions - for use, reproduction, or distribution of Your modifications, or - for any such Derivative Works as a whole, provided Your use, - reproduction, and distribution of the Work otherwise complies with - the conditions stated in this License. - - 5. Submission of Contributions. Unless You explicitly state otherwise, - any Contribution intentionally submitted for inclusion in the Work - by You to the Licensor shall be under the terms and conditions of - this License, without any additional terms or conditions. - Notwithstanding the above, nothing herein shall supersede or modify - the terms of any separate license agreement you may have executed - with Licensor regarding such Contributions. - - 6. Trademarks. This License does not grant permission to use the trade - names, trademarks, service marks, or product names of the Licensor, - except as required for reasonable and customary use in describing the - origin of the Work and reproducing the content of the NOTICE file. - - 7. Disclaimer of Warranty. Unless required by applicable law or - agreed to in writing, Licensor provides the Work (and each - Contributor provides its Contributions) on an "AS IS" BASIS, - WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or - implied, including, without limitation, any warranties or conditions - of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A - PARTICULAR PURPOSE. You are solely responsible for determining the - appropriateness of using or redistributing the Work and assume any - risks associated with Your exercise of permissions under this License. - - 8. Limitation of Liability. In no event and under no legal theory, - whether in tort (including negligence), contract, or otherwise, - unless required by applicable law (such as deliberate and grossly - negligent acts) or agreed to in writing, shall any Contributor be - liable to You for damages, including any direct, indirect, special, - incidental, or consequential damages of any character arising as a - result of this License or out of the use or inability to use the - Work (including but not limited to damages for loss of goodwill, - work stoppage, computer failure or malfunction, or any and all - other commercial damages or losses), even if such Contributor - has been advised of the possibility of such damages. - - 9. Accepting Warranty or Additional Liability. While redistributing - the Work or Derivative Works thereof, You may choose to offer, - and charge a fee for, acceptance of support, warranty, indemnity, - or other liability obligations and/or rights consistent with this - License. However, in accepting such obligations, You may act only - on Your own behalf and on Your sole responsibility, not on behalf - of any other Contributor, and only if You agree to indemnify, - defend, and hold each Contributor harmless for any liability - incurred by, or claims asserted against, such Contributor by reason - of your accepting any such warranty or additional liability. - - END OF TERMS AND CONDITIONS - - APPENDIX: How to apply the Apache License to your work. - - To apply the Apache License to your work, attach the following - boilerplate notice, with the fields enclosed by brackets "[]" - replaced with your own identifying information. (Don't include - the brackets!) The text should be enclosed in the appropriate - comment syntax for the file format. We also recommend that a - file or class name and description of purpose be included on the - same "printed page" as the copyright notice for easier - identification within third-party archives. - - Copyright [yyyy] [name of copyright owner] - - Licensed 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. - --------------------------------------------------- -Library: jackson-core v2.9.5 -Url: https://github.com/FasterXML/jackson-core -License: Apache-2.0 - -# Jackson JSON processor - -Jackson is a high-performance, Free/Open Source JSON processing library. -It was originally written by Tatu Saloranta (tatu.saloranta@iki.fi), and has -been in development since 2007. -It is currently developed by a community of developers, as well as supported -commercially by FasterXML.com. - -## Licensing - -Jackson core and extension components may licensed under different licenses. -To find the details that apply to this artifact see the accompanying LICENSE file. -For more information, including possible other licensing options, contact -FasterXML.com (http://fasterxml.com). - -## Credits - -A list of contributors may be found from CREDITS file, which is included -in some artifacts (usually source distributions); but is always available -from the source code management (SCM) system project uses. - - - Apache License - Version 2.0, January 2004 - http://www.apache.org/licenses/ - - TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION - - 1. Definitions. - - "License" shall mean the terms and conditions for use, reproduction, - and distribution as defined by Sections 1 through 9 of this document. - - "Licensor" shall mean the copyright owner or entity authorized by - the copyright owner that is granting the License. - - "Legal Entity" shall mean the union of the acting entity and all - other entities that control, are controlled by, or are under common - control with that entity. For the purposes of this definition, - "control" means (i) the power, direct or indirect, to cause the - direction or management of such entity, whether by contract or - otherwise, or (ii) ownership of fifty percent (50%) or more of the - outstanding shares, or (iii) beneficial ownership of such entity. - - "You" (or "Your") shall mean an individual or Legal Entity - exercising permissions granted by this License. - - "Source" form shall mean the preferred form for making modifications, - including but not limited to software source code, documentation - source, and configuration files. - - "Object" form shall mean any form resulting from mechanical - transformation or translation of a Source form, including but - not limited to compiled object code, generated documentation, - and conversions to other media types. - - "Work" shall mean the work of authorship, whether in Source or - Object form, made available under the License, as indicated by a - copyright notice that is included in or attached to the work - (an example is provided in the Appendix below). - - "Derivative Works" shall mean any work, whether in Source or Object - form, that is based on (or derived from) the Work and for which the - editorial revisions, annotations, elaborations, or other modifications - represent, as a whole, an original work of authorship. For the purposes - of this License, Derivative Works shall not include works that remain - separable from, or merely link (or bind by name) to the interfaces of, - the Work and Derivative Works thereof. - - "Contribution" shall mean any work of authorship, including - the original version of the Work and any modifications or additions - to that Work or Derivative Works thereof, that is intentionally - submitted to Licensor for inclusion in the Work by the copyright owner - or by an individual or Legal Entity authorized to submit on behalf of - the copyright owner. For the purposes of this definition, "submitted" - means any form of electronic, verbal, or written communication sent - to the Licensor or its representatives, including but not limited to - communication on electronic mailing lists, source code control systems, - and issue tracking systems that are managed by, or on behalf of, the - Licensor for the purpose of discussing and improving the Work, but - excluding communication that is conspicuously marked or otherwise - designated in writing by the copyright owner as "Not a Contribution." - - "Contributor" shall mean Licensor and any individual or Legal Entity - on behalf of whom a Contribution has been received by Licensor and - subsequently incorporated within the Work. - - 2. Grant of Copyright License. Subject to the terms and conditions of - this License, each Contributor hereby grants to You a perpetual, - worldwide, non-exclusive, no-charge, royalty-free, irrevocable - copyright license to reproduce, prepare Derivative Works of, - publicly display, publicly perform, sublicense, and distribute the - Work and such Derivative Works in Source or Object form. - - 3. Grant of Patent License. Subject to the terms and conditions of - this License, each Contributor hereby grants to You a perpetual, - worldwide, non-exclusive, no-charge, royalty-free, irrevocable - (except as stated in this section) patent license to make, have made, - use, offer to sell, sell, import, and otherwise transfer the Work, - where such license applies only to those patent claims licensable - by such Contributor that are necessarily infringed by their - Contribution(s) alone or by combination of their Contribution(s) - with the Work to which such Contribution(s) was submitted. If You - institute patent litigation against any entity (including a - cross-claim or counterclaim in a lawsuit) alleging that the Work - or a Contribution incorporated within the Work constitutes direct - or contributory patent infringement, then any patent licenses - granted to You under this License for that Work shall terminate - as of the date such litigation is filed. - - 4. Redistribution. You may reproduce and distribute copies of the - Work or Derivative Works thereof in any medium, with or without - modifications, and in Source or Object form, provided that You - meet the following conditions: - - (a) You must give any other recipients of the Work or - Derivative Works a copy of this License; and - - (b) You must cause any modified files to carry prominent notices - stating that You changed the files; and - - (c) You must retain, in the Source form of any Derivative Works - that You distribute, all copyright, patent, trademark, and - attribution notices from the Source form of the Work, - excluding those notices that do not pertain to any part of - the Derivative Works; and - - (d) If the Work includes a "NOTICE" text file as part of its - distribution, then any Derivative Works that You distribute must - include a readable copy of the attribution notices contained - within such NOTICE file, excluding those notices that do not - pertain to any part of the Derivative Works, in at least one - of the following places: within a NOTICE text file distributed - as part of the Derivative Works; within the Source form or - documentation, if provided along with the Derivative Works; or, - within a display generated by the Derivative Works, if and - wherever such third-party notices normally appear. The contents - of the NOTICE file are for informational purposes only and - do not modify the License. You may add Your own attribution - notices within Derivative Works that You distribute, alongside - or as an addendum to the NOTICE text from the Work, provided - that such additional attribution notices cannot be construed - as modifying the License. - - You may add Your own copyright statement to Your modifications and - may provide additional or different license terms and conditions - for use, reproduction, or distribution of Your modifications, or - for any such Derivative Works as a whole, provided Your use, - reproduction, and distribution of the Work otherwise complies with - the conditions stated in this License. - - 5. Submission of Contributions. Unless You explicitly state otherwise, - any Contribution intentionally submitted for inclusion in the Work - by You to the Licensor shall be under the terms and conditions of - this License, without any additional terms or conditions. - Notwithstanding the above, nothing herein shall supersede or modify - the terms of any separate license agreement you may have executed - with Licensor regarding such Contributions. - - 6. Trademarks. This License does not grant permission to use the trade - names, trademarks, service marks, or product names of the Licensor, - except as required for reasonable and customary use in describing the - origin of the Work and reproducing the content of the NOTICE file. - - 7. Disclaimer of Warranty. Unless required by applicable law or - agreed to in writing, Licensor provides the Work (and each - Contributor provides its Contributions) on an "AS IS" BASIS, - WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or - implied, including, without limitation, any warranties or conditions - of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A - PARTICULAR PURPOSE. You are solely responsible for determining the - appropriateness of using or redistributing the Work and assume any - risks associated with Your exercise of permissions under this License. - - 8. Limitation of Liability. In no event and under no legal theory, - whether in tort (including negligence), contract, or otherwise, - unless required by applicable law (such as deliberate and grossly - negligent acts) or agreed to in writing, shall any Contributor be - liable to You for damages, including any direct, indirect, special, - incidental, or consequential damages of any character arising as a - result of this License or out of the use or inability to use the - Work (including but not limited to damages for loss of goodwill, - work stoppage, computer failure or malfunction, or any and all - other commercial damages or losses), even if such Contributor - has been advised of the possibility of such damages. - - 9. Accepting Warranty or Additional Liability. While redistributing - the Work or Derivative Works thereof, You may choose to offer, - and charge a fee for, acceptance of support, warranty, indemnity, - or other liability obligations and/or rights consistent with this - License. However, in accepting such obligations, You may act only - on Your own behalf and on Your sole responsibility, not on behalf - of any other Contributor, and only if You agree to indemnify, - defend, and hold each Contributor harmless for any liability - incurred by, or claims asserted against, such Contributor by reason - of your accepting any such warranty or additional liability. - - END OF TERMS AND CONDITIONS - - APPENDIX: How to apply the Apache License to your work. - - To apply the Apache License to your work, attach the following - boilerplate notice, with the fields enclosed by brackets "[]" - replaced with your own identifying information. (Don't include - the brackets!) The text should be enclosed in the appropriate - comment syntax for the file format. We also recommend that a - file or class name and description of purpose be included on the - same "printed page" as the copyright notice for easier - identification within third-party archives. - - Copyright [yyyy] [name of copyright owner] - - Licensed 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. - --------------------------------------------------- -Library: jackson-databind v2.9.5 -Url: https://github.com/FasterXML/jackson-databind -License: Apache-2.0 - -# Jackson JSON processor - -Jackson is a high-performance, Free/Open Source JSON processing library. -It was originally written by Tatu Saloranta (tatu.saloranta@iki.fi), and has -been in development since 2007. -It is currently developed by a community of developers, as well as supported -commercially by FasterXML.com. - -## Licensing - -Jackson core and extension components may be licensed under different licenses. -To find the details that apply to this artifact see the accompanying LICENSE file. -For more information, including possible other licensing options, contact -FasterXML.com (http://fasterxml.com). - -## Credits - -A list of contributors may be found from CREDITS file, which is included -in some artifacts (usually source distributions); but is always available -from the source code management (SCM) system project uses. - -This copy of Jackson JSON processor databind module is licensed under the -Apache (Software) License, version 2.0 ("the License"). -See the License for details about distribution rights, and the -specific rights regarding derivate works. - -You may obtain a copy of the License at: - -http://www.apache.org/licenses/LICENSE-2.0 - - - Apache License - Version 2.0, January 2004 - http://www.apache.org/licenses/ - - TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION - - 1. Definitions. - - "License" shall mean the terms and conditions for use, reproduction, - and distribution as defined by Sections 1 through 9 of this document. - - "Licensor" shall mean the copyright owner or entity authorized by - the copyright owner that is granting the License. - - "Legal Entity" shall mean the union of the acting entity and all - other entities that control, are controlled by, or are under common - control with that entity. For the purposes of this definition, - "control" means (i) the power, direct or indirect, to cause the - direction or management of such entity, whether by contract or - otherwise, or (ii) ownership of fifty percent (50%) or more of the - outstanding shares, or (iii) beneficial ownership of such entity. - - "You" (or "Your") shall mean an individual or Legal Entity - exercising permissions granted by this License. - - "Source" form shall mean the preferred form for making modifications, - including but not limited to software source code, documentation - source, and configuration files. - - "Object" form shall mean any form resulting from mechanical - transformation or translation of a Source form, including but - not limited to compiled object code, generated documentation, - and conversions to other media types. - - "Work" shall mean the work of authorship, whether in Source or - Object form, made available under the License, as indicated by a - copyright notice that is included in or attached to the work - (an example is provided in the Appendix below). - - "Derivative Works" shall mean any work, whether in Source or Object - form, that is based on (or derived from) the Work and for which the - editorial revisions, annotations, elaborations, or other modifications - represent, as a whole, an original work of authorship. For the purposes - of this License, Derivative Works shall not include works that remain - separable from, or merely link (or bind by name) to the interfaces of, - the Work and Derivative Works thereof. - - "Contribution" shall mean any work of authorship, including - the original version of the Work and any modifications or additions - to that Work or Derivative Works thereof, that is intentionally - submitted to Licensor for inclusion in the Work by the copyright owner - or by an individual or Legal Entity authorized to submit on behalf of - the copyright owner. For the purposes of this definition, "submitted" - means any form of electronic, verbal, or written communication sent - to the Licensor or its representatives, including but not limited to - communication on electronic mailing lists, source code control systems, - and issue tracking systems that are managed by, or on behalf of, the - Licensor for the purpose of discussing and improving the Work, but - excluding communication that is conspicuously marked or otherwise - designated in writing by the copyright owner as "Not a Contribution." - - "Contributor" shall mean Licensor and any individual or Legal Entity - on behalf of whom a Contribution has been received by Licensor and - subsequently incorporated within the Work. - - 2. Grant of Copyright License. Subject to the terms and conditions of - this License, each Contributor hereby grants to You a perpetual, - worldwide, non-exclusive, no-charge, royalty-free, irrevocable - copyright license to reproduce, prepare Derivative Works of, - publicly display, publicly perform, sublicense, and distribute the - Work and such Derivative Works in Source or Object form. - - 3. Grant of Patent License. Subject to the terms and conditions of - this License, each Contributor hereby grants to You a perpetual, - worldwide, non-exclusive, no-charge, royalty-free, irrevocable - (except as stated in this section) patent license to make, have made, - use, offer to sell, sell, import, and otherwise transfer the Work, - where such license applies only to those patent claims licensable - by such Contributor that are necessarily infringed by their - Contribution(s) alone or by combination of their Contribution(s) - with the Work to which such Contribution(s) was submitted. If You - institute patent litigation against any entity (including a - cross-claim or counterclaim in a lawsuit) alleging that the Work - or a Contribution incorporated within the Work constitutes direct - or contributory patent infringement, then any patent licenses - granted to You under this License for that Work shall terminate - as of the date such litigation is filed. - - 4. Redistribution. You may reproduce and distribute copies of the - Work or Derivative Works thereof in any medium, with or without - modifications, and in Source or Object form, provided that You - meet the following conditions: - - (a) You must give any other recipients of the Work or - Derivative Works a copy of this License; and - - (b) You must cause any modified files to carry prominent notices - stating that You changed the files; and - - (c) You must retain, in the Source form of any Derivative Works - that You distribute, all copyright, patent, trademark, and - attribution notices from the Source form of the Work, - excluding those notices that do not pertain to any part of - the Derivative Works; and - - (d) If the Work includes a "NOTICE" text file as part of its - distribution, then any Derivative Works that You distribute must - include a readable copy of the attribution notices contained - within such NOTICE file, excluding those notices that do not - pertain to any part of the Derivative Works, in at least one - of the following places: within a NOTICE text file distributed - as part of the Derivative Works; within the Source form or - documentation, if provided along with the Derivative Works; or, - within a display generated by the Derivative Works, if and - wherever such third-party notices normally appear. The contents - of the NOTICE file are for informational purposes only and - do not modify the License. You may add Your own attribution - notices within Derivative Works that You distribute, alongside - or as an addendum to the NOTICE text from the Work, provided - that such additional attribution notices cannot be construed - as modifying the License. - - You may add Your own copyright statement to Your modifications and - may provide additional or different license terms and conditions - for use, reproduction, or distribution of Your modifications, or - for any such Derivative Works as a whole, provided Your use, - reproduction, and distribution of the Work otherwise complies with - the conditions stated in this License. - - 5. Submission of Contributions. Unless You explicitly state otherwise, - any Contribution intentionally submitted for inclusion in the Work - by You to the Licensor shall be under the terms and conditions of - this License, without any additional terms or conditions. - Notwithstanding the above, nothing herein shall supersede or modify - the terms of any separate license agreement you may have executed - with Licensor regarding such Contributions. - - 6. Trademarks. This License does not grant permission to use the trade - names, trademarks, service marks, or product names of the Licensor, - except as required for reasonable and customary use in describing the - origin of the Work and reproducing the content of the NOTICE file. - - 7. Disclaimer of Warranty. Unless required by applicable law or - agreed to in writing, Licensor provides the Work (and each - Contributor provides its Contributions) on an "AS IS" BASIS, - WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or - implied, including, without limitation, any warranties or conditions - of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A - PARTICULAR PURPOSE. You are solely responsible for determining the - appropriateness of using or redistributing the Work and assume any - risks associated with Your exercise of permissions under this License. - - 8. Limitation of Liability. In no event and under no legal theory, - whether in tort (including negligence), contract, or otherwise, - unless required by applicable law (such as deliberate and grossly - negligent acts) or agreed to in writing, shall any Contributor be - liable to You for damages, including any direct, indirect, special, - incidental, or consequential damages of any character arising as a - result of this License or out of the use or inability to use the - Work (including but not limited to damages for loss of goodwill, - work stoppage, computer failure or malfunction, or any and all - other commercial damages or losses), even if such Contributor - has been advised of the possibility of such damages. - - 9. Accepting Warranty or Additional Liability. While redistributing - the Work or Derivative Works thereof, You may choose to offer, - and charge a fee for, acceptance of support, warranty, indemnity, - or other liability obligations and/or rights consistent with this - License. However, in accepting such obligations, You may act only - on Your own behalf and on Your sole responsibility, not on behalf - of any other Contributor, and only if You agree to indemnify, - defend, and hold each Contributor harmless for any liability - incurred by, or claims asserted against, such Contributor by reason - of your accepting any such warranty or additional liability. - - END OF TERMS AND CONDITIONS - - APPENDIX: How to apply the Apache License to your work. - - To apply the Apache License to your work, attach the following - boilerplate notice, with the fields enclosed by brackets "[]" - replaced with your own identifying information. (Don't include - the brackets!) The text should be enclosed in the appropriate - comment syntax for the file format. We also recommend that a - file or class name and description of purpose be included on the - same "printed page" as the copyright notice for easier - identification within third-party archives. - - Copyright [yyyy] [name of copyright owner] - - Licensed 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. - --------------------------------------------------- -Library: jackson-dataformat-cbor v2.9.5 -Url: https://github.com/FasterXML/jackson-dataformats-binary -License: Apache-2.0 - -This copy of Jackson JSON processor databind module is licensed under the -Apache (Software) License, version 2.0 ("the License"). -See the License for details about distribution rights, and the -specific rights regarding derivate works. - -You may obtain a copy of the License at: - -http://www.apache.org/licenses/LICENSE-2.0 - - - Apache License - Version 2.0, January 2004 - http://www.apache.org/licenses/ - - TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION - - 1. Definitions. - - "License" shall mean the terms and conditions for use, reproduction, - and distribution as defined by Sections 1 through 9 of this document. - - "Licensor" shall mean the copyright owner or entity authorized by - the copyright owner that is granting the License. - - "Legal Entity" shall mean the union of the acting entity and all - other entities that control, are controlled by, or are under common - control with that entity. For the purposes of this definition, - "control" means (i) the power, direct or indirect, to cause the - direction or management of such entity, whether by contract or - otherwise, or (ii) ownership of fifty percent (50%) or more of the - outstanding shares, or (iii) beneficial ownership of such entity. - - "You" (or "Your") shall mean an individual or Legal Entity - exercising permissions granted by this License. - - "Source" form shall mean the preferred form for making modifications, - including but not limited to software source code, documentation - source, and configuration files. - - "Object" form shall mean any form resulting from mechanical - transformation or translation of a Source form, including but - not limited to compiled object code, generated documentation, - and conversions to other media types. - - "Work" shall mean the work of authorship, whether in Source or - Object form, made available under the License, as indicated by a - copyright notice that is included in or attached to the work - (an example is provided in the Appendix below). - - "Derivative Works" shall mean any work, whether in Source or Object - form, that is based on (or derived from) the Work and for which the - editorial revisions, annotations, elaborations, or other modifications - represent, as a whole, an original work of authorship. For the purposes - of this License, Derivative Works shall not include works that remain - separable from, or merely link (or bind by name) to the interfaces of, - the Work and Derivative Works thereof. - - "Contribution" shall mean any work of authorship, including - the original version of the Work and any modifications or additions - to that Work or Derivative Works thereof, that is intentionally - submitted to Licensor for inclusion in the Work by the copyright owner - or by an individual or Legal Entity authorized to submit on behalf of - the copyright owner. For the purposes of this definition, "submitted" - means any form of electronic, verbal, or written communication sent - to the Licensor or its representatives, including but not limited to - communication on electronic mailing lists, source code control systems, - and issue tracking systems that are managed by, or on behalf of, the - Licensor for the purpose of discussing and improving the Work, but - excluding communication that is conspicuously marked or otherwise - designated in writing by the copyright owner as "Not a Contribution." - - "Contributor" shall mean Licensor and any individual or Legal Entity - on behalf of whom a Contribution has been received by Licensor and - subsequently incorporated within the Work. - - 2. Grant of Copyright License. Subject to the terms and conditions of - this License, each Contributor hereby grants to You a perpetual, - worldwide, non-exclusive, no-charge, royalty-free, irrevocable - copyright license to reproduce, prepare Derivative Works of, - publicly display, publicly perform, sublicense, and distribute the - Work and such Derivative Works in Source or Object form. - - 3. Grant of Patent License. Subject to the terms and conditions of - this License, each Contributor hereby grants to You a perpetual, - worldwide, non-exclusive, no-charge, royalty-free, irrevocable - (except as stated in this section) patent license to make, have made, - use, offer to sell, sell, import, and otherwise transfer the Work, - where such license applies only to those patent claims licensable - by such Contributor that are necessarily infringed by their - Contribution(s) alone or by combination of their Contribution(s) - with the Work to which such Contribution(s) was submitted. If You - institute patent litigation against any entity (including a - cross-claim or counterclaim in a lawsuit) alleging that the Work - or a Contribution incorporated within the Work constitutes direct - or contributory patent infringement, then any patent licenses - granted to You under this License for that Work shall terminate - as of the date such litigation is filed. - - 4. Redistribution. You may reproduce and distribute copies of the - Work or Derivative Works thereof in any medium, with or without - modifications, and in Source or Object form, provided that You - meet the following conditions: - - (a) You must give any other recipients of the Work or - Derivative Works a copy of this License; and - - (b) You must cause any modified files to carry prominent notices - stating that You changed the files; and - - (c) You must retain, in the Source form of any Derivative Works - that You distribute, all copyright, patent, trademark, and - attribution notices from the Source form of the Work, - excluding those notices that do not pertain to any part of - the Derivative Works; and - - (d) If the Work includes a "NOTICE" text file as part of its - distribution, then any Derivative Works that You distribute must - include a readable copy of the attribution notices contained - within such NOTICE file, excluding those notices that do not - pertain to any part of the Derivative Works, in at least one - of the following places: within a NOTICE text file distributed - as part of the Derivative Works; within the Source form or - documentation, if provided along with the Derivative Works; or, - within a display generated by the Derivative Works, if and - wherever such third-party notices normally appear. The contents - of the NOTICE file are for informational purposes only and - do not modify the License. You may add Your own attribution - notices within Derivative Works that You distribute, alongside - or as an addendum to the NOTICE text from the Work, provided - that such additional attribution notices cannot be construed - as modifying the License. - - You may add Your own copyright statement to Your modifications and - may provide additional or different license terms and conditions - for use, reproduction, or distribution of Your modifications, or - for any such Derivative Works as a whole, provided Your use, - reproduction, and distribution of the Work otherwise complies with - the conditions stated in this License. - - 5. Submission of Contributions. Unless You explicitly state otherwise, - any Contribution intentionally submitted for inclusion in the Work - by You to the Licensor shall be under the terms and conditions of - this License, without any additional terms or conditions. - Notwithstanding the above, nothing herein shall supersede or modify - the terms of any separate license agreement you may have executed - with Licensor regarding such Contributions. - - 6. Trademarks. This License does not grant permission to use the trade - names, trademarks, service marks, or product names of the Licensor, - except as required for reasonable and customary use in describing the - origin of the Work and reproducing the content of the NOTICE file. - - 7. Disclaimer of Warranty. Unless required by applicable law or - agreed to in writing, Licensor provides the Work (and each - Contributor provides its Contributions) on an "AS IS" BASIS, - WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or - implied, including, without limitation, any warranties or conditions - of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A - PARTICULAR PURPOSE. You are solely responsible for determining the - appropriateness of using or redistributing the Work and assume any - risks associated with Your exercise of permissions under this License. - - 8. Limitation of Liability. In no event and under no legal theory, - whether in tort (including negligence), contract, or otherwise, - unless required by applicable law (such as deliberate and grossly - negligent acts) or agreed to in writing, shall any Contributor be - liable to You for damages, including any direct, indirect, special, - incidental, or consequential damages of any character arising as a - result of this License or out of the use or inability to use the - Work (including but not limited to damages for loss of goodwill, - work stoppage, computer failure or malfunction, or any and all - other commercial damages or losses), even if such Contributor - has been advised of the possibility of such damages. - - 9. Accepting Warranty or Additional Liability. While redistributing - the Work or Derivative Works thereof, You may choose to offer, - and charge a fee for, acceptance of support, warranty, indemnity, - or other liability obligations and/or rights consistent with this - License. However, in accepting such obligations, You may act only - on Your own behalf and on Your sole responsibility, not on behalf - of any other Contributor, and only if You agree to indemnify, - defend, and hold each Contributor harmless for any liability - incurred by, or claims asserted against, such Contributor by reason - of your accepting any such warranty or additional liability. - - END OF TERMS AND CONDITIONS - - APPENDIX: How to apply the Apache License to your work. - - To apply the Apache License to your work, attach the following - boilerplate notice, with the fields enclosed by brackets "[]" - replaced with your own identifying information. (Don't include - the brackets!) The text should be enclosed in the appropriate - comment syntax for the file format. We also recommend that a - file or class name and description of purpose be included on the - same "printed page" as the copyright notice for easier - identification within third-party archives. - - Copyright [yyyy] [name of copyright owner] - - Licensed 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. - --------------------------------------------------- -Library: jackson-module-afterburner v2.9.5 -Url: https://github.com/FasterXML/jackson-modules-base -License: Apache-2.0 - -This copy of Jackson JSON processor databind module is licensed under the -Apache (Software) License, version 2.0 ("the License"). -See the License for details about distribution rights, and the -specific rights regarding derivate works. - -You may obtain a copy of the License at: - -http://www.apache.org/licenses/LICENSE-2.0 - - - Apache License - Version 2.0, January 2004 - http://www.apache.org/licenses/ - - TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION - - 1. Definitions. - - "License" shall mean the terms and conditions for use, reproduction, - and distribution as defined by Sections 1 through 9 of this document. - - "Licensor" shall mean the copyright owner or entity authorized by - the copyright owner that is granting the License. - - "Legal Entity" shall mean the union of the acting entity and all - other entities that control, are controlled by, or are under common - control with that entity. For the purposes of this definition, - "control" means (i) the power, direct or indirect, to cause the - direction or management of such entity, whether by contract or - otherwise, or (ii) ownership of fifty percent (50%) or more of the - outstanding shares, or (iii) beneficial ownership of such entity. - - "You" (or "Your") shall mean an individual or Legal Entity - exercising permissions granted by this License. - - "Source" form shall mean the preferred form for making modifications, - including but not limited to software source code, documentation - source, and configuration files. - - "Object" form shall mean any form resulting from mechanical - transformation or translation of a Source form, including but - not limited to compiled object code, generated documentation, - and conversions to other media types. - - "Work" shall mean the work of authorship, whether in Source or - Object form, made available under the License, as indicated by a - copyright notice that is included in or attached to the work - (an example is provided in the Appendix below). - - "Derivative Works" shall mean any work, whether in Source or Object - form, that is based on (or derived from) the Work and for which the - editorial revisions, annotations, elaborations, or other modifications - represent, as a whole, an original work of authorship. For the purposes - of this License, Derivative Works shall not include works that remain - separable from, or merely link (or bind by name) to the interfaces of, - the Work and Derivative Works thereof. - - "Contribution" shall mean any work of authorship, including - the original version of the Work and any modifications or additions - to that Work or Derivative Works thereof, that is intentionally - submitted to Licensor for inclusion in the Work by the copyright owner - or by an individual or Legal Entity authorized to submit on behalf of - the copyright owner. For the purposes of this definition, "submitted" - means any form of electronic, verbal, or written communication sent - to the Licensor or its representatives, including but not limited to - communication on electronic mailing lists, source code control systems, - and issue tracking systems that are managed by, or on behalf of, the - Licensor for the purpose of discussing and improving the Work, but - excluding communication that is conspicuously marked or otherwise - designated in writing by the copyright owner as "Not a Contribution." - - "Contributor" shall mean Licensor and any individual or Legal Entity - on behalf of whom a Contribution has been received by Licensor and - subsequently incorporated within the Work. - - 2. Grant of Copyright License. Subject to the terms and conditions of - this License, each Contributor hereby grants to You a perpetual, - worldwide, non-exclusive, no-charge, royalty-free, irrevocable - copyright license to reproduce, prepare Derivative Works of, - publicly display, publicly perform, sublicense, and distribute the - Work and such Derivative Works in Source or Object form. - - 3. Grant of Patent License. Subject to the terms and conditions of - this License, each Contributor hereby grants to You a perpetual, - worldwide, non-exclusive, no-charge, royalty-free, irrevocable - (except as stated in this section) patent license to make, have made, - use, offer to sell, sell, import, and otherwise transfer the Work, - where such license applies only to those patent claims licensable - by such Contributor that are necessarily infringed by their - Contribution(s) alone or by combination of their Contribution(s) - with the Work to which such Contribution(s) was submitted. If You - institute patent litigation against any entity (including a - cross-claim or counterclaim in a lawsuit) alleging that the Work - or a Contribution incorporated within the Work constitutes direct - or contributory patent infringement, then any patent licenses - granted to You under this License for that Work shall terminate - as of the date such litigation is filed. - - 4. Redistribution. You may reproduce and distribute copies of the - Work or Derivative Works thereof in any medium, with or without - modifications, and in Source or Object form, provided that You - meet the following conditions: - - (a) You must give any other recipients of the Work or - Derivative Works a copy of this License; and - - (b) You must cause any modified files to carry prominent notices - stating that You changed the files; and - - (c) You must retain, in the Source form of any Derivative Works - that You distribute, all copyright, patent, trademark, and - attribution notices from the Source form of the Work, - excluding those notices that do not pertain to any part of - the Derivative Works; and - - (d) If the Work includes a "NOTICE" text file as part of its - distribution, then any Derivative Works that You distribute must - include a readable copy of the attribution notices contained - within such NOTICE file, excluding those notices that do not - pertain to any part of the Derivative Works, in at least one - of the following places: within a NOTICE text file distributed - as part of the Derivative Works; within the Source form or - documentation, if provided along with the Derivative Works; or, - within a display generated by the Derivative Works, if and - wherever such third-party notices normally appear. The contents - of the NOTICE file are for informational purposes only and - do not modify the License. You may add Your own attribution - notices within Derivative Works that You distribute, alongside - or as an addendum to the NOTICE text from the Work, provided - that such additional attribution notices cannot be construed - as modifying the License. - - You may add Your own copyright statement to Your modifications and - may provide additional or different license terms and conditions - for use, reproduction, or distribution of Your modifications, or - for any such Derivative Works as a whole, provided Your use, - reproduction, and distribution of the Work otherwise complies with - the conditions stated in this License. - - 5. Submission of Contributions. Unless You explicitly state otherwise, - any Contribution intentionally submitted for inclusion in the Work - by You to the Licensor shall be under the terms and conditions of - this License, without any additional terms or conditions. - Notwithstanding the above, nothing herein shall supersede or modify - the terms of any separate license agreement you may have executed - with Licensor regarding such Contributions. - - 6. Trademarks. This License does not grant permission to use the trade - names, trademarks, service marks, or product names of the Licensor, - except as required for reasonable and customary use in describing the - origin of the Work and reproducing the content of the NOTICE file. - - 7. Disclaimer of Warranty. Unless required by applicable law or - agreed to in writing, Licensor provides the Work (and each - Contributor provides its Contributions) on an "AS IS" BASIS, - WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or - implied, including, without limitation, any warranties or conditions - of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A - PARTICULAR PURPOSE. You are solely responsible for determining the - appropriateness of using or redistributing the Work and assume any - risks associated with Your exercise of permissions under this License. - - 8. Limitation of Liability. In no event and under no legal theory, - whether in tort (including negligence), contract, or otherwise, - unless required by applicable law (such as deliberate and grossly - negligent acts) or agreed to in writing, shall any Contributor be - liable to You for damages, including any direct, indirect, special, - incidental, or consequential damages of any character arising as a - result of this License or out of the use or inability to use the - Work (including but not limited to damages for loss of goodwill, - work stoppage, computer failure or malfunction, or any and all - other commercial damages or losses), even if such Contributor - has been advised of the possibility of such damages. - - 9. Accepting Warranty or Additional Liability. While redistributing - the Work or Derivative Works thereof, You may choose to offer, - and charge a fee for, acceptance of support, warranty, indemnity, - or other liability obligations and/or rights consistent with this - License. However, in accepting such obligations, You may act only - on Your own behalf and on Your sole responsibility, not on behalf - of any other Contributor, and only if You agree to indemnify, - defend, and hold each Contributor harmless for any liability - incurred by, or claims asserted against, such Contributor by reason - of your accepting any such warranty or additional liability. - - END OF TERMS AND CONDITIONS - - APPENDIX: How to apply the Apache License to your work. - - To apply the Apache License to your work, attach the following - boilerplate notice, with the fields enclosed by brackets "[]" - replaced with your own identifying information. (Don't include - the brackets!) The text should be enclosed in the appropriate - comment syntax for the file format. We also recommend that a - file or class name and description of purpose be included on the - same "printed page" as the copyright notice for easier - identification within third-party archives. - - Copyright [yyyy] [name of copyright owner] - - Licensed 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. - --------------------------------------------------- -Library: jnr-unixsocket v -Url: "https://github.com/jnr/jnr-unixsocket" -License: Apache-2.0 - -source: https://github.com/jnr/jnr-unixsocket/search?q=copyright - -Files in this project are licensed under the Apache-2.0 License, and are variably copyright as follows: - - Copyright (C) 2009 Wayne Meissner - Copyright (C) 2014 Greg Vanore - Copyright (C) 2016 Fritz Elfert - Copyright (C) 2016 Marcus Linke - -source: https://github.com/jnr/jnr-unixsocket/blob/jnr-unixsocket-0.18/LICENSE - - Licensed 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. - --------------------------------------------------- -Library: jnr-x86asm v -Url: "https://github.com/jnr/jnr-x86asm" -License: MIT - -source: https://github.com/jnr/jnr-x86asm/blob/1.0.2/LICENSE - - Copyright (C) 2010 Wayne Meissner - Copyright (c) 2008-2009, Petr Kobalicek - - Permission is hereby granted, free of charge, to any person - obtaining a copy of this software and associated documentation - files (the "Software"), to deal in the Software without - restriction, including without limitation the rights to use, - copy, modify, merge, publish, distribute, sublicense, and/or sell - copies of the Software, and to permit persons to whom the - Software is furnished to do so, subject to the following - conditions: - - The above copyright notice and this permission notice shall be - included in all copies or substantial portions of the Software. - - THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, - EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES - OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND - NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT - HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, - WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING - FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR - OTHER DEALINGS IN THE SOFTWARE. - --------------------------------------------------- -Library: google-java-format v1.1 -Url: https://github.com/google/google-java-format -License: Apache-2.0 - -Copyright 2015 Google Inc. - - Apache License - Version 2.0, January 2004 - http://www.apache.org/licenses/ - - TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION - - 1. Definitions. - - "License" shall mean the terms and conditions for use, reproduction, - and distribution as defined by Sections 1 through 9 of this document. - - "Licensor" shall mean the copyright owner or entity authorized by - the copyright owner that is granting the License. - - "Legal Entity" shall mean the union of the acting entity and all - other entities that control, are controlled by, or are under common - control with that entity. For the purposes of this definition, - "control" means (i) the power, direct or indirect, to cause the - direction or management of such entity, whether by contract or - otherwise, or (ii) ownership of fifty percent (50%) or more of the - outstanding shares, or (iii) beneficial ownership of such entity. - - "You" (or "Your") shall mean an individual or Legal Entity - exercising permissions granted by this License. - - "Source" form shall mean the preferred form for making modifications, - including but not limited to software source code, documentation - source, and configuration files. - - "Object" form shall mean any form resulting from mechanical - transformation or translation of a Source form, including but - not limited to compiled object code, generated documentation, - and conversions to other media types. - - "Work" shall mean the work of authorship, whether in Source or - Object form, made available under the License, as indicated by a - copyright notice that is included in or attached to the work - (an example is provided in the Appendix below). - - "Derivative Works" shall mean any work, whether in Source or Object - form, that is based on (or derived from) the Work and for which the - editorial revisions, annotations, elaborations, or other modifications - represent, as a whole, an original work of authorship. For the purposes - of this License, Derivative Works shall not include works that remain - separable from, or merely link (or bind by name) to the interfaces of, - the Work and Derivative Works thereof. - - "Contribution" shall mean any work of authorship, including - the original version of the Work and any modifications or additions - to that Work or Derivative Works thereof, that is intentionally - submitted to Licensor for inclusion in the Work by the copyright owner - or by an individual or Legal Entity authorized to submit on behalf of - the copyright owner. For the purposes of this definition, "submitted" - means any form of electronic, verbal, or written communication sent - to the Licensor or its representatives, including but not limited to - communication on electronic mailing lists, source code control systems, - and issue tracking systems that are managed by, or on behalf of, the - Licensor for the purpose of discussing and improving the Work, but - excluding communication that is conspicuously marked or otherwise - designated in writing by the copyright owner as "Not a Contribution." - - "Contributor" shall mean Licensor and any individual or Legal Entity - on behalf of whom a Contribution has been received by Licensor and - subsequently incorporated within the Work. - - 2. Grant of Copyright License. Subject to the terms and conditions of - this License, each Contributor hereby grants to You a perpetual, - worldwide, non-exclusive, no-charge, royalty-free, irrevocable - copyright license to reproduce, prepare Derivative Works of, - publicly display, publicly perform, sublicense, and distribute the - Work and such Derivative Works in Source or Object form. - - 3. Grant of Patent License. Subject to the terms and conditions of - this License, each Contributor hereby grants to You a perpetual, - worldwide, non-exclusive, no-charge, royalty-free, irrevocable - (except as stated in this section) patent license to make, have made, - use, offer to sell, sell, import, and otherwise transfer the Work, - where such license applies only to those patent claims licensable - by such Contributor that are necessarily infringed by their - Contribution(s) alone or by combination of their Contribution(s) - with the Work to which such Contribution(s) was submitted. If You - institute patent litigation against any entity (including a - cross-claim or counterclaim in a lawsuit) alleging that the Work - or a Contribution incorporated within the Work constitutes direct - or contributory patent infringement, then any patent licenses - granted to You under this License for that Work shall terminate - as of the date such litigation is filed. - - 4. Redistribution. You may reproduce and distribute copies of the - Work or Derivative Works thereof in any medium, with or without - modifications, and in Source or Object form, provided that You - meet the following conditions: - - (a) You must give any other recipients of the Work or - Derivative Works a copy of this License; and - - (b) You must cause any modified files to carry prominent notices - stating that You changed the files; and - - (c) You must retain, in the Source form of any Derivative Works - that You distribute, all copyright, patent, trademark, and - attribution notices from the Source form of the Work, - excluding those notices that do not pertain to any part of - the Derivative Works; and - - (d) If the Work includes a "NOTICE" text file as part of its - distribution, then any Derivative Works that You distribute must - include a readable copy of the attribution notices contained - within such NOTICE file, excluding those notices that do not - pertain to any part of the Derivative Works, in at least one - of the following places: within a NOTICE text file distributed - as part of the Derivative Works; within the Source form or - documentation, if provided along with the Derivative Works; or, - within a display generated by the Derivative Works, if and - wherever such third-party notices normally appear. The contents - of the NOTICE file are for informational purposes only and - do not modify the License. You may add Your own attribution - notices within Derivative Works that You distribute, alongside - or as an addendum to the NOTICE text from the Work, provided - that such additional attribution notices cannot be construed - as modifying the License. - - You may add Your own copyright statement to Your modifications and - may provide additional or different license terms and conditions - for use, reproduction, or distribution of Your modifications, or - for any such Derivative Works as a whole, provided Your use, - reproduction, and distribution of the Work otherwise complies with - the conditions stated in this License. - - 5. Submission of Contributions. Unless You explicitly state otherwise, - any Contribution intentionally submitted for inclusion in the Work - by You to the Licensor shall be under the terms and conditions of - this License, without any additional terms or conditions. - Notwithstanding the above, nothing herein shall supersede or modify - the terms of any separate license agreement you may have executed - with Licensor regarding such Contributions. - - 6. Trademarks. This License does not grant permission to use the trade - names, trademarks, service marks, or product names of the Licensor, - except as required for reasonable and customary use in describing the - origin of the Work and reproducing the content of the NOTICE file. - - 7. Disclaimer of Warranty. Unless required by applicable law or - agreed to in writing, Licensor provides the Work (and each - Contributor provides its Contributions) on an "AS IS" BASIS, - WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or - implied, including, without limitation, any warranties or conditions - of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A - PARTICULAR PURPOSE. You are solely responsible for determining the - appropriateness of using or redistributing the Work and assume any - risks associated with Your exercise of permissions under this License. - - 8. Limitation of Liability. In no event and under no legal theory, - whether in tort (including negligence), contract, or otherwise, - unless required by applicable law (such as deliberate and grossly - negligent acts) or agreed to in writing, shall any Contributor be - liable to You for damages, including any direct, indirect, special, - incidental, or consequential damages of any character arising as a - result of this License or out of the use or inability to use the - Work (including but not limited to damages for loss of goodwill, - work stoppage, computer failure or malfunction, or any and all - other commercial damages or losses), even if such Contributor - has been advised of the possibility of such damages. - - 9. Accepting Warranty or Additional Liability. While redistributing - the Work or Derivative Works thereof, You may choose to offer, - and charge a fee for, acceptance of support, warranty, indemnity, - or other liability obligations and/or rights consistent with this - License. However, in accepting such obligations, You may act only - on Your own behalf and on Your sole responsibility, not on behalf - of any other Contributor, and only if You agree to indemnify, - defend, and hold each Contributor harmless for any liability - incurred by, or claims asserted against, such Contributor by reason - of your accepting any such warranty or additional liability. - - END OF TERMS AND CONDITIONS - - APPENDIX: How to apply the Apache License to your work. - - To apply the Apache License to your work, attach the following - boilerplate notice, with the fields enclosed by brackets "[]" - replaced with your own identifying information. (Don't include - the brackets!) The text should be enclosed in the appropriate - comment syntax for the file format. We also recommend that a - file or class name and description of purpose be included on the - same "printed page" as the copyright notice for easier - identification within third-party archives. - - Copyright [yyyy] [name of copyright owner] - - Licensed 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. - ------------------------------------------------------------------------------- - -The following NCSA license applies only to google-java-format-diff.py. - -============================================================================== -LLVM Release License -============================================================================== -University of Illinois/NCSA -Open Source License - -Copyright (c) 2007-2015 University of Illinois at Urbana-Champaign. -All rights reserved. - -Developed by: - - LLVM Team - - University of Illinois at Urbana-Champaign - - http://llvm.org - -Permission is hereby granted, free of charge, to any person obtaining a copy of -this software and associated documentation files (the "Software"), to deal with -the Software without restriction, including without limitation the rights to -use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies -of the Software, and to permit persons to whom the Software is furnished to do -so, subject to the following conditions: - - * Redistributions of source code must retain the above copyright notice, - this list of conditions and the following disclaimers. - - * Redistributions in binary form must reproduce the above copyright notice, - this list of conditions and the following disclaimers in the - documentation and/or other materials provided with the distribution. - - * Neither the names of the LLVM Team, University of Illinois at - Urbana-Champaign, nor the names of its contributors may be used to - endorse or promote products derived from this Software without specific - prior written permission. - -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS -FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -CONTRIBUTORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS WITH THE -SOFTWARE. - -============================================================================== -The LLVM software contains code written by third parties. Such software will -have its own individual LICENSE.TXT file in the directory in which it appears. -This file will describe the copyrights, license, and restrictions which apply -to that code. - -The disclaimer of warranty in the University of Illinois Open Source License -applies to all code in the LLVM Distribution, and nothing in any of the -other licenses gives permission to use the names of the LLVM Team or the -University of Illinois to endorse or promote products derived from this -Software. - -The following pieces of software have additional or alternate copyrights, -licenses, and/or restrictions: - -Program Directory -------- --------- - - - --------------------------------------------------- -Library: guava v19.0 -Url: https://github.com/google/guava -License: Apache-2.0 - - - Apache License - Version 2.0, January 2004 - http://www.apache.org/licenses/ - - TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION - - 1. Definitions. - - "License" shall mean the terms and conditions for use, reproduction, - and distribution as defined by Sections 1 through 9 of this document. - - "Licensor" shall mean the copyright owner or entity authorized by - the copyright owner that is granting the License. - - "Legal Entity" shall mean the union of the acting entity and all - other entities that control, are controlled by, or are under common - control with that entity. For the purposes of this definition, - "control" means (i) the power, direct or indirect, to cause the - direction or management of such entity, whether by contract or - otherwise, or (ii) ownership of fifty percent (50%) or more of the - outstanding shares, or (iii) beneficial ownership of such entity. - - "You" (or "Your") shall mean an individual or Legal Entity - exercising permissions granted by this License. - - "Source" form shall mean the preferred form for making modifications, - including but not limited to software source code, documentation - source, and configuration files. - - "Object" form shall mean any form resulting from mechanical - transformation or translation of a Source form, including but - not limited to compiled object code, generated documentation, - and conversions to other media types. - - "Work" shall mean the work of authorship, whether in Source or - Object form, made available under the License, as indicated by a - copyright notice that is included in or attached to the work - (an example is provided in the Appendix below). - - "Derivative Works" shall mean any work, whether in Source or Object - form, that is based on (or derived from) the Work and for which the - editorial revisions, annotations, elaborations, or other modifications - represent, as a whole, an original work of authorship. For the purposes - of this License, Derivative Works shall not include works that remain - separable from, or merely link (or bind by name) to the interfaces of, - the Work and Derivative Works thereof. - - "Contribution" shall mean any work of authorship, including - the original version of the Work and any modifications or additions - to that Work or Derivative Works thereof, that is intentionally - submitted to Licensor for inclusion in the Work by the copyright owner - or by an individual or Legal Entity authorized to submit on behalf of - the copyright owner. For the purposes of this definition, "submitted" - means any form of electronic, verbal, or written communication sent - to the Licensor or its representatives, including but not limited to - communication on electronic mailing lists, source code control systems, - and issue tracking systems that are managed by, or on behalf of, the - Licensor for the purpose of discussing and improving the Work, but - excluding communication that is conspicuously marked or otherwise - designated in writing by the copyright owner as "Not a Contribution." - - "Contributor" shall mean Licensor and any individual or Legal Entity - on behalf of whom a Contribution has been received by Licensor and - subsequently incorporated within the Work. - - 2. Grant of Copyright License. Subject to the terms and conditions of - this License, each Contributor hereby grants to You a perpetual, - worldwide, non-exclusive, no-charge, royalty-free, irrevocable - copyright license to reproduce, prepare Derivative Works of, - publicly display, publicly perform, sublicense, and distribute the - Work and such Derivative Works in Source or Object form. - - 3. Grant of Patent License. Subject to the terms and conditions of - this License, each Contributor hereby grants to You a perpetual, - worldwide, non-exclusive, no-charge, royalty-free, irrevocable - (except as stated in this section) patent license to make, have made, - use, offer to sell, sell, import, and otherwise transfer the Work, - where such license applies only to those patent claims licensable - by such Contributor that are necessarily infringed by their - Contribution(s) alone or by combination of their Contribution(s) - with the Work to which such Contribution(s) was submitted. If You - institute patent litigation against any entity (including a - cross-claim or counterclaim in a lawsuit) alleging that the Work - or a Contribution incorporated within the Work constitutes direct - or contributory patent infringement, then any patent licenses - granted to You under this License for that Work shall terminate - as of the date such litigation is filed. - - 4. Redistribution. You may reproduce and distribute copies of the - Work or Derivative Works thereof in any medium, with or without - modifications, and in Source or Object form, provided that You - meet the following conditions: - - (a) You must give any other recipients of the Work or - Derivative Works a copy of this License; and - - (b) You must cause any modified files to carry prominent notices - stating that You changed the files; and - - (c) You must retain, in the Source form of any Derivative Works - that You distribute, all copyright, patent, trademark, and - attribution notices from the Source form of the Work, - excluding those notices that do not pertain to any part of - the Derivative Works; and - - (d) If the Work includes a "NOTICE" text file as part of its - distribution, then any Derivative Works that You distribute must - include a readable copy of the attribution notices contained - within such NOTICE file, excluding those notices that do not - pertain to any part of the Derivative Works, in at least one - of the following places: within a NOTICE text file distributed - as part of the Derivative Works; within the Source form or - documentation, if provided along with the Derivative Works; or, - within a display generated by the Derivative Works, if and - wherever such third-party notices normally appear. The contents - of the NOTICE file are for informational purposes only and - do not modify the License. You may add Your own attribution - notices within Derivative Works that You distribute, alongside - or as an addendum to the NOTICE text from the Work, provided - that such additional attribution notices cannot be construed - as modifying the License. - - You may add Your own copyright statement to Your modifications and - may provide additional or different license terms and conditions - for use, reproduction, or distribution of Your modifications, or - for any such Derivative Works as a whole, provided Your use, - reproduction, and distribution of the Work otherwise complies with - the conditions stated in this License. - - 5. Submission of Contributions. Unless You explicitly state otherwise, - any Contribution intentionally submitted for inclusion in the Work - by You to the Licensor shall be under the terms and conditions of - this License, without any additional terms or conditions. - Notwithstanding the above, nothing herein shall supersede or modify - the terms of any separate license agreement you may have executed - with Licensor regarding such Contributions. - - 6. Trademarks. This License does not grant permission to use the trade - names, trademarks, service marks, or product names of the Licensor, - except as required for reasonable and customary use in describing the - origin of the Work and reproducing the content of the NOTICE file. - - 7. Disclaimer of Warranty. Unless required by applicable law or - agreed to in writing, Licensor provides the Work (and each - Contributor provides its Contributions) on an "AS IS" BASIS, - WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or - implied, including, without limitation, any warranties or conditions - of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A - PARTICULAR PURPOSE. You are solely responsible for determining the - appropriateness of using or redistributing the Work and assume any - risks associated with Your exercise of permissions under this License. - - 8. Limitation of Liability. In no event and under no legal theory, - whether in tort (including negligence), contract, or otherwise, - unless required by applicable law (such as deliberate and grossly - negligent acts) or agreed to in writing, shall any Contributor be - liable to You for damages, including any direct, indirect, special, - incidental, or consequential damages of any character arising as a - result of this License or out of the use or inability to use the - Work (including but not limited to damages for loss of goodwill, - work stoppage, computer failure or malfunction, or any and all - other commercial damages or losses), even if such Contributor - has been advised of the possibility of such damages. - - 9. Accepting Warranty or Additional Liability. While redistributing - the Work or Derivative Works thereof, You may choose to offer, - and charge a fee for, acceptance of support, warranty, indemnity, - or other liability obligations and/or rights consistent with this - License. However, in accepting such obligations, You may act only - on Your own behalf and on Your sole responsibility, not on behalf - of any other Contributor, and only if You agree to indemnify, - defend, and hold each Contributor harmless for any liability - incurred by, or claims asserted against, such Contributor by reason - of your accepting any such warranty or additional liability. - - END OF TERMS AND CONDITIONS - - APPENDIX: How to apply the Apache License to your work. - - To apply the Apache License to your work, attach the following - boilerplate notice, with the fields enclosed by brackets "[]" - replaced with your own identifying information. (Don't include - the brackets!) The text should be enclosed in the appropriate - comment syntax for the file format. We also recommend that a - file or class name and description of purpose be included on the - same "printed page" as the copyright notice for easier - identification within third-party archives. - - Copyright [yyyy] [name of copyright owner] - - Licensed 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. - --------------------------------------------------- -Library: commons-codec v1.10.0 -Url: http://commons.apache.org/proper/commons-codec/ -License: Apache-2.0 - -Apache Commons Codec -Copyright 2002-2017 The Apache Software Foundation - -This product includes software developed at -The Apache Software Foundation (http://www.apache.org/). - -src/test/org/apache/commons/codec/language/DoubleMetaphoneTest.java -contains test data from http://aspell.net/test/orig/batch0.tab. -Copyright (C) 2002 Kevin Atkinson (kevina@gnu.org) - -=============================================================================== - -The content of package org.apache.commons.codec.language.bm has been translated -from the original php source code available at http://stevemorse.org/phoneticinfo.htm -with permission from the original authors. -Original source copyright: -Copyright (c) 2008 Alexander Beider & Stephen P. Morse. - - - Apache License - Version 2.0, January 2004 - http://www.apache.org/licenses/ - - TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION - - 1. Definitions. - - "License" shall mean the terms and conditions for use, reproduction, - and distribution as defined by Sections 1 through 9 of this document. - - "Licensor" shall mean the copyright owner or entity authorized by - the copyright owner that is granting the License. - - "Legal Entity" shall mean the union of the acting entity and all - other entities that control, are controlled by, or are under common - control with that entity. For the purposes of this definition, - "control" means (i) the power, direct or indirect, to cause the - direction or management of such entity, whether by contract or - otherwise, or (ii) ownership of fifty percent (50%) or more of the - outstanding shares, or (iii) beneficial ownership of such entity. - - "You" (or "Your") shall mean an individual or Legal Entity - exercising permissions granted by this License. - - "Source" form shall mean the preferred form for making modifications, - including but not limited to software source code, documentation - source, and configuration files. - - "Object" form shall mean any form resulting from mechanical - transformation or translation of a Source form, including but - not limited to compiled object code, generated documentation, - and conversions to other media types. - - "Work" shall mean the work of authorship, whether in Source or - Object form, made available under the License, as indicated by a - copyright notice that is included in or attached to the work - (an example is provided in the Appendix below). - - "Derivative Works" shall mean any work, whether in Source or Object - form, that is based on (or derived from) the Work and for which the - editorial revisions, annotations, elaborations, or other modifications - represent, as a whole, an original work of authorship. For the purposes - of this License, Derivative Works shall not include works that remain - separable from, or merely link (or bind by name) to the interfaces of, - the Work and Derivative Works thereof. - - "Contribution" shall mean any work of authorship, including - the original version of the Work and any modifications or additions - to that Work or Derivative Works thereof, that is intentionally - submitted to Licensor for inclusion in the Work by the copyright owner - or by an individual or Legal Entity authorized to submit on behalf of - the copyright owner. For the purposes of this definition, "submitted" - means any form of electronic, verbal, or written communication sent - to the Licensor or its representatives, including but not limited to - communication on electronic mailing lists, source code control systems, - and issue tracking systems that are managed by, or on behalf of, the - Licensor for the purpose of discussing and improving the Work, but - excluding communication that is conspicuously marked or otherwise - designated in writing by the copyright owner as "Not a Contribution." - - "Contributor" shall mean Licensor and any individual or Legal Entity - on behalf of whom a Contribution has been received by Licensor and - subsequently incorporated within the Work. - - 2. Grant of Copyright License. Subject to the terms and conditions of - this License, each Contributor hereby grants to You a perpetual, - worldwide, non-exclusive, no-charge, royalty-free, irrevocable - copyright license to reproduce, prepare Derivative Works of, - publicly display, publicly perform, sublicense, and distribute the - Work and such Derivative Works in Source or Object form. - - 3. Grant of Patent License. Subject to the terms and conditions of - this License, each Contributor hereby grants to You a perpetual, - worldwide, non-exclusive, no-charge, royalty-free, irrevocable - (except as stated in this section) patent license to make, have made, - use, offer to sell, sell, import, and otherwise transfer the Work, - where such license applies only to those patent claims licensable - by such Contributor that are necessarily infringed by their - Contribution(s) alone or by combination of their Contribution(s) - with the Work to which such Contribution(s) was submitted. If You - institute patent litigation against any entity (including a - cross-claim or counterclaim in a lawsuit) alleging that the Work - or a Contribution incorporated within the Work constitutes direct - or contributory patent infringement, then any patent licenses - granted to You under this License for that Work shall terminate - as of the date such litigation is filed. - - 4. Redistribution. You may reproduce and distribute copies of the - Work or Derivative Works thereof in any medium, with or without - modifications, and in Source or Object form, provided that You - meet the following conditions: - - (a) You must give any other recipients of the Work or - Derivative Works a copy of this License; and - - (b) You must cause any modified files to carry prominent notices - stating that You changed the files; and - - (c) You must retain, in the Source form of any Derivative Works - that You distribute, all copyright, patent, trademark, and - attribution notices from the Source form of the Work, - excluding those notices that do not pertain to any part of - the Derivative Works; and - - (d) If the Work includes a "NOTICE" text file as part of its - distribution, then any Derivative Works that You distribute must - include a readable copy of the attribution notices contained - within such NOTICE file, excluding those notices that do not - pertain to any part of the Derivative Works, in at least one - of the following places: within a NOTICE text file distributed - as part of the Derivative Works; within the Source form or - documentation, if provided along with the Derivative Works; or, - within a display generated by the Derivative Works, if and - wherever such third-party notices normally appear. The contents - of the NOTICE file are for informational purposes only and - do not modify the License. You may add Your own attribution - notices within Derivative Works that You distribute, alongside - or as an addendum to the NOTICE text from the Work, provided - that such additional attribution notices cannot be construed - as modifying the License. - - You may add Your own copyright statement to Your modifications and - may provide additional or different license terms and conditions - for use, reproduction, or distribution of Your modifications, or - for any such Derivative Works as a whole, provided Your use, - reproduction, and distribution of the Work otherwise complies with - the conditions stated in this License. - - 5. Submission of Contributions. Unless You explicitly state otherwise, - any Contribution intentionally submitted for inclusion in the Work - by You to the Licensor shall be under the terms and conditions of - this License, without any additional terms or conditions. - Notwithstanding the above, nothing herein shall supersede or modify - the terms of any separate license agreement you may have executed - with Licensor regarding such Contributions. - - 6. Trademarks. This License does not grant permission to use the trade - names, trademarks, service marks, or product names of the Licensor, - except as required for reasonable and customary use in describing the - origin of the Work and reproducing the content of the NOTICE file. - - 7. Disclaimer of Warranty. Unless required by applicable law or - agreed to in writing, Licensor provides the Work (and each - Contributor provides its Contributions) on an "AS IS" BASIS, - WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or - implied, including, without limitation, any warranties or conditions - of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A - PARTICULAR PURPOSE. You are solely responsible for determining the - appropriateness of using or redistributing the Work and assume any - risks associated with Your exercise of permissions under this License. - - 8. Limitation of Liability. In no event and under no legal theory, - whether in tort (including negligence), contract, or otherwise, - unless required by applicable law (such as deliberate and grossly - negligent acts) or agreed to in writing, shall any Contributor be - liable to You for damages, including any direct, indirect, special, - incidental, or consequential damages of any character arising as a - result of this License or out of the use or inability to use the - Work (including but not limited to damages for loss of goodwill, - work stoppage, computer failure or malfunction, or any and all - other commercial damages or losses), even if such Contributor - has been advised of the possibility of such damages. - - 9. Accepting Warranty or Additional Liability. While redistributing - the Work or Derivative Works thereof, You may choose to offer, - and charge a fee for, acceptance of support, warranty, indemnity, - or other liability obligations and/or rights consistent with this - License. However, in accepting such obligations, You may act only - on Your own behalf and on Your sole responsibility, not on behalf - of any other Contributor, and only if You agree to indemnify, - defend, and hold each Contributor harmless for any liability - incurred by, or claims asserted against, such Contributor by reason - of your accepting any such warranty or additional liability. - - END OF TERMS AND CONDITIONS - - APPENDIX: How to apply the Apache License to your work. - - To apply the Apache License to your work, attach the following - boilerplate notice, with the fields enclosed by brackets "[]" - replaced with your own identifying information. (Don't include - the brackets!) The text should be enclosed in the appropriate - comment syntax for the file format. We also recommend that a - file or class name and description of purpose be included on the - same "printed page" as the copyright notice for easier - identification within third-party archives. - - Copyright [yyyy] [name of copyright owner] - - Licensed 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. - --------------------------------------------------- -Library: commons-logging v1.2.0 -Url: http://commons.apache.org/proper/commons-logging/ -License: Apache-2.0 - -Apache Commons Logging -Copyright 2003-2016 The Apache Software Foundation - -This product includes software developed at -The Apache Software Foundation (http://www.apache.org/). - - - Apache License - Version 2.0, January 2004 - http://www.apache.org/licenses/ - - TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION - - 1. Definitions. - - "License" shall mean the terms and conditions for use, reproduction, - and distribution as defined by Sections 1 through 9 of this document. - - "Licensor" shall mean the copyright owner or entity authorized by - the copyright owner that is granting the License. - - "Legal Entity" shall mean the union of the acting entity and all - other entities that control, are controlled by, or are under common - control with that entity. For the purposes of this definition, - "control" means (i) the power, direct or indirect, to cause the - direction or management of such entity, whether by contract or - otherwise, or (ii) ownership of fifty percent (50%) or more of the - outstanding shares, or (iii) beneficial ownership of such entity. - - "You" (or "Your") shall mean an individual or Legal Entity - exercising permissions granted by this License. - - "Source" form shall mean the preferred form for making modifications, - including but not limited to software source code, documentation - source, and configuration files. - - "Object" form shall mean any form resulting from mechanical - transformation or translation of a Source form, including but - not limited to compiled object code, generated documentation, - and conversions to other media types. - - "Work" shall mean the work of authorship, whether in Source or - Object form, made available under the License, as indicated by a - copyright notice that is included in or attached to the work - (an example is provided in the Appendix below). - - "Derivative Works" shall mean any work, whether in Source or Object - form, that is based on (or derived from) the Work and for which the - editorial revisions, annotations, elaborations, or other modifications - represent, as a whole, an original work of authorship. For the purposes - of this License, Derivative Works shall not include works that remain - separable from, or merely link (or bind by name) to the interfaces of, - the Work and Derivative Works thereof. - - "Contribution" shall mean any work of authorship, including - the original version of the Work and any modifications or additions - to that Work or Derivative Works thereof, that is intentionally - submitted to Licensor for inclusion in the Work by the copyright owner - or by an individual or Legal Entity authorized to submit on behalf of - the copyright owner. For the purposes of this definition, "submitted" - means any form of electronic, verbal, or written communication sent - to the Licensor or its representatives, including but not limited to - communication on electronic mailing lists, source code control systems, - and issue tracking systems that are managed by, or on behalf of, the - Licensor for the purpose of discussing and improving the Work, but - excluding communication that is conspicuously marked or otherwise - designated in writing by the copyright owner as "Not a Contribution." - - "Contributor" shall mean Licensor and any individual or Legal Entity - on behalf of whom a Contribution has been received by Licensor and - subsequently incorporated within the Work. - - 2. Grant of Copyright License. Subject to the terms and conditions of - this License, each Contributor hereby grants to You a perpetual, - worldwide, non-exclusive, no-charge, royalty-free, irrevocable - copyright license to reproduce, prepare Derivative Works of, - publicly display, publicly perform, sublicense, and distribute the - Work and such Derivative Works in Source or Object form. - - 3. Grant of Patent License. Subject to the terms and conditions of - this License, each Contributor hereby grants to You a perpetual, - worldwide, non-exclusive, no-charge, royalty-free, irrevocable - (except as stated in this section) patent license to make, have made, - use, offer to sell, sell, import, and otherwise transfer the Work, - where such license applies only to those patent claims licensable - by such Contributor that are necessarily infringed by their - Contribution(s) alone or by combination of their Contribution(s) - with the Work to which such Contribution(s) was submitted. If You - institute patent litigation against any entity (including a - cross-claim or counterclaim in a lawsuit) alleging that the Work - or a Contribution incorporated within the Work constitutes direct - or contributory patent infringement, then any patent licenses - granted to You under this License for that Work shall terminate - as of the date such litigation is filed. - - 4. Redistribution. You may reproduce and distribute copies of the - Work or Derivative Works thereof in any medium, with or without - modifications, and in Source or Object form, provided that You - meet the following conditions: - - (a) You must give any other recipients of the Work or - Derivative Works a copy of this License; and - - (b) You must cause any modified files to carry prominent notices - stating that You changed the files; and - - (c) You must retain, in the Source form of any Derivative Works - that You distribute, all copyright, patent, trademark, and - attribution notices from the Source form of the Work, - excluding those notices that do not pertain to any part of - the Derivative Works; and - - (d) If the Work includes a "NOTICE" text file as part of its - distribution, then any Derivative Works that You distribute must - include a readable copy of the attribution notices contained - within such NOTICE file, excluding those notices that do not - pertain to any part of the Derivative Works, in at least one - of the following places: within a NOTICE text file distributed - as part of the Derivative Works; within the Source form or - documentation, if provided along with the Derivative Works; or, - within a display generated by the Derivative Works, if and - wherever such third-party notices normally appear. The contents - of the NOTICE file are for informational purposes only and - do not modify the License. You may add Your own attribution - notices within Derivative Works that You distribute, alongside - or as an addendum to the NOTICE text from the Work, provided - that such additional attribution notices cannot be construed - as modifying the License. - - You may add Your own copyright statement to Your modifications and - may provide additional or different license terms and conditions - for use, reproduction, or distribution of Your modifications, or - for any such Derivative Works as a whole, provided Your use, - reproduction, and distribution of the Work otherwise complies with - the conditions stated in this License. - - 5. Submission of Contributions. Unless You explicitly state otherwise, - any Contribution intentionally submitted for inclusion in the Work - by You to the Licensor shall be under the terms and conditions of - this License, without any additional terms or conditions. - Notwithstanding the above, nothing herein shall supersede or modify - the terms of any separate license agreement you may have executed - with Licensor regarding such Contributions. - - 6. Trademarks. This License does not grant permission to use the trade - names, trademarks, service marks, or product names of the Licensor, - except as required for reasonable and customary use in describing the - origin of the Work and reproducing the content of the NOTICE file. - - 7. Disclaimer of Warranty. Unless required by applicable law or - agreed to in writing, Licensor provides the Work (and each - Contributor provides its Contributions) on an "AS IS" BASIS, - WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or - implied, including, without limitation, any warranties or conditions - of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A - PARTICULAR PURPOSE. You are solely responsible for determining the - appropriateness of using or redistributing the Work and assume any - risks associated with Your exercise of permissions under this License. - - 8. Limitation of Liability. In no event and under no legal theory, - whether in tort (including negligence), contract, or otherwise, - unless required by applicable law (such as deliberate and grossly - negligent acts) or agreed to in writing, shall any Contributor be - liable to You for damages, including any direct, indirect, special, - incidental, or consequential damages of any character arising as a - result of this License or out of the use or inability to use the - Work (including but not limited to damages for loss of goodwill, - work stoppage, computer failure or malfunction, or any and all - other commercial damages or losses), even if such Contributor - has been advised of the possibility of such damages. - - 9. Accepting Warranty or Additional Liability. While redistributing - the Work or Derivative Works thereof, You may choose to offer, - and charge a fee for, acceptance of support, warranty, indemnity, - or other liability obligations and/or rights consistent with this - License. However, in accepting such obligations, You may act only - on Your own behalf and on Your sole responsibility, not on behalf - of any other Contributor, and only if You agree to indemnify, - defend, and hold each Contributor harmless for any liability - incurred by, or claims asserted against, such Contributor by reason - of your accepting any such warranty or additional liability. - - END OF TERMS AND CONDITIONS - - APPENDIX: How to apply the Apache License to your work. - - To apply the Apache License to your work, attach the following - boilerplate notice, with the fields enclosed by brackets "[]" - replaced with your own identifying information. (Don't include - the brackets!) The text should be enclosed in the appropriate - comment syntax for the file format. We also recommend that a - file or class name and description of purpose be included on the - same "printed page" as the copyright notice for easier - identification within third-party archives. - - Copyright [yyyy] [name of copyright owner] - - Licensed 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. - --------------------------------------------------- -Library: concurrent-ruby v1.0.5 -Url: http://www.concurrent-ruby.com -License: MIT - -Copyright (c) Jerry D'Antonio -- released under the MIT license. - -http://www.opensource.org/licenses/mit-license.php - -Permission is hereby granted, free of charge, to any person obtaining a copy -of this software and associated documentation files (the "Software"), to deal -in the Software without restriction, including without limitation the rights -to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -copies of the Software, and to permit persons to whom the Software is -furnished to do so, subject to the following conditions: - -The above copyright notice and this permission notice shall be included in -all copies or substantial portions of the Software. - -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN -THE SOFTWARE. - --------------------------------------------------- -Library: controls.js v -Url: https://github.com/controlsjs/controls.js -License: GPL-3.0-only - -404: Not Found - --------------------------------------------------- -Library: crack v0.4.3 -Url: http://github.com/jnunemaker/crack -License: MIT - -Copyright (c) 2009 John Nunemaker - -Permission is hereby granted, free of charge, to any person obtaining -a copy of this software and associated documentation files (the -"Software"), to deal in the Software without restriction, including -without limitation the rights to use, copy, modify, merge, publish, -distribute, sublicense, and/or sell copies of the Software, and to -permit persons to whom the Software is furnished to do so, subject to -the following conditions: - -The above copyright notice and this permission notice shall be -included in all copies or substantial portions of the Software. - -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, -EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF -MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND -NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE -LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION -OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION -WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. - --------------------------------------------------- -Library: diff-lcs v1.3 -Url: https://github.com/halostatue/diff-lcs -License: MIT - -Copyright 2004–2013 Austin Ziegler. - -Permission is hereby granted, free of charge, to any person obtaining a copy of -this software and associated documentation files (the "Software"), to deal in -the Software without restriction, including without limitation the rights to -use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies -of the Software, and to permit persons to whom the Software is furnished to do -so, subject to the following conditions: - -The above copyright notice and this permission notice shall be included in all -copies or substantial portions of the Software. - -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE -SOFTWARE. - --------------------------------------------------- -Library: domain_name v0.5.20180417 -Url: https://github.com/knu/ruby-domain_name -License: BSD-2-Clause - -Copyright (c) 2011-2017 Akinori MUSHA - -All rights reserved. - -Redistribution and use in source and binary forms, with or without -modification, are permitted provided that the following conditions -are met: -1. Redistributions of source code must retain the above copyright - notice, this list of conditions and the following disclaimer. -2. Redistributions in binary form must reproduce the above copyright - notice, this list of conditions and the following disclaimer in the - documentation and/or other materials provided with the distribution. - -THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND -ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE -IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE -ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE -FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL -DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS -OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) -HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT -LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY -OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF -SUCH DAMAGE. - -* lib/domain_name/punycode.rb - -This file is derived from the implementation of punycode available at -here: - -https://www.verisign.com/en_US/channel-resources/domain-registry-products/idn-sdks/index.xhtml - -Copyright (C) 2000-2002 Verisign Inc., All rights reserved. - -Redistribution and use in source and binary forms, with or -without modification, are permitted provided that the following -conditions are met: - - 1) Redistributions of source code must retain the above copyright - notice, this list of conditions and the following disclaimer. - - 2) Redistributions in binary form must reproduce the above copyright - notice, this list of conditions and the following disclaimer in - the documentation and/or other materials provided with the - distribution. - - 3) Neither the name of the VeriSign Inc. nor the names of its - contributors may be used to endorse or promote products derived - from this software without specific prior written permission. - -THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS -"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT -LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS -FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE -COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, -INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, -BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS -OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED -AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT -LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN -ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE -POSSIBILITY OF SUCH DAMAGE. - -This software is licensed under the BSD open source license. For more -information visit www.opensource.org. - -Authors: - John Colosi (VeriSign) - Srikanth Veeramachaneni (VeriSign) - Nagesh Chigurupati (Verisign) - Praveen Srinivasan(Verisign) - -* lib/domain_name/etld_data.rb - -This file is generated from the Public Suffix List -(https://publicsuffix.org/), which is licensed under MPL 2.0: - -https://mozilla.org/MPL/2.0/ - --------------------------------------------------- -Library: dotenv v2.4.0 -Url: https://github.com/bkeepers/dotenv -License: MIT - -Copyright (c) 2012 Brandon Keepers - -MIT License - -Permission is hereby granted, free of charge, to any person obtaining -a copy of this software and associated documentation files (the -"Software"), to deal in the Software without restriction, including -without limitation the rights to use, copy, modify, merge, publish, -distribute, sublicense, and/or sell copies of the Software, and to -permit persons to whom the Software is furnished to do so, subject to -the following conditions: - -The above copyright notice and this permission notice shall be -included in all copies or substantial portions of the Software. - -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, -EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF -MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND -NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE -LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION -OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION -WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. - --------------------------------------------------- -Library: edn v1.1.1 -Url: https://github.com/relevance/edn-ruby -License: MIT - -Copyright (c) 2012 Relevance Inc & Clinton N. Dreisbach - -MIT License - -Permission is hereby granted, free of charge, to any person obtaining -a copy of this software and associated documentation files (the -"Software"), to deal in the Software without restriction, including -without limitation the rights to use, copy, modify, merge, publish, -distribute, sublicense, and/or sell copies of the Software, and to -permit persons to whom the Software is furnished to do so, subject to -the following conditions: - -The above copyright notice and this permission notice shall be -included in all copies or substantial portions of the Software. - -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, -EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF -MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND -NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE -LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION -OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION -WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. - --------------------------------------------------- -Library: elasticsearch-api v5.0.4 -Url: https://github.com/elastic/elasticsearch-ruby -License: Apache-2.0 - -source: https://github.com/elastic/elasticsearch-ruby/blob/v5.0.4/elasticsearch-transport/LICENSE.txt - -Copyright (c) 2013 Elasticsearch - -Licensed 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. - --------------------------------------------------- -Library: elasticsearch-transport v5.0.4 -Url: https://github.com/elastic/elasticsearch-ruby -License: Apache-2.0 - -source: https://github.com/elastic/elasticsearch-ruby/blob/v5.0.4/elasticsearch/LICENSE.txt - -Copyright (c) 2013 Elasticsearch - -Licensed 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. - --------------------------------------------------- -Library: elasticsearch v5.0.4 -Url: https://github.com/elastic/elasticsearch-ruby -License: Apache-2.0 - -source: https://github.com/elastic/elasticsearch-ruby/blob/v5.0.4/elasticsearch-api/LICENSE.txt - -Copyright 2013 Elasticsearch - -Licensed 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. - --------------------------------------------------- -Library: equalizer v0.0.10 -Url: https://github.com/dkubb/equalizer -License: MIT - -source: https://github.com/dkubb/equalizer/blob/v0.0.10/LICENSE - -Copyright (c) 2009-2013 Dan Kubb -Copyright (c) 2012 Markus Schirp (packaging) - -Permission is hereby granted, free of charge, to any person obtaining -a copy of this software and associated documentation files (the -"Software"), to deal in the Software without restriction, including -without limitation the rights to use, copy, modify, merge, publish, -distribute, sublicense, and/or sell copies of the Software, and to -permit persons to whom the Software is furnished to do so, subject to -the following conditions: - -The above copyright notice and this permission notice shall be -included in all copies or substantial portions of the Software. - -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, -EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF -MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND -NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE -LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION -OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION -WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. - --------------------------------------------------- -Library: faraday v0.9.2 -Url: https://github.com/lostisland/faraday -License: MIT - -source: https://github.com/lostisland/faraday/blob/v0.9.2/LICENSE.md - -Copyright (c) 2009-2015 Rick Olson, Zack Hobson - -Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: - -The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. - -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. - --------------------------------------------------- -Library: ffi v1.9.23 -Url: https://github.com/ffi/ffi -License: BSD-3-CLAUSE - -source: https://github.com/ffi/ffi/blob/1.9.23/LICENSE - -Copyright (c) 2008-2016, Ruby FFI project contributors -All rights reserved. - -Redistribution and use in source and binary forms, with or without -modification, are permitted provided that the following conditions are met: - * Redistributions of source code must retain the above copyright - notice, this list of conditions and the following disclaimer. - * Redistributions in binary form must reproduce the above copyright - notice, this list of conditions and the following disclaimer in the - documentation and/or other materials provided with the distribution. - * Neither the name of the Ruby FFI project nor the - names of its contributors may be used to endorse or promote products - derived from this software without specific prior written permission. - -THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND -ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED -WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE -DISCLAIMED. IN NO EVENT SHALL BE LIABLE FOR ANY -DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES -(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; -LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND -ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS -SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - --------------------------------------------------- -Library: filesize v0.0.4 -Url: https://github.com/dominikh -License: MIT - -https://github.com/dominikh/filesize/blob/v0.0.4/LICENSE - -Copyright (c) 2009 Dominik Honnef - -Permission is hereby granted, free of charge, to any person obtaining a copy -of this software and associated documentation files (the "Software"), to deal -in the Software without restriction, including without limitation the rights -to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -copies of the Software, and to permit persons to whom the Software is -furnished to do so, subject to the following conditions: - -The above copyright notice and this permission notice shall be included in -all copies or substantial portions of the Software. - -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN -THE SOFTWARE. - --------------------------------------------------- -Library: filewatch v0.9.0 -Url: https://github.com/jordansissel/ruby-filewatch -License: MIT - -https://github.com/jordansissel/ruby-filewatch/blob/master/LICENSE - -License is MIT (very permissive). - --------------------------------------------------- -Library: ftw v0.0.48 -Url: https://github.com/jordansissel/ruby-ftw -License: Apache-2.0 - -source: https://github.com/jordansissel/ruby-ftw/blob/master/ftw.gemspec#L19 - -Apache License (2.0) - --------------------------------------------------- -Library: gelf v3.0.0 -Url: https://github.com/graylog-labs/gelf-rb -License: MIT - -source: https://github.com/graylog-labs/gelf-rb/blob/v3.0.0/LICENSE - -Copyright (c) 2010-2016 Lennart Koopmann, Alexey Palazhchenko - -Permission is hereby granted, free of charge, to any person obtaining -a copy of this software and associated documentation files (the -"Software"), to deal in the Software without restriction, including -without limitation the rights to use, copy, modify, merge, publish, -distribute, sublicense, and/or sell copies of the Software, and to -permit persons to whom the Software is furnished to do so, subject to -the following conditions: - -The above copyright notice and this permission notice shall be -included in all copies or substantial portions of the Software. - -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, -EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF -MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND -NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE -LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION -OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION -WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. - --------------------------------------------------- -Library: gelfd v0.2.0 -Url: https://github.com/lusis/gelfd -License: Apache-2.0 - -source: https://github.com/lusis/gelfd/blob/master/LICENSE - -Copyright 2011-2013 John E. Vincent and contributors. - -Licensed 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. - - --------------------------------------------------- -Library: gems v0.8.3 -Url: https://github.com/rubygems/gems -License: MIT - -source: https://github.com/rubygems/gems/blob/v0.8.3/LICENSE.md - -Copyright (c) 2011-2013 Erik Michaels-Ober - -Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: - -The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. - -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. - --------------------------------------------------- -Library: gmetric v0.1.3 -Url: https://github.com/igrigorik/gmetric -License: MIT - -source: https://github.com/igrigorik/gmetric/blob/master/README.md - -The MIT License, Copyright (c) 2009 Ilya Grigorik - --------------------------------------------------- -Library: gradle-license-report v0.7.1 -Url: https://github.com/jk1/Gradle-License-Report -License: Apache-2.0 - -source: https://github.com/jk1/Gradle-License-Report/blob/master/LICENSE - - Apache License - Version 2.0, January 2004 - http://www.apache.org/licenses/ - - TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION - - 1. Definitions. - - "License" shall mean the terms and conditions for use, reproduction, - and distribution as defined by Sections 1 through 9 of this document. - - "Licensor" shall mean the copyright owner or entity authorized by - the copyright owner that is granting the License. - - "Legal Entity" shall mean the union of the acting entity and all - other entities that control, are controlled by, or are under common - control with that entity. For the purposes of this definition, - "control" means (i) the power, direct or indirect, to cause the - direction or management of such entity, whether by contract or - otherwise, or (ii) ownership of fifty percent (50%) or more of the - outstanding shares, or (iii) beneficial ownership of such entity. - - "You" (or "Your") shall mean an individual or Legal Entity - exercising permissions granted by this License. - - "Source" form shall mean the preferred form for making modifications, - including but not limited to software source code, documentation - source, and configuration files. - - "Object" form shall mean any form resulting from mechanical - transformation or translation of a Source form, including but - not limited to compiled object code, generated documentation, - and conversions to other media types. - - "Work" shall mean the work of authorship, whether in Source or - Object form, made available under the License, as indicated by a - copyright notice that is included in or attached to the work - (an example is provided in the Appendix below). - - "Derivative Works" shall mean any work, whether in Source or Object - form, that is based on (or derived from) the Work and for which the - editorial revisions, annotations, elaborations, or other modifications - represent, as a whole, an original work of authorship. For the purposes - of this License, Derivative Works shall not include works that remain - separable from, or merely link (or bind by name) to the interfaces of, - the Work and Derivative Works thereof. - - "Contribution" shall mean any work of authorship, including - the original version of the Work and any modifications or additions - to that Work or Derivative Works thereof, that is intentionally - submitted to Licensor for inclusion in the Work by the copyright owner - or by an individual or Legal Entity authorized to submit on behalf of - the copyright owner. For the purposes of this definition, "submitted" - means any form of electronic, verbal, or written communication sent - to the Licensor or its representatives, including but not limited to - communication on electronic mailing lists, source code control systems, - and issue tracking systems that are managed by, or on behalf of, the - Licensor for the purpose of discussing and improving the Work, but - excluding communication that is conspicuously marked or otherwise - designated in writing by the copyright owner as "Not a Contribution." - - "Contributor" shall mean Licensor and any individual or Legal Entity - on behalf of whom a Contribution has been received by Licensor and - subsequently incorporated within the Work. - - 2. Grant of Copyright License. Subject to the terms and conditions of - this License, each Contributor hereby grants to You a perpetual, - worldwide, non-exclusive, no-charge, royalty-free, irrevocable - copyright license to reproduce, prepare Derivative Works of, - publicly display, publicly perform, sublicense, and distribute the - Work and such Derivative Works in Source or Object form. - - 3. Grant of Patent License. Subject to the terms and conditions of - this License, each Contributor hereby grants to You a perpetual, - worldwide, non-exclusive, no-charge, royalty-free, irrevocable - (except as stated in this section) patent license to make, have made, - use, offer to sell, sell, import, and otherwise transfer the Work, - where such license applies only to those patent claims licensable - by such Contributor that are necessarily infringed by their - Contribution(s) alone or by combination of their Contribution(s) - with the Work to which such Contribution(s) was submitted. If You - institute patent litigation against any entity (including a - cross-claim or counterclaim in a lawsuit) alleging that the Work - or a Contribution incorporated within the Work constitutes direct - or contributory patent infringement, then any patent licenses - granted to You under this License for that Work shall terminate - as of the date such litigation is filed. - - 4. Redistribution. You may reproduce and distribute copies of the - Work or Derivative Works thereof in any medium, with or without - modifications, and in Source or Object form, provided that You - meet the following conditions: - - (a) You must give any other recipients of the Work or - Derivative Works a copy of this License; and - - (b) You must cause any modified files to carry prominent notices - stating that You changed the files; and - - (c) You must retain, in the Source form of any Derivative Works - that You distribute, all copyright, patent, trademark, and - attribution notices from the Source form of the Work, - excluding those notices that do not pertain to any part of - the Derivative Works; and - - (d) If the Work includes a "NOTICE" text file as part of its - distribution, then any Derivative Works that You distribute must - include a readable copy of the attribution notices contained - within such NOTICE file, excluding those notices that do not - pertain to any part of the Derivative Works, in at least one - of the following places: within a NOTICE text file distributed - as part of the Derivative Works; within the Source form or - documentation, if provided along with the Derivative Works; or, - within a display generated by the Derivative Works, if and - wherever such third-party notices normally appear. The contents - of the NOTICE file are for informational purposes only and - do not modify the License. You may add Your own attribution - notices within Derivative Works that You distribute, alongside - or as an addendum to the NOTICE text from the Work, provided - that such additional attribution notices cannot be construed - as modifying the License. - - You may add Your own copyright statement to Your modifications and - may provide additional or different license terms and conditions - for use, reproduction, or distribution of Your modifications, or - for any such Derivative Works as a whole, provided Your use, - reproduction, and distribution of the Work otherwise complies with - the conditions stated in this License. - - 5. Submission of Contributions. Unless You explicitly state otherwise, - any Contribution intentionally submitted for inclusion in the Work - by You to the Licensor shall be under the terms and conditions of - this License, without any additional terms or conditions. - Notwithstanding the above, nothing herein shall supersede or modify - the terms of any separate license agreement you may have executed - with Licensor regarding such Contributions. - - 6. Trademarks. This License does not grant permission to use the trade - names, trademarks, service marks, or product names of the Licensor, - except as required for reasonable and customary use in describing the - origin of the Work and reproducing the content of the NOTICE file. - - 7. Disclaimer of Warranty. Unless required by applicable law or - agreed to in writing, Licensor provides the Work (and each - Contributor provides its Contributions) on an "AS IS" BASIS, - WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or - implied, including, without limitation, any warranties or conditions - of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A - PARTICULAR PURPOSE. You are solely responsible for determining the - appropriateness of using or redistributing the Work and assume any - risks associated with Your exercise of permissions under this License. - - 8. Limitation of Liability. In no event and under no legal theory, - whether in tort (including negligence), contract, or otherwise, - unless required by applicable law (such as deliberate and grossly - negligent acts) or agreed to in writing, shall any Contributor be - liable to You for damages, including any direct, indirect, special, - incidental, or consequential damages of any character arising as a - result of this License or out of the use or inability to use the - Work (including but not limited to damages for loss of goodwill, - work stoppage, computer failure or malfunction, or any and all - other commercial damages or losses), even if such Contributor - has been advised of the possibility of such damages. - - 9. Accepting Warranty or Additional Liability. While redistributing - the Work or Derivative Works thereof, You may choose to offer, - and charge a fee for, acceptance of support, warranty, indemnity, - or other liability obligations and/or rights consistent with this - License. However, in accepting such obligations, You may act only - on Your own behalf and on Your sole responsibility, not on behalf - of any other Contributor, and only if You agree to indemnify, - defend, and hold each Contributor harmless for any liability - incurred by, or claims asserted against, such Contributor by reason - of your accepting any such warranty or additional liability. - - END OF TERMS AND CONDITIONS - - APPENDIX: How to apply the Apache License to your work. - - To apply the Apache License to your work, attach the following - boilerplate notice, with the fields enclosed by brackets "{}" - replaced with your own identifying information. (Don't include - the brackets!) The text should be enclosed in the appropriate - comment syntax for the file format. We also recommend that a - file or class name and description of purpose be included on the - same "printed page" as the copyright notice for easier - identification within third-party archives. - - Copyright {yyyy} {name of copyright owner} - - Licensed 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. - --------------------------------------------------- -Library: gserver v0.0.1 -Url: https://github.com/ruby/gserver/blob -License: Ruby - -Source: https://github.com/ruby/gserver/blob/v0.0.1/LICENSE.txt - -Ruby is copyrighted free software by Yukihiro Matsumoto . -You can redistribute it and/or modify it under either the terms of the -2-clause BSDL (see the file BSDL), or the conditions below: - - 1. You may make and give away verbatim copies of the source form of the - software without restriction, provided that you duplicate all of the - original copyright notices and associated disclaimers. - - 2. You may modify your copy of the software in any way, provided that - you do at least ONE of the following: - - a) place your modifications in the Public Domain or otherwise - make them Freely Available, such as by posting said - modifications to Usenet or an equivalent medium, or by allowing - the author to include your modifications in the software. - - b) use the modified software only within your corporation or - organization. - - c) give non-standard binaries non-standard names, with - instructions on where to get the original software distribution. - - d) make other distribution arrangements with the author. - - 3. You may distribute the software in object code or binary form, - provided that you do at least ONE of the following: - - a) distribute the binaries and library files of the software, - together with instructions (in the manual page or equivalent) - on where to get the original distribution. - - b) accompany the distribution with the machine-readable source of - the software. - - c) give non-standard binaries non-standard names, with - instructions on where to get the original software distribution. - - d) make other distribution arrangements with the author. - - 4. You may modify and include the part of the software into any other - software (possibly commercial). But some files in the distribution - are not written by the author, so that they are not under these terms. - - For the list of those files and their copying conditions, see the - file LEGAL. - - 5. The scripts and library files supplied as input to or produced as - output from the software do not automatically fall under the - copyright of the software, but belong to whomever generated them, - and may be sold commercially, and may be aggregated with this - software. - - 6. THIS SOFTWARE IS PROVIDED "AS IS" AND WITHOUT ANY EXPRESS OR - IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED - WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR - PURPOSE. - --------------------------------------------------- -Library: hitimes v1.2.6 -Url: https://github.com/copiousfreetime/hitimes -License: ISC - -source: https://github.com/copiousfreetime/hitimes/blob/v1.2.6/LICENSE - -ISC LICENSE - http://opensource.org/licenses/isc-license.txt - -Copyright (c) 2008-2015 Jeremy Hinegardner - -Permission to use, copy, modify, and/or distribute this software for any -purpose with or without fee is hereby granted, provided that the above -copyright notice and this permission notice appear in all copies. - -THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES -WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF -MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR -ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES -WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN -ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF -OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. - --------------------------------------------------- -Library: http-cookie v1.0.3 -Url: https://github.com/sparklemotion/http-cookie -License: MIT - -source: https://github.com/sparklemotion/http-cookie/blob/v1.0.3/LICENSE.txt - -Copyright (c) 2013 Akinori MUSHA -Copyright (c) 2011-2012 Akinori MUSHA, Eric Hodel -Copyright (c) 2006-2011 Aaron Patterson, Mike Dalessio - -MIT License - -Permission is hereby granted, free of charge, to any person obtaining -a copy of this software and associated documentation files (the -"Software"), to deal in the Software without restriction, including -without limitation the rights to use, copy, modify, merge, publish, -distribute, sublicense, and/or sell copies of the Software, and to -permit persons to whom the Software is furnished to do so, subject to -the following conditions: - -The above copyright notice and this permission notice shall be -included in all copies or substantial portions of the Software. - -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, -EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF -MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND -NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE -LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION -OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION -WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. - --------------------------------------------------- -Library: http-form_data v1.0.1 -Url: https://github.com/httprb/form_data -License: MIT - -source: https://github.com/httprb/form_data/blob/v1.0.1/LICENSE.txt - -Copyright (c) 2015 Aleksey V Zapparov - -MIT License - -Permission is hereby granted, free of charge, to any person obtaining -a copy of this software and associated documentation files (the -"Software"), to deal in the Software without restriction, including -without limitation the rights to use, copy, modify, merge, publish, -distribute, sublicense, and/or sell copies of the Software, and to -permit persons to whom the Software is furnished to do so, subject to -the following conditions: - -The above copyright notice and this permission notice shall be -included in all copies or substantial portions of the Software. - -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, -EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF -MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND -NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE -LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION -OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION -WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. - - --------------------------------------------------- -Library: http v0.9.9 -Url: https://github.com/httprb/http -License: MIT - -source: https://github.com/httprb/http/blob/v0.9.9/LICENSE.txt - -Copyright (c) 2011-2015 Tony Arcieri, Erik Michaels-Ober, Alexey V. Zapparov, Zachary Anker - -Permission is hereby granted, free of charge, to any person obtaining -a copy of this software and associated documentation files (the -"Software"), to deal in the Software without restriction, including -without limitation the rights to use, copy, modify, merge, publish, -distribute, sublicense, and/or sell copies of the Software, and to -permit persons to whom the Software is furnished to do so, subject to -the following conditions: - -The above copyright notice and this permission notice shall be -included in all copies or substantial portions of the Software. - -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, -EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF -MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND -NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE -LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION -OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION -WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. - - --------------------------------------------------- -Library: http-parser.rb v0.6.0 -Url: https://github.com/tmm1/http_parser.rb -License: MIT - -source: https://github.com/tmm1/http_parser.rb/blob/v0.6.0/LICENSE-MIT - -Copyright 2009,2010 Marc-André Cournoyer -Copyright 2010,2011 Aman Gupta - -Permission is hereby granted, free of charge, to any person obtaining a copy -of this software and associated documentation files (the "Software"), to -deal in the Software without restriction, including without limitation the -rights to use, copy, modify, merge, publish, distribute, sublicense, and/or -sell copies of the Software, and to permit persons to whom the Software is -furnished to do so, subject to the following conditions: - -The above copyright notice and this permission notice shall be included in -all copies or substantial portions of the Software. - -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING -FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS -IN THE SOFTWARE. - --------------------------------------------------- -Library: i18n v0.6.9 -Url: https://github.com/svenfuchs/i18n -License: MIT - -source: https://github.com/svenfuchs/i18n/blob/v0.6.9/MIT-LICENSE - -Copyright (c) 2008 The Ruby I18n team - -Permission is hereby granted, free of charge, to any person obtaining -a copy of this software and associated documentation files (the -"Software"), to deal in the Software without restriction, including -without limitation the rights to use, copy, modify, merge, publish, -distribute, sublicense, and/or sell copies of the Software, and to -permit persons to whom the Software is furnished to do so, subject to -the following conditions: - -The above copyright notice and this permission notice shall be -included in all copies or substantial portions of the Software. - -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, -EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF -MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND -NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE -LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION -OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION -WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. - --------------------------------------------------- -Library: insist v1.0.0 -Url: https://github.com/jordansissel/ruby-insist -License: Apache-2.0 - -source: https://github.com/jordansissel/ruby-insist/blob/master/LICENSE - -Copyright 2012-2013 Jordan Sissel and contributors. - -Licensed 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. - --------------------------------------------------- -Library: invokebinder v1.7 -Url: https://github.com/headius/invokebinder -License: Apache-2.0 - -source: https://github.com/headius/invokebinder/search?q=copyright - -Copyright 2012-2014 headius. - -Licensed 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. - --------------------------------------------------- -Library: jar-dependencies v0.3.12 -Url: https://github.com/mkristian/jar-dependencies -License: MIT - -source: https://github.com/mkristian/jar-dependencies/blob/0.3.12/MIT-LICENSE - -Copyright (c) 2014 Christian Meier - -Permission is hereby granted, free of charge, to any person obtaining -a copy of this software and associated documentation files (the -"Software"), to deal in the Software without restriction, including -without limitation the rights to use, copy, modify, merge, publish, -distribute, sublicense, and/or sell copies of the Software, and to -permit persons to whom the Software is furnished to do so, subject to -the following conditions: - -The above copyright notice and this permission notice shall be -included in all copies or substantial portions of the Software. - -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, -EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF -MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND -NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE -LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION -OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION -WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. - - --------------------------------------------------- -Library: jay-yydebug v -Url: https://github.com/jruby/jay-yydebug -License: EPL-2.0|GPL-2.0|LGPL-2.1 - -source: https://github.com/jruby/jruby/blob/master/COPYING - -JRuby is Copyright (c) 2007-2018 The JRuby project, and is released -under a tri EPL/GPL/LGPL license. You can use it, redistribute it -and/or modify it under the terms of the: - - Eclipse Public License version 2.0 - OR - GNU General Public License version 2 - OR - GNU Lesser General Public License version 2.1 - -bytelist (http://github.com/jruby/bytelist), -jnr-posix (https://github.com/jnr/jnr-posix), -jruby-openssl (https://github.com/jruby/jruby-openssl), -jruby-readline (https://github.com/jruby/jruby-readline), -psych (https://github.com/ruby/psych), -yydebug (https://github.com/jruby/jay-yydebug/) -are released under the same copyright/license. - - --------------------------------------------------- -Library: jcodings v1.0.18 -Url: https://github.com/jruby/jcodings -License: MIT - -source: https://github.com/jruby/jcodings/blob/master/LICENSE.txt - -Permission is hereby granted, free of charge, to any person obtaining a copy of -this software and associated documentation files (the "Software"), to deal in -the Software without restriction, including without limitation the rights to -use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies -of the Software, and to permit persons to whom the Software is furnished to do -so, subject to the following conditions: - -The above copyright notice and this permission notice shall be included in all -copies or substantial portions of the Software. - -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE -SOFTWARE. - --------------------------------------------------- -Library: jdbc-derby v10.12.1.1 -Url: https://github.com/jruby/activerecord-jdbc-adapter -License: Apache-2.0 - -source: https://github.com/jruby/activerecord-jdbc-adapter/blob/master/jdbc-derby/LICENSE.txt - - Apache License - Version 2.0, January 2004 - http://www.apache.org/licenses/ - - TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION - - 1. Definitions. - - "License" shall mean the terms and conditions for use, reproduction, - and distribution as defined by Sections 1 through 9 of this document. - - "Licensor" shall mean the copyright owner or entity authorized by - the copyright owner that is granting the License. - - "Legal Entity" shall mean the union of the acting entity and all - other entities that control, are controlled by, or are under common - control with that entity. For the purposes of this definition, - "control" means (i) the power, direct or indirect, to cause the - direction or management of such entity, whether by contract or - otherwise, or (ii) ownership of fifty percent (50%) or more of the - outstanding shares, or (iii) beneficial ownership of such entity. - - "You" (or "Your") shall mean an individual or Legal Entity - exercising permissions granted by this License. - - "Source" form shall mean the preferred form for making modifications, - including but not limited to software source code, documentation - source, and configuration files. - - "Object" form shall mean any form resulting from mechanical - transformation or translation of a Source form, including but - not limited to compiled object code, generated documentation, - and conversions to other media types. - - "Work" shall mean the work of authorship, whether in Source or - Object form, made available under the License, as indicated by a - copyright notice that is included in or attached to the work - (an example is provided in the Appendix below). - - "Derivative Works" shall mean any work, whether in Source or Object - form, that is based on (or derived from) the Work and for which the - editorial revisions, annotations, elaborations, or other modifications - represent, as a whole, an original work of authorship. For the purposes - of this License, Derivative Works shall not include works that remain - separable from, or merely link (or bind by name) to the interfaces of, - the Work and Derivative Works thereof. - - "Contribution" shall mean any work of authorship, including - the original version of the Work and any modifications or additions - to that Work or Derivative Works thereof, that is intentionally - submitted to Licensor for inclusion in the Work by the copyright owner - or by an individual or Legal Entity authorized to submit on behalf of - the copyright owner. For the purposes of this definition, "submitted" - means any form of electronic, verbal, or written communication sent - to the Licensor or its representatives, including but not limited to - communication on electronic mailing lists, source code control systems, - and issue tracking systems that are managed by, or on behalf of, the - Licensor for the purpose of discussing and improving the Work, but - excluding communication that is conspicuously marked or otherwise - designated in writing by the copyright owner as "Not a Contribution." - - "Contributor" shall mean Licensor and any individual or Legal Entity - on behalf of whom a Contribution has been received by Licensor and - subsequently incorporated within the Work. - - 2. Grant of Copyright License. Subject to the terms and conditions of - this License, each Contributor hereby grants to You a perpetual, - worldwide, non-exclusive, no-charge, royalty-free, irrevocable - copyright license to reproduce, prepare Derivative Works of, - publicly display, publicly perform, sublicense, and distribute the - Work and such Derivative Works in Source or Object form. - - 3. Grant of Patent License. Subject to the terms and conditions of - this License, each Contributor hereby grants to You a perpetual, - worldwide, non-exclusive, no-charge, royalty-free, irrevocable - (except as stated in this section) patent license to make, have made, - use, offer to sell, sell, import, and otherwise transfer the Work, - where such license applies only to those patent claims licensable - by such Contributor that are necessarily infringed by their - Contribution(s) alone or by combination of their Contribution(s) - with the Work to which such Contribution(s) was submitted. If You - institute patent litigation against any entity (including a - cross-claim or counterclaim in a lawsuit) alleging that the Work - or a Contribution incorporated within the Work constitutes direct - or contributory patent infringement, then any patent licenses - granted to You under this License for that Work shall terminate - as of the date such litigation is filed. - - 4. Redistribution. You may reproduce and distribute copies of the - Work or Derivative Works thereof in any medium, with or without - modifications, and in Source or Object form, provided that You - meet the following conditions: - - (a) You must give any other recipients of the Work or - Derivative Works a copy of this License; and - - (b) You must cause any modified files to carry prominent notices - stating that You changed the files; and - - (c) You must retain, in the Source form of any Derivative Works - that You distribute, all copyright, patent, trademark, and - attribution notices from the Source form of the Work, - excluding those notices that do not pertain to any part of - the Derivative Works; and - - (d) If the Work includes a "NOTICE" text file as part of its - distribution, then any Derivative Works that You distribute must - include a readable copy of the attribution notices contained - within such NOTICE file, excluding those notices that do not - pertain to any part of the Derivative Works, in at least one - of the following places: within a NOTICE text file distributed - as part of the Derivative Works; within the Source form or - documentation, if provided along with the Derivative Works; or, - within a display generated by the Derivative Works, if and - wherever such third-party notices normally appear. The contents - of the NOTICE file are for informational purposes only and - do not modify the License. You may add Your own attribution - notices within Derivative Works that You distribute, alongside - or as an addendum to the NOTICE text from the Work, provided - that such additional attribution notices cannot be construed - as modifying the License. - - You may add Your own copyright statement to Your modifications and - may provide additional or different license terms and conditions - for use, reproduction, or distribution of Your modifications, or - for any such Derivative Works as a whole, provided Your use, - reproduction, and distribution of the Work otherwise complies with - the conditions stated in this License. - - 5. Submission of Contributions. Unless You explicitly state otherwise, - any Contribution intentionally submitted for inclusion in the Work - by You to the Licensor shall be under the terms and conditions of - this License, without any additional terms or conditions. - Notwithstanding the above, nothing herein shall supersede or modify - the terms of any separate license agreement you may have executed - with Licensor regarding such Contributions. - - 6. Trademarks. This License does not grant permission to use the trade - names, trademarks, service marks, or product names of the Licensor, - except as required for reasonable and customary use in describing the - origin of the Work and reproducing the content of the NOTICE file. - - 7. Disclaimer of Warranty. Unless required by applicable law or - agreed to in writing, Licensor provides the Work (and each - Contributor provides its Contributions) on an "AS IS" BASIS, - WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or - implied, including, without limitation, any warranties or conditions - of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A - PARTICULAR PURPOSE. You are solely responsible for determining the - appropriateness of using or redistributing the Work and assume any - risks associated with Your exercise of permissions under this License. - - 8. Limitation of Liability. In no event and under no legal theory, - whether in tort (including negligence), contract, or otherwise, - unless required by applicable law (such as deliberate and grossly - negligent acts) or agreed to in writing, shall any Contributor be - liable to You for damages, including any direct, indirect, special, - incidental, or consequential damages of any character arising as a - result of this License or out of the use or inability to use the - Work (including but not limited to damages for loss of goodwill, - work stoppage, computer failure or malfunction, or any and all - other commercial damages or losses), even if such Contributor - has been advised of the possibility of such damages. - - 9. Accepting Warranty or Additional Liability. While redistributing - the Work or Derivative Works thereof, You may choose to offer, - and charge a fee for, acceptance of support, warranty, indemnity, - or other liability obligations and/or rights consistent with this - License. However, in accepting such obligations, You may act only - on Your own behalf and on Your sole responsibility, not on behalf - of any other Contributor, and only if You agree to indemnify, - defend, and hold each Contributor harmless for any liability - incurred by, or claims asserted against, such Contributor by reason - of your accepting any such warranty or additional liability. - - END OF TERMS AND CONDITIONS - - APPENDIX: How to apply the Apache License to your work. - - To apply the Apache License to your work, attach the following - boilerplate notice, with the fields enclosed by brackets "[]" - replaced with your own identifying information. (Don't include - the brackets!) The text should be enclosed in the appropriate - comment syntax for the file format. We also recommend that a - file or class name and description of purpose be included on the - same "printed page" as the copyright notice for easier - identification within third-party archives. - - Copyright [yyyy] [name of copyright owner] - - Licensed 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. - --------------------------------------------------- -Library: jffi v1.2.16 -Url: https://github.com/jnr/jffi -License: Apache-2.0|LGPL-3.0 - -source: https://github.com/jnr/jffi/blob/master/LICENSE - -Licensed 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. - - - Alternatively, you can redistribute it and/or modify it under - the terms of the GNU Lesser General Public License as published by - the Free Software Foundation, either version 3 of the License, or - (at your option) any later version. - - This code is distributed in the hope that it will be useful, but WITHOUT - ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License - version 3 for more details. - - You should have received a copy of the GNU Lesser General Public License - version 3 along with this work. If not, see . - --------------------------------------------------- -Library: jitescript v0.4.1 -Url: https://github.com/qmx/jitescript -License: Apache-2.0 - - source: https://github.com/qmx/jitescript/blob/master/LICENSE - - Apache License - Version 2.0, January 2004 - http://www.apache.org/licenses/ - - TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION - - 1. Definitions. - - "License" shall mean the terms and conditions for use, reproduction, - and distribution as defined by Sections 1 through 9 of this document. - - "Licensor" shall mean the copyright owner or entity authorized by - the copyright owner that is granting the License. - - "Legal Entity" shall mean the union of the acting entity and all - other entities that control, are controlled by, or are under common - control with that entity. For the purposes of this definition, - "control" means (i) the power, direct or indirect, to cause the - direction or management of such entity, whether by contract or - otherwise, or (ii) ownership of fifty percent (50%) or more of the - outstanding shares, or (iii) beneficial ownership of such entity. - - "You" (or "Your") shall mean an individual or Legal Entity - exercising permissions granted by this License. - - "Source" form shall mean the preferred form for making modifications, - including but not limited to software source code, documentation - source, and configuration files. - - "Object" form shall mean any form resulting from mechanical - transformation or translation of a Source form, including but - not limited to compiled object code, generated documentation, - and conversions to other media types. - - "Work" shall mean the work of authorship, whether in Source or - Object form, made available under the License, as indicated by a - copyright notice that is included in or attached to the work - (an example is provided in the Appendix below). - - "Derivative Works" shall mean any work, whether in Source or Object - form, that is based on (or derived from) the Work and for which the - editorial revisions, annotations, elaborations, or other modifications - represent, as a whole, an original work of authorship. For the purposes - of this License, Derivative Works shall not include works that remain - separable from, or merely link (or bind by name) to the interfaces of, - the Work and Derivative Works thereof. - - "Contribution" shall mean any work of authorship, including - the original version of the Work and any modifications or additions - to that Work or Derivative Works thereof, that is intentionally - submitted to Licensor for inclusion in the Work by the copyright owner - or by an individual or Legal Entity authorized to submit on behalf of - the copyright owner. For the purposes of this definition, "submitted" - means any form of electronic, verbal, or written communication sent - to the Licensor or its representatives, including but not limited to - communication on electronic mailing lists, source code control systems, - and issue tracking systems that are managed by, or on behalf of, the - Licensor for the purpose of discussing and improving the Work, but - excluding communication that is conspicuously marked or otherwise - designated in writing by the copyright owner as "Not a Contribution." - - "Contributor" shall mean Licensor and any individual or Legal Entity - on behalf of whom a Contribution has been received by Licensor and - subsequently incorporated within the Work. - - 2. Grant of Copyright License. Subject to the terms and conditions of - this License, each Contributor hereby grants to You a perpetual, - worldwide, non-exclusive, no-charge, royalty-free, irrevocable - copyright license to reproduce, prepare Derivative Works of, - publicly display, publicly perform, sublicense, and distribute the - Work and such Derivative Works in Source or Object form. - - 3. Grant of Patent License. Subject to the terms and conditions of - this License, each Contributor hereby grants to You a perpetual, - worldwide, non-exclusive, no-charge, royalty-free, irrevocable - (except as stated in this section) patent license to make, have made, - use, offer to sell, sell, import, and otherwise transfer the Work, - where such license applies only to those patent claims licensable - by such Contributor that are necessarily infringed by their - Contribution(s) alone or by combination of their Contribution(s) - with the Work to which such Contribution(s) was submitted. If You - institute patent litigation against any entity (including a - cross-claim or counterclaim in a lawsuit) alleging that the Work - or a Contribution incorporated within the Work constitutes direct - or contributory patent infringement, then any patent licenses - granted to You under this License for that Work shall terminate - as of the date such litigation is filed. - - 4. Redistribution. You may reproduce and distribute copies of the - Work or Derivative Works thereof in any medium, with or without - modifications, and in Source or Object form, provided that You - meet the following conditions: - - (a) You must give any other recipients of the Work or - Derivative Works a copy of this License; and - - (b) You must cause any modified files to carry prominent notices - stating that You changed the files; and - - (c) You must retain, in the Source form of any Derivative Works - that You distribute, all copyright, patent, trademark, and - attribution notices from the Source form of the Work, - excluding those notices that do not pertain to any part of - the Derivative Works; and - - (d) If the Work includes a "NOTICE" text file as part of its - distribution, then any Derivative Works that You distribute must - include a readable copy of the attribution notices contained - within such NOTICE file, excluding those notices that do not - pertain to any part of the Derivative Works, in at least one - of the following places: within a NOTICE text file distributed - as part of the Derivative Works; within the Source form or - documentation, if provided along with the Derivative Works; or, - within a display generated by the Derivative Works, if and - wherever such third-party notices normally appear. The contents - of the NOTICE file are for informational purposes only and - do not modify the License. You may add Your own attribution - notices within Derivative Works that You distribute, alongside - or as an addendum to the NOTICE text from the Work, provided - that such additional attribution notices cannot be construed - as modifying the License. - - You may add Your own copyright statement to Your modifications and - may provide additional or different license terms and conditions - for use, reproduction, or distribution of Your modifications, or - for any such Derivative Works as a whole, provided Your use, - reproduction, and distribution of the Work otherwise complies with - the conditions stated in this License. - - 5. Submission of Contributions. Unless You explicitly state otherwise, - any Contribution intentionally submitted for inclusion in the Work - by You to the Licensor shall be under the terms and conditions of - this License, without any additional terms or conditions. - Notwithstanding the above, nothing herein shall supersede or modify - the terms of any separate license agreement you may have executed - with Licensor regarding such Contributions. - - 6. Trademarks. This License does not grant permission to use the trade - names, trademarks, service marks, or product names of the Licensor, - except as required for reasonable and customary use in describing the - origin of the Work and reproducing the content of the NOTICE file. - - 7. Disclaimer of Warranty. Unless required by applicable law or - agreed to in writing, Licensor provides the Work (and each - Contributor provides its Contributions) on an "AS IS" BASIS, - WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or - implied, including, without limitation, any warranties or conditions - of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A - PARTICULAR PURPOSE. You are solely responsible for determining the - appropriateness of using or redistributing the Work and assume any - risks associated with Your exercise of permissions under this License. - - 8. Limitation of Liability. In no event and under no legal theory, - whether in tort (including negligence), contract, or otherwise, - unless required by applicable law (such as deliberate and grossly - negligent acts) or agreed to in writing, shall any Contributor be - liable to You for damages, including any direct, indirect, special, - incidental, or consequential damages of any character arising as a - result of this License or out of the use or inability to use the - Work (including but not limited to damages for loss of goodwill, - work stoppage, computer failure or malfunction, or any and all - other commercial damages or losses), even if such Contributor - has been advised of the possibility of such damages. - - 9. Accepting Warranty or Additional Liability. While redistributing - the Work or Derivative Works thereof, You may choose to offer, - and charge a fee for, acceptance of support, warranty, indemnity, - or other liability obligations and/or rights consistent with this - License. However, in accepting such obligations, You may act only - on Your own behalf and on Your sole responsibility, not on behalf - of any other Contributor, and only if You agree to indemnify, - defend, and hold each Contributor harmless for any liability - incurred by, or claims asserted against, such Contributor by reason - of your accepting any such warranty or additional liability. - - END OF TERMS AND CONDITIONS - - --------------------------------------------------- -Library: jline2 v2.1.1 -Url: https://github.com/jline/jline2 -License: BSD-2-Clause - -source: https://github.com/jline/jline2/blob/master/LICENSE.txt - -Copyright (c) 2002-2016, the original author or authors. -All rights reserved. - -http://www.opensource.org/licenses/bsd-license.php - -Redistribution and use in source and binary forms, with or -without modification, are permitted provided that the following -conditions are met: - -Redistributions of source code must retain the above copyright -notice, this list of conditions and the following disclaimer. - -Redistributions in binary form must reproduce the above copyright -notice, this list of conditions and the following disclaimer -in the documentation and/or other materials provided with -the distribution. - -Neither the name of JLine nor the names of its contributors -may be used to endorse or promote products derived from this -software without specific prior written permission. - -THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS -"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, -BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY -AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO -EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE -FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, -OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, -PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, -DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED -AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT -LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING -IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED -OF THE POSSIBILITY OF SUCH DAMAGE. - --------------------------------------------------- -Library: jls-grok v0.11.4 -Url: https://github.com/jordansissel/ruby-grok -License: Apache-2.0 - -source: https://github.com/jordansissel/ruby-grok/blob/master/LICENSE - - Apache License - Version 2.0, January 2004 - http://www.apache.org/licenses/ - - TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION - - 1. Definitions. - - "License" shall mean the terms and conditions for use, reproduction, - and distribution as defined by Sections 1 through 9 of this document. - - "Licensor" shall mean the copyright owner or entity authorized by - the copyright owner that is granting the License. - - "Legal Entity" shall mean the union of the acting entity and all - other entities that control, are controlled by, or are under common - control with that entity. For the purposes of this definition, - "control" means (i) the power, direct or indirect, to cause the - direction or management of such entity, whether by contract or - otherwise, or (ii) ownership of fifty percent (50%) or more of the - outstanding shares, or (iii) beneficial ownership of such entity. - - "You" (or "Your") shall mean an individual or Legal Entity - exercising permissions granted by this License. - - "Source" form shall mean the preferred form for making modifications, - including but not limited to software source code, documentation - source, and configuration files. - - "Object" form shall mean any form resulting from mechanical - transformation or translation of a Source form, including but - not limited to compiled object code, generated documentation, - and conversions to other media types. - - "Work" shall mean the work of authorship, whether in Source or - Object form, made available under the License, as indicated by a - copyright notice that is included in or attached to the work - (an example is provided in the Appendix below). - - "Derivative Works" shall mean any work, whether in Source or Object - form, that is based on (or derived from) the Work and for which the - editorial revisions, annotations, elaborations, or other modifications - represent, as a whole, an original work of authorship. For the purposes - of this License, Derivative Works shall not include works that remain - separable from, or merely link (or bind by name) to the interfaces of, - the Work and Derivative Works thereof. - - "Contribution" shall mean any work of authorship, including - the original version of the Work and any modifications or additions - to that Work or Derivative Works thereof, that is intentionally - submitted to Licensor for inclusion in the Work by the copyright owner - or by an individual or Legal Entity authorized to submit on behalf of - the copyright owner. For the purposes of this definition, "submitted" - means any form of electronic, verbal, or written communication sent - to the Licensor or its representatives, including but not limited to - communication on electronic mailing lists, source code control systems, - and issue tracking systems that are managed by, or on behalf of, the - Licensor for the purpose of discussing and improving the Work, but - excluding communication that is conspicuously marked or otherwise - designated in writing by the copyright owner as "Not a Contribution." - - "Contributor" shall mean Licensor and any individual or Legal Entity - on behalf of whom a Contribution has been received by Licensor and - subsequently incorporated within the Work. - - 2. Grant of Copyright License. Subject to the terms and conditions of - this License, each Contributor hereby grants to You a perpetual, - worldwide, non-exclusive, no-charge, royalty-free, irrevocable - copyright license to reproduce, prepare Derivative Works of, - publicly display, publicly perform, sublicense, and distribute the - Work and such Derivative Works in Source or Object form. - - 3. Grant of Patent License. Subject to the terms and conditions of - this License, each Contributor hereby grants to You a perpetual, - worldwide, non-exclusive, no-charge, royalty-free, irrevocable - (except as stated in this section) patent license to make, have made, - use, offer to sell, sell, import, and otherwise transfer the Work, - where such license applies only to those patent claims licensable - by such Contributor that are necessarily infringed by their - Contribution(s) alone or by combination of their Contribution(s) - with the Work to which such Contribution(s) was submitted. If You - institute patent litigation against any entity (including a - cross-claim or counterclaim in a lawsuit) alleging that the Work - or a Contribution incorporated within the Work constitutes direct - or contributory patent infringement, then any patent licenses - granted to You under this License for that Work shall terminate - as of the date such litigation is filed. - - 4. Redistribution. You may reproduce and distribute copies of the - Work or Derivative Works thereof in any medium, with or without - modifications, and in Source or Object form, provided that You - meet the following conditions: - - (a) You must give any other recipients of the Work or - Derivative Works a copy of this License; and - - (b) You must cause any modified files to carry prominent notices - stating that You changed the files; and - - (c) You must retain, in the Source form of any Derivative Works - that You distribute, all copyright, patent, trademark, and - attribution notices from the Source form of the Work, - excluding those notices that do not pertain to any part of - the Derivative Works; and - - (d) If the Work includes a "NOTICE" text file as part of its - distribution, then any Derivative Works that You distribute must - include a readable copy of the attribution notices contained - within such NOTICE file, excluding those notices that do not - pertain to any part of the Derivative Works, in at least one - of the following places: within a NOTICE text file distributed - as part of the Derivative Works; within the Source form or - documentation, if provided along with the Derivative Works; or, - within a display generated by the Derivative Works, if and - wherever such third-party notices normally appear. The contents - of the NOTICE file are for informational purposes only and - do not modify the License. You may add Your own attribution - notices within Derivative Works that You distribute, alongside - or as an addendum to the NOTICE text from the Work, provided - that such additional attribution notices cannot be construed - as modifying the License. - - You may add Your own copyright statement to Your modifications and - may provide additional or different license terms and conditions - for use, reproduction, or distribution of Your modifications, or - for any such Derivative Works as a whole, provided Your use, - reproduction, and distribution of the Work otherwise complies with - the conditions stated in this License. - - 5. Submission of Contributions. Unless You explicitly state otherwise, - any Contribution intentionally submitted for inclusion in the Work - by You to the Licensor shall be under the terms and conditions of - this License, without any additional terms or conditions. - Notwithstanding the above, nothing herein shall supersede or modify - the terms of any separate license agreement you may have executed - with Licensor regarding such Contributions. - - 6. Trademarks. This License does not grant permission to use the trade - names, trademarks, service marks, or product names of the Licensor, - except as required for reasonable and customary use in describing the - origin of the Work and reproducing the content of the NOTICE file. - - 7. Disclaimer of Warranty. Unless required by applicable law or - agreed to in writing, Licensor provides the Work (and each - Contributor provides its Contributions) on an "AS IS" BASIS, - WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or - implied, including, without limitation, any warranties or conditions - of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A - PARTICULAR PURPOSE. You are solely responsible for determining the - appropriateness of using or redistributing the Work and assume any - risks associated with Your exercise of permissions under this License. - - 8. Limitation of Liability. In no event and under no legal theory, - whether in tort (including negligence), contract, or otherwise, - unless required by applicable law (such as deliberate and grossly - negligent acts) or agreed to in writing, shall any Contributor be - liable to You for damages, including any direct, indirect, special, - incidental, or consequential damages of any character arising as a - result of this License or out of the use or inability to use the - Work (including but not limited to damages for loss of goodwill, - work stoppage, computer failure or malfunction, or any and all - other commercial damages or losses), even if such Contributor - has been advised of the possibility of such damages. - - 9. Accepting Warranty or Additional Liability. While redistributing - the Work or Derivative Works thereof, You may choose to offer, - and charge a fee for, acceptance of support, warranty, indemnity, - or other liability obligations and/or rights consistent with this - License. However, in accepting such obligations, You may act only - on Your own behalf and on Your sole responsibility, not on behalf - of any other Contributor, and only if You agree to indemnify, - defend, and hold each Contributor harmless for any liability - incurred by, or claims asserted against, such Contributor by reason - of your accepting any such warranty or additional liability. - - END OF TERMS AND CONDITIONS - - APPENDIX: How to apply the Apache License to your work. - - To apply the Apache License to your work, attach the following - boilerplate notice, with the fields enclosed by brackets "[]" - replaced with your own identifying information. (Don't include - the brackets!) The text should be enclosed in the appropriate - comment syntax for the file format. We also recommend that a - file or class name and description of purpose be included on the - same "printed page" as the copyright notice for easier - identification within third-party archives. - - Copyright [yyyy] [name of copyright owner] - - Licensed 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. - --------------------------------------------------- -Library: jls-lumberjack v0.0.26 -Url: https://github.com/elastic/ruby-lumberjack -License: Apache-2.0 - -source: https://github.com/elastic/ruby-lumberjack/blob/master/LICENSE - - -Copyright 2012–2015 Jordan Sissel and contributors. - -Licensed 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. - --------------------------------------------------- -Library: jmespath v1.4.0 -Url: https://github.com/jmespath/jmespath.rb -License: Apache-2.0 - -source: https://github.com/jmespath/jmespath.rb/blob/v1.4.0/LICENSE.txt - - Apache License - Version 2.0, January 2004 - http://www.apache.org/licenses/ - -TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION - -1. Definitions. - - "License" shall mean the terms and conditions for use, reproduction, - and distribution as defined by Sections 1 through 9 of this document. - - "Licensor" shall mean the copyright owner or entity authorized by - the copyright owner that is granting the License. - - "Legal Entity" shall mean the union of the acting entity and all - other entities that control, are controlled by, or are under common - control with that entity. For the purposes of this definition, - "control" means (i) the power, direct or indirect, to cause the - direction or management of such entity, whether by contract or - otherwise, or (ii) ownership of fifty percent (50%) or more of the - outstanding shares, or (iii) beneficial ownership of such entity. - - "You" (or "Your") shall mean an individual or Legal Entity - exercising permissions granted by this License. - - "Source" form shall mean the preferred form for making modifications, - including but not limited to software source code, documentation - source, and configuration files. - - "Object" form shall mean any form resulting from mechanical - transformation or translation of a Source form, including but - not limited to compiled object code, generated documentation, - and conversions to other media types. - - "Work" shall mean the work of authorship, whether in Source or - Object form, made available under the License, as indicated by a - copyright notice that is included in or attached to the work - (an example is provided in the Appendix below). - - "Derivative Works" shall mean any work, whether in Source or Object - form, that is based on (or derived from) the Work and for which the - editorial revisions, annotations, elaborations, or other modifications - represent, as a whole, an original work of authorship. For the purposes - of this License, Derivative Works shall not include works that remain - separable from, or merely link (or bind by name) to the interfaces of, - the Work and Derivative Works thereof. - - "Contribution" shall mean any work of authorship, including - the original version of the Work and any modifications or additions - to that Work or Derivative Works thereof, that is intentionally - submitted to Licensor for inclusion in the Work by the copyright owner - or by an individual or Legal Entity authorized to submit on behalf of - the copyright owner. For the purposes of this definition, "submitted" - means any form of electronic, verbal, or written communication sent - to the Licensor or its representatives, including but not limited to - communication on electronic mailing lists, source code control systems, - and issue tracking systems that are managed by, or on behalf of, the - Licensor for the purpose of discussing and improving the Work, but - excluding communication that is conspicuously marked or otherwise - designated in writing by the copyright owner as "Not a Contribution." - - "Contributor" shall mean Licensor and any individual or Legal Entity - on behalf of whom a Contribution has been received by Licensor and - subsequently incorporated within the Work. - -2. Grant of Copyright License. Subject to the terms and conditions of - this License, each Contributor hereby grants to You a perpetual, - worldwide, non-exclusive, no-charge, royalty-free, irrevocable - copyright license to reproduce, prepare Derivative Works of, - publicly display, publicly perform, sublicense, and distribute the - Work and such Derivative Works in Source or Object form. - -3. Grant of Patent License. Subject to the terms and conditions of - this License, each Contributor hereby grants to You a perpetual, - worldwide, non-exclusive, no-charge, royalty-free, irrevocable - (except as stated in this section) patent license to make, have made, - use, offer to sell, sell, import, and otherwise transfer the Work, - where such license applies only to those patent claims licensable - by such Contributor that are necessarily infringed by their - Contribution(s) alone or by combination of their Contribution(s) - with the Work to which such Contribution(s) was submitted. If You - institute patent litigation against any entity (including a - cross-claim or counterclaim in a lawsuit) alleging that the Work - or a Contribution incorporated within the Work constitutes direct - or contributory patent infringement, then any patent licenses - granted to You under this License for that Work shall terminate - as of the date such litigation is filed. - -4. Redistribution. You may reproduce and distribute copies of the - Work or Derivative Works thereof in any medium, with or without - modifications, and in Source or Object form, provided that You - meet the following conditions: - - (a) You must give any other recipients of the Work or - Derivative Works a copy of this License; and - - (b) You must cause any modified files to carry prominent notices - stating that You changed the files; and - - (c) You must retain, in the Source form of any Derivative Works - that You distribute, all copyright, patent, trademark, and - attribution notices from the Source form of the Work, - excluding those notices that do not pertain to any part of - the Derivative Works; and - - (d) If the Work includes a "NOTICE" text file as part of its - distribution, then any Derivative Works that You distribute must - include a readable copy of the attribution notices contained - within such NOTICE file, excluding those notices that do not - pertain to any part of the Derivative Works, in at least one - of the following places: within a NOTICE text file distributed - as part of the Derivative Works; within the Source form or - documentation, if provided along with the Derivative Works; or, - within a display generated by the Derivative Works, if and - wherever such third-party notices normally appear. The contents - of the NOTICE file are for informational purposes only and - do not modify the License. You may add Your own attribution - notices within Derivative Works that You distribute, alongside - or as an addendum to the NOTICE text from the Work, provided - that such additional attribution notices cannot be construed - as modifying the License. - - You may add Your own copyright statement to Your modifications and - may provide additional or different license terms and conditions - for use, reproduction, or distribution of Your modifications, or - for any such Derivative Works as a whole, provided Your use, - reproduction, and distribution of the Work otherwise complies with - the conditions stated in this License. - -5. Submission of Contributions. Unless You explicitly state otherwise, - any Contribution intentionally submitted for inclusion in the Work - by You to the Licensor shall be under the terms and conditions of - this License, without any additional terms or conditions. - Notwithstanding the above, nothing herein shall supersede or modify - the terms of any separate license agreement you may have executed - with Licensor regarding such Contributions. - -6. Trademarks. This License does not grant permission to use the trade - names, trademarks, service marks, or product names of the Licensor, - except as required for reasonable and customary use in describing the - origin of the Work and reproducing the content of the NOTICE file. - -7. Disclaimer of Warranty. Unless required by applicable law or - agreed to in writing, Licensor provides the Work (and each - Contributor provides its Contributions) on an "AS IS" BASIS, - WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or - implied, including, without limitation, any warranties or conditions - of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A - PARTICULAR PURPOSE. You are solely responsible for determining the - appropriateness of using or redistributing the Work and assume any - risks associated with Your exercise of permissions under this License. - -8. Limitation of Liability. In no event and under no legal theory, - whether in tort (including negligence), contract, or otherwise, - unless required by applicable law (such as deliberate and grossly - negligent acts) or agreed to in writing, shall any Contributor be - liable to You for damages, including any direct, indirect, special, - incidental, or consequential damages of any character arising as a - result of this License or out of the use or inability to use the - Work (including but not limited to damages for loss of goodwill, - work stoppage, computer failure or malfunction, or any and all - other commercial damages or losses), even if such Contributor - has been advised of the possibility of such damages. - -9. Accepting Warranty or Additional Liability. While redistributing - the Work or Derivative Works thereof, You may choose to offer, - and charge a fee for, acceptance of support, warranty, indemnity, - or other liability obligations and/or rights consistent with this - License. However, in accepting such obligations, You may act only - on Your own behalf and on Your sole responsibility, not on behalf - of any other Contributor, and only if You agree to indemnify, - defend, and hold each Contributor harmless for any liability - incurred by, or claims asserted against, such Contributor by reason - of your accepting any such warranty or additional liability. - --------------------------------------------------- -Library: jnr-constants v0.9.9 -Url: https://github.com/jnr/jnr-constants -License: Apache-2.0|LGPL-3.0 - -source: https://github.com/jnr/jnr-constants/blob/jnr-constants-0.9.9/LICENSE - -Licensed 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. - - - Alternatively, you can redistribute it and/or modify it under - the terms of the GNU Lesser General Public License as published by - the Free Software Foundation, either version 3 of the License, or - (at your option) any later version. - - This code is distributed in the hope that it will be useful, but WITHOUT - ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License - version 3 for more details. - - You should have received a copy of the GNU Lesser General Public License - version 3 along with this work. If not, see . - --------------------------------------------------- -Library: jnr-enxio v0.16 -Url: https://github.com/jnr/jnr-enxio -License: Apache-2.0|LGPL-3.0 - -source: https://github.com/jnr/jnr-enxio/blob/jnr-enxio-0.16/LICENSE - -Licensed 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. - --------------------------------------------------- -Library: jnr-ffi v2.1.7 -Url: https://github.com/jnr/jnr-ffi -License: Apache-2.0|LGPL-3.0 - -source: https://github.com/jnr/jnr-ffi/blob/master/LICENSE - -Licensed 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. - - - Alternatively, you can redistribute it and/or modify it under - the terms of the GNU Lesser General Public License as published by - the Free Software Foundation, either version 3 of the License, or - (at your option) any later version. - - This code is distributed in the hope that it will be useful, but WITHOUT - ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License - version 3 for more details. - - You should have received a copy of the GNU Lesser General Public License - version 3 along with this work. If not, see . - --------------------------------------------------- -Library: jnr-netdb v1.1.6 -Url: https://github.com/jnr/jnr-netdb -License: Apache-2.0 - -source: https://github.com/jnr/jnr-netdb/blob/master/LICENSE - -Licensed 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. - --------------------------------------------------- -Library: jnr-posix v3.0.41 -Url: https://github.com/jnr/jnr-posix -License: EPL-2.0|GPL-2.0|LGPL-2.1dependency - -source: https://github.com/jnr/jnr-posix/blob/master/LICENSE.txt - -jnr-posix is released under a tri EPL/GPL/LGPL license. You can use it, -redistribute it and/or modify it under the terms of the: - - Eclipse Public License version 1.0 - GNU General Public License version 2 - GNU Lesser General Public License version 2.1 - -The complete text of the Eclipse Public License is as follows: - - Eclipse Public License - v 1.0 - - THE ACCOMPANYING PROGRAM IS PROVIDED UNDER THE TERMS OF THIS ECLIPSE - PUBLIC LICENSE ("AGREEMENT"). ANY USE, REPRODUCTION OR DISTRIBUTION - OF THE PROGRAM CONSTITUTES RECIPIENT'S ACCEPTANCE OF THIS AGREEMENT. - - 1. DEFINITIONS - - "Contribution" means: - - a) in the case of the initial Contributor, the initial code and - documentation distributed under this Agreement, and - - b) in the case of each subsequent Contributor: - - i) changes to the Program, and - - ii) additions to the Program; - where such changes and/or additions to the Program - originate from and are distributed by that particular - Contributor. A Contribution 'originates' from a - Contributor if it was added to the Program by such - Contributor itself or anyone acting on such - Contributor's behalf. Contributions do not include - additions to the Program which: (i) are separate modules - of software distributed in conjunction with the Program - under their own license agreement, and (ii) are not - derivative works of the Program. - - "Contributor" means any person or entity that distributes the Program. - - "Licensed Patents" mean patent claims licensable by a Contributor - which are necessarily infringed by the use or sale of its - Contribution alone or when combined with the Program. - - "Program" means the Contributions distributed in accordance with - this Agreement. - - "Recipient" means anyone who receives the Program under this - Agreement, including all Contributors. - - 2. GRANT OF RIGHTS - - a) Subject to the terms of this Agreement, each Contributor - hereby grants Recipient a non-exclusive, worldwide, - royalty-free copyright license to reproduce, prepare - derivative works of, publicly display, publicly perform, - distribute and sublicense the Contribution of such - Contributor, if any, and such derivative works, in source - code and object code form. - - b) Subject to the terms of this Agreement, each Contributor - hereby grants Recipient a non-exclusive, worldwide, - royalty-free patent license under Licensed Patents to make, - use, sell, offer to sell, import and otherwise transfer the - Contribution of such Contributor, if any, in source code and - object code form. This patent license shall apply to the - combination of the Contribution and the Program if, at the - time the Contribution is added by the Contributor, such - addition of the Contribution causes such combination to be - covered by the Licensed Patents. The patent license shall not - apply to any other combinations which include the - Contribution. No hardware per se is licensed hereunder. - - c) Recipient understands that although each Contributor grants - the licenses to its Contributions set forth herein, no - assurances are provided by any Contributor that the Program - does not infringe the patent or other intellectual property - rights of any other entity. Each Contributor disclaims any - liability to Recipient for claims brought by any other entity - based on infringement of intellectual property rights or - otherwise. As a condition to exercising the rights and - licenses granted hereunder, each Recipient hereby assumes - sole responsibility to secure any other intellectual property - rights needed, if any. For example, if a third party patent - license is required to allow Recipient to distribute the - Program, it is Recipient's responsibility to acquire that - license before distributing the Program. - - d) Each Contributor represents that to its knowledge it has - sufficient copyright rights in its Contribution, if any, to - grant the copyright license set forth in this Agreement. - - 3. REQUIREMENTS - - A Contributor may choose to distribute the Program in object code - form under its own license agreement, provided that: - - a) it complies with the terms and conditions of this Agreement; and - - b) its license agreement: - - i) effectively disclaims on behalf of all Contributors all - warranties and conditions, express and implied, including - warranties or conditions of title and non-infringement, - and implied warranties or conditions of merchantability - and fitness for a particular purpose; - - ii) effectively excludes on behalf of all Contributors all - liability for damages, including direct, indirect, - special, incidental and consequential damages, such as - lost profits; - - iii) states that any provisions which differ from this - Agreement are offered by that Contributor alone and not - by any other party; and - - iv) states that source code for the Program is available - from such Contributor, and informs licensees how to - obtain it in a reasonable manner on or through a medium - customarily used for software exchange. - - When the Program is made available in source code form: - - a) it must be made available under this Agreement; and - - b) a copy of this Agreement must be included with each copy of - the Program. - - Contributors may not remove or alter any copyright notices contained - within the Program. - - Each Contributor must identify itself as the originator of its - Contribution, if any, in a manner that reasonably allows subsequent - Recipients to identify the originator of the Contribution. - - 4. COMMERCIAL DISTRIBUTION - - Commercial distributors of software may accept certain - responsibilities with respect to end users, business partners and - the like. While this license is intended to facilitate the - commercial use of the Program, the Contributor who includes the - Program in a commercial product offering should do so in a manner - which does not create potential liability for other Contributors. - Therefore, if a Contributor includes the Program in a commercial - product offering, such Contributor ("Commercial Contributor") hereby - agrees to defend and indemnify every other Contributor ("Indemnified - Contributor") against any losses, damages and costs (collectively - "Losses") arising from claims, lawsuits and other legal actions - brought by a third party against the Indemnified Contributor to the - extent caused by the acts or omissions of such Commercial - Contributor in connection with its distribution of the Program in a - commercial product offering. The obligations in this section do not - apply to any claims or Losses relating to any actual or alleged - intellectual property infringement. In order to qualify, an - Indemnified Contributor must: a) promptly notify the Commercial - Contributor in writing of such claim, and b) allow the Commercial - Contributor to control, and cooperate with the Commercial - Contributor in, the defense and any related settlement negotiations. - The Indemnified Contributor may participate in any such claim at its - own expense. - - For example, a Contributor might include the Program in a commercial - product offering, Product X. That Contributor is then a Commercial - Contributor. If that Commercial Contributor then makes performance - claims, or offers warranties related to Product X, those performance - claims and warranties are such Commercial Contributor's - responsibility alone. Under this section, the Commercial Contributor - would have to defend claims against the other Contributors related - to those performance claims and warranties, and if a court requires - any other Contributor to pay any damages as a result, the Commercial - Contributor must pay those damages. - - 5. NO WARRANTY - - EXCEPT AS EXPRESSLY SET FORTH IN THIS AGREEMENT, THE PROGRAM IS - PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF - ANY KIND, EITHER EXPRESS OR IMPLIED INCLUDING, WITHOUT LIMITATION, - ANY WARRANTIES OR CONDITIONS OF TITLE, NON-INFRINGEMENT, - MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE. Each Recipient - is solely responsible for determining the appropriateness of using - and distributing the Program and assumes all risks associated with - its exercise of rights under this Agreement , including but not - limited to the risks and costs of program errors, compliance with - applicable laws, damage to or loss of data, programs or equipment, - and unavailability or interruption of operations. - - 6. DISCLAIMER OF LIABILITY - - EXCEPT AS EXPRESSLY SET FORTH IN THIS AGREEMENT, NEITHER RECIPIENT - NOR ANY CONTRIBUTORS SHALL HAVE ANY LIABILITY FOR ANY DIRECT, - INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES - (INCLUDING WITHOUT LIMITATION LOST PROFITS), HOWEVER CAUSED AND ON - ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR - TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF - THE USE OR DISTRIBUTION OF THE PROGRAM OR THE EXERCISE OF ANY RIGHTS - GRANTED HEREUNDER, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH - DAMAGES. - - 7. GENERAL - - If any provision of this Agreement is invalid or unenforceable under - applicable law, it shall not affect the validity or enforceability - of the remainder of the terms of this Agreement, and without further - action by the parties hereto, such provision shall be reformed to - the minimum extent necessary to make such provision valid and - enforceable. - - If Recipient institutes patent litigation against any entity - (including a cross-claim or counterclaim in a lawsuit) alleging that - the Program itself (excluding combinations of the Program with other - software or hardware) infringes such Recipient's patent(s), then - such Recipient's rights granted under Section 2(b) shall terminate - as of the date such litigation is filed. - - All Recipient's rights under this Agreement shall terminate if it - fails to comply with any of the material terms or conditions of this - Agreement and does not cure such failure in a reasonable period of - time after becoming aware of such noncompliance. If all Recipient's - rights under this Agreement terminate, Recipient agrees to cease use - and distribution of the Program as soon as reasonably practicable. - However, Recipient's obligations under this Agreement and any - licenses granted by Recipient relating to the Program shall continue - and survive. - - Everyone is permitted to copy and distribute copies of this - Agreement, but in order to avoid inconsistency the Agreement is - copyrighted and may only be modified in the following manner. The - Agreement Steward reserves the right to publish new versions - (including revisions) of this Agreement from time to time. No one - other than the Agreement Steward has the right to modify this - Agreement. The Eclipse Foundation is the initial Agreement Steward. - The Eclipse Foundation may assign the responsibility to serve as the - Agreement Steward to a suitable separate entity. Each new version of - the Agreement will be given a distinguishing version number. The - Program (including Contributions) may always be distributed subject - to the version of the Agreement under which it was received. In - addition, after a new version of the Agreement is published, - Contributor may elect to distribute the Program (including its - Contributions) under the new version. Except as expressly stated in - Sections 2(a) and 2(b) above, Recipient receives no rights or - licenses to the intellectual property of any Contributor under this - Agreement, whether expressly, by implication, estoppel or otherwise. - All rights in the Program not expressly granted under this Agreement - are reserved. - - This Agreement is governed by the laws of the State of New York and - the intellectual property laws of the United States of America. No - party to this Agreement will bring a legal action under this - Agreement more than one year after the cause of action arose. Each - party waives its rights to a jury trial in any resulting litigation. - -The complete text of the Common Public License is as follows: - - Common Public License - v 1.0 - - THE ACCOMPANYING PROGRAM IS PROVIDED UNDER THE TERMS OF THIS COMMON - PUBLIC LICENSE ("AGREEMENT"). ANY USE, REPRODUCTION OR DISTRIBUTION OF - THE PROGRAM CONSTITUTES RECIPIENT'S ACCEPTANCE OF THIS AGREEMENT. - - 1. DEFINITIONS - - "Contribution" means: - - a) in the case of the initial Contributor, the initial code and - documentation distributed under this Agreement, and - - b) in the case of each subsequent Contributor: - - i) changes to the Program, and - - ii) additions to the Program; - - where such changes and/or additions to the Program originate - from and are distributed by that particular Contributor. A - Contribution 'originates' from a Contributor if it was added to the - Program by such Contributor itself or anyone acting on such - Contributor's behalf. Contributions do not include additions to the - Program which: (i) are separate modules of software distributed in - conjunction with the Program under their own license agreement, - and (ii) are not derivative works of the Program. - - "Contributor" means any person or entity that distributes the Program. - - "Licensed Patents " mean patent claims licensable by a Contributor - which are necessarily infringed by the use or sale of its Contribution - alone or when combined with the Program. - - "Program" means the Contributions distributed in accordance with this Agreement. - - "Recipient" means anyone who receives the Program under this - Agreement, including all Contributors. - - 2. GRANT OF RIGHTS - - a) Subject to the terms of this Agreement, each Contributor - hereby grants Recipient a non-exclusive, worldwide, royalty-free - copyright license to reproduce, prepare derivative works of, publicly - display, publicly perform, distribute and sublicense the Contribution - of such Contributor, if any, and such derivative works, in source code - and object code form. - - b) Subject to the terms of this Agreement, each Contributor - hereby grants Recipient a non-exclusive, worldwide, royalty-free - patent license under Licensed Patents to make, use, sell, offer to - sell, import and otherwise transfer the Contribution of such - Contributor, if any, in source code and object code form. This patent - license shall apply to the combination of the Contribution and the - Program if, at the time the Contribution is added by the Contributor, - such addition of the Contribution causes such combination to be - covered by the Licensed Patents. The patent license shall not apply to - any other combinations which include the Contribution. No hardware per - se is licensed hereunder. - - c) Recipient understands that although each Contributor grants - the licenses to its Contributions set forth herein, no assurances are - provided by any Contributor that the Program does not infringe the - patent or other intellectual property rights of any other entity. Each - Contributor disclaims any liability to Recipient for claims brought by - any other entity based on infringement of intellectual property rights - or otherwise. As a condition to exercising the rights and licenses - granted hereunder, each Recipient hereby assumes sole responsibility - to secure any other intellectual property rights needed, if any. For - example, if a third party patent license is required to allow - Recipient to distribute the Program, it is Recipient's responsibility - to acquire that license before distributing the Program. - - d) Each Contributor represents that to its knowledge it has - sufficient copyright rights in its Contribution, if any, to grant the - copyright license set forth in this Agreement. - - 3. REQUIREMENTS - - A Contributor may choose to distribute the Program in object code form - under its own license agreement, provided that: - - a) it complies with the terms and conditions of this Agreement; - and - - b) its license agreement: - - i) effectively disclaims on behalf of all Contributors all - warranties and conditions, express and implied, including warranties - or conditions of title and non-infringement, and implied warranties or - conditions of merchantability and fitness for a particular purpose; - - ii) effectively excludes on behalf of all Contributors all - liability for damages, including direct, indirect, special, incidental - and consequential damages, such as lost profits; - - iii) states that any provisions which differ from this Agreement - are offered by that Contributor alone and not by any other party; and - - iv) states that source code for the Program is available from - such Contributor, and informs licensees how to obtain it in a - reasonable manner on or through a medium customarily used for software - exchange. - - When the Program is made available in source code form: - - a) it must be made available under this Agreement; and - - b) a copy of this Agreement must be included with each copy of - the Program. - - Contributors may not remove or alter any copyright notices contained - within the Program. - - Each Contributor must identify itself as the originator of its - Contribution, if any, in a manner that reasonably allows subsequent - Recipients to identify the originator of the Contribution. - - 4. COMMERCIAL DISTRIBUTION - - Commercial distributors of software may accept certain - responsibilities with respect to end users, business partners and the - like. While this license is intended to facilitate the commercial use - of the Program, the Contributor who includes the Program in a - commercial product offering should do so in a manner which does not - create potential liability for other Contributors. Therefore, if a - Contributor includes the Program in a commercial product offering, - such Contributor ("Commercial Contributor") hereby agrees to defend - and indemnify every other Contributor ("Indemnified Contributor") - against any losses, damages and costs (collectively "Losses") arising - from claims, lawsuits and other legal actions brought by a third party - against the Indemnified Contributor to the extent caused by the acts - or omissions of such Commercial Contributor in connection with its - distribution of the Program in a commercial product offering. The - obligations in this section do not apply to any claims or Losses - relating to any actual or alleged intellectual property - infringement. In order to qualify, an Indemnified Contributor must: a) - promptly notify the Commercial Contributor in writing of such claim, - and b) allow the Commercial Contributor to control, and cooperate with - the Commercial Contributor in, the defense and any related settlement - negotiations. The Indemnified Contributor may participate in any such - claim at its own expense. - - For example, a Contributor might include the Program in a commercial - product offering, Product X. That Contributor is then a Commercial - Contributor. If that Commercial Contributor then makes performance - claims, or offers warranties related to Product X, those performance - claims and warranties are such Commercial Contributor's responsibility - alone. Under this section, the Commercial Contributor would have to - defend claims against the other Contributors related to those - performance claims and warranties, and if a court requires any other - Contributor to pay any damages as a result, the Commercial Contributor - must pay those damages. - - 5. NO WARRANTY - - EXCEPT AS EXPRESSLY SET FORTH IN THIS AGREEMENT, THE PROGRAM IS - PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - KIND, EITHER EXPRESS OR IMPLIED INCLUDING, WITHOUT LIMITATION, ANY - WARRANTIES OR CONDITIONS OF TITLE, NON-INFRINGEMENT, MERCHANTABILITY - OR FITNESS FOR A PARTICULAR PURPOSE. Each Recipient is solely - responsible for determining the appropriateness of using and - distributing the Program and assumes all risks associated with its - exercise of rights under this Agreement, including but not limited to - the risks and costs of program errors, compliance with applicable - laws, damage to or loss of data, programs or equipment, and - unavailability or interruption of operations. - - 6. DISCLAIMER OF LIABILITY - - EXCEPT AS EXPRESSLY SET FORTH IN THIS AGREEMENT, NEITHER RECIPIENT NOR - ANY CONTRIBUTORS SHALL HAVE ANY LIABILITY FOR ANY DIRECT, INDIRECT, - INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING - WITHOUT LIMITATION LOST PROFITS), HOWEVER CAUSED AND ON ANY THEORY OF - LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING - NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OR - DISTRIBUTION OF THE PROGRAM OR THE EXERCISE OF ANY RIGHTS GRANTED - HEREUNDER, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGES. - - 7. GENERAL - - If any provision of this Agreement is invalid or unenforceable under - applicable law, it shall not affect the validity or enforceability of - the remainder of the terms of this Agreement, and without further - action by the parties hereto, such provision shall be reformed to the - minimum extent necessary to make such provision valid and enforceable. - - If Recipient institutes patent litigation against a Contributor with - respect to a patent applicable to software (including a cross-claim or - counterclaim in a lawsuit), then any patent licenses granted by that - Contributor to such Recipient under this Agreement shall terminate as - of the date such litigation is filed. In addition, if Recipient - institutes patent litigation against any entity (including a - cross-claim or counterclaim in a lawsuit) alleging that the Program - itself (excluding combinations of the Program with other software or - hardware) infringes such Recipient's patent(s), then such Recipient's - rights granted under Section 2(b) shall terminate as of the date such - litigation is filed. - - All Recipient's rights under this Agreement shall terminate if it - fails to comply with any of the material terms or conditions of this - Agreement and does not cure such failure in a reasonable period of - time after becoming aware of such noncompliance. If all Recipient's - rights under this Agreement terminate, Recipient agrees to cease use - and distribution of the Program as soon as reasonably - practicable. However, Recipient's obligations under this Agreement and - any licenses granted by Recipient relating to the Program shall - continue and survive. - - Everyone is permitted to copy and distribute copies of this Agreement, - but in order to avoid inconsistency the Agreement is copyrighted and - may only be modified in the following manner. The Agreement Steward - reserves the right to publish new versions (including revisions) of - this Agreement from time to time. No one other than the Agreement - Steward has the right to modify this Agreement. IBM is the initial - Agreement Steward. IBM may assign the responsibility to serve as the - Agreement Steward to a suitable separate entity. Each new version of - the Agreement will be given a distinguishing version number. The - Program (including Contributions) may always be distributed subject to - the version of the Agreement under which it was received. In addition, - after a new version of the Agreement is published, Contributor may - elect to distribute the Program (including its Contributions) under - the new version. Except as expressly stated in Sections 2(a) and 2(b) - above, Recipient receives no rights or licenses to the intellectual - property of any Contributor under this Agreement, whether expressly, - by implication, estoppel or otherwise. All rights in the Program not - expressly granted under this Agreement are reserved. - - This Agreement is governed by the laws of the State of New York and - the intellectual property laws of the United States of America. No - party to this Agreement will bring a legal action under this Agreement - more than one year after the cause of action arose. Each party waives - its rights to a jury trial in any resulting litigation. - -The complete text of the GNU General Public License v2 is as follows: - - GNU GENERAL PUBLIC LICENSE - Version 2, June 1991 - - Copyright (C) 1989, 1991 Free Software Foundation, Inc. - 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - Everyone is permitted to copy and distribute verbatim copies - of this license document, but changing it is not allowed. - - Preamble - - The licenses for most software are designed to take away your - freedom to share and change it. By contrast, the GNU General Public - License is intended to guarantee your freedom to share and change free - software--to make sure the software is free for all its users. This - General Public License applies to most of the Free Software - Foundation's software and to any other program whose authors commit to - using it. (Some other Free Software Foundation software is covered by - the GNU Library General Public License instead.) You can apply it to - your programs, too. - - When we speak of free software, we are referring to freedom, not - price. Our General Public Licenses are designed to make sure that you - have the freedom to distribute copies of free software (and charge for - this service if you wish), that you receive source code or can get it - if you want it, that you can change the software or use pieces of it - in new free programs; and that you know you can do these things. - - To protect your rights, we need to make restrictions that forbid - anyone to deny you these rights or to ask you to surrender the rights. - These restrictions translate to certain responsibilities for you if you - distribute copies of the software, or if you modify it. - - For example, if you distribute copies of such a program, whether - gratis or for a fee, you must give the recipients all the rights that - you have. You must make sure that they, too, receive or can get the - source code. And you must show them these terms so they know their - rights. - - We protect your rights with two steps: (1) copyright the software, and - (2) offer you this license which gives you legal permission to copy, - distribute and/or modify the software. - - Also, for each author's protection and ours, we want to make certain - that everyone understands that there is no warranty for this free - software. If the software is modified by someone else and passed on, we - want its recipients to know that what they have is not the original, so - that any problems introduced by others will not reflect on the original - authors' reputations. - - Finally, any free program is threatened constantly by software - patents. We wish to avoid the danger that redistributors of a free - program will individually obtain patent licenses, in effect making the - program proprietary. To prevent this, we have made it clear that any - patent must be licensed for everyone's free use or not licensed at all. - - The precise terms and conditions for copying, distribution and - modification follow. - - GNU GENERAL PUBLIC LICENSE - TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION - - 0. This License applies to any program or other work which contains - a notice placed by the copyright holder saying it may be distributed - under the terms of this General Public License. The "Program", below, - refers to any such program or work, and a "work based on the Program" - means either the Program or any derivative work under copyright law: - that is to say, a work containing the Program or a portion of it, - either verbatim or with modifications and/or translated into another - language. (Hereinafter, translation is included without limitation in - the term "modification".) Each licensee is addressed as "you". - - Activities other than copying, distribution and modification are not - covered by this License; they are outside its scope. The act of - running the Program is not restricted, and the output from the Program - is covered only if its contents constitute a work based on the - Program (independent of having been made by running the Program). - Whether that is true depends on what the Program does. - - 1. You may copy and distribute verbatim copies of the Program's - source code as you receive it, in any medium, provided that you - conspicuously and appropriately publish on each copy an appropriate - copyright notice and disclaimer of warranty; keep intact all the - notices that refer to this License and to the absence of any warranty; - and give any other recipients of the Program a copy of this License - along with the Program. - - You may charge a fee for the physical act of transferring a copy, and - you may at your option offer warranty protection in exchange for a fee. - - 2. You may modify your copy or copies of the Program or any portion - of it, thus forming a work based on the Program, and copy and - distribute such modifications or work under the terms of Section 1 - above, provided that you also meet all of these conditions: - - a) You must cause the modified files to carry prominent notices - stating that you changed the files and the date of any change. - - b) You must cause any work that you distribute or publish, that in - whole or in part contains or is derived from the Program or any - part thereof, to be licensed as a whole at no charge to all third - parties under the terms of this License. - - c) If the modified program normally reads commands interactively - when run, you must cause it, when started running for such - interactive use in the most ordinary way, to print or display an - announcement including an appropriate copyright notice and a - notice that there is no warranty (or else, saying that you provide - a warranty) and that users may redistribute the program under - these conditions, and telling the user how to view a copy of this - License. (Exception: if the Program itself is interactive but - does not normally print such an announcement, your work based on - the Program is not required to print an announcement.) - - These requirements apply to the modified work as a whole. If - identifiable sections of that work are not derived from the Program, - and can be reasonably considered independent and separate works in - themselves, then this License, and its terms, do not apply to those - sections when you distribute them as separate works. But when you - distribute the same sections as part of a whole which is a work based - on the Program, the distribution of the whole must be on the terms of - this License, whose permissions for other licensees extend to the - entire whole, and thus to each and every part regardless of who wrote it. - - Thus, it is not the intent of this section to claim rights or contest - your rights to work written entirely by you; rather, the intent is to - exercise the right to control the distribution of derivative or - collective works based on the Program. - - In addition, mere aggregation of another work not based on the Program - with the Program (or with a work based on the Program) on a volume of - a storage or distribution medium does not bring the other work under - the scope of this License. - - 3. You may copy and distribute the Program (or a work based on it, - under Section 2) in object code or executable form under the terms of - Sections 1 and 2 above provided that you also do one of the following: - - a) Accompany it with the complete corresponding machine-readable - source code, which must be distributed under the terms of Sections - 1 and 2 above on a medium customarily used for software interchange; or, - - b) Accompany it with a written offer, valid for at least three - years, to give any third party, for a charge no more than your - cost of physically performing source distribution, a complete - machine-readable copy of the corresponding source code, to be - distributed under the terms of Sections 1 and 2 above on a medium - customarily used for software interchange; or, - - c) Accompany it with the information you received as to the offer - to distribute corresponding source code. (This alternative is - allowed only for noncommercial distribution and only if you - received the program in object code or executable form with such - an offer, in accord with Subsection b above.) - - The source code for a work means the preferred form of the work for - making modifications to it. For an executable work, complete source - code means all the source code for all modules it contains, plus any - associated interface definition files, plus the scripts used to - control compilation and installation of the executable. However, as a - special exception, the source code distributed need not include - anything that is normally distributed (in either source or binary - form) with the major components (compiler, kernel, and so on) of the - operating system on which the executable runs, unless that component - itself accompanies the executable. - - If distribution of executable or object code is made by offering - access to copy from a designated place, then offering equivalent - access to copy the source code from the same place counts as - distribution of the source code, even though third parties are not - compelled to copy the source along with the object code. - - 4. You may not copy, modify, sublicense, or distribute the Program - except as expressly provided under this License. Any attempt - otherwise to copy, modify, sublicense or distribute the Program is - void, and will automatically terminate your rights under this License. - However, parties who have received copies, or rights, from you under - this License will not have their licenses terminated so long as such - parties remain in full compliance. - - 5. You are not required to accept this License, since you have not - signed it. However, nothing else grants you permission to modify or - distribute the Program or its derivative works. These actions are - prohibited by law if you do not accept this License. Therefore, by - modifying or distributing the Program (or any work based on the - Program), you indicate your acceptance of this License to do so, and - all its terms and conditions for copying, distributing or modifying - the Program or works based on it. - - 6. Each time you redistribute the Program (or any work based on the - Program), the recipient automatically receives a license from the - original licensor to copy, distribute or modify the Program subject to - these terms and conditions. You may not impose any further - restrictions on the recipients' exercise of the rights granted herein. - You are not responsible for enforcing compliance by third parties to - this License. - - 7. If, as a consequence of a court judgment or allegation of patent - infringement or for any other reason (not limited to patent issues), - conditions are imposed on you (whether by court order, agreement or - otherwise) that contradict the conditions of this License, they do not - excuse you from the conditions of this License. If you cannot - distribute so as to satisfy simultaneously your obligations under this - License and any other pertinent obligations, then as a consequence you - may not distribute the Program at all. For example, if a patent - license would not permit royalty-free redistribution of the Program by - all those who receive copies directly or indirectly through you, then - the only way you could satisfy both it and this License would be to - refrain entirely from distribution of the Program. - - If any portion of this section is held invalid or unenforceable under - any particular circumstance, the balance of the section is intended to - apply and the section as a whole is intended to apply in other - circumstances. - - It is not the purpose of this section to induce you to infringe any - patents or other property right claims or to contest validity of any - such claims; this section has the sole purpose of protecting the - integrity of the free software distribution system, which is - implemented by public license practices. Many people have made - generous contributions to the wide range of software distributed - through that system in reliance on consistent application of that - system; it is up to the author/donor to decide if he or she is willing - to distribute software through any other system and a licensee cannot - impose that choice. - - This section is intended to make thoroughly clear what is believed to - be a consequence of the rest of this License. - - 8. If the distribution and/or use of the Program is restricted in - certain countries either by patents or by copyrighted interfaces, the - original copyright holder who places the Program under this License - may add an explicit geographical distribution limitation excluding - those countries, so that distribution is permitted only in or among - countries not thus excluded. In such case, this License incorporates - the limitation as if written in the body of this License. - - 9. The Free Software Foundation may publish revised and/or new versions - of the General Public License from time to time. Such new versions will - be similar in spirit to the present version, but may differ in detail to - address new problems or concerns. - - Each version is given a distinguishing version number. If the Program - specifies a version number of this License which applies to it and "any - later version", you have the option of following the terms and conditions - either of that version or of any later version published by the Free - Software Foundation. If the Program does not specify a version number of - this License, you may choose any version ever published by the Free Software - Foundation. - - 10. If you wish to incorporate parts of the Program into other free - programs whose distribution conditions are different, write to the author - to ask for permission. For software which is copyrighted by the Free - Software Foundation, write to the Free Software Foundation; we sometimes - make exceptions for this. Our decision will be guided by the two goals - of preserving the free status of all derivatives of our free software and - of promoting the sharing and reuse of software generally. - - NO WARRANTY - - 11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY - FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN - OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES - PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED - OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF - MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS - TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE - PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING, - REPAIR OR CORRECTION. - - 12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING - WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR - REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, - INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING - OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED - TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY - YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER - PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE - POSSIBILITY OF SUCH DAMAGES. - - END OF TERMS AND CONDITIONS - -The complete text of the GNU Lesser General Public License 2.1 is as follows: - - GNU LESSER GENERAL PUBLIC LICENSE - Version 2.1, February 1999 - - Copyright (C) 1991, 1999 Free Software Foundation, Inc. - 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - Everyone is permitted to copy and distribute verbatim copies - of this license document, but changing it is not allowed. - - [This is the first released version of the Lesser GPL. It also counts - as the successor of the GNU Library Public License, version 2, hence - the version number 2.1.] - - Preamble - - The licenses for most software are designed to take away your - freedom to share and change it. By contrast, the GNU General Public - Licenses are intended to guarantee your freedom to share and change - free software--to make sure the software is free for all its users. - - This license, the Lesser General Public License, applies to some - specially designated software packages--typically libraries--of the - Free Software Foundation and other authors who decide to use it. You - can use it too, but we suggest you first think carefully about whether - this license or the ordinary General Public License is the better - strategy to use in any particular case, based on the explanations below. - - When we speak of free software, we are referring to freedom of use, - not price. Our General Public Licenses are designed to make sure that - you have the freedom to distribute copies of free software (and charge - for this service if you wish); that you receive source code or can get - it if you want it; that you can change the software and use pieces of - it in new free programs; and that you are informed that you can do - these things. - - To protect your rights, we need to make restrictions that forbid - distributors to deny you these rights or to ask you to surrender these - rights. These restrictions translate to certain responsibilities for - you if you distribute copies of the library or if you modify it. - - For example, if you distribute copies of the library, whether gratis - or for a fee, you must give the recipients all the rights that we gave - you. You must make sure that they, too, receive or can get the source - code. If you link other code with the library, you must provide - complete object files to the recipients, so that they can relink them - with the library after making changes to the library and recompiling - it. And you must show them these terms so they know their rights. - - We protect your rights with a two-step method: (1) we copyright the - library, and (2) we offer you this license, which gives you legal - permission to copy, distribute and/or modify the library. - - To protect each distributor, we want to make it very clear that - there is no warranty for the free library. Also, if the library is - modified by someone else and passed on, the recipients should know - that what they have is not the original version, so that the original - author's reputation will not be affected by problems that might be - introduced by others. - - Finally, software patents pose a constant threat to the existence of - any free program. We wish to make sure that a company cannot - effectively restrict the users of a free program by obtaining a - restrictive license from a patent holder. Therefore, we insist that - any patent license obtained for a version of the library must be - consistent with the full freedom of use specified in this license. - - Most GNU software, including some libraries, is covered by the - ordinary GNU General Public License. This license, the GNU Lesser - General Public License, applies to certain designated libraries, and - is quite different from the ordinary General Public License. We use - this license for certain libraries in order to permit linking those - libraries into non-free programs. - - When a program is linked with a library, whether statically or using - a shared library, the combination of the two is legally speaking a - combined work, a derivative of the original library. The ordinary - General Public License therefore permits such linking only if the - entire combination fits its criteria of freedom. The Lesser General - Public License permits more lax criteria for linking other code with - the library. - - We call this license the "Lesser" General Public License because it - does Less to protect the user's freedom than the ordinary General - Public License. It also provides other free software developers Less - of an advantage over competing non-free programs. These disadvantages - are the reason we use the ordinary General Public License for many - libraries. However, the Lesser license provides advantages in certain - special circumstances. - - For example, on rare occasions, there may be a special need to - encourage the widest possible use of a certain library, so that it becomes - a de-facto standard. To achieve this, non-free programs must be - allowed to use the library. A more frequent case is that a free - library does the same job as widely used non-free libraries. In this - case, there is little to gain by limiting the free library to free - software only, so we use the Lesser General Public License. - - In other cases, permission to use a particular library in non-free - programs enables a greater number of people to use a large body of - free software. For example, permission to use the GNU C Library in - non-free programs enables many more people to use the whole GNU - operating system, as well as its variant, the GNU/Linux operating - system. - - Although the Lesser General Public License is Less protective of the - users' freedom, it does ensure that the user of a program that is - linked with the Library has the freedom and the wherewithal to run - that program using a modified version of the Library. - - The precise terms and conditions for copying, distribution and - modification follow. Pay close attention to the difference between a - "work based on the library" and a "work that uses the library". The - former contains code derived from the library, whereas the latter must - be combined with the library in order to run. - - GNU LESSER GENERAL PUBLIC LICENSE - TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION - - 0. This License Agreement applies to any software library or other - program which contains a notice placed by the copyright holder or - other authorized party saying it may be distributed under the terms of - this Lesser General Public License (also called "this License"). - Each licensee is addressed as "you". - - A "library" means a collection of software functions and/or data - prepared so as to be conveniently linked with application programs - (which use some of those functions and data) to form executables. - - The "Library", below, refers to any such software library or work - which has been distributed under these terms. A "work based on the - Library" means either the Library or any derivative work under - copyright law: that is to say, a work containing the Library or a - portion of it, either verbatim or with modifications and/or translated - straightforwardly into another language. (Hereinafter, translation is - included without limitation in the term "modification".) - - "Source code" for a work means the preferred form of the work for - making modifications to it. For a library, complete source code means - all the source code for all modules it contains, plus any associated - interface definition files, plus the scripts used to control compilation - and installation of the library. - - Activities other than copying, distribution and modification are not - covered by this License; they are outside its scope. The act of - running a program using the Library is not restricted, and output from - such a program is covered only if its contents constitute a work based - on the Library (independent of the use of the Library in a tool for - writing it). Whether that is true depends on what the Library does - and what the program that uses the Library does. - - 1. You may copy and distribute verbatim copies of the Library's - complete source code as you receive it, in any medium, provided that - you conspicuously and appropriately publish on each copy an - appropriate copyright notice and disclaimer of warranty; keep intact - all the notices that refer to this License and to the absence of any - warranty; and distribute a copy of this License along with the - Library. - - You may charge a fee for the physical act of transferring a copy, - and you may at your option offer warranty protection in exchange for a - fee. - - 2. You may modify your copy or copies of the Library or any portion - of it, thus forming a work based on the Library, and copy and - distribute such modifications or work under the terms of Section 1 - above, provided that you also meet all of these conditions: - - a) The modified work must itself be a software library. - - b) You must cause the files modified to carry prominent notices - stating that you changed the files and the date of any change. - - c) You must cause the whole of the work to be licensed at no - charge to all third parties under the terms of this License. - - d) If a facility in the modified Library refers to a function or a - table of data to be supplied by an application program that uses - the facility, other than as an argument passed when the facility - is invoked, then you must make a good faith effort to ensure that, - in the event an application does not supply such function or - table, the facility still operates, and performs whatever part of - its purpose remains meaningful. - - (For example, a function in a library to compute square roots has - a purpose that is entirely well-defined independent of the - application. Therefore, Subsection 2d requires that any - application-supplied function or table used by this function must - be optional: if the application does not supply it, the square - root function must still compute square roots.) - - These requirements apply to the modified work as a whole. If - identifiable sections of that work are not derived from the Library, - and can be reasonably considered independent and separate works in - themselves, then this License, and its terms, do not apply to those - sections when you distribute them as separate works. But when you - distribute the same sections as part of a whole which is a work based - on the Library, the distribution of the whole must be on the terms of - this License, whose permissions for other licensees extend to the - entire whole, and thus to each and every part regardless of who wrote - it. - - Thus, it is not the intent of this section to claim rights or contest - your rights to work written entirely by you; rather, the intent is to - exercise the right to control the distribution of derivative or - collective works based on the Library. - - In addition, mere aggregation of another work not based on the Library - with the Library (or with a work based on the Library) on a volume of - a storage or distribution medium does not bring the other work under - the scope of this License. - - 3. You may opt to apply the terms of the ordinary GNU General Public - License instead of this License to a given copy of the Library. To do - this, you must alter all the notices that refer to this License, so - that they refer to the ordinary GNU General Public License, version 2, - instead of to this License. (If a newer version than version 2 of the - ordinary GNU General Public License has appeared, then you can specify - that version instead if you wish.) Do not make any other change in - these notices. - - Once this change is made in a given copy, it is irreversible for - that copy, so the ordinary GNU General Public License applies to all - subsequent copies and derivative works made from that copy. - - This option is useful when you wish to copy part of the code of - the Library into a program that is not a library. - - 4. You may copy and distribute the Library (or a portion or - derivative of it, under Section 2) in object code or executable form - under the terms of Sections 1 and 2 above provided that you accompany - it with the complete corresponding machine-readable source code, which - must be distributed under the terms of Sections 1 and 2 above on a - medium customarily used for software interchange. - - If distribution of object code is made by offering access to copy - from a designated place, then offering equivalent access to copy the - source code from the same place satisfies the requirement to - distribute the source code, even though third parties are not - compelled to copy the source along with the object code. - - 5. A program that contains no derivative of any portion of the - Library, but is designed to work with the Library by being compiled or - linked with it, is called a "work that uses the Library". Such a - work, in isolation, is not a derivative work of the Library, and - therefore falls outside the scope of this License. - - However, linking a "work that uses the Library" with the Library - creates an executable that is a derivative of the Library (because it - contains portions of the Library), rather than a "work that uses the - library". The executable is therefore covered by this License. - Section 6 states terms for distribution of such executables. - - When a "work that uses the Library" uses material from a header file - that is part of the Library, the object code for the work may be a - derivative work of the Library even though the source code is not. - Whether this is true is especially significant if the work can be - linked without the Library, or if the work is itself a library. The - threshold for this to be true is not precisely defined by law. - - If such an object file uses only numerical parameters, data - structure layouts and accessors, and small macros and small inline - functions (ten lines or less in length), then the use of the object - file is unrestricted, regardless of whether it is legally a derivative - work. (Executables containing this object code plus portions of the - Library will still fall under Section 6.) - - Otherwise, if the work is a derivative of the Library, you may - distribute the object code for the work under the terms of Section 6. - Any executables containing that work also fall under Section 6, - whether or not they are linked directly with the Library itself. - - 6. As an exception to the Sections above, you may also combine or - link a "work that uses the Library" with the Library to produce a - work containing portions of the Library, and distribute that work - under terms of your choice, provided that the terms permit - modification of the work for the customer's own use and reverse - engineering for debugging such modifications. - - You must give prominent notice with each copy of the work that the - Library is used in it and that the Library and its use are covered by - this License. You must supply a copy of this License. If the work - during execution displays copyright notices, you must include the - copyright notice for the Library among them, as well as a reference - directing the user to the copy of this License. Also, you must do one - of these things: - - a) Accompany the work with the complete corresponding - machine-readable source code for the Library including whatever - changes were used in the work (which must be distributed under - Sections 1 and 2 above); and, if the work is an executable linked - with the Library, with the complete machine-readable "work that - uses the Library", as object code and/or source code, so that the - user can modify the Library and then relink to produce a modified - executable containing the modified Library. (It is understood - that the user who changes the contents of definitions files in the - Library will not necessarily be able to recompile the application - to use the modified definitions.) - - b) Use a suitable shared library mechanism for linking with the - Library. A suitable mechanism is one that (1) uses at run time a - copy of the library already present on the user's computer system, - rather than copying library functions into the executable, and (2) - will operate properly with a modified version of the library, if - the user installs one, as long as the modified version is - interface-compatible with the version that the work was made with. - - c) Accompany the work with a written offer, valid for at - least three years, to give the same user the materials - specified in Subsection 6a, above, for a charge no more - than the cost of performing this distribution. - - d) If distribution of the work is made by offering access to copy - from a designated place, offer equivalent access to copy the above - specified materials from the same place. - - e) Verify that the user has already received a copy of these - materials or that you have already sent this user a copy. - - For an executable, the required form of the "work that uses the - Library" must include any data and utility programs needed for - reproducing the executable from it. However, as a special exception, - the materials to be distributed need not include anything that is - normally distributed (in either source or binary form) with the major - components (compiler, kernel, and so on) of the operating system on - which the executable runs, unless that component itself accompanies - the executable. - - It may happen that this requirement contradicts the license - restrictions of other proprietary libraries that do not normally - accompany the operating system. Such a contradiction means you cannot - use both them and the Library together in an executable that you - distribute. - - 7. You may place library facilities that are a work based on the - Library side-by-side in a single library together with other library - facilities not covered by this License, and distribute such a combined - library, provided that the separate distribution of the work based on - the Library and of the other library facilities is otherwise - permitted, and provided that you do these two things: - - a) Accompany the combined library with a copy of the same work - based on the Library, uncombined with any other library - facilities. This must be distributed under the terms of the - Sections above. - - b) Give prominent notice with the combined library of the fact - that part of it is a work based on the Library, and explaining - where to find the accompanying uncombined form of the same work. - - 8. You may not copy, modify, sublicense, link with, or distribute - the Library except as expressly provided under this License. Any - attempt otherwise to copy, modify, sublicense, link with, or - distribute the Library is void, and will automatically terminate your - rights under this License. However, parties who have received copies, - or rights, from you under this License will not have their licenses - terminated so long as such parties remain in full compliance. - - 9. You are not required to accept this License, since you have not - signed it. However, nothing else grants you permission to modify or - distribute the Library or its derivative works. These actions are - prohibited by law if you do not accept this License. Therefore, by - modifying or distributing the Library (or any work based on the - Library), you indicate your acceptance of this License to do so, and - all its terms and conditions for copying, distributing or modifying - the Library or works based on it. - - 10. Each time you redistribute the Library (or any work based on the - Library), the recipient automatically receives a license from the - original licensor to copy, distribute, link with or modify the Library - subject to these terms and conditions. You may not impose any further - restrictions on the recipients' exercise of the rights granted herein. - You are not responsible for enforcing compliance by third parties with - this License. - - 11. If, as a consequence of a court judgment or allegation of patent - infringement or for any other reason (not limited to patent issues), - conditions are imposed on you (whether by court order, agreement or - otherwise) that contradict the conditions of this License, they do not - excuse you from the conditions of this License. If you cannot - distribute so as to satisfy simultaneously your obligations under this - License and any other pertinent obligations, then as a consequence you - may not distribute the Library at all. For example, if a patent - license would not permit royalty-free redistribution of the Library by - all those who receive copies directly or indirectly through you, then - the only way you could satisfy both it and this License would be to - refrain entirely from distribution of the Library. - - If any portion of this section is held invalid or unenforceable under any - particular circumstance, the balance of the section is intended to apply, - and the section as a whole is intended to apply in other circumstances. - - It is not the purpose of this section to induce you to infringe any - patents or other property right claims or to contest validity of any - such claims; this section has the sole purpose of protecting the - integrity of the free software distribution system which is - implemented by public license practices. Many people have made - generous contributions to the wide range of software distributed - through that system in reliance on consistent application of that - system; it is up to the author/donor to decide if he or she is willing - to distribute software through any other system and a licensee cannot - impose that choice. - - This section is intended to make thoroughly clear what is believed to - be a consequence of the rest of this License. - - 12. If the distribution and/or use of the Library is restricted in - certain countries either by patents or by copyrighted interfaces, the - original copyright holder who places the Library under this License may add - an explicit geographical distribution limitation excluding those countries, - so that distribution is permitted only in or among countries not thus - excluded. In such case, this License incorporates the limitation as if - written in the body of this License. - - 13. The Free Software Foundation may publish revised and/or new - versions of the Lesser General Public License from time to time. - Such new versions will be similar in spirit to the present version, - but may differ in detail to address new problems or concerns. - - Each version is given a distinguishing version number. If the Library - specifies a version number of this License which applies to it and - "any later version", you have the option of following the terms and - conditions either of that version or of any later version published by - the Free Software Foundation. If the Library does not specify a - license version number, you may choose any version ever published by - the Free Software Foundation. - - 14. If you wish to incorporate parts of the Library into other free - programs whose distribution conditions are incompatible with these, - write to the author to ask for permission. For software which is - copyrighted by the Free Software Foundation, write to the Free - Software Foundation; we sometimes make exceptions for this. Our - decision will be guided by the two goals of preserving the free status - of all derivatives of our free software and of promoting the sharing - and reuse of software generally. - - NO WARRANTY - - 15. BECAUSE THE LIBRARY IS LICENSED FREE OF CHARGE, THERE IS NO - WARRANTY FOR THE LIBRARY, TO THE EXTENT PERMITTED BY APPLICABLE LAW. - EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR - OTHER PARTIES PROVIDE THE LIBRARY "AS IS" WITHOUT WARRANTY OF ANY - KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE - IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR - PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE - LIBRARY IS WITH YOU. SHOULD THE LIBRARY PROVE DEFECTIVE, YOU ASSUME - THE COST OF ALL NECESSARY SERVICING, REPAIR OR CORRECTION. - - 16. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN - WRITING WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY - AND/OR REDISTRIBUTE THE LIBRARY AS PERMITTED ABOVE, BE LIABLE TO YOU - FOR DAMAGES, INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR - CONSEQUENTIAL DAMAGES ARISING OUT OF THE USE OR INABILITY TO USE THE - LIBRARY (INCLUDING BUT NOT LIMITED TO LOSS OF DATA OR DATA BEING - RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD PARTIES OR A - FAILURE OF THE LIBRARY TO OPERATE WITH ANY OTHER SOFTWARE), EVEN IF - SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH - DAMAGES. - - END OF TERMS AND CONDITIONS - - How to Apply These Terms to Your New Libraries - - If you develop a new library, and you want it to be of the greatest - possible use to the public, we recommend making it free software that - everyone can redistribute and change. You can do so by permitting - redistribution under these terms (or, alternatively, under the terms of the - ordinary General Public License). - - To apply these terms, attach the following notices to the library. It is - safest to attach them to the start of each source file to most effectively - convey the exclusion of warranty; and each file should have at least the - "copyright" line and a pointer to where the full notice is found. - - - Copyright (C) - - This library is free software; you can redistribute it and/or - modify it under the terms of the GNU Lesser General Public - License as published by the Free Software Foundation; either - version 2.1 of the License, or (at your option) any later version. - - This library is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - Lesser General Public License for more details. - - You should have received a copy of the GNU Lesser General Public - License along with this library; if not, write to the Free Software - Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - - Also add information on how to contact you by electronic and paper mail. - - You should also get your employer (if you work as a programmer) or your - school, if any, to sign a "copyright disclaimer" for the library, if - necessary. Here is a sample; alter the names: - - Yoyodyne, Inc., hereby disclaims all copyright interest in the - library `Frob' (a library for tweaking knobs) written by James Random Hacker. - - , 1 April 1990 - Ty Coon, President of Vice - - That's all there is to it! - -The following licenses cover code other than JRuby which is included with JRuby. - -Licenses listed below include: - -* GNU General Public License version 3 -* Apache 2.0 License -* BSD License -* Apache Software License Version 1.1 -* MIT License - -The complete text of the GNU General Public License version 3 is as follows: - - GNU GENERAL PUBLIC LICENSE - Version 3, 29 June 2007 - - Copyright (C) 2007 Free Software Foundation, Inc. - Everyone is permitted to copy and distribute verbatim copies - of this license document, but changing it is not allowed. - - Preamble - - The GNU General Public License is a free, copyleft license for - software and other kinds of works. - - The licenses for most software and other practical works are designed - to take away your freedom to share and change the works. By contrast, - the GNU General Public License is intended to guarantee your freedom to - share and change all versions of a program--to make sure it remains free - software for all its users. We, the Free Software Foundation, use the - GNU General Public License for most of our software; it applies also to - any other work released this way by its authors. You can apply it to - your programs, too. - - When we speak of free software, we are referring to freedom, not - price. Our General Public Licenses are designed to make sure that you - have the freedom to distribute copies of free software (and charge for - them if you wish), that you receive source code or can get it if you - want it, that you can change the software or use pieces of it in new - free programs, and that you know you can do these things. - - To protect your rights, we need to prevent others from denying you - these rights or asking you to surrender the rights. Therefore, you have - certain responsibilities if you distribute copies of the software, or if - you modify it: responsibilities to respect the freedom of others. - - For example, if you distribute copies of such a program, whether - gratis or for a fee, you must pass on to the recipients the same - freedoms that you received. You must make sure that they, too, receive - or can get the source code. And you must show them these terms so they - know their rights. - - Developers that use the GNU GPL protect your rights with two steps: - (1) assert copyright on the software, and (2) offer you this License - giving you legal permission to copy, distribute and/or modify it. - - For the developers' and authors' protection, the GPL clearly explains - that there is no warranty for this free software. For both users' and - authors' sake, the GPL requires that modified versions be marked as - changed, so that their problems will not be attributed erroneously to - authors of previous versions. - - Some devices are designed to deny users access to install or run - modified versions of the software inside them, although the manufacturer - can do so. This is fundamentally incompatible with the aim of - protecting users' freedom to change the software. The systematic - pattern of such abuse occurs in the area of products for individuals to - use, which is precisely where it is most unacceptable. Therefore, we - have designed this version of the GPL to prohibit the practice for those - products. If such problems arise substantially in other domains, we - stand ready to extend this provision to those domains in future versions - of the GPL, as needed to protect the freedom of users. - - Finally, every program is threatened constantly by software patents. - States should not allow patents to restrict development and use of - software on general-purpose computers, but in those that do, we wish to - avoid the special danger that patents applied to a free program could - make it effectively proprietary. To prevent this, the GPL assures that - patents cannot be used to render the program non-free. - - The precise terms and conditions for copying, distribution and - modification follow. - - TERMS AND CONDITIONS - - 0. Definitions. - - "This License" refers to version 3 of the GNU General Public License. - - "Copyright" also means copyright-like laws that apply to other kinds of - works, such as semiconductor masks. - - "The Program" refers to any copyrightable work licensed under this - License. Each licensee is addressed as "you". "Licensees" and - "recipients" may be individuals or organizations. - - To "modify" a work means to copy from or adapt all or part of the work - in a fashion requiring copyright permission, other than the making of an - exact copy. The resulting work is called a "modified version" of the - earlier work or a work "based on" the earlier work. - - A "covered work" means either the unmodified Program or a work based - on the Program. - - To "propagate" a work means to do anything with it that, without - permission, would make you directly or secondarily liable for - infringement under applicable copyright law, except executing it on a - computer or modifying a private copy. Propagation includes copying, - distribution (with or without modification), making available to the - public, and in some countries other activities as well. - - To "convey" a work means any kind of propagation that enables other - parties to make or receive copies. Mere interaction with a user through - a computer network, with no transfer of a copy, is not conveying. - - An interactive user interface displays "Appropriate Legal Notices" - to the extent that it includes a convenient and prominently visible - feature that (1) displays an appropriate copyright notice, and (2) - tells the user that there is no warranty for the work (except to the - extent that warranties are provided), that licensees may convey the - work under this License, and how to view a copy of this License. If - the interface presents a list of user commands or options, such as a - menu, a prominent item in the list meets this criterion. - - 1. Source Code. - - The "source code" for a work means the preferred form of the work - for making modifications to it. "Object code" means any non-source - form of a work. - - A "Standard Interface" means an interface that either is an official - standard defined by a recognized standards body, or, in the case of - interfaces specified for a particular programming language, one that - is widely used among developers working in that language. - - The "System Libraries" of an executable work include anything, other - than the work as a whole, that (a) is included in the normal form of - packaging a Major Component, but which is not part of that Major - Component, and (b) serves only to enable use of the work with that - Major Component, or to implement a Standard Interface for which an - implementation is available to the public in source code form. A - "Major Component", in this context, means a major essential component - (kernel, window system, and so on) of the specific operating system - (if any) on which the executable work runs, or a compiler used to - produce the work, or an object code interpreter used to run it. - - The "Corresponding Source" for a work in object code form means all - the source code needed to generate, install, and (for an executable - work) run the object code and to modify the work, including scripts to - control those activities. However, it does not include the work's - System Libraries, or general-purpose tools or generally available free - programs which are used unmodified in performing those activities but - which are not part of the work. For example, Corresponding Source - includes interface definition files associated with source files for - the work, and the source code for shared libraries and dynamically - linked subprograms that the work is specifically designed to require, - such as by intimate data communication or control flow between those - subprograms and other parts of the work. - - The Corresponding Source need not include anything that users - can regenerate automatically from other parts of the Corresponding - Source. - - The Corresponding Source for a work in source code form is that - same work. - - 2. Basic Permissions. - - All rights granted under this License are granted for the term of - copyright on the Program, and are irrevocable provided the stated - conditions are met. This License explicitly affirms your unlimited - permission to run the unmodified Program. The output from running a - covered work is covered by this License only if the output, given its - content, constitutes a covered work. This License acknowledges your - rights of fair use or other equivalent, as provided by copyright law. - - You may make, run and propagate covered works that you do not - convey, without conditions so long as your license otherwise remains - in force. You may convey covered works to others for the sole purpose - of having them make modifications exclusively for you, or provide you - with facilities for running those works, provided that you comply with - the terms of this License in conveying all material for which you do - not control copyright. Those thus making or running the covered works - for you must do so exclusively on your behalf, under your direction - and control, on terms that prohibit them from making any copies of - your copyrighted material outside their relationship with you. - - Conveying under any other circumstances is permitted solely under - the conditions stated below. Sublicensing is not allowed; section 10 - makes it unnecessary. - - 3. Protecting Users' Legal Rights From Anti-Circumvention Law. - - No covered work shall be deemed part of an effective technological - measure under any applicable law fulfilling obligations under article - 11 of the WIPO copyright treaty adopted on 20 December 1996, or - similar laws prohibiting or restricting circumvention of such - measures. - - When you convey a covered work, you waive any legal power to forbid - circumvention of technological measures to the extent such circumvention - is effected by exercising rights under this License with respect to - the covered work, and you disclaim any intention to limit operation or - modification of the work as a means of enforcing, against the work's - users, your or third parties' legal rights to forbid circumvention of - technological measures. - - 4. Conveying Verbatim Copies. - - You may convey verbatim copies of the Program's source code as you - receive it, in any medium, provided that you conspicuously and - appropriately publish on each copy an appropriate copyright notice; - keep intact all notices stating that this License and any - non-permissive terms added in accord with section 7 apply to the code; - keep intact all notices of the absence of any warranty; and give all - recipients a copy of this License along with the Program. - - You may charge any price or no price for each copy that you convey, - and you may offer support or warranty protection for a fee. - - 5. Conveying Modified Source Versions. - - You may convey a work based on the Program, or the modifications to - produce it from the Program, in the form of source code under the - terms of section 4, provided that you also meet all of these conditions: - - a) The work must carry prominent notices stating that you modified - it, and giving a relevant date. - - b) The work must carry prominent notices stating that it is - released under this License and any conditions added under section - 7. This requirement modifies the requirement in section 4 to - "keep intact all notices". - - c) You must license the entire work, as a whole, under this - License to anyone who comes into possession of a copy. This - License will therefore apply, along with any applicable section 7 - additional terms, to the whole of the work, and all its parts, - regardless of how they are packaged. This License gives no - permission to license the work in any other way, but it does not - invalidate such permission if you have separately received it. - - d) If the work has interactive user interfaces, each must display - Appropriate Legal Notices; however, if the Program has interactive - interfaces that do not display Appropriate Legal Notices, your - work need not make them do so. - - A compilation of a covered work with other separate and independent - works, which are not by their nature extensions of the covered work, - and which are not combined with it such as to form a larger program, - in or on a volume of a storage or distribution medium, is called an - "aggregate" if the compilation and its resulting copyright are not - used to limit the access or legal rights of the compilation's users - beyond what the individual works permit. Inclusion of a covered work - in an aggregate does not cause this License to apply to the other - parts of the aggregate. - - 6. Conveying Non-Source Forms. - - You may convey a covered work in object code form under the terms - of sections 4 and 5, provided that you also convey the - machine-readable Corresponding Source under the terms of this License, - in one of these ways: - - a) Convey the object code in, or embodied in, a physical product - (including a physical distribution medium), accompanied by the - Corresponding Source fixed on a durable physical medium - customarily used for software interchange. - - b) Convey the object code in, or embodied in, a physical product - (including a physical distribution medium), accompanied by a - written offer, valid for at least three years and valid for as - long as you offer spare parts or customer support for that product - model, to give anyone who possesses the object code either (1) a - copy of the Corresponding Source for all the software in the - product that is covered by this License, on a durable physical - medium customarily used for software interchange, for a price no - more than your reasonable cost of physically performing this - conveying of source, or (2) access to copy the - Corresponding Source from a network server at no charge. - - c) Convey individual copies of the object code with a copy of the - written offer to provide the Corresponding Source. This - alternative is allowed only occasionally and noncommercially, and - only if you received the object code with such an offer, in accord - with subsection 6b. - - d) Convey the object code by offering access from a designated - place (gratis or for a charge), and offer equivalent access to the - Corresponding Source in the same way through the same place at no - further charge. You need not require recipients to copy the - Corresponding Source along with the object code. If the place to - copy the object code is a network server, the Corresponding Source - may be on a different server (operated by you or a third party) - that supports equivalent copying facilities, provided you maintain - clear directions next to the object code saying where to find the - Corresponding Source. Regardless of what server hosts the - Corresponding Source, you remain obligated to ensure that it is - available for as long as needed to satisfy these requirements. - - e) Convey the object code using peer-to-peer transmission, provided - you inform other peers where the object code and Corresponding - Source of the work are being offered to the general public at no - charge under subsection 6d. - - A separable portion of the object code, whose source code is excluded - from the Corresponding Source as a System Library, need not be - included in conveying the object code work. - - A "User Product" is either (1) a "consumer product", which means any - tangible personal property which is normally used for personal, family, - or household purposes, or (2) anything designed or sold for incorporation - into a dwelling. In determining whether a product is a consumer product, - doubtful cases shall be resolved in favor of coverage. For a particular - product received by a particular user, "normally used" refers to a - typical or common use of that class of product, regardless of the status - of the particular user or of the way in which the particular user - actually uses, or expects or is expected to use, the product. A product - is a consumer product regardless of whether the product has substantial - commercial, industrial or non-consumer uses, unless such uses represent - the only significant mode of use of the product. - - "Installation Information" for a User Product means any methods, - procedures, authorization keys, or other information required to install - and execute modified versions of a covered work in that User Product from - a modified version of its Corresponding Source. The information must - suffice to ensure that the continued functioning of the modified object - code is in no case prevented or interfered with solely because - modification has been made. - - If you convey an object code work under this section in, or with, or - specifically for use in, a User Product, and the conveying occurs as - part of a transaction in which the right of possession and use of the - User Product is transferred to the recipient in perpetuity or for a - fixed term (regardless of how the transaction is characterized), the - Corresponding Source conveyed under this section must be accompanied - by the Installation Information. But this requirement does not apply - if neither you nor any third party retains the ability to install - modified object code on the User Product (for example, the work has - been installed in ROM). - - The requirement to provide Installation Information does not include a - requirement to continue to provide support service, warranty, or updates - for a work that has been modified or installed by the recipient, or for - the User Product in which it has been modified or installed. Access to a - network may be denied when the modification itself materially and - adversely affects the operation of the network or violates the rules and - protocols for communication across the network. - - Corresponding Source conveyed, and Installation Information provided, - in accord with this section must be in a format that is publicly - documented (and with an implementation available to the public in - source code form), and must require no special password or key for - unpacking, reading or copying. - - 7. Additional Terms. - - "Additional permissions" are terms that supplement the terms of this - License by making exceptions from one or more of its conditions. - Additional permissions that are applicable to the entire Program shall - be treated as though they were included in this License, to the extent - that they are valid under applicable law. If additional permissions - apply only to part of the Program, that part may be used separately - under those permissions, but the entire Program remains governed by - this License without regard to the additional permissions. - - When you convey a copy of a covered work, you may at your option - remove any additional permissions from that copy, or from any part of - it. (Additional permissions may be written to require their own - removal in certain cases when you modify the work.) You may place - additional permissions on material, added by you to a covered work, - for which you have or can give appropriate copyright permission. - - Notwithstanding any other provision of this License, for material you - add to a covered work, you may (if authorized by the copyright holders of - that material) supplement the terms of this License with terms: - - a) Disclaiming warranty or limiting liability differently from the - terms of sections 15 and 16 of this License; or - - b) Requiring preservation of specified reasonable legal notices or - author attributions in that material or in the Appropriate Legal - Notices displayed by works containing it; or - - c) Prohibiting misrepresentation of the origin of that material, or - requiring that modified versions of such material be marked in - reasonable ways as different from the original version; or - - d) Limiting the use for publicity purposes of names of licensors or - authors of the material; or - - e) Declining to grant rights under trademark law for use of some - trade names, trademarks, or service marks; or - - f) Requiring indemnification of licensors and authors of that - material by anyone who conveys the material (or modified versions of - it) with contractual assumptions of liability to the recipient, for - any liability that these contractual assumptions directly impose on - those licensors and authors. - - All other non-permissive additional terms are considered "further - restrictions" within the meaning of section 10. If the Program as you - received it, or any part of it, contains a notice stating that it is - governed by this License along with a term that is a further - restriction, you may remove that term. If a license document contains - a further restriction but permits relicensing or conveying under this - License, you may add to a covered work material governed by the terms - of that license document, provided that the further restriction does - not survive such relicensing or conveying. - - If you add terms to a covered work in accord with this section, you - must place, in the relevant source files, a statement of the - additional terms that apply to those files, or a notice indicating - where to find the applicable terms. - - Additional terms, permissive or non-permissive, may be stated in the - form of a separately written license, or stated as exceptions; - the above requirements apply either way. - - 8. Termination. - - You may not propagate or modify a covered work except as expressly - provided under this License. Any attempt otherwise to propagate or - modify it is void, and will automatically terminate your rights under - this License (including any patent licenses granted under the third - paragraph of section 11). - - However, if you cease all violation of this License, then your - license from a particular copyright holder is reinstated (a) - provisionally, unless and until the copyright holder explicitly and - finally terminates your license, and (b) permanently, if the copyright - holder fails to notify you of the violation by some reasonable means - prior to 60 days after the cessation. - - Moreover, your license from a particular copyright holder is - reinstated permanently if the copyright holder notifies you of the - violation by some reasonable means, this is the first time you have - received notice of violation of this License (for any work) from that - copyright holder, and you cure the violation prior to 30 days after - your receipt of the notice. - - Termination of your rights under this section does not terminate the - licenses of parties who have received copies or rights from you under - this License. If your rights have been terminated and not permanently - reinstated, you do not qualify to receive new licenses for the same - material under section 10. - - 9. Acceptance Not Required for Having Copies. - - You are not required to accept this License in order to receive or - run a copy of the Program. Ancillary propagation of a covered work - occurring solely as a consequence of using peer-to-peer transmission - to receive a copy likewise does not require acceptance. However, - nothing other than this License grants you permission to propagate or - modify any covered work. These actions infringe copyright if you do - not accept this License. Therefore, by modifying or propagating a - covered work, you indicate your acceptance of this License to do so. - - 10. Automatic Licensing of Downstream Recipients. - - Each time you convey a covered work, the recipient automatically - receives a license from the original licensors, to run, modify and - propagate that work, subject to this License. You are not responsible - for enforcing compliance by third parties with this License. - - An "entity transaction" is a transaction transferring control of an - organization, or substantially all assets of one, or subdividing an - organization, or merging organizations. If propagation of a covered - work results from an entity transaction, each party to that - transaction who receives a copy of the work also receives whatever - licenses to the work the party's predecessor in interest had or could - give under the previous paragraph, plus a right to possession of the - Corresponding Source of the work from the predecessor in interest, if - the predecessor has it or can get it with reasonable efforts. - - You may not impose any further restrictions on the exercise of the - rights granted or affirmed under this License. For example, you may - not impose a license fee, royalty, or other charge for exercise of - rights granted under this License, and you may not initiate litigation - (including a cross-claim or counterclaim in a lawsuit) alleging that - any patent claim is infringed by making, using, selling, offering for - sale, or importing the Program or any portion of it. - - 11. Patents. - - A "contributor" is a copyright holder who authorizes use under this - License of the Program or a work on which the Program is based. The - work thus licensed is called the contributor's "contributor version". - - A contributor's "essential patent claims" are all patent claims - owned or controlled by the contributor, whether already acquired or - hereafter acquired, that would be infringed by some manner, permitted - by this License, of making, using, or selling its contributor version, - but do not include claims that would be infringed only as a - consequence of further modification of the contributor version. For - purposes of this definition, "control" includes the right to grant - patent sublicenses in a manner consistent with the requirements of - this License. - - Each contributor grants you a non-exclusive, worldwide, royalty-free - patent license under the contributor's essential patent claims, to - make, use, sell, offer for sale, import and otherwise run, modify and - propagate the contents of its contributor version. - - In the following three paragraphs, a "patent license" is any express - agreement or commitment, however denominated, not to enforce a patent - (such as an express permission to practice a patent or covenant not to - sue for patent infringement). To "grant" such a patent license to a - party means to make such an agreement or commitment not to enforce a - patent against the party. - - If you convey a covered work, knowingly relying on a patent license, - and the Corresponding Source of the work is not available for anyone - to copy, free of charge and under the terms of this License, through a - publicly available network server or other readily accessible means, - then you must either (1) cause the Corresponding Source to be so - available, or (2) arrange to deprive yourself of the benefit of the - patent license for this particular work, or (3) arrange, in a manner - consistent with the requirements of this License, to extend the patent - license to downstream recipients. "Knowingly relying" means you have - actual knowledge that, but for the patent license, your conveying the - covered work in a country, or your recipient's use of the covered work - in a country, would infringe one or more identifiable patents in that - country that you have reason to believe are valid. - - If, pursuant to or in connection with a single transaction or - arrangement, you convey, or propagate by procuring conveyance of, a - covered work, and grant a patent license to some of the parties - receiving the covered work authorizing them to use, propagate, modify - or convey a specific copy of the covered work, then the patent license - you grant is automatically extended to all recipients of the covered - work and works based on it. - - A patent license is "discriminatory" if it does not include within - the scope of its coverage, prohibits the exercise of, or is - conditioned on the non-exercise of one or more of the rights that are - specifically granted under this License. You may not convey a covered - work if you are a party to an arrangement with a third party that is - in the business of distributing software, under which you make payment - to the third party based on the extent of your activity of conveying - the work, and under which the third party grants, to any of the - parties who would receive the covered work from you, a discriminatory - patent license (a) in connection with copies of the covered work - conveyed by you (or copies made from those copies), or (b) primarily - for and in connection with specific products or compilations that - contain the covered work, unless you entered into that arrangement, - or that patent license was granted, prior to 28 March 2007. - - Nothing in this License shall be construed as excluding or limiting - any implied license or other defenses to infringement that may - otherwise be available to you under applicable patent law. - - 12. No Surrender of Others' Freedom. - - If conditions are imposed on you (whether by court order, agreement or - otherwise) that contradict the conditions of this License, they do not - excuse you from the conditions of this License. If you cannot convey a - covered work so as to satisfy simultaneously your obligations under this - License and any other pertinent obligations, then as a consequence you may - not convey it at all. For example, if you agree to terms that obligate you - to collect a royalty for further conveying from those to whom you convey - the Program, the only way you could satisfy both those terms and this - License would be to refrain entirely from conveying the Program. - - 13. Use with the GNU Affero General Public License. - - Notwithstanding any other provision of this License, you have - permission to link or combine any covered work with a work licensed - under version 3 of the GNU Affero General Public License into a single - combined work, and to convey the resulting work. The terms of this - License will continue to apply to the part which is the covered work, - but the special requirements of the GNU Affero General Public License, - section 13, concerning interaction through a network will apply to the - combination as such. - - 14. Revised Versions of this License. - - The Free Software Foundation may publish revised and/or new versions of - the GNU General Public License from time to time. Such new versions will - be similar in spirit to the present version, but may differ in detail to - address new problems or concerns. - - Each version is given a distinguishing version number. If the - Program specifies that a certain numbered version of the GNU General - Public License "or any later version" applies to it, you have the - option of following the terms and conditions either of that numbered - version or of any later version published by the Free Software - Foundation. If the Program does not specify a version number of the - GNU General Public License, you may choose any version ever published - by the Free Software Foundation. - - If the Program specifies that a proxy can decide which future - versions of the GNU General Public License can be used, that proxy's - public statement of acceptance of a version permanently authorizes you - to choose that version for the Program. - - Later license versions may give you additional or different - permissions. However, no additional obligations are imposed on any - author or copyright holder as a result of your choosing to follow a - later version. - - 15. Disclaimer of Warranty. - - THERE IS NO WARRANTY FOR THE PROGRAM, TO THE EXTENT PERMITTED BY - APPLICABLE LAW. EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT - HOLDERS AND/OR OTHER PARTIES PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY - OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, - THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR - PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE PROGRAM - IS WITH YOU. SHOULD THE PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF - ALL NECESSARY SERVICING, REPAIR OR CORRECTION. - - 16. Limitation of Liability. - - IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING - WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MODIFIES AND/OR CONVEYS - THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY - GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE - USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED TO LOSS OF - DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD - PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER PROGRAMS), - EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF - SUCH DAMAGES. - - 17. Interpretation of Sections 15 and 16. - - If the disclaimer of warranty and limitation of liability provided - above cannot be given local legal effect according to their terms, - reviewing courts shall apply local law that most closely approximates - an absolute waiver of all civil liability in connection with the - Program, unless a warranty or assumption of liability accompanies a - copy of the Program in return for a fee. - - END OF TERMS AND CONDITIONS - - How to Apply These Terms to Your New Programs - - If you develop a new program, and you want it to be of the greatest - possible use to the public, the best way to achieve this is to make it - free software which everyone can redistribute and change under these terms. - - To do so, attach the following notices to the program. It is safest - to attach them to the start of each source file to most effectively - state the exclusion of warranty; and each file should have at least - the "copyright" line and a pointer to where the full notice is found. - - - Copyright (C) - - This program is free software: you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation, either version 3 of the License, or - (at your option) any later version. - - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program. If not, see . - - Also add information on how to contact you by electronic and paper mail. - - If the program does terminal interaction, make it output a short - notice like this when it starts in an interactive mode: - - Copyright (C) - This program comes with ABSOLUTELY NO WARRANTY; for details type `show w'. - This is free software, and you are welcome to redistribute it - under certain conditions; type `show c' for details. - - The hypothetical commands `show w' and `show c' should show the appropriate - parts of the General Public License. Of course, your program's commands - might be different; for a GUI interface, you would use an "about box". - - You should also get your employer (if you work as a programmer) or school, - if any, to sign a "copyright disclaimer" for the program, if necessary. - For more information on this, and how to apply and follow the GNU GPL, see - . - - The GNU General Public License does not permit incorporating your program - into proprietary programs. If your program is a subroutine library, you - may consider it more useful to permit linking proprietary applications with - the library. If this is what you want to do, use the GNU Lesser General - Public License instead of this License. But first, please read - . - -The complete text of the Apache 2.0 License is as follows: - - Apache License - Version 2.0, January 2004 - http://www.apache.org/licenses/ - - TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION - - 1. Definitions. - - "License" shall mean the terms and conditions for use, reproduction, - and distribution as defined by Sections 1 through 9 of this document. - - "Licensor" shall mean the copyright owner or entity authorized by - the copyright owner that is granting the License. - - "Legal Entity" shall mean the union of the acting entity and all - other entities that control, are controlled by, or are under common - control with that entity. For the purposes of this definition, - "control" means (i) the power, direct or indirect, to cause the - direction or management of such entity, whether by contract or - otherwise, or (ii) ownership of fifty percent (50%) or more of the - outstanding shares, or (iii) beneficial ownership of such entity. - - "You" (or "Your") shall mean an individual or Legal Entity - exercising permissions granted by this License. - - "Source" form shall mean the preferred form for making modifications, - including but not limited to software source code, documentation - source, and configuration files. - - "Object" form shall mean any form resulting from mechanical - transformation or translation of a Source form, including but - not limited to compiled object code, generated documentation, - and conversions to other media types. - - "Work" shall mean the work of authorship, whether in Source or - Object form, made available under the License, as indicated by a - copyright notice that is included in or attached to the work - (an example is provided in the Appendix below). - - "Derivative Works" shall mean any work, whether in Source or Object - form, that is based on (or derived from) the Work and for which the - editorial revisions, annotations, elaborations, or other modifications - represent, as a whole, an original work of authorship. For the purposes - of this License, Derivative Works shall not include works that remain - separable from, or merely link (or bind by name) to the interfaces of, - the Work and Derivative Works thereof. - - "Contribution" shall mean any work of authorship, including - the original version of the Work and any modifications or additions - to that Work or Derivative Works thereof, that is intentionally - submitted to Licensor for inclusion in the Work by the copyright owner - or by an individual or Legal Entity authorized to submit on behalf of - the copyright owner. For the purposes of this definition, "submitted" - means any form of electronic, verbal, or written communication sent - to the Licensor or its representatives, including but not limited to - communication on electronic mailing lists, source code control systems, - and issue tracking systems that are managed by, or on behalf of, the - Licensor for the purpose of discussing and improving the Work, but - excluding communication that is conspicuously marked or otherwise - designated in writing by the copyright owner as "Not a Contribution." - - "Contributor" shall mean Licensor and any individual or Legal Entity - on behalf of whom a Contribution has been received by Licensor and - subsequently incorporated within the Work. - - 2. Grant of Copyright License. Subject to the terms and conditions of - this License, each Contributor hereby grants to You a perpetual, - worldwide, non-exclusive, no-charge, royalty-free, irrevocable - copyright license to reproduce, prepare Derivative Works of, - publicly display, publicly perform, sublicense, and distribute the - Work and such Derivative Works in Source or Object form. - - 3. Grant of Patent License. Subject to the terms and conditions of - this License, each Contributor hereby grants to You a perpetual, - worldwide, non-exclusive, no-charge, royalty-free, irrevocable - (except as stated in this section) patent license to make, have made, - use, offer to sell, sell, import, and otherwise transfer the Work, - where such license applies only to those patent claims licensable - by such Contributor that are necessarily infringed by their - Contribution(s) alone or by combination of their Contribution(s) - with the Work to which such Contribution(s) was submitted. If You - institute patent litigation against any entity (including a - cross-claim or counterclaim in a lawsuit) alleging that the Work - or a Contribution incorporated within the Work constitutes direct - or contributory patent infringement, then any patent licenses - granted to You under this License for that Work shall terminate - as of the date such litigation is filed. - - 4. Redistribution. You may reproduce and distribute copies of the - Work or Derivative Works thereof in any medium, with or without - modifications, and in Source or Object form, provided that You - meet the following conditions: - - (a) You must give any other recipients of the Work or - Derivative Works a copy of this License; and - - (b) You must cause any modified files to carry prominent notices - stating that You changed the files; and - - (c) You must retain, in the Source form of any Derivative Works - that You distribute, all copyright, patent, trademark, and - attribution notices from the Source form of the Work, - excluding those notices that do not pertain to any part of - the Derivative Works; and - - (d) If the Work includes a "NOTICE" text file as part of its - distribution, then any Derivative Works that You distribute must - include a readable copy of the attribution notices contained - within such NOTICE file, excluding those notices that do not - pertain to any part of the Derivative Works, in at least one - of the following places: within a NOTICE text file distributed - as part of the Derivative Works; within the Source form or - documentation, if provided along with the Derivative Works; or, - within a display generated by the Derivative Works, if and - wherever such third-party notices normally appear. The contents - of the NOTICE file are for informational purposes only and - do not modify the License. You may add Your own attribution - notices within Derivative Works that You distribute, alongside - or as an addendum to the NOTICE text from the Work, provided - that such additional attribution notices cannot be construed - as modifying the License. - - You may add Your own copyright statement to Your modifications and - may provide additional or different license terms and conditions - for use, reproduction, or distribution of Your modifications, or - for any such Derivative Works as a whole, provided Your use, - reproduction, and distribution of the Work otherwise complies with - the conditions stated in this License. - - 5. Submission of Contributions. Unless You explicitly state otherwise, - any Contribution intentionally submitted for inclusion in the Work - by You to the Licensor shall be under the terms and conditions of - this License, without any additional terms or conditions. - Notwithstanding the above, nothing herein shall supersede or modify - the terms of any separate license agreement you may have executed - with Licensor regarding such Contributions. - - 6. Trademarks. This License does not grant permission to use the trade - names, trademarks, service marks, or product names of the Licensor, - except as required for reasonable and customary use in describing the - origin of the Work and reproducing the content of the NOTICE file. - - 7. Disclaimer of Warranty. Unless required by applicable law or - agreed to in writing, Licensor provides the Work (and each - Contributor provides its Contributions) on an "AS IS" BASIS, - WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or - implied, including, without limitation, any warranties or conditions - of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A - PARTICULAR PURPOSE. You are solely responsible for determining the - appropriateness of using or redistributing the Work and assume any - risks associated with Your exercise of permissions under this License. - - 8. Limitation of Liability. In no event and under no legal theory, - whether in tort (including negligence), contract, or otherwise, - unless required by applicable law (such as deliberate and grossly - negligent acts) or agreed to in writing, shall any Contributor be - liable to You for damages, including any direct, indirect, special, - incidental, or consequential damages of any character arising as a - result of this License or out of the use or inability to use the - Work (including but not limited to damages for loss of goodwill, - work stoppage, computer failure or malfunction, or any and all - other commercial damages or losses), even if such Contributor - has been advised of the possibility of such damages. - - 9. Accepting Warranty or Additional Liability. While redistributing - the Work or Derivative Works thereof, You may choose to offer, - and charge a fee for, acceptance of support, warranty, indemnity, - or other liability obligations and/or rights consistent with this - License. However, in accepting such obligations, You may act only - on Your own behalf and on Your sole responsibility, not on behalf - of any other Contributor, and only if You agree to indemnify, - defend, and hold each Contributor harmless for any liability - incurred by, or claims asserted against, such Contributor by reason - of your accepting any such warranty or additional liability. - - END OF TERMS AND CONDITIONS - - APPENDIX: How to apply the Apache License to your work. - - To apply the Apache License to your work, attach the following - boilerplate notice, with the fields enclosed by brackets "[]" - replaced with your own identifying information. (Don't include - the brackets!) The text should be enclosed in the appropriate - comment syntax for the file format. We also recommend that a - file or class name and description of purpose be included on the - same "printed page" as the copyright notice for easier - identification within third-party archives. - - Copyright [yyyy] [name of copyright owner] - - Licensed 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. - -The complete text of the BSD license can be is as follows: - - Copyright (c) The Regents of the University of California. - All rights reserved. - - Redistribution and use in source and binary forms, with or without - modification, are permitted provided that the following conditions - are met: - 1. Redistributions of source code must retain the above copyright - notice, this list of conditions and the following disclaimer. - 2. Redistributions in binary form must reproduce the above copyright - notice, this list of conditions and the following disclaimer in the - documentation and/or other materials provided with the distribution. - 3. Neither the name of the University nor the names of its contributors - may be used to endorse or promote products derived from this software - without specific prior written permission. - - THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND - ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE - ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE - FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL - DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS - OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) - HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT - LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY - OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF - SUCH DAMAGE. - -The complete text of the Apache Software License Version 1.1 is as follows: - - /* - * ================================================================ - * The Apache Software License, Version 1.1 - * ================================================================ - * - * Copyright (C) 2000-2002 The Apache Software Foundation. All - * rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following - * conditions are met: - * - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in - * the documentation and/or other materials provided with the - * distribution. - * - * 3. The end-user documentation included with the redistribution, if - * any, must include the following acknowledgment: "This product - * includes software developed by the Apache Software Foundation - * (http://www.apache.org/)." Alternately, this acknowledgment may - * appear in the software itself, if and wherever such third-party - * acknowledgments normally appear. - * - * 4. The names "Ant" and "Apache Software Foundation" must not be - * used to endorse or promote products derived from this software - * without prior written permission. For written permission, please - * contact apache@apache.org. - * - * 5. Products derived from this software may not be called "Apache", - * nor may "Apache" appear in their name, without prior written - * permission of the Apache Software Foundation. - * - * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED - * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES - * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE - * DISCLAIMED. IN NO EVENT SHALL THE APACHE SOFTWARE FOUNDATION - * OR ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT - * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, - * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON - * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR - * TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT - * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY - * OF SUCH DAMAGE. - * - * This software consists of voluntary contributions made by many - * individuals on behalf of the Apache Software Foundation. For more - * information on the Apache Software Foundation, please see - * . - * - */ - -The complete text of the MIT license is as follows: - - Permission is hereby granted, free of charge, to any person - obtaining a copy of this software and associated documentation - files (the “Software”), to deal in the Software without - restriction, including without limitation the rights to use, - copy, modify, merge, publish, distribute, sublicense, and/or sell - copies of the Software, and to permit persons to whom the - Software is furnished to do so, subject to the following - conditions: - - The above copyright notice and this permission notice shall be - included in all copies or substantial portions of the Software. - - THE SOFTWARE IS PROVIDED “AS IS”, WITHOUT WARRANTY OF ANY KIND, - EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES - OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND - NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT - HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, - WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING - FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR - OTHER DEALINGS IN THE SOFTWARE. - -The complete text of the Eclipse Public License v1.0 is as follows: - - Eclipse Public License - v 1.0 - - THE ACCOMPANYING PROGRAM IS PROVIDED UNDER THE TERMS OF THIS ECLIPSE PUBLIC - LICENSE ("AGREEMENT"). ANY USE, REPRODUCTION OR DISTRIBUTION OF THE PROGRAM - CONSTITUTES RECIPIENT’S ACCEPTANCE OF THIS AGREEMENT. - - 1. DEFINITIONS - - "Contribution" means: - - a) in the case of the initial Contributor, the initial code and documentation - distributed under this Agreement, and - b) in the case of each subsequent Contributor: - - i) changes to the Program, and - - ii) additions to the Program; - - where such changes and/or additions to the Program originate from and are - distributed by that particular Contributor. A Contribution 'originates' from a - Contributor if it was added to the Program by such Contributor itself or anyone - acting on such Contributor’s behalf. Contributions do not include additions to - the Program which: (i) are separate modules of software distributed in - conjunction with the Program under their own license agreement, and (ii) are not - derivative works of the Program. - - "Contributor" means any person or entity that distributes the Program. - - "Licensed Patents " mean patent claims licensable by a Contributor which are - necessarily infringed by the use or sale of its Contribution alone or when - combined with the Program. - - "Program" means the Contributions distributed in accordance with this Agreement. - - "Recipient" means anyone who receives the Program under this Agreement, - including all Contributors. - - 2. GRANT OF RIGHTS - - a) Subject to the terms of this Agreement, each Contributor hereby grants - Recipient a non-exclusive, worldwide, royalty-free copyright license to - reproduce, prepare derivative works of, publicly display, publicly perform, - distribute and sublicense the Contribution of such Contributor, if any, and such - derivative works, in source code and object code form. - - b) Subject to the terms of this Agreement, each Contributor hereby grants - Recipient a non-exclusive, worldwide, royalty-free patent license under Licensed - Patents to make, use, sell, offer to sell, import and otherwise transfer the - Contribution of such Contributor, if any, in source code and object code form. - This patent license shall apply to the combination of the Contribution and the - Program if, at the time the Contribution is added by the Contributor, such - addition of the Contribution causes such combination to be covered by the - Licensed Patents. The patent license shall not apply to any other combinations - which include the Contribution. No hardware per se is licensed hereunder. - - c) Recipient understands that although each Contributor grants the licenses to - its Contributions set forth herein, no assurances are provided by any - Contributor that the Program does not infringe the patent or other intellectual - property rights of any other entity. Each Contributor disclaims any liability to - Recipient for claims brought by any other entity based on infringement of - intellectual property rights or otherwise. As a condition to exercising the - rights and licenses granted hereunder, each Recipient hereby assumes sole - responsibility to secure any other intellectual property rights needed, if any. - For example, if a third party patent license is required to allow Recipient to - distribute the Program, it is Recipient’s responsibility to acquire that license - before distributing the Program. - - d) Each Contributor represents that to its knowledge it has sufficient copyright - rights in its Contribution, if any, to grant the copyright license set forth in - this Agreement. - - 3. REQUIREMENTS - - A Contributor may choose to distribute the Program in object code form under its - own license agreement, provided that: - - a) it complies with the terms and conditions of this Agreement; and - - b) its license agreement: - - i) effectively disclaims on behalf of all Contributors all warranties and - conditions, express and implied, including warranties or conditions of title and - non-infringement, and implied warranties or conditions of merchantability and - fitness for a particular purpose; - - ii) effectively excludes on behalf of all Contributors all liability for - damages, including direct, indirect, special, incidental and consequential - damages, such as lost profits; - - iii) states that any provisions which differ from this Agreement are offered by - that Contributor alone and not by any other party; and - - iv) states that source code for the Program is available from such Contributor, - and informs licensees how to obtain it in a reasonable manner on or through a - medium customarily used for software exchange. - - When the Program is made available in source code form: - - a) it must be made available under this Agreement; and - b) a copy of this Agreement must be included with each copy of the Program. - - Contributors may not remove or alter any copyright notices contained within the - Program. - - Each Contributor must identify itself as the originator of its Contribution, if - any, in a manner that reasonably allows subsequent Recipients to identify the - originator of the Contribution. - - 4. COMMERCIAL DISTRIBUTION - - Commercial distributors of software may accept certain responsibilities with - respect to end users, business partners and the like. While this license is - intended to facilitate the commercial use of the Program, the Contributor who - includes the Program in a commercial product offering should do so in a manner - which does not create potential liability for other Contributors. Therefore, if - a Contributor includes the Program in a commercial product offering, such - Contributor ("Commercial Contributor") hereby agrees to defend and indemnify - every other Contributor ("Indemnified Contributor") against any losses, damages - and costs (collectively "Losses") arising from claims, lawsuits and other legal - actions brought by a third party against the Indemnified Contributor to the - extent caused by the acts or omissions of such Commercial Contributor in - connection with its distribution of the Program in a commercial product - offering. The obligations in this section do not apply to any claims or Losses - relating to any actual or alleged intellectual property infringement. In order - to qualify, an Indemnified Contributor must: a) promptly notify the Commercial - Contributor in writing of such claim, and b) allow the Commercial Contributor to - control, and cooperate with the Commercial Contributor in, the defense and any - related settlement negotiations. The Indemnified Contributor may participate in - any such claim at its own expense. - - For example, a Contributor might include the Program in a commercial product - offering, Product X. That Contributor is then a Commercial Contributor. If that - Commercial Contributor then makes performance claims, or offers warranties - related to Product X, those performance claims and warranties are such - Commercial Contributor’s responsibility alone. Under this section, the - Commercial Contributor would have to defend claims against the other - Contributors related to those performance claims and warranties, and if a court - requires any other Contributor to pay any damages as a result, the Commercial - Contributor must pay those damages. - - 5. NO WARRANTY - - EXCEPT AS EXPRESSLY SET FORTH IN THIS AGREEMENT, THE PROGRAM IS PROVIDED ON AN - "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, EITHER EXPRESS OR - IMPLIED INCLUDING, WITHOUT LIMITATION, ANY WARRANTIES OR CONDITIONS OF TITLE, - NON-INFRINGEMENT, MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE. Each - Recipient is solely responsible for determining the appropriateness of using and - distributing the Program and assumes all risks associated with its exercise of - rights under this Agreement , including but not limited to the risks and costs - of program errors, compliance with applicable laws, damage to or loss of data, - programs or equipment, and unavailability or interruption of operations. - - 6. DISCLAIMER OF LIABILITY - - EXCEPT AS EXPRESSLY SET FORTH IN THIS AGREEMENT, NEITHER RECIPIENT NOR ANY - CONTRIBUTORS SHALL HAVE ANY LIABILITY FOR ANY DIRECT, INDIRECT, INCIDENTAL, - SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING WITHOUT LIMITATION LOST - PROFITS), HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, - STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY - OUT OF THE USE OR DISTRIBUTION OF THE PROGRAM OR THE EXERCISE OF ANY RIGHTS - GRANTED HEREUNDER, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGES. - - 7. GENERAL - - If any provision of this Agreement is invalid or unenforceable under applicable - law, it shall not affect the validity or enforceability of the remainder of the - terms of this Agreement, and without further action by the parties hereto, such - provision shall be reformed to the minimum extent necessary to make such - provision valid and enforceable. - - If Recipient institutes patent litigation against any entity (including a - cross-claim or counterclaim in a lawsuit) alleging that the Program itself - (excluding combinations of the Program with other software or hardware) - infringes such Recipient’s patent(s), then such Recipient’s rights granted under - Section 2(b) shall terminate as of the date such litigation is filed. - - All Recipient’s rights under this Agreement shall terminate if it fails to - comply with any of the material terms or conditions of this Agreement and does - not cure such failure in a reasonable period of time after becoming aware of - such noncompliance. If all Recipient’s rights under this Agreement terminate, - Recipient agrees to cease use and distribution of the Program as soon as - reasonably practicable. However, Recipient’s obligations under this Agreement - and any licenses granted by Recipient relating to the Program shall continue and - survive. - - Everyone is permitted to copy and distribute copies of this Agreement, but in - order to avoid inconsistency the Agreement is copyrighted and may only be - modified in the following manner. The Agreement Steward reserves the right to - publish new versions (including revisions) of this Agreement from time to time. - No one other than the Agreement Steward has the right to modify this Agreement. - The Eclipse Foundation is the initial Agreement Steward. The Eclipse Foundation - may assign the responsibility to serve as the Agreement Steward to a suitable - separate entity. Each new version of the Agreement will be given a - distinguishing version number. The Program (including Contributions) may always - be distributed subject to the version of the Agreement under which it was - received. In addition, after a new version of the Agreement is published, - Contributor may elect to distribute the Program (including its Contributions) - under the new version. Except as expressly stated in Sections 2(a) and 2(b) - above, Recipient receives no rights or licenses to the intellectual property of - any Contributor under this Agreement, whether expressly, by implication, - estoppel or otherwise. All rights in the Program not expressly granted under - this Agreement are reserved. - - This Agreement is governed by the laws of the State of New York and the - intellectual property laws of the United States of America. No party to this - Agreement will bring a legal action under this Agreement more than one year - after the cause of action arose. Each party waives its rights to a jury trial in - any resulting litigation. - --------------------------------------------------- -Library: joda-time v -Url: "http://www.joda.org/joda-time/" -License: Apache-2.0 - -source: https://github.com/JodaOrg/joda-time/blob/v2.9.9/NOTICE.txt - -This product includes software developed by -Joda.org (http://www.joda.org/). - --------------------------------------------------- -Library: joni v -Url: "https://github.com/jruby/joni/" -License: MIT - -source: https://github.com/jruby/joni/blob/joni-2.1.16/LICENSE - -MIT License - -Copyright (c) 2017 JRuby Team - -Permission is hereby granted, free of charge, to any person obtaining a copy -of this software and associated documentation files (the "Software"), to deal -in the Software without restriction, including without limitation the rights -to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -copies of the Software, and to permit persons to whom the Software is -furnished to do so, subject to the following conditions: - -The above copyright notice and this permission notice shall be included in all -copies or substantial portions of the Software. - -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE -SOFTWARE. - --------------------------------------------------- -Library: jrjackson v0.4.6 -Url: "" -License: Apache-2.0 - -https://github.com/guyboertje/jrjackson/blob/v0.4.6/README.md - -LICENSE applicable to this library: - -Apache License 2.0 see http://www.apache.org/licenses/LICENSE-2.0 - --------------------------------------------------- -Library: jruby-openssl v0.9.21 -Url: "https://github.com/jruby/jruby-openssl/" -License: EPL-1.0 - -source: https://github.com/jruby/jruby-openssl/blob/v0.9.21/LICENSE.txt - -JRuby-OpenSSL is distributed under the same license as JRuby a tri EPL/GPL/LGPL -license. You can use it, redistribute it and/or modify it under the terms of the: - - Eclipse Public License version 1.0 - GNU General Public License version 2.0 - GNU Lesser General Public License version 2.1 - -The contents of this file are subject to the Common Public License Version 1.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.eclipse.org/legal/cpl-v10.html - -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS -FOR APARTICULAR PURPOSE AND NONINFRINGEMENT. -IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, -DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, -ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER -DEALINGS IN THE SOFTWARE. - - Copyright (C) 2007-2009 Ola Bini - Copyright (C) 2009-2017 The JRuby Team - -Alternatively, the contents of this file may be used under the terms of -either of the GNU General Public License Version 2 or later (the "GPL"), -or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), -in which case the provisions of the GPL or the LGPL are applicable instead -of those above. If you wish to allow use of your version of this file only -under the terms of either the GPL or the LGPL, and not to allow others to -use your version of this file under the terms of the EPL, indicate your -decision by deleting the provisions above and replace them with the notice -and other provisions required by the GPL or the LGPL. If you do not delete -the provisions above, a recipient may use your version of this file under -the terms of any one of the EPL, the GPL or the LGPL. - - -JRuby-OpenSSL includes software by The Legion of the Bouncy Castle Inc. -Please, visit (http://bouncycastle.org/license.html) for licensing details. - --------------------------------------------------- -Library: jruby-readline v -Url: "https://github.com/jruby/jruby-readline" -License: EPL-1.0 - -source: https://github.com/jruby/jruby-readline/blob/1.2.2/License.txt - -JRuby-OpenSSL is distributed under the same license as JRuby (http://www.jruby.org/). - -Version: EPL 1.0/GPL 2.0/LGPL 2.1 - -The contents of this file are subject to the Common Public -License Version 1.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.eclipse.org/legal/cpl-v10.html - -Software distributed under the License is distributed on an "AS -IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or -implied. See the License for the specific language governing -rights and limitations under the License. - -Copyright (C) 2007 Ola Bini - -Alternatively, the contents of this file may be used under the terms of -either of the GNU General Public License Version 2 or later (the "GPL"), -or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), -in which case the provisions of the GPL or the LGPL are applicable instead -of those above. If you wish to allow use of your version of this file only -under the terms of either the GPL or the LGPL, and not to allow others to -use your version of this file under the terms of the EPL, indicate your -decision by deleting the provisions above and replace them with the notice -and other provisions required by the GPL or the LGPL. If you do not delete -the provisions above, a recipient may use your version of this file under -the terms of any one of the EPL, the GPL or the LGPL. - -JRuby-OpenSSL includes software by the Legion of the Bouncy Castle -(http://bouncycastle.org/license.html). - --------------------------------------------------- -Library: jruby-stdin-channel v0.2.0 -Url: "https://github.com/colinsurprenant/jruby-stdin-channel" -License: Apache-2.0 - -source: https://github.com/colinsurprenant/jruby-stdin-channel/blob/v0.2.0/LICENSE.md - -Licensed 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. - --------------------------------------------------- -Library: json-generator v -Url: "https://github.com/tmattia/json-generator/" -License: MIT - -source: https://github.com/tmattia/json-generator/blob/v0.1.0/LICENSE.txt - -Copyright (c) 2013 ThoughtWorks Brasil & Abril Midia - -MIT License - -Permission is hereby granted, free of charge, to any person obtaining -a copy of this software and associated documentation files (the -"Software"), to deal in the Software without restriction, including -without limitation the rights to use, copy, modify, merge, publish, -distribute, sublicense, and/or sell copies of the Software, and to -permit persons to whom the Software is furnished to do so, subject to -the following conditions: - -The above copyright notice and this permission notice shall be -included in all copies or substantial portions of the Software. - -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, -EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF -MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND -NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE -LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION -OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION -WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. - --------------------------------------------------- -Library: json v1.8.6 -Url: z -License: Ruby - -source: https://github.com/flori/json/blob/v1.8.6/README.md#license - -Ruby License, see https://www.ruby-lang.org/en/about/license.txt. - --------------------------------------------------- -Library: jzlib v -Url: "http://www.jcraft.com/jzlib/" -License: BSD - -source: https://github.com/ymnk/jzlib/blob/1.1.3/LICENSE.txt#L5-L29 - -Copyright (c) 2000-2011 ymnk, JCraft,Inc. All rights reserved. - -Redistribution and use in source and binary forms, with or without -modification, are permitted provided that the following conditions are met: - - 1. Redistributions of source code must retain the above copyright notice, - this list of conditions and the following disclaimer. - - 2. Redistributions in binary form must reproduce the above copyright - notice, this list of conditions and the following disclaimer in - the documentation and/or other materials provided with the distribution. - - 3. The names of the authors may not be used to endorse or promote products - derived from this software without specific prior written permission. - -THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED WARRANTIES, -INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND -FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL JCRAFT, -INC. OR ANY CONTRIBUTORS TO THIS SOFTWARE BE LIABLE FOR ANY DIRECT, INDIRECT, -INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT -LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, -OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF -LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING -NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, -EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - --------------------------------------------------- -Library: lru_redux v1.1.0 -Url: "https://github.com/SamSaffron/lru_redux/" -License: MIT - -source: https://github.com/SamSaffron/lru_redux/blob/v1.1.0/LICENSE.txt - -Copyright (c) 2013 Sam Saffron - -MIT License - -Permission is hereby granted, free of charge, to any person obtaining -a copy of this software and associated documentation files (the -"Software"), to deal in the Software without restriction, including -without limitation the rights to use, copy, modify, merge, publish, -distribute, sublicense, and/or sell copies of the Software, and to -permit persons to whom the Software is furnished to do so, subject to -the following conditions: - -The above copyright notice and this permission notice shall be -included in all copies or substantial portions of the Software. - -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, -EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF -MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND -NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE -LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION -OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION -WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. - --------------------------------------------------- -Library: mail v2.6.6 -Url: "https://github.com/mikel/mail/" -License: MIT - -source: https://github.com/mikel/mail/blob/2.6.6/MIT-LICENSE - -Copyright (c) 2009-2017 Mikel Lindsaar - -Permission is hereby granted, free of charge, to any person obtaining -a copy of this software and associated documentation files (the -'Software'), to deal in the Software without restriction, including -without limitation the rights to use, copy, modify, merge, publish, -distribute, sublicense, and/or sell copies of the Software, and to -permit persons to whom the Software is furnished to do so, subject to -the following conditions: - -The above copyright notice and this permission notice shall be -included in all copies or substantial portions of the Software. - -THE SOFTWARE IS PROVIDED 'AS IS', WITHOUT WARRANTY OF ANY KIND, -EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF -MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. -IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY -CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, -TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE -SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. - --------------------------------------------------- -Library: manticore v0.6.1 -Url: "https://github.com/cheald/manticore/" -License: MIT - -source: https://github.com/cheald/manticore/blob/v0.6.1/LICENSE.txt - -Copyright (c) 2015 Chris Heald - -Permission is hereby granted, free of charge, to any person obtaining -a copy of this software and associated documentation files (the -"Software"), to deal in the Software without restriction, including -without limitation the rights to use, copy, modify, merge, publish, -distribute, sublicense, and/or sell copies of the Software, and to -permit persons to whom the Software is furnished to do so, subject to -the following conditions: - -The above copyright notice and this permission notice shall be -included in all copies or substantial portions of the Software. - -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, -EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF -MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND -NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE -LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION -OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION -WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. - --------------------------------------------------- -Library: march_hare v3.1.1 -Url: "https://github.com/ruby-amqp/march_hare/" -License: MIT - -source: https://github.com/ruby-amqp/march_hare/blob/v3.1.1/LICENSE - -Copyright (c) 2011-2013 Theo Hultberg -Copyright (c) 2013-2017 Michael S. Klishin and contributors - -Permission is hereby granted, free of charge, to any person obtaining -a copy of this software and associated documentation files (the -"Software"), to deal in the Software without restriction, including -without limitation the rights to use, copy, modify, merge, publish, -distribute, sublicense, and/or sell copies of the Software, and to -permit persons to whom the Software is furnished to do so, subject to -the following conditions: - -The above copyright notice and this permission notice shall be -included in all copies or substantial portions of the Software. - -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, -EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF -MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND -NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE -LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION -OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION -WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. - --------------------------------------------------- -Library: memoizable v0.4.2 -Url: "https://github.com/dkubb/memoizable/" -License: MIT - -source: https://github.com/dkubb/memoizable/blob/v0.4.2/LICENSE.md - -Copyright (c) 2013 Dan Kubb, Erik Michaels-Ober - -Permission is hereby granted, free of charge, to any person obtaining -a copy of this software and associated documentation files (the -"Software"), to deal in the Software without restriction, including -without limitation the rights to use, copy, modify, merge, publish, -distribute, sublicense, and/or sell copies of the Software, and to -permit persons to whom the Software is furnished to do so, subject to -the following conditions: - -The above copyright notice and this permission notice shall be -included in all copies or substantial portions of the Software. - -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, -EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF -MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND -NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE -LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION -OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION -WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. - --------------------------------------------------- -Library: method_source v0.8.2 -Url: "https://github.com/banister/method_source/" -License: MIT - -source: https://github.com/banister/method_source/blob/v0.9.0/README.markdown#license - -Copyright (c) 2011 John Mair (banisterfiend) - -Permission is hereby granted, free of charge, to any person obtaining -a copy of this software and associated documentation files (the -'Software'), to deal in the Software without restriction, including -without limitation the rights to use, copy, modify, merge, publish, -distribute, sublicense, and/or sell copies of the Software, and to -permit persons to whom the Software is furnished to do so, subject to -the following conditions: - -The above copyright notice and this permission notice shall be -included in all copies or substantial portions of the Software. - -THE SOFTWARE IS PROVIDED 'AS IS', WITHOUT WARRANTY OF ANY KIND, -EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF -MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. -IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY -CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, -TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE -SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. - --------------------------------------------------- -Library: metriks v0.9.9.8 -Url: "https://github.com/eric/metriks/" -License: MIT - -source: https://github.com/eric/metriks/blob/v0.9.9.8/LICENSE - -Copyright (c) 2012 Eric Lindvall - -Permission is hereby granted, free of charge, to any person obtaining a copy -of this software and associated documentation files (the "Software"), to deal -in the Software without restriction, including without limitation the rights -to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -copies of the Software, and to permit persons to whom the Software is -furnished to do so, subject to the following conditions: - -The above copyright notice and this permission notice shall be included in -all copies or substantial portions of the Software. - -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN -THE SOFTWARE. - --------------------------------------------------- -Library: mime-types v2.6.2 -Url: -License: MIT - -source: https://github.com/mime-types/ruby-mime-types/blob/v2.6.2/Licence.rdoc - -* Copyright 2003–2015 Austin Ziegler. -* Adapted from MIME::Types (Perl) by Mark Overmeer. - -=== MIT License - -Permission is hereby granted, free of charge, to any person obtaining a copy of -this software and associated documentation files (the "Software"), to deal in -the Software without restriction, including without limitation the rights to -use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies -of the Software, and to permit persons to whom the Software is furnished to do -so, subject to the following conditions: - -The above copyright notice and this permission notice shall be included in all -copies or substantial portions of the Software. - -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE -SOFTWARE. - --------------------------------------------------- -Library: minitar v0.6.1 -Url: -License: RUBY|BSD-2-Clause - -source: https://github.com/halostatue/minitar/blob/v0.6.1/Licence.md - -minitar is free software that may be redistributed and/or modified under the -terms of Ruby’s licence or the Simplified BSD licence. - -* Copyright 2004–2017 Austin Ziegler. -* Portions copyright 2004 Mauricio Julio Fernández Pradier. - --------------------------------------------------- -Library: msgpack v1.2.4 -Url: "https://github.com/msgpack/msgpack-ruby" -License: Apache-2.0 - -source: https://github.com/msgpack/msgpack-ruby/blob/v1.2.4/ext/msgpack/ - - Copyright (C) 2008-2013 Sadayuki Furuhashi - - Licensed 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. - --------------------------------------------------- -Library: multi_json v1.13.1 -Url: "https://github.com/intridea/multi_json" -License: MIT - -source: https://github.com/intridea/multi_json/blob/v1.13.1/LICENSE.md - -Copyright (c) 2010-2013 Michael Bleigh, Josh Kalderimis, Erik Michaels-Ober, Pavel Pravosud - -Permission is hereby granted, free of charge, to any person obtaining -a copy of this software and associated documentation files (the -"Software"), to deal in the Software without restriction, including -without limitation the rights to use, copy, modify, merge, publish, -distribute, sublicense, and/or sell copies of the Software, and to -permit persons to whom the Software is furnished to do so, subject to -the following conditions: - -The above copyright notice and this permission notice shall be -included in all copies or substantial portions of the Software. - -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, -EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF -MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND -NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE -LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION -OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION -WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. - --------------------------------------------------- -Library: multipart-post v2.0.0 -Url: "https://github.com/nicksieger/multipart-post" -License: MIT - -source: https://github.com/nicksieger/multipart-post/blob/v2.0.0/README.md#license - -Copyright (c) 2007-2013 Nick Sieger - -Permission is hereby granted, free of charge, to any person obtaining -a copy of this software and associated documentation files (the -'Software'), to deal in the Software without restriction, including -without limitation the rights to use, copy, modify, merge, publish, -distribute, sublicense, and/or sell copies of the Software, and to -permit persons to whom the Software is furnished to do so, subject to -the following conditions: - -The above copyright notice and this permission notice shall be -included in all copies or substantial portions of the Software. - -THE SOFTWARE IS PROVIDED 'AS IS', WITHOUT WARRANTY OF ANY KIND, -EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF -MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. -IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY -CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, -TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE -SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. - --------------------------------------------------- -Library: murmurhash3 v0.1.6 -Url: "https://github.com/funny-falcon/" -License: MIT - -source: https://github.com/funny-falcon/murmurhash3-ruby/blob/v0.1.5/LICENSE - -Copyright (c) 2012 Sokolov Yura 'funny-falcon' - -MIT License - -Permission is hereby granted, free of charge, to any person obtaining -a copy of this software and associated documentation files (the -"Software"), to deal in the Software without restriction, including -without limitation the rights to use, copy, modify, merge, publish, -distribute, sublicense, and/or sell copies of the Software, and to -permit persons to whom the Software is furnished to do so, subject to -the following conditions: - -The above copyright notice and this permission notice shall be -included in all copies or substantial portions of the Software. - -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, -EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF -MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND -NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE -LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION -OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION -WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. - --------------------------------------------------- -Library: mustache v0.99.8 -Url: "https://github.com/mustache/mustache" -License: MIT - -source: https://github.com/mustache/mustache/blob/v0.99.8/LICENSE - -Copyright (c) 2009 Chris Wanstrath - -Permission is hereby granted, free of charge, to any person obtaining -a copy of this software and associated documentation files (the -"Software"), to deal in the Software without restriction, including -without limitation the rights to use, copy, modify, merge, publish, -distribute, sublicense, and/or sell copies of the Software, and to -permit persons to whom the Software is furnished to do so, subject to -the following conditions: - -The above copyright notice and this permission notice shall be -included in all copies or substantial portions of the Software. - -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, -EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF -MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND -NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE -LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION -OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION -WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. - --------------------------------------------------- -Library: nailgun v -Url: "http://martiansoftware.com/nailgun" -License: Apache-2.0 - -source: https://github.com/facebook/nailgun/blob/nailgun-all-0.9.3/LICENSE.txt - -Nailgun Copyright © 2004-2012, Martian Software, Inc. - -Apache License - --------------------------------------------------- -Library: naught v1.1.0 -Url: "https://github.com/avdi/naught/" -License: MIT - -source: https://github.com/avdi/naught/blob/v1.1.0/LICENSE.txt - -Copyright (c) 2013 Avdi Grimm - -MIT License - -Permission is hereby granted, free of charge, to any person obtaining -a copy of this software and associated documentation files (the -"Software"), to deal in the Software without restriction, including -without limitation the rights to use, copy, modify, merge, publish, -distribute, sublicense, and/or sell copies of the Software, and to -permit persons to whom the Software is furnished to do so, subject to -the following conditions: - -The above copyright notice and this permission notice shall be -included in all copies or substantial portions of the Software. - -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, -EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF -MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND -NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE -LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION -OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION -WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. - --------------------------------------------------- -Library: nokogiri v1.8.2 -Url: "http://nokogiri.org/" -License: MIT - -source: https://github.com/sparklemotion/nokogiri/blob/v1.8.2/LICENSE.md - -Copyright (c) 2008 - 2017: - -* [Aaron Patterson](http://tenderlovemaking.com) -* [Mike Dalessio](http://mike.daless.io) -* [Charles Nutter](http://blog.headius.com) -* [Sergio Arbeo](http://www.serabe.com) -* [Patrick Mahoney](http://polycrystal.org) -* [Yoko Harada](http://yokolet.blogspot.com) -* [Akinori MUSHA](https://akinori.org) -* [John Shahid](https://github.com/jvshahid) - -Permission is hereby granted, free of charge, to any person obtaining -a copy of this software and associated documentation files (the -'Software'), to deal in the Software without restriction, including -without limitation the rights to use, copy, modify, merge, publish, -distribute, sublicense, and/or sell copies of the Software, and to -permit persons to whom the Software is furnished to do so, subject to -the following conditions: - -The above copyright notice and this permission notice shall be -included in all copies or substantial portions of the Software. - -THE SOFTWARE IS PROVIDED 'AS IS', WITHOUT WARRANTY OF ANY KIND, -EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF -MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. -IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY -CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, -TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE -SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. - --------------------------------------------------- -Library: numerizer v0.1.1 -Url: "https://github.com/jduff/numerizer/" -License: MIT - -FAKER - --------------------------------------------------- -Library: options v -Url: https://github.com/headius/options -License: Apache-2.0 - -source: https://github.com/headius/options/blob/options-1.4/src/main/java/com/headius/options/Option.java#L1-L13 - -Licensed 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. - --------------------------------------------------- -Library: log4j-1.2-api v2.6.2 -Url: "https://logging.apache.org/log4j" -License: Apache-2.0 - -Apache Log4j -Copyright 1999-2017 Apache Software Foundation - -This product includes software developed at -The Apache Software Foundation (http://www.apache.org/). - -ResolverUtil.java -Copyright 2005-2006 Tim Fennell - -Dumbster SMTP test server -Copyright 2004 Jason Paul Kitchen - -TypeUtil.java -Copyright 2002-2012 Ramnivas Laddad, Juergen Hoeller, Chris Beams - -picocli (http://picocli.info) -Copyright 2017 Remko Popma - --------------------------------------------------- -Library: log4j-api v2.6.2 -Url: "https://logging.apache.org/log4j" -License: Apache-2.0 - -Apache Log4j -Copyright 1999-2017 Apache Software Foundation - -This product includes software developed at -The Apache Software Foundation (http://www.apache.org/). - -ResolverUtil.java -Copyright 2005-2006 Tim Fennell - -Dumbster SMTP test server -Copyright 2004 Jason Paul Kitchen - -TypeUtil.java -Copyright 2002-2012 Ramnivas Laddad, Juergen Hoeller, Chris Beams - -picocli (http://picocli.info) -Copyright 2017 Remko Popma - --------------------------------------------------- -Library: log4j-api v2.8.2 -Url: https://logging.apache.org/log4j/2.x/index.html -License: Apache-2.0 - -Apache Log4j -Copyright 1999-2017 Apache Software Foundation - -This product includes software developed at -The Apache Software Foundation (http://www.apache.org/). - -ResolverUtil.java -Copyright 2005-2006 Tim Fennell - -Dumbster SMTP test server -Copyright 2004 Jason Paul Kitchen - -TypeUtil.java -Copyright 2002-2012 Ramnivas Laddad, Juergen Hoeller, Chris Beams - -picocli (http://picocli.info) -Copyright 2017 Remko Popma - --------------------------------------------------- -Library: log4j-api v2.9.1 -Url: https://logging.apache.org/log4j/2.x/index.html -License: Apache-2.0 - -Apache Log4j -Copyright 1999-2017 Apache Software Foundation - -This product includes software developed at -The Apache Software Foundation (http://www.apache.org/). - -ResolverUtil.java -Copyright 2005-2006 Tim Fennell - -Dumbster SMTP test server -Copyright 2004 Jason Paul Kitchen - -TypeUtil.java -Copyright 2002-2012 Ramnivas Laddad, Juergen Hoeller, Chris Beams - -picocli (http://picocli.info) -Copyright 2017 Remko Popma - --------------------------------------------------- -Library: log4j-core v2.8.2 -Url: https://logging.apache.org/log4j/2.x/index.html -License: Apache-2.0 - -Apache Log4j -Copyright 1999-2017 Apache Software Foundation - -This product includes software developed at -The Apache Software Foundation (http://www.apache.org/). - -ResolverUtil.java -Copyright 2005-2006 Tim Fennell - -Dumbster SMTP test server -Copyright 2004 Jason Paul Kitchen - -TypeUtil.java -Copyright 2002-2012 Ramnivas Laddad, Juergen Hoeller, Chris Beams - -picocli (http://picocli.info) -Copyright 2017 Remko Popma - --------------------------------------------------- -Library: log4j-core v2.9.1 -Url: https://logging.apache.org/log4j/2.x/index.html -License: Apache-2.0 - -Apache Log4j -Copyright 1999-2017 Apache Software Foundation - -This product includes software developed at -The Apache Software Foundation (http://www.apache.org/). - -ResolverUtil.java -Copyright 2005-2006 Tim Fennell - -Dumbster SMTP test server -Copyright 2004 Jason Paul Kitchen - -TypeUtil.java -Copyright 2002-2012 Ramnivas Laddad, Juergen Hoeller, Chris Beams - -picocli (http://picocli.info) -Copyright 2017 Remko Popma - --------------------------------------------------- -Library: log4j-slf4j-impl v2.8.2 -Url: https://logging.apache.org/log4j/2.x/index.html -License: Apache-2.0 - -Apache Log4j -Copyright 1999-2017 Apache Software Foundation - -This product includes software developed at -The Apache Software Foundation (http://www.apache.org/). - -ResolverUtil.java -Copyright 2005-2006 Tim Fennell - -Dumbster SMTP test server -Copyright 2004 Jason Paul Kitchen - -TypeUtil.java -Copyright 2002-2012 Ramnivas Laddad, Juergen Hoeller, Chris Beams - -picocli (http://picocli.info) -Copyright 2017 Remko Popma - --------------------------------------------------- -Library: log4j-slf4j-impl v2.9.1 -Url: https://logging.apache.org/log4j/2.x/index.html -License: Apache-2.0 - -Apache Log4j -Copyright 1999-2017 Apache Software Foundation - -This product includes software developed at -The Apache Software Foundation (http://www.apache.org/). - -ResolverUtil.java -Copyright 2005-2006 Tim Fennell - -Dumbster SMTP test server -Copyright 2004 Jason Paul Kitchen - -TypeUtil.java -Copyright 2002-2012 Ramnivas Laddad, Juergen Hoeller, Chris Beams - -picocli (http://picocli.info) -Copyright 2017 Remko Popma - --------------------------------------------------- -Library: commons-compiler v3.0.8 -Url: https://github.com/janino-compiler/janino -License: BSD-3-Clause # Question: tweaked license on bullet point 3 - -Janino - An embedded Java[TM] compiler - -Copyright (c) 2001-2016, Arno Unkrig -Copyright (c) 2015-2016 TIBCO Software Inc. -All rights reserved. - -Redistribution and use in source and binary forms, with or without -modification, are permitted provided that the following conditions -are met: - - 1. Redistributions of source code must retain the above copyright - notice, this list of conditions and the following disclaimer. - 2. Redistributions in binary form must reproduce the above - copyright notice, this list of conditions and the following - disclaimer in the documentation and/or other materials - provided with the distribution. - 3. Neither the name of JANINO nor the names of its contributors - may be used to endorse or promote products derived from this - software without specific prior written permission. - -THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" -AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE -IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE -ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDERS OR CONTRIBUTORS BE -LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR -CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF -SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS -INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER -IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR -OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN -IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - --------------------------------------------------- -Library: janino v3.0.8 -Url: https://github.com/janino-compiler/janino -License: BSD-3-Clause # Question: tweaked license on bullet point 3 - -Janino - An embedded Java[TM] compiler - -Copyright (c) 2001-2016, Arno Unkrig -Copyright (c) 2015-2016 TIBCO Software Inc. -All rights reserved. - -Redistribution and use in source and binary forms, with or without -modification, are permitted provided that the following conditions -are met: - - 1. Redistributions of source code must retain the above copyright - notice, this list of conditions and the following disclaimer. - 2. Redistributions in binary form must reproduce the above - copyright notice, this list of conditions and the following - disclaimer in the documentation and/or other materials - provided with the distribution. - 3. Neither the name of JANINO nor the names of its contributors - may be used to endorse or promote products derived from this - software without specific prior written permission. - -THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" -AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE -IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE -ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDERS OR CONTRIBUTORS BE -LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR -CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF -SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS -INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER -IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR -OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN -IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - --------------------------------------------------- -Library: org.eclipse.core.commands v3.6.0 -Url: http://www.eclipse.org -License: EPL-1.0 - -Copyright © Eclipse Foundation, Inc. All Rights Reserved. - -Eclipse Public License - v 1.0 -THE ACCOMPANYING PROGRAM IS PROVIDED UNDER THE TERMS OF THIS ECLIPSE PUBLIC LICENSE ("AGREEMENT"). ANY USE, REPRODUCTION OR DISTRIBUTION OF THE PROGRAM CONSTITUTES RECIPIENT'S ACCEPTANCE OF THIS AGREEMENT. - -1. DEFINITIONS - -"Contribution" means: - -a) in the case of the initial Contributor, the initial code and documentation distributed under this Agreement, and - -b) in the case of each subsequent Contributor: - -i) changes to the Program, and - -ii) additions to the Program; - -where such changes and/or additions to the Program originate from and are distributed by that particular Contributor. A Contribution 'originates' from a Contributor if it was added to the Program by such Contributor itself or anyone acting on such Contributor's behalf. Contributions do not include additions to the Program which: (i) are separate modules of software distributed in conjunction with the Program under their own license agreement, and (ii) are not derivative works of the Program. - -"Contributor" means any person or entity that distributes the Program. - -"Licensed Patents" mean patent claims licensable by a Contributor which are necessarily infringed by the use or sale of its Contribution alone or when combined with the Program. - -"Program" means the Contributions distributed in accordance with this Agreement. - -"Recipient" means anyone who receives the Program under this Agreement, including all Contributors. - -2. GRANT OF RIGHTS - -a) Subject to the terms of this Agreement, each Contributor hereby grants Recipient a non-exclusive, worldwide, royalty-free copyright license to reproduce, prepare derivative works of, publicly display, publicly perform, distribute and sublicense the Contribution of such Contributor, if any, and such derivative works, in source code and object code form. - -b) Subject to the terms of this Agreement, each Contributor hereby grants Recipient a non-exclusive, worldwide, royalty-free patent license under Licensed Patents to make, use, sell, offer to sell, import and otherwise transfer the Contribution of such Contributor, if any, in source code and object code form. This patent license shall apply to the combination of the Contribution and the Program if, at the time the Contribution is added by the Contributor, such addition of the Contribution causes such combination to be covered by the Licensed Patents. The patent license shall not apply to any other combinations which include the Contribution. No hardware per se is licensed hereunder. - -c) Recipient understands that although each Contributor grants the licenses to its Contributions set forth herein, no assurances are provided by any Contributor that the Program does not infringe the patent or other intellectual property rights of any other entity. Each Contributor disclaims any liability to Recipient for claims brought by any other entity based on infringement of intellectual property rights or otherwise. As a condition to exercising the rights and licenses granted hereunder, each Recipient hereby assumes sole responsibility to secure any other intellectual property rights needed, if any. For example, if a third party patent license is required to allow Recipient to distribute the Program, it is Recipient's responsibility to acquire that license before distributing the Program. - -d) Each Contributor represents that to its knowledge it has sufficient copyright rights in its Contribution, if any, to grant the copyright license set forth in this Agreement. - -3. REQUIREMENTS - -A Contributor may choose to distribute the Program in object code form under its own license agreement, provided that: - -a) it complies with the terms and conditions of this Agreement; and - -b) its license agreement: - -i) effectively disclaims on behalf of all Contributors all warranties and conditions, express and implied, including warranties or conditions of title and non-infringement, and implied warranties or conditions of merchantability and fitness for a particular purpose; - -ii) effectively excludes on behalf of all Contributors all liability for damages, including direct, indirect, special, incidental and consequential damages, such as lost profits; - -iii) states that any provisions which differ from this Agreement are offered by that Contributor alone and not by any other party; and - -iv) states that source code for the Program is available from such Contributor, and informs licensees how to obtain it in a reasonable manner on or through a medium customarily used for software exchange. - -When the Program is made available in source code form: - -a) it must be made available under this Agreement; and - -b) a copy of this Agreement must be included with each copy of the Program. - -Contributors may not remove or alter any copyright notices contained within the Program. - -Each Contributor must identify itself as the originator of its Contribution, if any, in a manner that reasonably allows subsequent Recipients to identify the originator of the Contribution. - -4. COMMERCIAL DISTRIBUTION - -Commercial distributors of software may accept certain responsibilities with respect to end users, business partners and the like. While this license is intended to facilitate the commercial use of the Program, the Contributor who includes the Program in a commercial product offering should do so in a manner which does not create potential liability for other Contributors. Therefore, if a Contributor includes the Program in a commercial product offering, such Contributor ("Commercial Contributor") hereby agrees to defend and indemnify every other Contributor ("Indemnified Contributor") against any losses, damages and costs (collectively "Losses") arising from claims, lawsuits and other legal actions brought by a third party against the Indemnified Contributor to the extent caused by the acts or omissions of such Commercial Contributor in connection with its distribution of the Program in a commercial product offering. The obligations in this section do not apply to any claims or Losses relating to any actual or alleged intellectual property infringement. In order to qualify, an Indemnified Contributor must: a) promptly notify the Commercial Contributor in writing of such claim, and b) allow the Commercial Contributor to control, and cooperate with the Commercial Contributor in, the defense and any related settlement negotiations. The Indemnified Contributor may participate in any such claim at its own expense. - -For example, a Contributor might include the Program in a commercial product offering, Product X. That Contributor is then a Commercial Contributor. If that Commercial Contributor then makes performance claims, or offers warranties related to Product X, those performance claims and warranties are such Commercial Contributor's responsibility alone. Under this section, the Commercial Contributor would have to defend claims against the other Contributors related to those performance claims and warranties, and if a court requires any other Contributor to pay any damages as a result, the Commercial Contributor must pay those damages. - -5. NO WARRANTY - -EXCEPT AS EXPRESSLY SET FORTH IN THIS AGREEMENT, THE PROGRAM IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED INCLUDING, WITHOUT LIMITATION, ANY WARRANTIES OR CONDITIONS OF TITLE, NON-INFRINGEMENT, MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE. Each Recipient is solely responsible for determining the appropriateness of using and distributing the Program and assumes all risks associated with its exercise of rights under this Agreement , including but not limited to the risks and costs of program errors, compliance with applicable laws, damage to or loss of data, programs or equipment, and unavailability or interruption of operations. - -6. DISCLAIMER OF LIABILITY - -EXCEPT AS EXPRESSLY SET FORTH IN THIS AGREEMENT, NEITHER RECIPIENT NOR ANY CONTRIBUTORS SHALL HAVE ANY LIABILITY FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING WITHOUT LIMITATION LOST PROFITS), HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OR DISTRIBUTION OF THE PROGRAM OR THE EXERCISE OF ANY RIGHTS GRANTED HEREUNDER, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGES. - -7. GENERAL - -If any provision of this Agreement is invalid or unenforceable under applicable law, it shall not affect the validity or enforceability of the remainder of the terms of this Agreement, and without further action by the parties hereto, such provision shall be reformed to the minimum extent necessary to make such provision valid and enforceable. - -If Recipient institutes patent litigation against any entity (including a cross-claim or counterclaim in a lawsuit) alleging that the Program itself (excluding combinations of the Program with other software or hardware) infringes such Recipient's patent(s), then such Recipient's rights granted under Section 2(b) shall terminate as of the date such litigation is filed. - -All Recipient's rights under this Agreement shall terminate if it fails to comply with any of the material terms or conditions of this Agreement and does not cure such failure in a reasonable period of time after becoming aware of such noncompliance. If all Recipient's rights under this Agreement terminate, Recipient agrees to cease use and distribution of the Program as soon as reasonably practicable. However, Recipient's obligations under this Agreement and any licenses granted by Recipient relating to the Program shall continue and survive. - -Everyone is permitted to copy and distribute copies of this Agreement, but in order to avoid inconsistency the Agreement is copyrighted and may only be modified in the following manner. The Agreement Steward reserves the right to publish new versions (including revisions) of this Agreement from time to time. No one other than the Agreement Steward has the right to modify this Agreement. The Eclipse Foundation is the initial Agreement Steward. The Eclipse Foundation may assign the responsibility to serve as the Agreement Steward to a suitable separate entity. Each new version of the Agreement will be given a distinguishing version number. The Program (including Contributions) may always be distributed subject to the version of the Agreement under which it was received. In addition, after a new version of the Agreement is published, Contributor may elect to distribute the Program (including its Contributions) under the new version. Except as expressly stated in Sections 2(a) and 2(b) above, Recipient receives no rights or licenses to the intellectual property of any Contributor under this Agreement, whether expressly, by implication, estoppel or otherwise. All rights in the Program not expressly granted under this Agreement are reserved. - -This Agreement is governed by the laws of the State of New York and the intellectual property laws of the United States of America. No party to this Agreement will bring a legal action under this Agreement more than one year after the cause of action arose. Each party waives its rights to a jury trial in any resulting litigation. - --------------------------------------------------- -Library: org.eclipse.core.contenttype v3.4.100 -Url: http://www.eclipse.org -License: EPL-1.0 - -Copyright © Eclipse Foundation, Inc. All Rights Reserved. - -Eclipse Public License - v 1.0 -THE ACCOMPANYING PROGRAM IS PROVIDED UNDER THE TERMS OF THIS ECLIPSE PUBLIC LICENSE ("AGREEMENT"). ANY USE, REPRODUCTION OR DISTRIBUTION OF THE PROGRAM CONSTITUTES RECIPIENT'S ACCEPTANCE OF THIS AGREEMENT. - -1. DEFINITIONS - -"Contribution" means: - -a) in the case of the initial Contributor, the initial code and documentation distributed under this Agreement, and - -b) in the case of each subsequent Contributor: - -i) changes to the Program, and - -ii) additions to the Program; - -where such changes and/or additions to the Program originate from and are distributed by that particular Contributor. A Contribution 'originates' from a Contributor if it was added to the Program by such Contributor itself or anyone acting on such Contributor's behalf. Contributions do not include additions to the Program which: (i) are separate modules of software distributed in conjunction with the Program under their own license agreement, and (ii) are not derivative works of the Program. - -"Contributor" means any person or entity that distributes the Program. - -"Licensed Patents" mean patent claims licensable by a Contributor which are necessarily infringed by the use or sale of its Contribution alone or when combined with the Program. - -"Program" means the Contributions distributed in accordance with this Agreement. - -"Recipient" means anyone who receives the Program under this Agreement, including all Contributors. - -2. GRANT OF RIGHTS - -a) Subject to the terms of this Agreement, each Contributor hereby grants Recipient a non-exclusive, worldwide, royalty-free copyright license to reproduce, prepare derivative works of, publicly display, publicly perform, distribute and sublicense the Contribution of such Contributor, if any, and such derivative works, in source code and object code form. - -b) Subject to the terms of this Agreement, each Contributor hereby grants Recipient a non-exclusive, worldwide, royalty-free patent license under Licensed Patents to make, use, sell, offer to sell, import and otherwise transfer the Contribution of such Contributor, if any, in source code and object code form. This patent license shall apply to the combination of the Contribution and the Program if, at the time the Contribution is added by the Contributor, such addition of the Contribution causes such combination to be covered by the Licensed Patents. The patent license shall not apply to any other combinations which include the Contribution. No hardware per se is licensed hereunder. - -c) Recipient understands that although each Contributor grants the licenses to its Contributions set forth herein, no assurances are provided by any Contributor that the Program does not infringe the patent or other intellectual property rights of any other entity. Each Contributor disclaims any liability to Recipient for claims brought by any other entity based on infringement of intellectual property rights or otherwise. As a condition to exercising the rights and licenses granted hereunder, each Recipient hereby assumes sole responsibility to secure any other intellectual property rights needed, if any. For example, if a third party patent license is required to allow Recipient to distribute the Program, it is Recipient's responsibility to acquire that license before distributing the Program. - -d) Each Contributor represents that to its knowledge it has sufficient copyright rights in its Contribution, if any, to grant the copyright license set forth in this Agreement. - -3. REQUIREMENTS - -A Contributor may choose to distribute the Program in object code form under its own license agreement, provided that: - -a) it complies with the terms and conditions of this Agreement; and - -b) its license agreement: - -i) effectively disclaims on behalf of all Contributors all warranties and conditions, express and implied, including warranties or conditions of title and non-infringement, and implied warranties or conditions of merchantability and fitness for a particular purpose; - -ii) effectively excludes on behalf of all Contributors all liability for damages, including direct, indirect, special, incidental and consequential damages, such as lost profits; - -iii) states that any provisions which differ from this Agreement are offered by that Contributor alone and not by any other party; and - -iv) states that source code for the Program is available from such Contributor, and informs licensees how to obtain it in a reasonable manner on or through a medium customarily used for software exchange. - -When the Program is made available in source code form: - -a) it must be made available under this Agreement; and - -b) a copy of this Agreement must be included with each copy of the Program. - -Contributors may not remove or alter any copyright notices contained within the Program. - -Each Contributor must identify itself as the originator of its Contribution, if any, in a manner that reasonably allows subsequent Recipients to identify the originator of the Contribution. - -4. COMMERCIAL DISTRIBUTION - -Commercial distributors of software may accept certain responsibilities with respect to end users, business partners and the like. While this license is intended to facilitate the commercial use of the Program, the Contributor who includes the Program in a commercial product offering should do so in a manner which does not create potential liability for other Contributors. Therefore, if a Contributor includes the Program in a commercial product offering, such Contributor ("Commercial Contributor") hereby agrees to defend and indemnify every other Contributor ("Indemnified Contributor") against any losses, damages and costs (collectively "Losses") arising from claims, lawsuits and other legal actions brought by a third party against the Indemnified Contributor to the extent caused by the acts or omissions of such Commercial Contributor in connection with its distribution of the Program in a commercial product offering. The obligations in this section do not apply to any claims or Losses relating to any actual or alleged intellectual property infringement. In order to qualify, an Indemnified Contributor must: a) promptly notify the Commercial Contributor in writing of such claim, and b) allow the Commercial Contributor to control, and cooperate with the Commercial Contributor in, the defense and any related settlement negotiations. The Indemnified Contributor may participate in any such claim at its own expense. - -For example, a Contributor might include the Program in a commercial product offering, Product X. That Contributor is then a Commercial Contributor. If that Commercial Contributor then makes performance claims, or offers warranties related to Product X, those performance claims and warranties are such Commercial Contributor's responsibility alone. Under this section, the Commercial Contributor would have to defend claims against the other Contributors related to those performance claims and warranties, and if a court requires any other Contributor to pay any damages as a result, the Commercial Contributor must pay those damages. - -5. NO WARRANTY - -EXCEPT AS EXPRESSLY SET FORTH IN THIS AGREEMENT, THE PROGRAM IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED INCLUDING, WITHOUT LIMITATION, ANY WARRANTIES OR CONDITIONS OF TITLE, NON-INFRINGEMENT, MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE. Each Recipient is solely responsible for determining the appropriateness of using and distributing the Program and assumes all risks associated with its exercise of rights under this Agreement , including but not limited to the risks and costs of program errors, compliance with applicable laws, damage to or loss of data, programs or equipment, and unavailability or interruption of operations. - -6. DISCLAIMER OF LIABILITY - -EXCEPT AS EXPRESSLY SET FORTH IN THIS AGREEMENT, NEITHER RECIPIENT NOR ANY CONTRIBUTORS SHALL HAVE ANY LIABILITY FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING WITHOUT LIMITATION LOST PROFITS), HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OR DISTRIBUTION OF THE PROGRAM OR THE EXERCISE OF ANY RIGHTS GRANTED HEREUNDER, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGES. - -7. GENERAL - -If any provision of this Agreement is invalid or unenforceable under applicable law, it shall not affect the validity or enforceability of the remainder of the terms of this Agreement, and without further action by the parties hereto, such provision shall be reformed to the minimum extent necessary to make such provision valid and enforceable. - -If Recipient institutes patent litigation against any entity (including a cross-claim or counterclaim in a lawsuit) alleging that the Program itself (excluding combinations of the Program with other software or hardware) infringes such Recipient's patent(s), then such Recipient's rights granted under Section 2(b) shall terminate as of the date such litigation is filed. - -All Recipient's rights under this Agreement shall terminate if it fails to comply with any of the material terms or conditions of this Agreement and does not cure such failure in a reasonable period of time after becoming aware of such noncompliance. If all Recipient's rights under this Agreement terminate, Recipient agrees to cease use and distribution of the Program as soon as reasonably practicable. However, Recipient's obligations under this Agreement and any licenses granted by Recipient relating to the Program shall continue and survive. - -Everyone is permitted to copy and distribute copies of this Agreement, but in order to avoid inconsistency the Agreement is copyrighted and may only be modified in the following manner. The Agreement Steward reserves the right to publish new versions (including revisions) of this Agreement from time to time. No one other than the Agreement Steward has the right to modify this Agreement. The Eclipse Foundation is the initial Agreement Steward. The Eclipse Foundation may assign the responsibility to serve as the Agreement Steward to a suitable separate entity. Each new version of the Agreement will be given a distinguishing version number. The Program (including Contributions) may always be distributed subject to the version of the Agreement under which it was received. In addition, after a new version of the Agreement is published, Contributor may elect to distribute the Program (including its Contributions) under the new version. Except as expressly stated in Sections 2(a) and 2(b) above, Recipient receives no rights or licenses to the intellectual property of any Contributor under this Agreement, whether expressly, by implication, estoppel or otherwise. All rights in the Program not expressly granted under this Agreement are reserved. - -This Agreement is governed by the laws of the State of New York and the intellectual property laws of the United States of America. No party to this Agreement will bring a legal action under this Agreement more than one year after the cause of action arose. Each party waives its rights to a jury trial in any resulting litigation. - --------------------------------------------------- -Library: org.eclipse.core.expressions v3.4.300 -Url: http://www.eclipse.org -License: EPL-1.0 - -Copyright © Eclipse Foundation, Inc. All Rights Reserved. - -Eclipse Public License - v 1.0 -THE ACCOMPANYING PROGRAM IS PROVIDED UNDER THE TERMS OF THIS ECLIPSE PUBLIC LICENSE ("AGREEMENT"). ANY USE, REPRODUCTION OR DISTRIBUTION OF THE PROGRAM CONSTITUTES RECIPIENT'S ACCEPTANCE OF THIS AGREEMENT. - -1. DEFINITIONS - -"Contribution" means: - -a) in the case of the initial Contributor, the initial code and documentation distributed under this Agreement, and - -b) in the case of each subsequent Contributor: - -i) changes to the Program, and - -ii) additions to the Program; - -where such changes and/or additions to the Program originate from and are distributed by that particular Contributor. A Contribution 'originates' from a Contributor if it was added to the Program by such Contributor itself or anyone acting on such Contributor's behalf. Contributions do not include additions to the Program which: (i) are separate modules of software distributed in conjunction with the Program under their own license agreement, and (ii) are not derivative works of the Program. - -"Contributor" means any person or entity that distributes the Program. - -"Licensed Patents" mean patent claims licensable by a Contributor which are necessarily infringed by the use or sale of its Contribution alone or when combined with the Program. - -"Program" means the Contributions distributed in accordance with this Agreement. - -"Recipient" means anyone who receives the Program under this Agreement, including all Contributors. - -2. GRANT OF RIGHTS - -a) Subject to the terms of this Agreement, each Contributor hereby grants Recipient a non-exclusive, worldwide, royalty-free copyright license to reproduce, prepare derivative works of, publicly display, publicly perform, distribute and sublicense the Contribution of such Contributor, if any, and such derivative works, in source code and object code form. - -b) Subject to the terms of this Agreement, each Contributor hereby grants Recipient a non-exclusive, worldwide, royalty-free patent license under Licensed Patents to make, use, sell, offer to sell, import and otherwise transfer the Contribution of such Contributor, if any, in source code and object code form. This patent license shall apply to the combination of the Contribution and the Program if, at the time the Contribution is added by the Contributor, such addition of the Contribution causes such combination to be covered by the Licensed Patents. The patent license shall not apply to any other combinations which include the Contribution. No hardware per se is licensed hereunder. - -c) Recipient understands that although each Contributor grants the licenses to its Contributions set forth herein, no assurances are provided by any Contributor that the Program does not infringe the patent or other intellectual property rights of any other entity. Each Contributor disclaims any liability to Recipient for claims brought by any other entity based on infringement of intellectual property rights or otherwise. As a condition to exercising the rights and licenses granted hereunder, each Recipient hereby assumes sole responsibility to secure any other intellectual property rights needed, if any. For example, if a third party patent license is required to allow Recipient to distribute the Program, it is Recipient's responsibility to acquire that license before distributing the Program. - -d) Each Contributor represents that to its knowledge it has sufficient copyright rights in its Contribution, if any, to grant the copyright license set forth in this Agreement. - -3. REQUIREMENTS - -A Contributor may choose to distribute the Program in object code form under its own license agreement, provided that: - -a) it complies with the terms and conditions of this Agreement; and - -b) its license agreement: - -i) effectively disclaims on behalf of all Contributors all warranties and conditions, express and implied, including warranties or conditions of title and non-infringement, and implied warranties or conditions of merchantability and fitness for a particular purpose; - -ii) effectively excludes on behalf of all Contributors all liability for damages, including direct, indirect, special, incidental and consequential damages, such as lost profits; - -iii) states that any provisions which differ from this Agreement are offered by that Contributor alone and not by any other party; and - -iv) states that source code for the Program is available from such Contributor, and informs licensees how to obtain it in a reasonable manner on or through a medium customarily used for software exchange. - -When the Program is made available in source code form: - -a) it must be made available under this Agreement; and - -b) a copy of this Agreement must be included with each copy of the Program. - -Contributors may not remove or alter any copyright notices contained within the Program. - -Each Contributor must identify itself as the originator of its Contribution, if any, in a manner that reasonably allows subsequent Recipients to identify the originator of the Contribution. - -4. COMMERCIAL DISTRIBUTION - -Commercial distributors of software may accept certain responsibilities with respect to end users, business partners and the like. While this license is intended to facilitate the commercial use of the Program, the Contributor who includes the Program in a commercial product offering should do so in a manner which does not create potential liability for other Contributors. Therefore, if a Contributor includes the Program in a commercial product offering, such Contributor ("Commercial Contributor") hereby agrees to defend and indemnify every other Contributor ("Indemnified Contributor") against any losses, damages and costs (collectively "Losses") arising from claims, lawsuits and other legal actions brought by a third party against the Indemnified Contributor to the extent caused by the acts or omissions of such Commercial Contributor in connection with its distribution of the Program in a commercial product offering. The obligations in this section do not apply to any claims or Losses relating to any actual or alleged intellectual property infringement. In order to qualify, an Indemnified Contributor must: a) promptly notify the Commercial Contributor in writing of such claim, and b) allow the Commercial Contributor to control, and cooperate with the Commercial Contributor in, the defense and any related settlement negotiations. The Indemnified Contributor may participate in any such claim at its own expense. - -For example, a Contributor might include the Program in a commercial product offering, Product X. That Contributor is then a Commercial Contributor. If that Commercial Contributor then makes performance claims, or offers warranties related to Product X, those performance claims and warranties are such Commercial Contributor's responsibility alone. Under this section, the Commercial Contributor would have to defend claims against the other Contributors related to those performance claims and warranties, and if a court requires any other Contributor to pay any damages as a result, the Commercial Contributor must pay those damages. - -5. NO WARRANTY - -EXCEPT AS EXPRESSLY SET FORTH IN THIS AGREEMENT, THE PROGRAM IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED INCLUDING, WITHOUT LIMITATION, ANY WARRANTIES OR CONDITIONS OF TITLE, NON-INFRINGEMENT, MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE. Each Recipient is solely responsible for determining the appropriateness of using and distributing the Program and assumes all risks associated with its exercise of rights under this Agreement , including but not limited to the risks and costs of program errors, compliance with applicable laws, damage to or loss of data, programs or equipment, and unavailability or interruption of operations. - -6. DISCLAIMER OF LIABILITY - -EXCEPT AS EXPRESSLY SET FORTH IN THIS AGREEMENT, NEITHER RECIPIENT NOR ANY CONTRIBUTORS SHALL HAVE ANY LIABILITY FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING WITHOUT LIMITATION LOST PROFITS), HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OR DISTRIBUTION OF THE PROGRAM OR THE EXERCISE OF ANY RIGHTS GRANTED HEREUNDER, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGES. - -7. GENERAL - -If any provision of this Agreement is invalid or unenforceable under applicable law, it shall not affect the validity or enforceability of the remainder of the terms of this Agreement, and without further action by the parties hereto, such provision shall be reformed to the minimum extent necessary to make such provision valid and enforceable. - -If Recipient institutes patent litigation against any entity (including a cross-claim or counterclaim in a lawsuit) alleging that the Program itself (excluding combinations of the Program with other software or hardware) infringes such Recipient's patent(s), then such Recipient's rights granted under Section 2(b) shall terminate as of the date such litigation is filed. - -All Recipient's rights under this Agreement shall terminate if it fails to comply with any of the material terms or conditions of this Agreement and does not cure such failure in a reasonable period of time after becoming aware of such noncompliance. If all Recipient's rights under this Agreement terminate, Recipient agrees to cease use and distribution of the Program as soon as reasonably practicable. However, Recipient's obligations under this Agreement and any licenses granted by Recipient relating to the Program shall continue and survive. - -Everyone is permitted to copy and distribute copies of this Agreement, but in order to avoid inconsistency the Agreement is copyrighted and may only be modified in the following manner. The Agreement Steward reserves the right to publish new versions (including revisions) of this Agreement from time to time. No one other than the Agreement Steward has the right to modify this Agreement. The Eclipse Foundation is the initial Agreement Steward. The Eclipse Foundation may assign the responsibility to serve as the Agreement Steward to a suitable separate entity. Each new version of the Agreement will be given a distinguishing version number. The Program (including Contributions) may always be distributed subject to the version of the Agreement under which it was received. In addition, after a new version of the Agreement is published, Contributor may elect to distribute the Program (including its Contributions) under the new version. Except as expressly stated in Sections 2(a) and 2(b) above, Recipient receives no rights or licenses to the intellectual property of any Contributor under this Agreement, whether expressly, by implication, estoppel or otherwise. All rights in the Program not expressly granted under this Agreement are reserved. - -This Agreement is governed by the laws of the State of New York and the intellectual property laws of the United States of America. No party to this Agreement will bring a legal action under this Agreement more than one year after the cause of action arose. Each party waives its rights to a jury trial in any resulting litigation. - --------------------------------------------------- -Library: org.eclipse.core.filesystem v1.3.100 -Url: http://www.eclipse.org -License: EPL-1.0 - -Copyright © Eclipse Foundation, Inc. All Rights Reserved. - -Eclipse Public License - v 1.0 -THE ACCOMPANYING PROGRAM IS PROVIDED UNDER THE TERMS OF THIS ECLIPSE PUBLIC LICENSE ("AGREEMENT"). ANY USE, REPRODUCTION OR DISTRIBUTION OF THE PROGRAM CONSTITUTES RECIPIENT'S ACCEPTANCE OF THIS AGREEMENT. - -1. DEFINITIONS - -"Contribution" means: - -a) in the case of the initial Contributor, the initial code and documentation distributed under this Agreement, and - -b) in the case of each subsequent Contributor: - -i) changes to the Program, and - -ii) additions to the Program; - -where such changes and/or additions to the Program originate from and are distributed by that particular Contributor. A Contribution 'originates' from a Contributor if it was added to the Program by such Contributor itself or anyone acting on such Contributor's behalf. Contributions do not include additions to the Program which: (i) are separate modules of software distributed in conjunction with the Program under their own license agreement, and (ii) are not derivative works of the Program. - -"Contributor" means any person or entity that distributes the Program. - -"Licensed Patents" mean patent claims licensable by a Contributor which are necessarily infringed by the use or sale of its Contribution alone or when combined with the Program. - -"Program" means the Contributions distributed in accordance with this Agreement. - -"Recipient" means anyone who receives the Program under this Agreement, including all Contributors. - -2. GRANT OF RIGHTS - -a) Subject to the terms of this Agreement, each Contributor hereby grants Recipient a non-exclusive, worldwide, royalty-free copyright license to reproduce, prepare derivative works of, publicly display, publicly perform, distribute and sublicense the Contribution of such Contributor, if any, and such derivative works, in source code and object code form. - -b) Subject to the terms of this Agreement, each Contributor hereby grants Recipient a non-exclusive, worldwide, royalty-free patent license under Licensed Patents to make, use, sell, offer to sell, import and otherwise transfer the Contribution of such Contributor, if any, in source code and object code form. This patent license shall apply to the combination of the Contribution and the Program if, at the time the Contribution is added by the Contributor, such addition of the Contribution causes such combination to be covered by the Licensed Patents. The patent license shall not apply to any other combinations which include the Contribution. No hardware per se is licensed hereunder. - -c) Recipient understands that although each Contributor grants the licenses to its Contributions set forth herein, no assurances are provided by any Contributor that the Program does not infringe the patent or other intellectual property rights of any other entity. Each Contributor disclaims any liability to Recipient for claims brought by any other entity based on infringement of intellectual property rights or otherwise. As a condition to exercising the rights and licenses granted hereunder, each Recipient hereby assumes sole responsibility to secure any other intellectual property rights needed, if any. For example, if a third party patent license is required to allow Recipient to distribute the Program, it is Recipient's responsibility to acquire that license before distributing the Program. - -d) Each Contributor represents that to its knowledge it has sufficient copyright rights in its Contribution, if any, to grant the copyright license set forth in this Agreement. - -3. REQUIREMENTS - -A Contributor may choose to distribute the Program in object code form under its own license agreement, provided that: - -a) it complies with the terms and conditions of this Agreement; and - -b) its license agreement: - -i) effectively disclaims on behalf of all Contributors all warranties and conditions, express and implied, including warranties or conditions of title and non-infringement, and implied warranties or conditions of merchantability and fitness for a particular purpose; - -ii) effectively excludes on behalf of all Contributors all liability for damages, including direct, indirect, special, incidental and consequential damages, such as lost profits; - -iii) states that any provisions which differ from this Agreement are offered by that Contributor alone and not by any other party; and - -iv) states that source code for the Program is available from such Contributor, and informs licensees how to obtain it in a reasonable manner on or through a medium customarily used for software exchange. - -When the Program is made available in source code form: - -a) it must be made available under this Agreement; and - -b) a copy of this Agreement must be included with each copy of the Program. - -Contributors may not remove or alter any copyright notices contained within the Program. - -Each Contributor must identify itself as the originator of its Contribution, if any, in a manner that reasonably allows subsequent Recipients to identify the originator of the Contribution. - -4. COMMERCIAL DISTRIBUTION - -Commercial distributors of software may accept certain responsibilities with respect to end users, business partners and the like. While this license is intended to facilitate the commercial use of the Program, the Contributor who includes the Program in a commercial product offering should do so in a manner which does not create potential liability for other Contributors. Therefore, if a Contributor includes the Program in a commercial product offering, such Contributor ("Commercial Contributor") hereby agrees to defend and indemnify every other Contributor ("Indemnified Contributor") against any losses, damages and costs (collectively "Losses") arising from claims, lawsuits and other legal actions brought by a third party against the Indemnified Contributor to the extent caused by the acts or omissions of such Commercial Contributor in connection with its distribution of the Program in a commercial product offering. The obligations in this section do not apply to any claims or Losses relating to any actual or alleged intellectual property infringement. In order to qualify, an Indemnified Contributor must: a) promptly notify the Commercial Contributor in writing of such claim, and b) allow the Commercial Contributor to control, and cooperate with the Commercial Contributor in, the defense and any related settlement negotiations. The Indemnified Contributor may participate in any such claim at its own expense. - -For example, a Contributor might include the Program in a commercial product offering, Product X. That Contributor is then a Commercial Contributor. If that Commercial Contributor then makes performance claims, or offers warranties related to Product X, those performance claims and warranties are such Commercial Contributor's responsibility alone. Under this section, the Commercial Contributor would have to defend claims against the other Contributors related to those performance claims and warranties, and if a court requires any other Contributor to pay any damages as a result, the Commercial Contributor must pay those damages. - -5. NO WARRANTY - -EXCEPT AS EXPRESSLY SET FORTH IN THIS AGREEMENT, THE PROGRAM IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED INCLUDING, WITHOUT LIMITATION, ANY WARRANTIES OR CONDITIONS OF TITLE, NON-INFRINGEMENT, MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE. Each Recipient is solely responsible for determining the appropriateness of using and distributing the Program and assumes all risks associated with its exercise of rights under this Agreement , including but not limited to the risks and costs of program errors, compliance with applicable laws, damage to or loss of data, programs or equipment, and unavailability or interruption of operations. - -6. DISCLAIMER OF LIABILITY - -EXCEPT AS EXPRESSLY SET FORTH IN THIS AGREEMENT, NEITHER RECIPIENT NOR ANY CONTRIBUTORS SHALL HAVE ANY LIABILITY FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING WITHOUT LIMITATION LOST PROFITS), HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OR DISTRIBUTION OF THE PROGRAM OR THE EXERCISE OF ANY RIGHTS GRANTED HEREUNDER, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGES. - -7. GENERAL - -If any provision of this Agreement is invalid or unenforceable under applicable law, it shall not affect the validity or enforceability of the remainder of the terms of this Agreement, and without further action by the parties hereto, such provision shall be reformed to the minimum extent necessary to make such provision valid and enforceable. - -If Recipient institutes patent litigation against any entity (including a cross-claim or counterclaim in a lawsuit) alleging that the Program itself (excluding combinations of the Program with other software or hardware) infringes such Recipient's patent(s), then such Recipient's rights granted under Section 2(b) shall terminate as of the date such litigation is filed. - -All Recipient's rights under this Agreement shall terminate if it fails to comply with any of the material terms or conditions of this Agreement and does not cure such failure in a reasonable period of time after becoming aware of such noncompliance. If all Recipient's rights under this Agreement terminate, Recipient agrees to cease use and distribution of the Program as soon as reasonably practicable. However, Recipient's obligations under this Agreement and any licenses granted by Recipient relating to the Program shall continue and survive. - -Everyone is permitted to copy and distribute copies of this Agreement, but in order to avoid inconsistency the Agreement is copyrighted and may only be modified in the following manner. The Agreement Steward reserves the right to publish new versions (including revisions) of this Agreement from time to time. No one other than the Agreement Steward has the right to modify this Agreement. The Eclipse Foundation is the initial Agreement Steward. The Eclipse Foundation may assign the responsibility to serve as the Agreement Steward to a suitable separate entity. Each new version of the Agreement will be given a distinguishing version number. The Program (including Contributions) may always be distributed subject to the version of the Agreement under which it was received. In addition, after a new version of the Agreement is published, Contributor may elect to distribute the Program (including its Contributions) under the new version. Except as expressly stated in Sections 2(a) and 2(b) above, Recipient receives no rights or licenses to the intellectual property of any Contributor under this Agreement, whether expressly, by implication, estoppel or otherwise. All rights in the Program not expressly granted under this Agreement are reserved. - -This Agreement is governed by the laws of the State of New York and the intellectual property laws of the United States of America. No party to this Agreement will bring a legal action under this Agreement more than one year after the cause of action arose. Each party waives its rights to a jury trial in any resulting litigation. - --------------------------------------------------- -Library: org.eclipse.core.jobs v3.5.100 -Url: http://www.eclipse.org -License: EPL-1.0 - -Copyright © Eclipse Foundation, Inc. All Rights Reserved. - -Eclipse Public License - v 1.0 -THE ACCOMPANYING PROGRAM IS PROVIDED UNDER THE TERMS OF THIS ECLIPSE PUBLIC LICENSE ("AGREEMENT"). ANY USE, REPRODUCTION OR DISTRIBUTION OF THE PROGRAM CONSTITUTES RECIPIENT'S ACCEPTANCE OF THIS AGREEMENT. - -1. DEFINITIONS - -"Contribution" means: - -a) in the case of the initial Contributor, the initial code and documentation distributed under this Agreement, and - -b) in the case of each subsequent Contributor: - -i) changes to the Program, and - -ii) additions to the Program; - -where such changes and/or additions to the Program originate from and are distributed by that particular Contributor. A Contribution 'originates' from a Contributor if it was added to the Program by such Contributor itself or anyone acting on such Contributor's behalf. Contributions do not include additions to the Program which: (i) are separate modules of software distributed in conjunction with the Program under their own license agreement, and (ii) are not derivative works of the Program. - -"Contributor" means any person or entity that distributes the Program. - -"Licensed Patents" mean patent claims licensable by a Contributor which are necessarily infringed by the use or sale of its Contribution alone or when combined with the Program. - -"Program" means the Contributions distributed in accordance with this Agreement. - -"Recipient" means anyone who receives the Program under this Agreement, including all Contributors. - -2. GRANT OF RIGHTS - -a) Subject to the terms of this Agreement, each Contributor hereby grants Recipient a non-exclusive, worldwide, royalty-free copyright license to reproduce, prepare derivative works of, publicly display, publicly perform, distribute and sublicense the Contribution of such Contributor, if any, and such derivative works, in source code and object code form. - -b) Subject to the terms of this Agreement, each Contributor hereby grants Recipient a non-exclusive, worldwide, royalty-free patent license under Licensed Patents to make, use, sell, offer to sell, import and otherwise transfer the Contribution of such Contributor, if any, in source code and object code form. This patent license shall apply to the combination of the Contribution and the Program if, at the time the Contribution is added by the Contributor, such addition of the Contribution causes such combination to be covered by the Licensed Patents. The patent license shall not apply to any other combinations which include the Contribution. No hardware per se is licensed hereunder. - -c) Recipient understands that although each Contributor grants the licenses to its Contributions set forth herein, no assurances are provided by any Contributor that the Program does not infringe the patent or other intellectual property rights of any other entity. Each Contributor disclaims any liability to Recipient for claims brought by any other entity based on infringement of intellectual property rights or otherwise. As a condition to exercising the rights and licenses granted hereunder, each Recipient hereby assumes sole responsibility to secure any other intellectual property rights needed, if any. For example, if a third party patent license is required to allow Recipient to distribute the Program, it is Recipient's responsibility to acquire that license before distributing the Program. - -d) Each Contributor represents that to its knowledge it has sufficient copyright rights in its Contribution, if any, to grant the copyright license set forth in this Agreement. - -3. REQUIREMENTS - -A Contributor may choose to distribute the Program in object code form under its own license agreement, provided that: - -a) it complies with the terms and conditions of this Agreement; and - -b) its license agreement: - -i) effectively disclaims on behalf of all Contributors all warranties and conditions, express and implied, including warranties or conditions of title and non-infringement, and implied warranties or conditions of merchantability and fitness for a particular purpose; - -ii) effectively excludes on behalf of all Contributors all liability for damages, including direct, indirect, special, incidental and consequential damages, such as lost profits; - -iii) states that any provisions which differ from this Agreement are offered by that Contributor alone and not by any other party; and - -iv) states that source code for the Program is available from such Contributor, and informs licensees how to obtain it in a reasonable manner on or through a medium customarily used for software exchange. - -When the Program is made available in source code form: - -a) it must be made available under this Agreement; and - -b) a copy of this Agreement must be included with each copy of the Program. - -Contributors may not remove or alter any copyright notices contained within the Program. - -Each Contributor must identify itself as the originator of its Contribution, if any, in a manner that reasonably allows subsequent Recipients to identify the originator of the Contribution. - -4. COMMERCIAL DISTRIBUTION - -Commercial distributors of software may accept certain responsibilities with respect to end users, business partners and the like. While this license is intended to facilitate the commercial use of the Program, the Contributor who includes the Program in a commercial product offering should do so in a manner which does not create potential liability for other Contributors. Therefore, if a Contributor includes the Program in a commercial product offering, such Contributor ("Commercial Contributor") hereby agrees to defend and indemnify every other Contributor ("Indemnified Contributor") against any losses, damages and costs (collectively "Losses") arising from claims, lawsuits and other legal actions brought by a third party against the Indemnified Contributor to the extent caused by the acts or omissions of such Commercial Contributor in connection with its distribution of the Program in a commercial product offering. The obligations in this section do not apply to any claims or Losses relating to any actual or alleged intellectual property infringement. In order to qualify, an Indemnified Contributor must: a) promptly notify the Commercial Contributor in writing of such claim, and b) allow the Commercial Contributor to control, and cooperate with the Commercial Contributor in, the defense and any related settlement negotiations. The Indemnified Contributor may participate in any such claim at its own expense. - -For example, a Contributor might include the Program in a commercial product offering, Product X. That Contributor is then a Commercial Contributor. If that Commercial Contributor then makes performance claims, or offers warranties related to Product X, those performance claims and warranties are such Commercial Contributor's responsibility alone. Under this section, the Commercial Contributor would have to defend claims against the other Contributors related to those performance claims and warranties, and if a court requires any other Contributor to pay any damages as a result, the Commercial Contributor must pay those damages. - -5. NO WARRANTY - -EXCEPT AS EXPRESSLY SET FORTH IN THIS AGREEMENT, THE PROGRAM IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED INCLUDING, WITHOUT LIMITATION, ANY WARRANTIES OR CONDITIONS OF TITLE, NON-INFRINGEMENT, MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE. Each Recipient is solely responsible for determining the appropriateness of using and distributing the Program and assumes all risks associated with its exercise of rights under this Agreement , including but not limited to the risks and costs of program errors, compliance with applicable laws, damage to or loss of data, programs or equipment, and unavailability or interruption of operations. - -6. DISCLAIMER OF LIABILITY - -EXCEPT AS EXPRESSLY SET FORTH IN THIS AGREEMENT, NEITHER RECIPIENT NOR ANY CONTRIBUTORS SHALL HAVE ANY LIABILITY FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING WITHOUT LIMITATION LOST PROFITS), HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OR DISTRIBUTION OF THE PROGRAM OR THE EXERCISE OF ANY RIGHTS GRANTED HEREUNDER, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGES. - -7. GENERAL - -If any provision of this Agreement is invalid or unenforceable under applicable law, it shall not affect the validity or enforceability of the remainder of the terms of this Agreement, and without further action by the parties hereto, such provision shall be reformed to the minimum extent necessary to make such provision valid and enforceable. - -If Recipient institutes patent litigation against any entity (including a cross-claim or counterclaim in a lawsuit) alleging that the Program itself (excluding combinations of the Program with other software or hardware) infringes such Recipient's patent(s), then such Recipient's rights granted under Section 2(b) shall terminate as of the date such litigation is filed. - -All Recipient's rights under this Agreement shall terminate if it fails to comply with any of the material terms or conditions of this Agreement and does not cure such failure in a reasonable period of time after becoming aware of such noncompliance. If all Recipient's rights under this Agreement terminate, Recipient agrees to cease use and distribution of the Program as soon as reasonably practicable. However, Recipient's obligations under this Agreement and any licenses granted by Recipient relating to the Program shall continue and survive. - -Everyone is permitted to copy and distribute copies of this Agreement, but in order to avoid inconsistency the Agreement is copyrighted and may only be modified in the following manner. The Agreement Steward reserves the right to publish new versions (including revisions) of this Agreement from time to time. No one other than the Agreement Steward has the right to modify this Agreement. The Eclipse Foundation is the initial Agreement Steward. The Eclipse Foundation may assign the responsibility to serve as the Agreement Steward to a suitable separate entity. Each new version of the Agreement will be given a distinguishing version number. The Program (including Contributions) may always be distributed subject to the version of the Agreement under which it was received. In addition, after a new version of the Agreement is published, Contributor may elect to distribute the Program (including its Contributions) under the new version. Except as expressly stated in Sections 2(a) and 2(b) above, Recipient receives no rights or licenses to the intellectual property of any Contributor under this Agreement, whether expressly, by implication, estoppel or otherwise. All rights in the Program not expressly granted under this Agreement are reserved. - -This Agreement is governed by the laws of the State of New York and the intellectual property laws of the United States of America. No party to this Agreement will bring a legal action under this Agreement more than one year after the cause of action arose. Each party waives its rights to a jury trial in any resulting litigation. - --------------------------------------------------- -Library: org.eclipse.core.resources v3.7.100 -Url: http://www.eclipse.org -License: EPL-1.0 - -Copyright © Eclipse Foundation, Inc. All Rights Reserved. - -Eclipse Public License - v 1.0 -THE ACCOMPANYING PROGRAM IS PROVIDED UNDER THE TERMS OF THIS ECLIPSE PUBLIC LICENSE ("AGREEMENT"). ANY USE, REPRODUCTION OR DISTRIBUTION OF THE PROGRAM CONSTITUTES RECIPIENT'S ACCEPTANCE OF THIS AGREEMENT. - -1. DEFINITIONS - -"Contribution" means: - -a) in the case of the initial Contributor, the initial code and documentation distributed under this Agreement, and - -b) in the case of each subsequent Contributor: - -i) changes to the Program, and - -ii) additions to the Program; - -where such changes and/or additions to the Program originate from and are distributed by that particular Contributor. A Contribution 'originates' from a Contributor if it was added to the Program by such Contributor itself or anyone acting on such Contributor's behalf. Contributions do not include additions to the Program which: (i) are separate modules of software distributed in conjunction with the Program under their own license agreement, and (ii) are not derivative works of the Program. - -"Contributor" means any person or entity that distributes the Program. - -"Licensed Patents" mean patent claims licensable by a Contributor which are necessarily infringed by the use or sale of its Contribution alone or when combined with the Program. - -"Program" means the Contributions distributed in accordance with this Agreement. - -"Recipient" means anyone who receives the Program under this Agreement, including all Contributors. - -2. GRANT OF RIGHTS - -a) Subject to the terms of this Agreement, each Contributor hereby grants Recipient a non-exclusive, worldwide, royalty-free copyright license to reproduce, prepare derivative works of, publicly display, publicly perform, distribute and sublicense the Contribution of such Contributor, if any, and such derivative works, in source code and object code form. - -b) Subject to the terms of this Agreement, each Contributor hereby grants Recipient a non-exclusive, worldwide, royalty-free patent license under Licensed Patents to make, use, sell, offer to sell, import and otherwise transfer the Contribution of such Contributor, if any, in source code and object code form. This patent license shall apply to the combination of the Contribution and the Program if, at the time the Contribution is added by the Contributor, such addition of the Contribution causes such combination to be covered by the Licensed Patents. The patent license shall not apply to any other combinations which include the Contribution. No hardware per se is licensed hereunder. - -c) Recipient understands that although each Contributor grants the licenses to its Contributions set forth herein, no assurances are provided by any Contributor that the Program does not infringe the patent or other intellectual property rights of any other entity. Each Contributor disclaims any liability to Recipient for claims brought by any other entity based on infringement of intellectual property rights or otherwise. As a condition to exercising the rights and licenses granted hereunder, each Recipient hereby assumes sole responsibility to secure any other intellectual property rights needed, if any. For example, if a third party patent license is required to allow Recipient to distribute the Program, it is Recipient's responsibility to acquire that license before distributing the Program. - -d) Each Contributor represents that to its knowledge it has sufficient copyright rights in its Contribution, if any, to grant the copyright license set forth in this Agreement. - -3. REQUIREMENTS - -A Contributor may choose to distribute the Program in object code form under its own license agreement, provided that: - -a) it complies with the terms and conditions of this Agreement; and - -b) its license agreement: - -i) effectively disclaims on behalf of all Contributors all warranties and conditions, express and implied, including warranties or conditions of title and non-infringement, and implied warranties or conditions of merchantability and fitness for a particular purpose; - -ii) effectively excludes on behalf of all Contributors all liability for damages, including direct, indirect, special, incidental and consequential damages, such as lost profits; - -iii) states that any provisions which differ from this Agreement are offered by that Contributor alone and not by any other party; and - -iv) states that source code for the Program is available from such Contributor, and informs licensees how to obtain it in a reasonable manner on or through a medium customarily used for software exchange. - -When the Program is made available in source code form: - -a) it must be made available under this Agreement; and - -b) a copy of this Agreement must be included with each copy of the Program. - -Contributors may not remove or alter any copyright notices contained within the Program. - -Each Contributor must identify itself as the originator of its Contribution, if any, in a manner that reasonably allows subsequent Recipients to identify the originator of the Contribution. - -4. COMMERCIAL DISTRIBUTION - -Commercial distributors of software may accept certain responsibilities with respect to end users, business partners and the like. While this license is intended to facilitate the commercial use of the Program, the Contributor who includes the Program in a commercial product offering should do so in a manner which does not create potential liability for other Contributors. Therefore, if a Contributor includes the Program in a commercial product offering, such Contributor ("Commercial Contributor") hereby agrees to defend and indemnify every other Contributor ("Indemnified Contributor") against any losses, damages and costs (collectively "Losses") arising from claims, lawsuits and other legal actions brought by a third party against the Indemnified Contributor to the extent caused by the acts or omissions of such Commercial Contributor in connection with its distribution of the Program in a commercial product offering. The obligations in this section do not apply to any claims or Losses relating to any actual or alleged intellectual property infringement. In order to qualify, an Indemnified Contributor must: a) promptly notify the Commercial Contributor in writing of such claim, and b) allow the Commercial Contributor to control, and cooperate with the Commercial Contributor in, the defense and any related settlement negotiations. The Indemnified Contributor may participate in any such claim at its own expense. - -For example, a Contributor might include the Program in a commercial product offering, Product X. That Contributor is then a Commercial Contributor. If that Commercial Contributor then makes performance claims, or offers warranties related to Product X, those performance claims and warranties are such Commercial Contributor's responsibility alone. Under this section, the Commercial Contributor would have to defend claims against the other Contributors related to those performance claims and warranties, and if a court requires any other Contributor to pay any damages as a result, the Commercial Contributor must pay those damages. - -5. NO WARRANTY - -EXCEPT AS EXPRESSLY SET FORTH IN THIS AGREEMENT, THE PROGRAM IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED INCLUDING, WITHOUT LIMITATION, ANY WARRANTIES OR CONDITIONS OF TITLE, NON-INFRINGEMENT, MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE. Each Recipient is solely responsible for determining the appropriateness of using and distributing the Program and assumes all risks associated with its exercise of rights under this Agreement , including but not limited to the risks and costs of program errors, compliance with applicable laws, damage to or loss of data, programs or equipment, and unavailability or interruption of operations. - -6. DISCLAIMER OF LIABILITY - -EXCEPT AS EXPRESSLY SET FORTH IN THIS AGREEMENT, NEITHER RECIPIENT NOR ANY CONTRIBUTORS SHALL HAVE ANY LIABILITY FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING WITHOUT LIMITATION LOST PROFITS), HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OR DISTRIBUTION OF THE PROGRAM OR THE EXERCISE OF ANY RIGHTS GRANTED HEREUNDER, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGES. - -7. GENERAL - -If any provision of this Agreement is invalid or unenforceable under applicable law, it shall not affect the validity or enforceability of the remainder of the terms of this Agreement, and without further action by the parties hereto, such provision shall be reformed to the minimum extent necessary to make such provision valid and enforceable. - -If Recipient institutes patent litigation against any entity (including a cross-claim or counterclaim in a lawsuit) alleging that the Program itself (excluding combinations of the Program with other software or hardware) infringes such Recipient's patent(s), then such Recipient's rights granted under Section 2(b) shall terminate as of the date such litigation is filed. - -All Recipient's rights under this Agreement shall terminate if it fails to comply with any of the material terms or conditions of this Agreement and does not cure such failure in a reasonable period of time after becoming aware of such noncompliance. If all Recipient's rights under this Agreement terminate, Recipient agrees to cease use and distribution of the Program as soon as reasonably practicable. However, Recipient's obligations under this Agreement and any licenses granted by Recipient relating to the Program shall continue and survive. - -Everyone is permitted to copy and distribute copies of this Agreement, but in order to avoid inconsistency the Agreement is copyrighted and may only be modified in the following manner. The Agreement Steward reserves the right to publish new versions (including revisions) of this Agreement from time to time. No one other than the Agreement Steward has the right to modify this Agreement. The Eclipse Foundation is the initial Agreement Steward. The Eclipse Foundation may assign the responsibility to serve as the Agreement Steward to a suitable separate entity. Each new version of the Agreement will be given a distinguishing version number. The Program (including Contributions) may always be distributed subject to the version of the Agreement under which it was received. In addition, after a new version of the Agreement is published, Contributor may elect to distribute the Program (including its Contributions) under the new version. Except as expressly stated in Sections 2(a) and 2(b) above, Recipient receives no rights or licenses to the intellectual property of any Contributor under this Agreement, whether expressly, by implication, estoppel or otherwise. All rights in the Program not expressly granted under this Agreement are reserved. - -This Agreement is governed by the laws of the State of New York and the intellectual property laws of the United States of America. No party to this Agreement will bring a legal action under this Agreement more than one year after the cause of action arose. Each party waives its rights to a jury trial in any resulting litigation. - --------------------------------------------------- -Library: org.eclipse.core.runtime v3.7.0 -Url: http://www.eclipse.org -License: EPL-1.0 - -Copyright © Eclipse Foundation, Inc. All Rights Reserved. - -Eclipse Public License - v 1.0 -THE ACCOMPANYING PROGRAM IS PROVIDED UNDER THE TERMS OF THIS ECLIPSE PUBLIC LICENSE ("AGREEMENT"). ANY USE, REPRODUCTION OR DISTRIBUTION OF THE PROGRAM CONSTITUTES RECIPIENT'S ACCEPTANCE OF THIS AGREEMENT. - -1. DEFINITIONS - -"Contribution" means: - -a) in the case of the initial Contributor, the initial code and documentation distributed under this Agreement, and - -b) in the case of each subsequent Contributor: - -i) changes to the Program, and - -ii) additions to the Program; - -where such changes and/or additions to the Program originate from and are distributed by that particular Contributor. A Contribution 'originates' from a Contributor if it was added to the Program by such Contributor itself or anyone acting on such Contributor's behalf. Contributions do not include additions to the Program which: (i) are separate modules of software distributed in conjunction with the Program under their own license agreement, and (ii) are not derivative works of the Program. - -"Contributor" means any person or entity that distributes the Program. - -"Licensed Patents" mean patent claims licensable by a Contributor which are necessarily infringed by the use or sale of its Contribution alone or when combined with the Program. - -"Program" means the Contributions distributed in accordance with this Agreement. - -"Recipient" means anyone who receives the Program under this Agreement, including all Contributors. - -2. GRANT OF RIGHTS - -a) Subject to the terms of this Agreement, each Contributor hereby grants Recipient a non-exclusive, worldwide, royalty-free copyright license to reproduce, prepare derivative works of, publicly display, publicly perform, distribute and sublicense the Contribution of such Contributor, if any, and such derivative works, in source code and object code form. - -b) Subject to the terms of this Agreement, each Contributor hereby grants Recipient a non-exclusive, worldwide, royalty-free patent license under Licensed Patents to make, use, sell, offer to sell, import and otherwise transfer the Contribution of such Contributor, if any, in source code and object code form. This patent license shall apply to the combination of the Contribution and the Program if, at the time the Contribution is added by the Contributor, such addition of the Contribution causes such combination to be covered by the Licensed Patents. The patent license shall not apply to any other combinations which include the Contribution. No hardware per se is licensed hereunder. - -c) Recipient understands that although each Contributor grants the licenses to its Contributions set forth herein, no assurances are provided by any Contributor that the Program does not infringe the patent or other intellectual property rights of any other entity. Each Contributor disclaims any liability to Recipient for claims brought by any other entity based on infringement of intellectual property rights or otherwise. As a condition to exercising the rights and licenses granted hereunder, each Recipient hereby assumes sole responsibility to secure any other intellectual property rights needed, if any. For example, if a third party patent license is required to allow Recipient to distribute the Program, it is Recipient's responsibility to acquire that license before distributing the Program. - -d) Each Contributor represents that to its knowledge it has sufficient copyright rights in its Contribution, if any, to grant the copyright license set forth in this Agreement. - -3. REQUIREMENTS - -A Contributor may choose to distribute the Program in object code form under its own license agreement, provided that: - -a) it complies with the terms and conditions of this Agreement; and - -b) its license agreement: - -i) effectively disclaims on behalf of all Contributors all warranties and conditions, express and implied, including warranties or conditions of title and non-infringement, and implied warranties or conditions of merchantability and fitness for a particular purpose; - -ii) effectively excludes on behalf of all Contributors all liability for damages, including direct, indirect, special, incidental and consequential damages, such as lost profits; - -iii) states that any provisions which differ from this Agreement are offered by that Contributor alone and not by any other party; and - -iv) states that source code for the Program is available from such Contributor, and informs licensees how to obtain it in a reasonable manner on or through a medium customarily used for software exchange. - -When the Program is made available in source code form: - -a) it must be made available under this Agreement; and - -b) a copy of this Agreement must be included with each copy of the Program. - -Contributors may not remove or alter any copyright notices contained within the Program. - -Each Contributor must identify itself as the originator of its Contribution, if any, in a manner that reasonably allows subsequent Recipients to identify the originator of the Contribution. - -4. COMMERCIAL DISTRIBUTION - -Commercial distributors of software may accept certain responsibilities with respect to end users, business partners and the like. While this license is intended to facilitate the commercial use of the Program, the Contributor who includes the Program in a commercial product offering should do so in a manner which does not create potential liability for other Contributors. Therefore, if a Contributor includes the Program in a commercial product offering, such Contributor ("Commercial Contributor") hereby agrees to defend and indemnify every other Contributor ("Indemnified Contributor") against any losses, damages and costs (collectively "Losses") arising from claims, lawsuits and other legal actions brought by a third party against the Indemnified Contributor to the extent caused by the acts or omissions of such Commercial Contributor in connection with its distribution of the Program in a commercial product offering. The obligations in this section do not apply to any claims or Losses relating to any actual or alleged intellectual property infringement. In order to qualify, an Indemnified Contributor must: a) promptly notify the Commercial Contributor in writing of such claim, and b) allow the Commercial Contributor to control, and cooperate with the Commercial Contributor in, the defense and any related settlement negotiations. The Indemnified Contributor may participate in any such claim at its own expense. - -For example, a Contributor might include the Program in a commercial product offering, Product X. That Contributor is then a Commercial Contributor. If that Commercial Contributor then makes performance claims, or offers warranties related to Product X, those performance claims and warranties are such Commercial Contributor's responsibility alone. Under this section, the Commercial Contributor would have to defend claims against the other Contributors related to those performance claims and warranties, and if a court requires any other Contributor to pay any damages as a result, the Commercial Contributor must pay those damages. - -5. NO WARRANTY - -EXCEPT AS EXPRESSLY SET FORTH IN THIS AGREEMENT, THE PROGRAM IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED INCLUDING, WITHOUT LIMITATION, ANY WARRANTIES OR CONDITIONS OF TITLE, NON-INFRINGEMENT, MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE. Each Recipient is solely responsible for determining the appropriateness of using and distributing the Program and assumes all risks associated with its exercise of rights under this Agreement , including but not limited to the risks and costs of program errors, compliance with applicable laws, damage to or loss of data, programs or equipment, and unavailability or interruption of operations. - -6. DISCLAIMER OF LIABILITY - -EXCEPT AS EXPRESSLY SET FORTH IN THIS AGREEMENT, NEITHER RECIPIENT NOR ANY CONTRIBUTORS SHALL HAVE ANY LIABILITY FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING WITHOUT LIMITATION LOST PROFITS), HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OR DISTRIBUTION OF THE PROGRAM OR THE EXERCISE OF ANY RIGHTS GRANTED HEREUNDER, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGES. - -7. GENERAL - -If any provision of this Agreement is invalid or unenforceable under applicable law, it shall not affect the validity or enforceability of the remainder of the terms of this Agreement, and without further action by the parties hereto, such provision shall be reformed to the minimum extent necessary to make such provision valid and enforceable. - -If Recipient institutes patent litigation against any entity (including a cross-claim or counterclaim in a lawsuit) alleging that the Program itself (excluding combinations of the Program with other software or hardware) infringes such Recipient's patent(s), then such Recipient's rights granted under Section 2(b) shall terminate as of the date such litigation is filed. - -All Recipient's rights under this Agreement shall terminate if it fails to comply with any of the material terms or conditions of this Agreement and does not cure such failure in a reasonable period of time after becoming aware of such noncompliance. If all Recipient's rights under this Agreement terminate, Recipient agrees to cease use and distribution of the Program as soon as reasonably practicable. However, Recipient's obligations under this Agreement and any licenses granted by Recipient relating to the Program shall continue and survive. - -Everyone is permitted to copy and distribute copies of this Agreement, but in order to avoid inconsistency the Agreement is copyrighted and may only be modified in the following manner. The Agreement Steward reserves the right to publish new versions (including revisions) of this Agreement from time to time. No one other than the Agreement Steward has the right to modify this Agreement. The Eclipse Foundation is the initial Agreement Steward. The Eclipse Foundation may assign the responsibility to serve as the Agreement Steward to a suitable separate entity. Each new version of the Agreement will be given a distinguishing version number. The Program (including Contributions) may always be distributed subject to the version of the Agreement under which it was received. In addition, after a new version of the Agreement is published, Contributor may elect to distribute the Program (including its Contributions) under the new version. Except as expressly stated in Sections 2(a) and 2(b) above, Recipient receives no rights or licenses to the intellectual property of any Contributor under this Agreement, whether expressly, by implication, estoppel or otherwise. All rights in the Program not expressly granted under this Agreement are reserved. - -This Agreement is governed by the laws of the State of New York and the intellectual property laws of the United States of America. No party to this Agreement will bring a legal action under this Agreement more than one year after the cause of action arose. Each party waives its rights to a jury trial in any resulting litigation. - --------------------------------------------------- -Library: org.eclipse.equinox.app v1.3.100 -Url: http://www.eclipse.org/platform -License: EPL-1.0 - - Copyright (c) 2012 Eclipse Foundation. - All rights reserved. This program and the accompanying materials - are made available under the terms of the Eclipse Distribution License v1.0 - which accompanies this distribution, and is available at - http://www.eclipse.org/org/documents/edl-v10.php - --------------------------------------------------- -Library: org.eclipse.equinox.common v3.6.0 -Url: http://www.eclipse.org/platform -License: EPL-1.0 - - Copyright (c) 2012 Eclipse Foundation. - All rights reserved. This program and the accompanying materials - are made available under the terms of the Eclipse Distribution License v1.0 - which accompanies this distribution, and is available at - http://www.eclipse.org/org/documents/edl-v10.php - --------------------------------------------------- -Library: org.eclipse.equinox.preferences v3.4.1 -Url: http://www.eclipse.org/platform -License: EPL-1.0 - - Copyright (c) 2012 Eclipse Foundation. - All rights reserved. This program and the accompanying materials - are made available under the terms of the Eclipse Distribution License v1.0 - which accompanies this distribution, and is available at - http://www.eclipse.org/org/documents/edl-v10.php - --------------------------------------------------- -Library: org.eclipse.equinox.registry v3.5.101 -Url: http://www.eclipse.org/platform -License: EPL-1.0 - - Copyright (c) 2012 Eclipse Foundation. - All rights reserved. This program and the accompanying materials - are made available under the terms of the Eclipse Distribution License v1.0 - which accompanies this distribution, and is available at - http://www.eclipse.org/org/documents/edl-v10.php - --------------------------------------------------- -Library: org.eclipse.jdt.core v3.10.0 -Url: http://www.eclipse.org/jdt -License: EPL-1.0 - - Copyright (c) 2012, 2016 Eclipse Foundation and others. - All rights reserved. This program and the accompanying materials - are made available under the terms of the Eclipse Distribution License v1.0 - which accompanies this distribution, and is available at - http://www.eclipse.org/org/documents/edl-v10.php - --------------------------------------------------- -Library: org.eclipse.osgi v3.7.1 -Url: http://www.eclipse.org/jdt -License: EPL-1.0 - - Copyright (c) 2012, 2017 Eclipse Foundation. - All rights reserved. This program and the accompanying materials - are made available under the terms of the Eclipse Distribution License v1.0 - which accompanies this distribution, and is available at - http://www.eclipse.org/org/documents/edl-v10.php - --------------------------------------------------- -Library: org.eclipse.text v3.5.101 -Url: http://www.eclipse.org/jdt -License: EPL-1.0 - -Copyright © Eclipse Foundation, Inc. All Rights Reserved. - -Eclipse Public License - v 1.0 -THE ACCOMPANYING PROGRAM IS PROVIDED UNDER THE TERMS OF THIS ECLIPSE PUBLIC LICENSE ("AGREEMENT"). ANY USE, REPRODUCTION OR DISTRIBUTION OF THE PROGRAM CONSTITUTES RECIPIENT'S ACCEPTANCE OF THIS AGREEMENT. - -1. DEFINITIONS - -"Contribution" means: - -a) in the case of the initial Contributor, the initial code and documentation distributed under this Agreement, and - -b) in the case of each subsequent Contributor: - -i) changes to the Program, and - -ii) additions to the Program; - -where such changes and/or additions to the Program originate from and are distributed by that particular Contributor. A Contribution 'originates' from a Contributor if it was added to the Program by such Contributor itself or anyone acting on such Contributor's behalf. Contributions do not include additions to the Program which: (i) are separate modules of software distributed in conjunction with the Program under their own license agreement, and (ii) are not derivative works of the Program. - -"Contributor" means any person or entity that distributes the Program. - -"Licensed Patents" mean patent claims licensable by a Contributor which are necessarily infringed by the use or sale of its Contribution alone or when combined with the Program. - -"Program" means the Contributions distributed in accordance with this Agreement. - -"Recipient" means anyone who receives the Program under this Agreement, including all Contributors. - -2. GRANT OF RIGHTS - -a) Subject to the terms of this Agreement, each Contributor hereby grants Recipient a non-exclusive, worldwide, royalty-free copyright license to reproduce, prepare derivative works of, publicly display, publicly perform, distribute and sublicense the Contribution of such Contributor, if any, and such derivative works, in source code and object code form. - -b) Subject to the terms of this Agreement, each Contributor hereby grants Recipient a non-exclusive, worldwide, royalty-free patent license under Licensed Patents to make, use, sell, offer to sell, import and otherwise transfer the Contribution of such Contributor, if any, in source code and object code form. This patent license shall apply to the combination of the Contribution and the Program if, at the time the Contribution is added by the Contributor, such addition of the Contribution causes such combination to be covered by the Licensed Patents. The patent license shall not apply to any other combinations which include the Contribution. No hardware per se is licensed hereunder. - -c) Recipient understands that although each Contributor grants the licenses to its Contributions set forth herein, no assurances are provided by any Contributor that the Program does not infringe the patent or other intellectual property rights of any other entity. Each Contributor disclaims any liability to Recipient for claims brought by any other entity based on infringement of intellectual property rights or otherwise. As a condition to exercising the rights and licenses granted hereunder, each Recipient hereby assumes sole responsibility to secure any other intellectual property rights needed, if any. For example, if a third party patent license is required to allow Recipient to distribute the Program, it is Recipient's responsibility to acquire that license before distributing the Program. - -d) Each Contributor represents that to its knowledge it has sufficient copyright rights in its Contribution, if any, to grant the copyright license set forth in this Agreement. - -3. REQUIREMENTS - -A Contributor may choose to distribute the Program in object code form under its own license agreement, provided that: - -a) it complies with the terms and conditions of this Agreement; and - -b) its license agreement: - -i) effectively disclaims on behalf of all Contributors all warranties and conditions, express and implied, including warranties or conditions of title and non-infringement, and implied warranties or conditions of merchantability and fitness for a particular purpose; - -ii) effectively excludes on behalf of all Contributors all liability for damages, including direct, indirect, special, incidental and consequential damages, such as lost profits; - -iii) states that any provisions which differ from this Agreement are offered by that Contributor alone and not by any other party; and - -iv) states that source code for the Program is available from such Contributor, and informs licensees how to obtain it in a reasonable manner on or through a medium customarily used for software exchange. - -When the Program is made available in source code form: - -a) it must be made available under this Agreement; and - -b) a copy of this Agreement must be included with each copy of the Program. - -Contributors may not remove or alter any copyright notices contained within the Program. - -Each Contributor must identify itself as the originator of its Contribution, if any, in a manner that reasonably allows subsequent Recipients to identify the originator of the Contribution. - -4. COMMERCIAL DISTRIBUTION - -Commercial distributors of software may accept certain responsibilities with respect to end users, business partners and the like. While this license is intended to facilitate the commercial use of the Program, the Contributor who includes the Program in a commercial product offering should do so in a manner which does not create potential liability for other Contributors. Therefore, if a Contributor includes the Program in a commercial product offering, such Contributor ("Commercial Contributor") hereby agrees to defend and indemnify every other Contributor ("Indemnified Contributor") against any losses, damages and costs (collectively "Losses") arising from claims, lawsuits and other legal actions brought by a third party against the Indemnified Contributor to the extent caused by the acts or omissions of such Commercial Contributor in connection with its distribution of the Program in a commercial product offering. The obligations in this section do not apply to any claims or Losses relating to any actual or alleged intellectual property infringement. In order to qualify, an Indemnified Contributor must: a) promptly notify the Commercial Contributor in writing of such claim, and b) allow the Commercial Contributor to control, and cooperate with the Commercial Contributor in, the defense and any related settlement negotiations. The Indemnified Contributor may participate in any such claim at its own expense. - -For example, a Contributor might include the Program in a commercial product offering, Product X. That Contributor is then a Commercial Contributor. If that Commercial Contributor then makes performance claims, or offers warranties related to Product X, those performance claims and warranties are such Commercial Contributor's responsibility alone. Under this section, the Commercial Contributor would have to defend claims against the other Contributors related to those performance claims and warranties, and if a court requires any other Contributor to pay any damages as a result, the Commercial Contributor must pay those damages. - -5. NO WARRANTY - -EXCEPT AS EXPRESSLY SET FORTH IN THIS AGREEMENT, THE PROGRAM IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED INCLUDING, WITHOUT LIMITATION, ANY WARRANTIES OR CONDITIONS OF TITLE, NON-INFRINGEMENT, MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE. Each Recipient is solely responsible for determining the appropriateness of using and distributing the Program and assumes all risks associated with its exercise of rights under this Agreement , including but not limited to the risks and costs of program errors, compliance with applicable laws, damage to or loss of data, programs or equipment, and unavailability or interruption of operations. - -6. DISCLAIMER OF LIABILITY - -EXCEPT AS EXPRESSLY SET FORTH IN THIS AGREEMENT, NEITHER RECIPIENT NOR ANY CONTRIBUTORS SHALL HAVE ANY LIABILITY FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING WITHOUT LIMITATION LOST PROFITS), HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OR DISTRIBUTION OF THE PROGRAM OR THE EXERCISE OF ANY RIGHTS GRANTED HEREUNDER, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGES. - -7. GENERAL - -If any provision of this Agreement is invalid or unenforceable under applicable law, it shall not affect the validity or enforceability of the remainder of the terms of this Agreement, and without further action by the parties hereto, such provision shall be reformed to the minimum extent necessary to make such provision valid and enforceable. - -If Recipient institutes patent litigation against any entity (including a cross-claim or counterclaim in a lawsuit) alleging that the Program itself (excluding combinations of the Program with other software or hardware) infringes such Recipient's patent(s), then such Recipient's rights granted under Section 2(b) shall terminate as of the date such litigation is filed. - -All Recipient's rights under this Agreement shall terminate if it fails to comply with any of the material terms or conditions of this Agreement and does not cure such failure in a reasonable period of time after becoming aware of such noncompliance. If all Recipient's rights under this Agreement terminate, Recipient agrees to cease use and distribution of the Program as soon as reasonably practicable. However, Recipient's obligations under this Agreement and any licenses granted by Recipient relating to the Program shall continue and survive. - -Everyone is permitted to copy and distribute copies of this Agreement, but in order to avoid inconsistency the Agreement is copyrighted and may only be modified in the following manner. The Agreement Steward reserves the right to publish new versions (including revisions) of this Agreement from time to time. No one other than the Agreement Steward has the right to modify this Agreement. The Eclipse Foundation is the initial Agreement Steward. The Eclipse Foundation may assign the responsibility to serve as the Agreement Steward to a suitable separate entity. Each new version of the Agreement will be given a distinguishing version number. The Program (including Contributions) may always be distributed subject to the version of the Agreement under which it was received. In addition, after a new version of the Agreement is published, Contributor may elect to distribute the Program (including its Contributions) under the new version. Except as expressly stated in Sections 2(a) and 2(b) above, Recipient receives no rights or licenses to the intellectual property of any Contributor under this Agreement, whether expressly, by implication, estoppel or otherwise. All rights in the Program not expressly granted under this Agreement are reserved. - -This Agreement is governed by the laws of the State of New York and the intellectual property laws of the United States of America. No party to this Agreement will bring a legal action under this Agreement more than one year after the cause of action arose. Each party waives its rights to a jury trial in any resulting litigation. - --------------------------------------------------- -Library: jruby-complete v9.1.13.0 -Url: http://jruby.org/ -License: EPL-2.0 - -JRuby is Copyright (c) 2007-2018 The JRuby project - -Eclipse Public License - v 2.0 - - THE ACCOMPANYING PROGRAM IS PROVIDED UNDER THE TERMS OF THIS ECLIPSE - PUBLIC LICENSE ("AGREEMENT"). ANY USE, REPRODUCTION OR DISTRIBUTION - OF THE PROGRAM CONSTITUTES RECIPIENT'S ACCEPTANCE OF THIS AGREEMENT. - - 1. DEFINITIONS - - "Contribution" means: - - a) in the case of the initial Contributor, the initial content - Distributed under this Agreement, and - - b) in the case of each subsequent Contributor: - i) changes to the Program, and - ii) additions to the Program; - where such changes and/or additions to the Program originate from - and are Distributed by that particular Contributor. A Contribution - "originates" from a Contributor if it was added to the Program by - such Contributor itself or anyone acting on such Contributor's behalf. - Contributions do not include changes or additions to the Program that - are not Modified Works. - - "Contributor" means any person or entity that Distributes the Program. - - "Licensed Patents" mean patent claims licensable by a Contributor which - are necessarily infringed by the use or sale of its Contribution alone - or when combined with the Program. - - "Program" means the Contributions Distributed in accordance with this - Agreement. - - "Recipient" means anyone who receives the Program under this Agreement - or any Secondary License (as applicable), including Contributors. - - "Derivative Works" shall mean any work, whether in Source Code or other - form, that is based on (or derived from) the Program and for which the - editorial revisions, annotations, elaborations, or other modifications - represent, as a whole, an original work of authorship. - - "Modified Works" shall mean any work in Source Code or other form that - results from an addition to, deletion from, or modification of the - contents of the Program, including, for purposes of clarity any new file - in Source Code form that contains any contents of the Program. Modified - Works shall not include works that contain only declarations, - interfaces, types, classes, structures, or files of the Program solely - in each case in order to link to, bind by name, or subclass the Program - or Modified Works thereof. - - "Distribute" means the acts of a) distributing or b) making available - in any manner that enables the transfer of a copy. - - "Source Code" means the form of a Program preferred for making - modifications, including but not limited to software source code, - documentation source, and configuration files. - - "Secondary License" means either the GNU General Public License, - Version 2.0, or any later versions of that license, including any - exceptions or additional permissions as identified by the initial - Contributor. - - 2. GRANT OF RIGHTS - - a) Subject to the terms of this Agreement, each Contributor hereby - grants Recipient a non-exclusive, worldwide, royalty-free copyright - license to reproduce, prepare Derivative Works of, publicly display, - publicly perform, Distribute and sublicense the Contribution of such - Contributor, if any, and such Derivative Works. - - b) Subject to the terms of this Agreement, each Contributor hereby - grants Recipient a non-exclusive, worldwide, royalty-free patent - license under Licensed Patents to make, use, sell, offer to sell, - import and otherwise transfer the Contribution of such Contributor, - if any, in Source Code or other form. This patent license shall - apply to the combination of the Contribution and the Program if, at - the time the Contribution is added by the Contributor, such addition - of the Contribution causes such combination to be covered by the - Licensed Patents. The patent license shall not apply to any other - combinations which include the Contribution. No hardware per se is - licensed hereunder. - - c) Recipient understands that although each Contributor grants the - licenses to its Contributions set forth herein, no assurances are - provided by any Contributor that the Program does not infringe the - patent or other intellectual property rights of any other entity. - Each Contributor disclaims any liability to Recipient for claims - brought by any other entity based on infringement of intellectual - property rights or otherwise. As a condition to exercising the - rights and licenses granted hereunder, each Recipient hereby - assumes sole responsibility to secure any other intellectual - property rights needed, if any. For example, if a third party - patent license is required to allow Recipient to Distribute the - Program, it is Recipient's responsibility to acquire that license - before distributing the Program. - - d) Each Contributor represents that to its knowledge it has - sufficient copyright rights in its Contribution, if any, to grant - the copyright license set forth in this Agreement. - - e) Notwithstanding the terms of any Secondary License, no - Contributor makes additional grants to any Recipient (other than - those set forth in this Agreement) as a result of such Recipient's - receipt of the Program under the terms of a Secondary License - (if permitted under the terms of Section 3). - - 3. REQUIREMENTS - - 3.1 If a Contributor Distributes the Program in any form, then: - - a) the Program must also be made available as Source Code, in - accordance with section 3.2, and the Contributor must accompany - the Program with a statement that the Source Code for the Program - is available under this Agreement, and informs Recipients how to - obtain it in a reasonable manner on or through a medium customarily - used for software exchange; and - - b) the Contributor may Distribute the Program under a license - different than this Agreement, provided that such license: - i) effectively disclaims on behalf of all other Contributors all - warranties and conditions, express and implied, including - warranties or conditions of title and non-infringement, and - implied warranties or conditions of merchantability and fitness - for a particular purpose; - - ii) effectively excludes on behalf of all other Contributors all - liability for damages, including direct, indirect, special, - incidental and consequential damages, such as lost profits; - - iii) does not attempt to limit or alter the recipients' rights - in the Source Code under section 3.2; and - - iv) requires any subsequent distribution of the Program by any - party to be under a license that satisfies the requirements - of this section 3. - - 3.2 When the Program is Distributed as Source Code: - - a) it must be made available under this Agreement, or if the - Program (i) is combined with other material in a separate file or - files made available under a Secondary License, and (ii) the initial - Contributor attached to the Source Code the notice described in - Exhibit A of this Agreement, then the Program may be made available - under the terms of such Secondary Licenses, and - - b) a copy of this Agreement must be included with each copy of - the Program. - - 3.3 Contributors may not remove or alter any copyright, patent, - trademark, attribution notices, disclaimers of warranty, or limitations - of liability ("notices") contained within the Program from any copy of - the Program which they Distribute, provided that Contributors may add - their own appropriate notices. - - 4. COMMERCIAL DISTRIBUTION - - Commercial distributors of software may accept certain responsibilities - with respect to end users, business partners and the like. While this - license is intended to facilitate the commercial use of the Program, - the Contributor who includes the Program in a commercial product - offering should do so in a manner which does not create potential - liability for other Contributors. Therefore, if a Contributor includes - the Program in a commercial product offering, such Contributor - ("Commercial Contributor") hereby agrees to defend and indemnify every - other Contributor ("Indemnified Contributor") against any losses, - damages and costs (collectively "Losses") arising from claims, lawsuits - and other legal actions brought by a third party against the Indemnified - Contributor to the extent caused by the acts or omissions of such - Commercial Contributor in connection with its distribution of the Program - in a commercial product offering. The obligations in this section do not - apply to any claims or Losses relating to any actual or alleged - intellectual property infringement. In order to qualify, an Indemnified - Contributor must: a) promptly notify the Commercial Contributor in - writing of such claim, and b) allow the Commercial Contributor to control, - and cooperate with the Commercial Contributor in, the defense and any - related settlement negotiations. The Indemnified Contributor may - participate in any such claim at its own expense. - - For example, a Contributor might include the Program in a commercial - product offering, Product X. That Contributor is then a Commercial - Contributor. If that Commercial Contributor then makes performance - claims, or offers warranties related to Product X, those performance - claims and warranties are such Commercial Contributor's responsibility - alone. Under this section, the Commercial Contributor would have to - defend claims against the other Contributors related to those performance - claims and warranties, and if a court requires any other Contributor to - pay any damages as a result, the Commercial Contributor must pay - those damages. - - 5. NO WARRANTY - - EXCEPT AS EXPRESSLY SET FORTH IN THIS AGREEMENT, AND TO THE EXTENT - PERMITTED BY APPLICABLE LAW, THE PROGRAM IS PROVIDED ON AN "AS IS" - BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, EITHER EXPRESS OR - IMPLIED INCLUDING, WITHOUT LIMITATION, ANY WARRANTIES OR CONDITIONS OF - TITLE, NON-INFRINGEMENT, MERCHANTABILITY OR FITNESS FOR A PARTICULAR - PURPOSE. Each Recipient is solely responsible for determining the - appropriateness of using and distributing the Program and assumes all - risks associated with its exercise of rights under this Agreement, - including but not limited to the risks and costs of program errors, - compliance with applicable laws, damage to or loss of data, programs - or equipment, and unavailability or interruption of operations. - - 6. DISCLAIMER OF LIABILITY - - EXCEPT AS EXPRESSLY SET FORTH IN THIS AGREEMENT, AND TO THE EXTENT - PERMITTED BY APPLICABLE LAW, NEITHER RECIPIENT NOR ANY CONTRIBUTORS - SHALL HAVE ANY LIABILITY FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, - EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING WITHOUT LIMITATION LOST - PROFITS), HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN - CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) - ARISING IN ANY WAY OUT OF THE USE OR DISTRIBUTION OF THE PROGRAM OR THE - EXERCISE OF ANY RIGHTS GRANTED HEREUNDER, EVEN IF ADVISED OF THE - POSSIBILITY OF SUCH DAMAGES. - - 7. GENERAL - - If any provision of this Agreement is invalid or unenforceable under - applicable law, it shall not affect the validity or enforceability of - the remainder of the terms of this Agreement, and without further - action by the parties hereto, such provision shall be reformed to the - minimum extent necessary to make such provision valid and enforceable. - - If Recipient institutes patent litigation against any entity - (including a cross-claim or counterclaim in a lawsuit) alleging that the - Program itself (excluding combinations of the Program with other software - or hardware) infringes such Recipient's patent(s), then such Recipient's - rights granted under Section 2(b) shall terminate as of the date such - litigation is filed. - - All Recipient's rights under this Agreement shall terminate if it - fails to comply with any of the material terms or conditions of this - Agreement and does not cure such failure in a reasonable period of - time after becoming aware of such noncompliance. If all Recipient's - rights under this Agreement terminate, Recipient agrees to cease use - and distribution of the Program as soon as reasonably practicable. - However, Recipient's obligations under this Agreement and any licenses - granted by Recipient relating to the Program shall continue and survive. - - Everyone is permitted to copy and distribute copies of this Agreement, - but in order to avoid inconsistency the Agreement is copyrighted and - may only be modified in the following manner. The Agreement Steward - reserves the right to publish new versions (including revisions) of - this Agreement from time to time. No one other than the Agreement - Steward has the right to modify this Agreement. The Eclipse Foundation - is the initial Agreement Steward. The Eclipse Foundation may assign the - responsibility to serve as the Agreement Steward to a suitable separate - entity. Each new version of the Agreement will be given a distinguishing - version number. The Program (including Contributions) may always be - Distributed subject to the version of the Agreement under which it was - received. In addition, after a new version of the Agreement is published, - Contributor may elect to Distribute the Program (including its - Contributions) under the new version. - - Except as expressly stated in Sections 2(a) and 2(b) above, Recipient - receives no rights or licenses to the intellectual property of any - Contributor under this Agreement, whether expressly, by implication, - estoppel or otherwise. All rights in the Program not expressly granted - under this Agreement are reserved. Nothing in this Agreement is intended - to be enforceable by any entity that is not a Contributor or Recipient. - No third-party beneficiary rights are created under this Agreement. - - Exhibit A - Form of Secondary Licenses Notice - - "This Source Code may also be made available under the following - Secondary Licenses when the conditions for such availability set forth - in the Eclipse Public License, v. 2.0 are satisfied: {name license(s), - version(s), and exceptions or additional permissions here}." - - Simply including a copy of this Agreement, including this Exhibit A - is not sufficient to license the Source Code under Secondary Licenses. - - If it is not possible or desirable to put the notice in a particular - file, then You may include the notice in a location (such as a LICENSE - file in a relevant directory) where a recipient would be likely to - look for such a notice. - - You may add additional accurate notices of copyright ownership. - --------------------------------------------------- -Library: slf4j-api v1.7.25 -Url: http://www.slf4j.org/ -License: MIT - -Copyright (c) 2004-2007 QOS.ch -All rights reserved. - -Permission is hereby granted, free of charge, to any person obtaining -a copy of this software and associated documentation files (the -"Software"), to deal in the Software without restriction, including -without limitation the rights to use, copy, modify, merge, publish, -distribute, sublicense, and/or sell copies of the Software, and to -permit persons to whom the Software is furnished to do so, subject to -the following conditions: - -The above copyright notice and this permission notice shall be -included in all copies or substantial portions of the Software. - -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, -EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF -MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND -NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE -LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION -OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION -WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. - --------------------------------------------------- -Library: paquet v0.2.1 -Url: https://github.com/elastic/logstash -License: Apache-2.0 - -Copyright (c) 2012–2016 Elasticsearch - -Licensed 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. - --------------------------------------------------- -Library: pleaserun v0.0.30 -Url: https://github.com/jordansissel/pleaserun -License: Apache-2.0 - -Copyright 2014 Jordan Sissel contributors. - -Licensed 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. - --------------------------------------------------- -Library: polyglot v0.3.5 -Url: http://github.com/cjheath/polyglot -License: MIT - -Copyright (c) 2007 Clifford Heath - -Permission is hereby granted, free of charge, to any person obtaining -a copy of this software and associated documentation files (the -"Software"), to deal in the Software without restriction, including -without limitation the rights to use, copy, modify, merge, publish, -distribute, sublicense, and/or sell copies of the Software, and to -permit persons to whom the Software is furnished to do so, subject to -the following conditions: - -The above copyright notice and this permission notice shall be -included in all copies or substantial portions of the Software. - -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, -EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF -MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND -NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE -LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION -OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION -WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. - --------------------------------------------------- -Library: poseidon v0.0.5 -Url: https://github.com/bpot/poseidon -License: MIT - -Copyright (c) 2013 Bob Potter - -MIT License - -Permission is hereby granted, free of charge, to any person obtaining -a copy of this software and associated documentation files (the -"Software"), to deal in the Software without restriction, including -without limitation the rights to use, copy, modify, merge, publish, -distribute, sublicense, and/or sell copies of the Software, and to -permit persons to whom the Software is furnished to do so, subject to -the following conditions: - -The above copyright notice and this permission notice shall be -included in all copies or substantial portions of the Software. - -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, -EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF -MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND -NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE -LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION -OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION -WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. - --------------------------------------------------- -Library: prototype.js v -Url: http://prototypejs.org -License: MIT TODO: Another jruby dependency that is not shipped with it - -TODO - --------------------------------------------------- -Library: pry v0.10.4 -Url: http://pryrepl.org -License: MIT - -Copyright (c) 2016 John Mair (banisterfiend) - -Permission is hereby granted, free of charge, to any person obtaining -a copy of this software and associated documentation files (the -'Software'), to deal in the Software without restriction, including -without limitation the rights to use, copy, modify, merge, publish, -distribute, sublicense, and/or sell copies of the Software, and to -permit persons to whom the Software is furnished to do so, subject to -the following conditions: - -The above copyright notice and this permission notice shall be -included in all copies or substantial portions of the Software. - -THE SOFTWARE IS PROVIDED 'AS IS', WITHOUT WARRANTY OF ANY KIND, -EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF -MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. -IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY -CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, -TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE -SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. - --------------------------------------------------- -Library: psych v2.2.4 -Url: https://github.com/ruby/psych -License: MIT - -Copyright 2009 Aaron Patterson, et al. - -Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the 'Software'), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: - -The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. - -THE SOFTWARE IS PROVIDED 'AS IS', WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. - --------------------------------------------------- -Library: public_suffix v1.4.6 -Url: https://simonecarletti.com/code/publicsuffix-ruby -License: MIT - -Copyright (c) 2009-2018 Simone Carletti - -MIT License - -Permission is hereby granted, free of charge, to any person obtaining -a copy of this software and associated documentation files (the -"Software"), to deal in the Software without restriction, including -without limitation the rights to use, copy, modify, merge, publish, -distribute, sublicense, and/or sell copies of the Software, and to -permit persons to whom the Software is furnished to do so, subject to -the following conditions: - -The above copyright notice and this permission notice shall be -included in all copies or substantial portions of the Software. - -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, -EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF -MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND -NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE -LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION -OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION -WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. - --------------------------------------------------- -Library: puma v4.2.1 -Url: http://puma.io -License: BSD-3-Clause - -Some code copyright (c) 2005, Zed Shaw -Copyright (c) 2011, Evan Phoenix -All rights reserved. - -Redistribution and use in source and binary forms, with or without -modification, are permitted provided that the following conditions are met: - -* Redistributions of source code must retain the above copyright notice, this - list of conditions and the following disclaimer. -* Redistributions in binary form must reproduce the above copyright notice - this list of conditions and the following disclaimer in the documentation - and/or other materials provided with the distribution. -* Neither the name of the Evan Phoenix nor the names of its contributors - may be used to endorse or promote products derived from this software - without specific prior written permission. - -THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" -AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE -IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE -DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE -FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL -DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR -SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER -CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, -OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE -OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - --------------------------------------------------- -Library: racc v -Url: https://github.com/tenderlove/racc -License: TODO: https://github.com/tenderlove/racc/blob/master/COPYING vs https://github.com/jruby/jruby/blob/master/COPYING#L89 - -TODO - - - -Racc is distributed under the terms of the GNU Lesser General -Public License version 2. Note that you do NOT need to follow -LGPL for your own parser (racc outputs). You can distribute those -files under any licenses you want.Racc is - --------------------------------------------------- -Library: rack-protection v1.5.5 -Url: http://github.com/rkh/rack-protection -License: MIT - -The MIT License (MIT) - -Copyright (c) 2011-2017 Konstantin Haase -Copyright (c) 2015-2017 Zachary Scott - -Permission is hereby granted, free of charge, to any person obtaining -a copy of this software and associated documentation files (the -'Software'), to deal in the Software without restriction, including -without limitation the rights to use, copy, modify, merge, publish, -distribute, sublicense, and/or sell copies of the Software, and to -permit persons to whom the Software is furnished to do so, subject to -the following conditions: - -The above copyright notice and this permission notice shall be -included in all copies or substantial portions of the Software. - -THE SOFTWARE IS PROVIDED 'AS IS', WITHOUT WARRANTY OF ANY KIND, -EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF -MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. -IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY -CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, -TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE -SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. - --------------------------------------------------- -Library: rack v1.6.6 -Url: http://rack.github.io/ -License: MIT - -The MIT License (MIT) - -Copyright (C) 2007-2018 Christian Neukirchen - -Permission is hereby granted, free of charge, to any person obtaining a copy -of this software and associated documentation files (the "Software"), to -deal in the Software without restriction, including without limitation the -rights to use, copy, modify, merge, publish, distribute, sublicense, and/or -sell copies of the Software, and to permit persons to whom the Software is -furnished to do so, subject to the following conditions: - -The above copyright notice and this permission notice shall be included in -all copies or substantial portions of the Software. - -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL -THE AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER -IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN -CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. - --------------------------------------------------- -Library: rake v10.4.2 -Url: https://github.com/ruby/rake -License: MIT - -Copyright (c) Jim Weirich - -Permission is hereby granted, free of charge, to any person obtaining -a copy of this software and associated documentation files (the -"Software"), to deal in the Software without restriction, including -without limitation the rights to use, copy, modify, merge, publish, -distribute, sublicense, and/or sell copies of the Software, and to -permit persons to whom the Software is furnished to do so, subject to -the following conditions: - -The above copyright notice and this permission notice shall be -included in all copies or substantial portions of the Software. - -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, -EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF -MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND -NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE -LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION -OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION -WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. - - --------------------------------------------------- -Library: redis v3.3.5 -Url: https://github.com/redis/redis-rb -License: MIT - -Copyright (c) 2009 Ezra Zygmuntowicz - -Permission is hereby granted, free of charge, to any person obtaining -a copy of this software and associated documentation files (the -"Software"), to deal in the Software without restriction, including -without limitation the rights to use, copy, modify, merge, publish, -distribute, sublicense, and/or sell copies of the Software, and to -permit persons to whom the Software is furnished to do so, subject to -the following conditions: - -The above copyright notice and this permission notice shall be -included in all copies or substantial portions of the Software. - -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, -EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF -MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND -NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE -LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION -OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION -WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. - --------------------------------------------------- -Library: rspec-core v3.7.1 -Url: https://github.com/rspec/rspec-core -License: MIT - -The MIT License (MIT) -===================== - -* Copyright © 2012 Chad Humphries, David Chelimsky, Myron Marston -* Copyright © 2009 Chad Humphries, David Chelimsky -* Copyright © 2006 David Chelimsky, The RSpec Development Team -* Copyright © 2005 Steven Baker - -Permission is hereby granted, free of charge, to any person obtaining -a copy of this software and associated documentation files (the -"Software"), to deal in the Software without restriction, including -without limitation the rights to use, copy, modify, merge, publish, -distribute, sublicense, and/or sell copies of the Software, and to -permit persons to whom the Software is furnished to do so, subject to -the following conditions: - -The above copyright notice and this permission notice shall be -included in all copies or substantial portions of the Software. - -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, -EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF -MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. -IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY -CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, -TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE -SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. - --------------------------------------------------- -Library: rspec-expectations v3.7.0 -Url: https://github.com/rspec/rspec-expectations -License: MIT - -The MIT License (MIT) -===================== - -* Copyright © 2012 David Chelimsky, Myron Marston -* Copyright © 2006 David Chelimsky, The RSpec Development Team -* Copyright © 2005 Steven Baker - -Permission is hereby granted, free of charge, to any person obtaining -a copy of this software and associated documentation files (the -"Software"), to deal in the Software without restriction, including -without limitation the rights to use, copy, modify, merge, publish, -distribute, sublicense, and/or sell copies of the Software, and to -permit persons to whom the Software is furnished to do so, subject to -the following conditions: - -The above copyright notice and this permission notice shall be -included in all copies or substantial portions of the Software. - -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, -EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF -MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. -IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY -CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, -TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE -SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. - --------------------------------------------------- -Library: rspec-mocks v3.7.0 -Url: https://github.com/rspec/rspec-mocks -License: MIT - -The MIT License (MIT) -===================== - -* Copyright © 2012 David Chelimsky, Myron Marston -* Copyright © 2006 David Chelimsky, The RSpec Development Team -* Copyright © 2005 Steven Baker - -Permission is hereby granted, free of charge, to any person obtaining -a copy of this software and associated documentation files (the -"Software"), to deal in the Software without restriction, including -without limitation the rights to use, copy, modify, merge, publish, -distribute, sublicense, and/or sell copies of the Software, and to -permit persons to whom the Software is furnished to do so, subject to -the following conditions: - -The above copyright notice and this permission notice shall be -included in all copies or substantial portions of the Software. - -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, -EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF -MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. -IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY -CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, -TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE -SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. - --------------------------------------------------- -Library: rspec-sequencing v0.1.0 -Url: https://github.com/elastic/rspec-sequencing -License: Apache-2.0 - -Copyright (c) 2016 Elasticsearch - - Apache License - Version 2.0, January 2004 - http://www.apache.org/licenses/ - - TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION - - 1. Definitions. - - "License" shall mean the terms and conditions for use, reproduction, - and distribution as defined by Sections 1 through 9 of this document. - - "Licensor" shall mean the copyright owner or entity authorized by - the copyright owner that is granting the License. - - "Legal Entity" shall mean the union of the acting entity and all - other entities that control, are controlled by, or are under common - control with that entity. For the purposes of this definition, - "control" means (i) the power, direct or indirect, to cause the - direction or management of such entity, whether by contract or - otherwise, or (ii) ownership of fifty percent (50%) or more of the - outstanding shares, or (iii) beneficial ownership of such entity. - - "You" (or "Your") shall mean an individual or Legal Entity - exercising permissions granted by this License. - - "Source" form shall mean the preferred form for making modifications, - including but not limited to software source code, documentation - source, and configuration files. - - "Object" form shall mean any form resulting from mechanical - transformation or translation of a Source form, including but - not limited to compiled object code, generated documentation, - and conversions to other media types. - - "Work" shall mean the work of authorship, whether in Source or - Object form, made available under the License, as indicated by a - copyright notice that is included in or attached to the work - (an example is provided in the Appendix below). - - "Derivative Works" shall mean any work, whether in Source or Object - form, that is based on (or derived from) the Work and for which the - editorial revisions, annotations, elaborations, or other modifications - represent, as a whole, an original work of authorship. For the purposes - of this License, Derivative Works shall not include works that remain - separable from, or merely link (or bind by name) to the interfaces of, - the Work and Derivative Works thereof. - - "Contribution" shall mean any work of authorship, including - the original version of the Work and any modifications or additions - to that Work or Derivative Works thereof, that is intentionally - submitted to Licensor for inclusion in the Work by the copyright owner - or by an individual or Legal Entity authorized to submit on behalf of - the copyright owner. For the purposes of this definition, "submitted" - means any form of electronic, verbal, or written communication sent - to the Licensor or its representatives, including but not limited to - communication on electronic mailing lists, source code control systems, - and issue tracking systems that are managed by, or on behalf of, the - Licensor for the purpose of discussing and improving the Work, but - excluding communication that is conspicuously marked or otherwise - designated in writing by the copyright owner as "Not a Contribution." - - "Contributor" shall mean Licensor and any individual or Legal Entity - on behalf of whom a Contribution has been received by Licensor and - subsequently incorporated within the Work. - - 2. Grant of Copyright License. Subject to the terms and conditions of - this License, each Contributor hereby grants to You a perpetual, - worldwide, non-exclusive, no-charge, royalty-free, irrevocable - copyright license to reproduce, prepare Derivative Works of, - publicly display, publicly perform, sublicense, and distribute the - Work and such Derivative Works in Source or Object form. - - 3. Grant of Patent License. Subject to the terms and conditions of - this License, each Contributor hereby grants to You a perpetual, - worldwide, non-exclusive, no-charge, royalty-free, irrevocable - (except as stated in this section) patent license to make, have made, - use, offer to sell, sell, import, and otherwise transfer the Work, - where such license applies only to those patent claims licensable - by such Contributor that are necessarily infringed by their - Contribution(s) alone or by combination of their Contribution(s) - with the Work to which such Contribution(s) was submitted. If You - institute patent litigation against any entity (including a - cross-claim or counterclaim in a lawsuit) alleging that the Work - or a Contribution incorporated within the Work constitutes direct - or contributory patent infringement, then any patent licenses - granted to You under this License for that Work shall terminate - as of the date such litigation is filed. - - 4. Redistribution. You may reproduce and distribute copies of the - Work or Derivative Works thereof in any medium, with or without - modifications, and in Source or Object form, provided that You - meet the following conditions: - - (a) You must give any other recipients of the Work or - Derivative Works a copy of this License; and - - (b) You must cause any modified files to carry prominent notices - stating that You changed the files; and - - (c) You must retain, in the Source form of any Derivative Works - that You distribute, all copyright, patent, trademark, and - attribution notices from the Source form of the Work, - excluding those notices that do not pertain to any part of - the Derivative Works; and - - (d) If the Work includes a "NOTICE" text file as part of its - distribution, then any Derivative Works that You distribute must - include a readable copy of the attribution notices contained - within such NOTICE file, excluding those notices that do not - pertain to any part of the Derivative Works, in at least one - of the following places: within a NOTICE text file distributed - as part of the Derivative Works; within the Source form or - documentation, if provided along with the Derivative Works; or, - within a display generated by the Derivative Works, if and - wherever such third-party notices normally appear. The contents - of the NOTICE file are for informational purposes only and - do not modify the License. You may add Your own attribution - notices within Derivative Works that You distribute, alongside - or as an addendum to the NOTICE text from the Work, provided - that such additional attribution notices cannot be construed - as modifying the License. - - You may add Your own copyright statement to Your modifications and - may provide additional or different license terms and conditions - for use, reproduction, or distribution of Your modifications, or - for any such Derivative Works as a whole, provided Your use, - reproduction, and distribution of the Work otherwise complies with - the conditions stated in this License. - - 5. Submission of Contributions. Unless You explicitly state otherwise, - any Contribution intentionally submitted for inclusion in the Work - by You to the Licensor shall be under the terms and conditions of - this License, without any additional terms or conditions. - Notwithstanding the above, nothing herein shall supersede or modify - the terms of any separate license agreement you may have executed - with Licensor regarding such Contributions. - - 6. Trademarks. This License does not grant permission to use the trade - names, trademarks, service marks, or product names of the Licensor, - except as required for reasonable and customary use in describing the - origin of the Work and reproducing the content of the NOTICE file. - - 7. Disclaimer of Warranty. Unless required by applicable law or - agreed to in writing, Licensor provides the Work (and each - Contributor provides its Contributions) on an "AS IS" BASIS, - WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or - implied, including, without limitation, any warranties or conditions - of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A - PARTICULAR PURPOSE. You are solely responsible for determining the - appropriateness of using or redistributing the Work and assume any - risks associated with Your exercise of permissions under this License. - - 8. Limitation of Liability. In no event and under no legal theory, - whether in tort (including negligence), contract, or otherwise, - unless required by applicable law (such as deliberate and grossly - negligent acts) or agreed to in writing, shall any Contributor be - liable to You for damages, including any direct, indirect, special, - incidental, or consequential damages of any character arising as a - result of this License or out of the use or inability to use the - Work (including but not limited to damages for loss of goodwill, - work stoppage, computer failure or malfunction, or any and all - other commercial damages or losses), even if such Contributor - has been advised of the possibility of such damages. - - 9. Accepting Warranty or Additional Liability. While redistributing - the Work or Derivative Works thereof, You may choose to offer, - and charge a fee for, acceptance of support, warranty, indemnity, - or other liability obligations and/or rights consistent with this - License. However, in accepting such obligations, You may act only - on Your own behalf and on Your sole responsibility, not on behalf - of any other Contributor, and only if You agree to indemnify, - defend, and hold each Contributor harmless for any liability - incurred by, or claims asserted against, such Contributor by reason - of your accepting any such warranty or additional liability. - - END OF TERMS AND CONDITIONS - - APPENDIX: How to apply the Apache License to your work. - - To apply the Apache License to your work, attach the following - boilerplate notice, with the fields enclosed by brackets "{}" - replaced with your own identifying information. (Don't include - the brackets!) The text should be enclosed in the appropriate - comment syntax for the file format. We also recommend that a - file or class name and description of purpose be included on the - same "printed page" as the copyright notice for easier - identification within third-party archives. - - Licensed 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. - - --------------------------------------------------- -Library: rspec-support v3.7.1 -Url: https://github.com/rspec/rspec-support -License: MIT - -* Copyright © 2013 David Chelimsky, Myron Marston, Jon Rowe, Sam Phippen, Xavier Shay, Bradley Schaefer - -Permission is hereby granted, free of charge, to any person obtaining -a copy of this software and associated documentation files (the -"Software"), to deal in the Software without restriction, including -without limitation the rights to use, copy, modify, merge, publish, -distribute, sublicense, and/or sell copies of the Software, and to -permit persons to whom the Software is furnished to do so, subject to -the following conditions: - -The above copyright notice and this permission notice shall be -included in all copies or substantial portions of the Software. - -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, -EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF -MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND -NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE -LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION -OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION -WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. - --------------------------------------------------- -Library: rspec-wait v0.0.9 -Url: https://github.com/laserlemon/rspec-wait -License: MIT - -Copyright (c) 2014 Steve Richert - -MIT License - -Permission is hereby granted, free of charge, to any person obtaining -a copy of this software and associated documentation files (the -"Software"), to deal in the Software without restriction, including -without limitation the rights to use, copy, modify, merge, publish, -distribute, sublicense, and/or sell copies of the Software, and to -permit persons to whom the Software is furnished to do so, subject to -the following conditions: - -The above copyright notice and this permission notice shall be -included in all copies or substantial portions of the Software. - -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, -EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF -MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND -NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE -LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION -OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION -WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. - --------------------------------------------------- -Library: rspec v3.7.0 -Url: https://github.com/rspec/rspec -License: MIT - -Copyright © 2009 Chad Humphries, David Chelimsky -Copyright © 2006 David Chelimsky, The RSpec Development Team -Copyright © 2005 Steven Baker - -Permission is hereby granted, free of charge, to any person -obtaining a copy of this software and associated documentation -files (the “Software”), to deal in the Software without -restriction, including without limitation the rights to use, -copy, modify, merge, publish, distribute, sublicense, and/or sell -copies of the Software, and to permit persons to whom the -Software is furnished to do so, subject to the following -conditions: - -The above copyright notice and this permission notice shall be -included in all copies or substantial portions of the Software. - -THE SOFTWARE IS PROVIDED “AS IS”, WITHOUT WARRANTY OF ANY KIND, -EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES -OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND -NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT -HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, -WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING -FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR -OTHER DEALINGS IN THE SOFTWARE. - --------------------------------------------------- -Library: ruby-progressbar v1.8.3 -Url: https://github.com/jfelchner/ruby-progressbar -License: MIT - -Copyright (c) 2010-2016 The Kompanee, Ltd - -Permission is hereby granted, free of charge, to any person obtaining a copy -of this software and associated documentation files (the "Software"), to deal -in the Software without restriction, including without limitation the rights -to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -copies of the Software, and to permit persons to whom the Software is -furnished to do so, subject to the following conditions: - -The above copyright notice and this permission notice shall be included in -all copies or substantial portions of the Software. - -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN -THE SOFTWARE. - --------------------------------------------------- -Library: rubyzip v1.2.1 -Url: https://github.com/rubyzip/rubyzip -License: BSD-2-Clause-FreeBSD - -Authors: - -* Alexander Simonov ( alex at simonov.me) -* Alan Harper ( alan at aussiegeek.net) -* Thomas Sondergaard (thomas at sondergaard.cc) -* Technorama Ltd. (oss-ruby-zip at technorama.net) -* extra-field support contributed by Tatsuki Sugiura (sugi at nemui.org) - -Rubyzip is distributed under the same license as ruby. See http://www.ruby-lang.org/en/LICENSE.txt: - -Ruby is copyrighted free software by Yukihiro Matsumoto . -You can redistribute it and/or modify it under either the terms of the -2-clause BSDL (see the file BSDL), or the conditions below: - - 1. You may make and give away verbatim copies of the source form of the - software without restriction, provided that you duplicate all of the - original copyright notices and associated disclaimers. - - 2. You may modify your copy of the software in any way, provided that - you do at least ONE of the following: - - a) place your modifications in the Public Domain or otherwise - make them Freely Available, such as by posting said - modifications to Usenet or an equivalent medium, or by allowing - the author to include your modifications in the software. - - b) use the modified software only within your corporation or - organization. - - c) give non-standard binaries non-standard names, with - instructions on where to get the original software distribution. - - d) make other distribution arrangements with the author. - - 3. You may distribute the software in object code or binary form, - provided that you do at least ONE of the following: - - a) distribute the binaries and library files of the software, - together with instructions (in the manual page or equivalent) - on where to get the original distribution. - - b) accompany the distribution with the machine-readable source of - the software. - - c) give non-standard binaries non-standard names, with - instructions on where to get the original software distribution. - - d) make other distribution arrangements with the author. - - 4. You may modify and include the part of the software into any other - software (possibly commercial). But some files in the distribution - are not written by the author, so that they are not under these terms. - - For the list of those files and their copying conditions, see the - file LEGAL. - - 5. The scripts and library files supplied as input to or produced as - output from the software do not automatically fall under the - copyright of the software, but belong to whomever generated them, - and may be sold commercially, and may be aggregated with this - software. - - 6. THIS SOFTWARE IS PROVIDED "AS IS" AND WITHOUT ANY EXPRESS OR - IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED - WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR - PURPOSE. - --------------------------------------------------- -Library: rumbster v1.1.0 -Url: https://github.com/aesterline/rumbster -License: Apache-2.0 - -Copyright (c) 2011 Adam Esterline. See LICENSE.txt for further details. - -Licensed 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. - --------------------------------------------------- -Library: safe_yaml v1.0.4 -Url: https://github.com/dtao/safe_yaml -License: MIT - -Copyright (c) 2013 Dan Tao - -MIT License - -Permission is hereby granted, free of charge, to any person obtaining -a copy of this software and associated documentation files (the -"Software"), to deal in the Software without restriction, including -without limitation the rights to use, copy, modify, merge, publish, -distribute, sublicense, and/or sell copies of the Software, and to -permit persons to whom the Software is furnished to do so, subject to -the following conditions: - -The above copyright notice and this permission notice shall be -included in all copies or substantial portions of the Software. - -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, -EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF -MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND -NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE -LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION -OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION -WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. - --------------------------------------------------- -Library: sequel v5.7.1 -Url: https://github.com/jeremyevans/sequel -License: MIT - -Copyright (c) 2007-2008 Sharon Rosner -Copyright (c) 2008-2018 Jeremy Evans - -Permission is hereby granted, free of charge, to any person obtaining a copy -of this software and associated documentation files (the "Software"), to -deal in the Software without restriction, including without limitation the -rights to use, copy, modify, merge, publish, distribute, sublicense, and/or -sell copies of the Software, and to permit persons to whom the Software is -furnished to do so, subject to the following conditions: - -The above copyright notice and this permission notice shall be included in -all copies or substantial portions of the Software. - -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL -THE AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER -IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN -CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. - --------------------------------------------------- -Library: simple_oauth v0.3.1 -Url: https://github.com/laserlemon/simple_oauth -License: MIT - -Copyright (c) 2010-2013 Steve Richert, Erik Michaels-Ober - -Permission is hereby granted, free of charge, to any person obtaining -a copy of this software and associated documentation files (the -"Software"), to deal in the Software without restriction, including -without limitation the rights to use, copy, modify, merge, publish, -distribute, sublicense, and/or sell copies of the Software, and to -permit persons to whom the Software is furnished to do so, subject to -the following conditions: - -The above copyright notice and this permission notice shall be -included in all copies or substantial portions of the Software. - -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, -EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF -MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND -NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE -LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION -OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION -WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. - --------------------------------------------------- -Library: sinatra v1.4.8 -Url: https://github.com/sinatra/sinatra -License: MIT - -Copyright (c) 2007, 2008, 2009 Blake Mizerany -Copyright (c) 2010, 2011, 2012, 2013, 2014, 2015, 2016 Konstantin Haase - -Permission is hereby granted, free of charge, to any person -obtaining a copy of this software and associated documentation -files (the "Software"), to deal in the Software without -restriction, including without limitation the rights to use, -copy, modify, merge, publish, distribute, sublicense, and/or sell -copies of the Software, and to permit persons to whom the -Software is furnished to do so, subject to the following -conditions: - -The above copyright notice and this permission notice shall be -included in all copies or substantial portions of the Software. - -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, -EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES -OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND -NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT -HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, -WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING -FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR -OTHER DEALINGS IN THE SOFTWARE. - --------------------------------------------------- -Library: slop v3.6.0 -Url: https://github.com/leejarvis/slop -License: MIT - -Copyright (c) 2012 Lee Jarvis - -Permission is hereby granted, free of charge, to any person obtaining -a copy of this software and associated documentation files (the -"Software"), to deal in the Software without restriction, including -without limitation the rights to use, copy, modify, merge, publish, -distribute, sublicense, and/or sell copies of the Software, and to -permit persons to whom the Software is furnished to do so, subject to -the following conditions: - -The above copyright notice and this permission notice shall be -included in all copies or substantial portions of the Software. - -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, -EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF -MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND -NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE -LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION -OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION -WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. - --------------------------------------------------- -Library: snakeyaml v1.18 -Url: https://bitbucket.org/asomov/snakeyaml/ -License: Apache-2.0 - -Copyright (c) 2008, http://www.snakeyaml.org - -Licensed 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. - --------------------------------------------------- -Library: snappy-jars v1.1.0.1.2 -Url: https://github.com/doxavore/snappy-jars -License: Apache-2.0 - -Copyright Doug Mayer (https://github.com/doxavore) - -README.md: "Per the real implementation, Apache License v2.0." - -Licensed 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. - --------------------------------------------------- -Library: snappy v0.0.12 -Url: https://github.com/miyucy/snappy -License: MIT - -Copyright (c) 2011-2013 miyucy - -MIT License - -Permission is hereby granted, free of charge, to any person obtaining -a copy of this software and associated documentation files (the -"Software"), to deal in the Software without restriction, including -without limitation the rights to use, copy, modify, merge, publish, -distribute, sublicense, and/or sell copies of the Software, and to -permit persons to whom the Software is furnished to do so, subject to -the following conditions: - -The above copyright notice and this permission notice shall be -included in all copies or substantial portions of the Software. - -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, -EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF -MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND -NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE -LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION -OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION -WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. - --------------------------------------------------- -Library: snmp v1.2.0 -Url: https://github.com/hallidave/ruby-snmp -License: MIT - -Copyright (c) 2004-2014 David R. Halliday - -Permission is hereby granted, free of charge, to any person obtaining a copy -of this software and associated documentation files (the "Software"), to deal -in the Software without restriction, including without limitation the rights -to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -copies of the Software, and to permit persons to whom the Software is -furnished to do so, subject to the following conditions: - -The above copyright notice and this permission notice shall be included in -all copies or substantial portions of the Software. - -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN -THE SOFTWARE. - --------------------------------------------------- -Library: spoon v0.0.6 -Url: https://github.com/headius/spoon -License: Apache-2.0 - -Apache License - -Version 2.0, January 2004 - -http://www.apache.org/licenses/ - -TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION - -1. Definitions. - -"License" shall mean the terms and conditions for use, reproduction, and distribution as -defined by Sections 1 through 9 of this document. - -"Licensor" shall mean the copyright owner or entity authorized by the copyright owner that -is granting the License. - -"Legal Entity" shall mean the union of the acting entity and all other entities that -control, are controlled by, or are under common control with that entity. For the purposes -of this definition, "control" means (i) the power, direct or indirect, to cause the -direction or management of such entity, whether by contract or otherwise, or (ii) ownership -of fifty percent (50%) or more of the outstanding shares, or (iii) beneficial ownership of -such entity. - -"You" (or "Your") shall mean an individual or Legal Entity exercising permissions granted by -this License. - -"Source" form shall mean the preferred form for making modifications, including but not -limited to software source code, documentation source, and configuration files. - -"Object" form shall mean any form resulting from mechanical transformation or translation of -a Source form, including but not limited to compiled object code, generated documentation, -and conversions to other media types. - -"Work" shall mean the work of authorship, whether in Source or Object form, made available -under the License, as indicated by a copyright notice that is included in or attached to the -work (an example is provided in the Appendix below). - -"Derivative Works" shall mean any work, whether in Source or Object form, that is based on -(or derived from) the Work and for which the editorial revisions, annotations, elaborations, -or other modifications represent, as a whole, an original work of authorship. For the -purposes of this License, Derivative Works shall not include works that remain separable -from, or merely link (or bind by name) to the interfaces of, the Work and Derivative Works -thereof. - -"Contribution" shall mean any work of authorship, including the original version of the Work -and any modifications or additions to that Work or Derivative Works thereof, that is -intentionally submitted to Licensor for inclusion in the Work by the copyright owner or by -an individual or Legal Entity authorized to submit on behalf of the copyright owner. For the -purposes of this definition, "submitted" means any form of electronic, verbal, or written -communication sent to the Licensor or its representatives, including but not limited to -communication on electronic mailing lists, source code control systems, and issue tracking -systems that are managed by, or on behalf of, the Licensor for the purpose of discussing and -improving the Work, but excluding communication that is conspicuously marked or otherwise -designated in writing by the copyright owner as "Not a Contribution." - -"Contributor" shall mean Licensor and any individual or Legal Entity on behalf of whom a -Contribution has been received by Licensor and subsequently incorporated within the Work. - -2. Grant of Copyright License. Subject to the terms and conditions of this License, each -Contributor hereby grants to You a perpetual, worldwide, non-exclusive, no-charge, -royalty-free, irrevocable copyright license to reproduce, prepare Derivative Works of, -publicly display, publicly perform, sublicense, and distribute the Work and such Derivative -Works in Source or Object form. - -3. Grant of Patent License. Subject to the terms and conditions of this License, each -Contributor hereby grants to You a perpetual, worldwide, non-exclusive, no-charge, -royalty-free, irrevocable (except as stated in this section) patent license to make, have -made, use, offer to sell, sell, import, and otherwise transfer the Work, where such license -applies only to those patent claims licensable by such Contributor that are necessarily -infringed by their Contribution(s) alone or by combination of their Contribution(s) with the -Work to which such Contribution(s) was submitted. If You institute patent litigation against -any entity (including a cross-claim or counterclaim in a lawsuit) alleging that the Work or -a Contribution incorporated within the Work constitutes direct or contributory patent -infringement, then any patent licenses granted to You under this License for that Work shall -terminate as of the date such litigation is filed. - -4. Redistribution. You may reproduce and distribute copies of the Work or Derivative Works -thereof in any medium, with or without modifications, and in Source or Object form, provided -that You meet the following conditions: - -You must give any other recipients of the Work or Derivative Works a copy of this License; -and - -You must cause any modified files to carry prominent notices stating that You changed the -files; and - -You must retain, in the Source form of any Derivative Works that You distribute, all -copyright, patent, trademark, and attribution notices from the Source form of the Work, -excluding those notices that do not pertain to any part of the Derivative Works; and - -If the Work includes a "NOTICE" text file as part of its distribution, then any Derivative -Works that You distribute must include a readable copy of the attribution notices contained -within such NOTICE file, excluding those notices that do not pertain to any part of the -Derivative Works, in at least one of the following places: within a NOTICE text file -distributed as part of the Derivative Works; within the Source form or documentation, if -provided along with the Derivative Works; or, within a display generated by the Derivative -Works, if and wherever such third-party notices normally appear. The contents of the NOTICE -file are for informational purposes only and do not modify the License. You may add Your own -attribution notices within Derivative Works that You distribute, alongside or as an addendum -to the NOTICE text from the Work, provided that such additional attribution notices cannot -be construed as modifying the License. You may add Your own copyright statement to Your -modifications and may provide additional or different license terms and conditions for use, -reproduction, or distribution of Your modifications, or for any such Derivative Works as a -whole, provided Your use, reproduction, and distribution of the Work otherwise complies with -the conditions stated in this License. - -5. Submission of Contributions. Unless You explicitly state otherwise, any Contribution -intentionally submitted for inclusion in the Work by You to the Licensor shall be under the -terms and conditions of this License, without any additional terms or conditions. -Notwithstanding the above, nothing herein shall supersede or modify the terms of any -separate license agreement you may have executed with Licensor regarding such Contributions. - -6. Trademarks. This License does not grant permission to use the trade names, trademarks, -service marks, or product names of the Licensor, except as required for reasonable and -customary use in describing the origin of the Work and reproducing the content of the NOTICE -file. - -7. Disclaimer of Warranty. Unless required by applicable law or agreed to in writing, -Licensor provides the Work (and each Contributor provides its Contributions) on an "AS IS" -BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied, including, -without limitation, any warranties or conditions of TITLE, NON-INFRINGEMENT, -MERCHANTABILITY, or FITNESS FOR A PARTICULAR PURPOSE. You are solely responsible for -determining the appropriateness of using or redistributing the Work and assume any risks -associated with Your exercise of permissions under this License. - -8. Limitation of Liability. In no event and under no legal theory, whether in tort -(including negligence), contract, or otherwise, unless required by applicable law (such as -deliberate and grossly negligent acts) or agreed to in writing, shall any Contributor be -liable to You for damages, including any direct, indirect, special, incidental, or -consequential damages of any character arising as a result of this License or out of the use -or inability to use the Work (including but not limited to damages for loss of goodwill, -work stoppage, computer failure or malfunction, or any and all other commercial damages or -losses), even if such Contributor has been advised of the possibility of such damages. - -9. Accepting Warranty or Additional Liability. While redistributing the Work or Derivative -Works thereof, You may choose to offer, and charge a fee for, acceptance of support, -warranty, indemnity, or other liability obligations and/or rights consistent with this -License. However, in accepting such obligations, You may act only on Your own behalf and on -Your sole responsibility, not on behalf of any other Contributor, and only if You agree to -indemnify, defend, and hold each Contributor harmless for any liability incurred by, or -claims asserted against, such Contributor by reason of your accepting any such warranty or -additional liability. - -END OF TERMS AND CONDITIONS - --------------------------------------------------- -Library: stud v0.0.23 -Url: https://github.com/jordansissel/ruby-stud -License: Apache-2.0 - -Copyright 2012-2013 Jordan Sissel and contributors. - -Licensed 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. - --------------------------------------------------- -Library: thread_safe v0.3.6 -Url: https://github.com/ruby-concurrency/thread_safe -License: Apache-2.0 - -Apache License - -Version 2.0, January 2004 - -http://www.apache.org/licenses/ - -TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION - -1. Definitions. - -"License" shall mean the terms and conditions for use, reproduction, and distribution as -defined by Sections 1 through 9 of this document. - -"Licensor" shall mean the copyright owner or entity authorized by the copyright owner that -is granting the License. - -"Legal Entity" shall mean the union of the acting entity and all other entities that -control, are controlled by, or are under common control with that entity. For the purposes -of this definition, "control" means (i) the power, direct or indirect, to cause the -direction or management of such entity, whether by contract or otherwise, or (ii) ownership -of fifty percent (50%) or more of the outstanding shares, or (iii) beneficial ownership of -such entity. - -"You" (or "Your") shall mean an individual or Legal Entity exercising permissions granted by -this License. - -"Source" form shall mean the preferred form for making modifications, including but not -limited to software source code, documentation source, and configuration files. - -"Object" form shall mean any form resulting from mechanical transformation or translation of -a Source form, including but not limited to compiled object code, generated documentation, -and conversions to other media types. - -"Work" shall mean the work of authorship, whether in Source or Object form, made available -under the License, as indicated by a copyright notice that is included in or attached to the -work (an example is provided in the Appendix below). - -"Derivative Works" shall mean any work, whether in Source or Object form, that is based on -(or derived from) the Work and for which the editorial revisions, annotations, elaborations, -or other modifications represent, as a whole, an original work of authorship. For the -purposes of this License, Derivative Works shall not include works that remain separable -from, or merely link (or bind by name) to the interfaces of, the Work and Derivative Works -thereof. - -"Contribution" shall mean any work of authorship, including the original version of the Work -and any modifications or additions to that Work or Derivative Works thereof, that is -intentionally submitted to Licensor for inclusion in the Work by the copyright owner or by -an individual or Legal Entity authorized to submit on behalf of the copyright owner. For the -purposes of this definition, "submitted" means any form of electronic, verbal, or written -communication sent to the Licensor or its representatives, including but not limited to -communication on electronic mailing lists, source code control systems, and issue tracking -systems that are managed by, or on behalf of, the Licensor for the purpose of discussing and -improving the Work, but excluding communication that is conspicuously marked or otherwise -designated in writing by the copyright owner as "Not a Contribution." - -"Contributor" shall mean Licensor and any individual or Legal Entity on behalf of whom a -Contribution has been received by Licensor and subsequently incorporated within the Work. - -2. Grant of Copyright License. Subject to the terms and conditions of this License, each -Contributor hereby grants to You a perpetual, worldwide, non-exclusive, no-charge, -royalty-free, irrevocable copyright license to reproduce, prepare Derivative Works of, -publicly display, publicly perform, sublicense, and distribute the Work and such Derivative -Works in Source or Object form. - -3. Grant of Patent License. Subject to the terms and conditions of this License, each -Contributor hereby grants to You a perpetual, worldwide, non-exclusive, no-charge, -royalty-free, irrevocable (except as stated in this section) patent license to make, have -made, use, offer to sell, sell, import, and otherwise transfer the Work, where such license -applies only to those patent claims licensable by such Contributor that are necessarily -infringed by their Contribution(s) alone or by combination of their Contribution(s) with the -Work to which such Contribution(s) was submitted. If You institute patent litigation against -any entity (including a cross-claim or counterclaim in a lawsuit) alleging that the Work or -a Contribution incorporated within the Work constitutes direct or contributory patent -infringement, then any patent licenses granted to You under this License for that Work shall -terminate as of the date such litigation is filed. - -4. Redistribution. You may reproduce and distribute copies of the Work or Derivative Works -thereof in any medium, with or without modifications, and in Source or Object form, provided -that You meet the following conditions: - -You must give any other recipients of the Work or Derivative Works a copy of this License; -and - -You must cause any modified files to carry prominent notices stating that You changed the -files; and - -You must retain, in the Source form of any Derivative Works that You distribute, all -copyright, patent, trademark, and attribution notices from the Source form of the Work, -excluding those notices that do not pertain to any part of the Derivative Works; and - -If the Work includes a "NOTICE" text file as part of its distribution, then any Derivative -Works that You distribute must include a readable copy of the attribution notices contained -within such NOTICE file, excluding those notices that do not pertain to any part of the -Derivative Works, in at least one of the following places: within a NOTICE text file -distributed as part of the Derivative Works; within the Source form or documentation, if -provided along with the Derivative Works; or, within a display generated by the Derivative -Works, if and wherever such third-party notices normally appear. The contents of the NOTICE -file are for informational purposes only and do not modify the License. You may add Your own -attribution notices within Derivative Works that You distribute, alongside or as an addendum -to the NOTICE text from the Work, provided that such additional attribution notices cannot -be construed as modifying the License. You may add Your own copyright statement to Your -modifications and may provide additional or different license terms and conditions for use, -reproduction, or distribution of Your modifications, or for any such Derivative Works as a -whole, provided Your use, reproduction, and distribution of the Work otherwise complies with -the conditions stated in this License. - -5. Submission of Contributions. Unless You explicitly state otherwise, any Contribution -intentionally submitted for inclusion in the Work by You to the Licensor shall be under the -terms and conditions of this License, without any additional terms or conditions. -Notwithstanding the above, nothing herein shall supersede or modify the terms of any -separate license agreement you may have executed with Licensor regarding such Contributions. - -6. Trademarks. This License does not grant permission to use the trade names, trademarks, -service marks, or product names of the Licensor, except as required for reasonable and -customary use in describing the origin of the Work and reproducing the content of the NOTICE -file. - -7. Disclaimer of Warranty. Unless required by applicable law or agreed to in writing, -Licensor provides the Work (and each Contributor provides its Contributions) on an "AS IS" -BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied, including, -without limitation, any warranties or conditions of TITLE, NON-INFRINGEMENT, -MERCHANTABILITY, or FITNESS FOR A PARTICULAR PURPOSE. You are solely responsible for -determining the appropriateness of using or redistributing the Work and assume any risks -associated with Your exercise of permissions under this License. - -8. Limitation of Liability. In no event and under no legal theory, whether in tort -(including negligence), contract, or otherwise, unless required by applicable law (such as -deliberate and grossly negligent acts) or agreed to in writing, shall any Contributor be -liable to You for damages, including any direct, indirect, special, incidental, or -consequential damages of any character arising as a result of this License or out of the use -or inability to use the Work (including but not limited to damages for loss of goodwill, -work stoppage, computer failure or malfunction, or any and all other commercial damages or -losses), even if such Contributor has been advised of the possibility of such damages. - -9. Accepting Warranty or Additional Liability. While redistributing the Work or Derivative -Works thereof, You may choose to offer, and charge a fee for, acceptance of support, -warranty, indemnity, or other liability obligations and/or rights consistent with this -License. However, in accepting such obligations, You may act only on Your own behalf and on -Your sole responsibility, not on behalf of any other Contributor, and only if You agree to -indemnify, defend, and hold each Contributor harmless for any liability incurred by, or -claims asserted against, such Contributor by reason of your accepting any such warranty or -additional liability. - -END OF TERMS AND CONDITIONS - --------------------------------------------------- -Library: tilt v2.0.8 -Url: https://github.com/rtomayko/tilt -License: MIT - -Copyright (c) 2010-2016 Ryan Tomayko - -Permission is hereby granted, free of charge, to any person obtaining a copy -of this software and associated documentation files (the "Software"), to -deal in the Software without restriction, including without limitation the -rights to use, copy, modify, merge, publish, distribute, sublicense, and/or -sell copies of the Software, and to permit persons to whom the Software is -furnished to do so, subject to the following conditions: - -The above copyright notice and this permission notice shall be included in -all copies or substantial portions of the Software. - -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL -THE AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER -IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN -CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. - --------------------------------------------------- -Library: timecop v0.9.1 -Url: https://github.com/travisjeffery/timecop -License: MIT - -(The MIT License) - -Copyright (c) 2012 — Travis Jeffery, John Trupiano - -Permission is hereby granted, free of charge, to any person obtaining -a copy of this software and associated documentation files (the -'Software'), to deal in the Software without restriction, including -without limitation the rights to use, copy, modify, merge, publish, -distribute, sublicense, and/or sell copies of the Software, and to -permit persons to whom the Software is furnished to do so, subject to -the following conditions: - -The above copyright notice and this permission notice shall be -included in all copies or substantial portions of the Software. - -THE SOFTWARE IS PROVIDED 'AS IS', WITHOUT WARRANTY OF ANY KIND, -EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF -MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. -IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY -CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, -TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE -SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. - --------------------------------------------------- -Library: treetop v1.4.15 -Url: https://github.com/cjheath/treetop -License: MIT - -Copyright (c) 2007 Nathan Sobo. - -Permission is hereby granted, free of charge, to any person obtaining a copy -of this software and associated documentation files (the "Software"), to deal -in the Software without restriction, including without limitation the rights -to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -copies of the Software, and to permit persons to whom the Software is -furnished to do so, subject to the following conditions: - -The above copyright notice and this permission notice shall be included in -all copies or substantial portions of the Software. - -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN -THE SOFTWARE. - --------------------------------------------------- -Library: twitter v5.15.0 -Url: https://github.com/sferik/twitter -License: MIT - -Copyright (c) 2006-2015 Erik Michaels-Ober, John Nunemaker, Wynn Netherland, Steve Richert, Steve Agalloco - -Permission is hereby granted, free of charge, to any person obtaining -a copy of this software and associated documentation files (the -"Software"), to deal in the Software without restriction, including -without limitation the rights to use, copy, modify, merge, publish, -distribute, sublicense, and/or sell copies of the Software, and to -permit persons to whom the Software is furnished to do so, subject to -the following conditions: - -The above copyright notice and this permission notice shall be -included in all copies or substantial portions of the Software. - -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, -EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF -MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND -NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE -LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION -OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION -WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. - --------------------------------------------------- -Library: tzinfo-data v1.2018.4 -Url: https://github.com/tzinfo/tzinfo-data -License: MIT - -Copyright (c) 2005-2018 Philip Ross - -Permission is hereby granted, free of charge, to any person obtaining a copy of -this software and associated documentation files (the "Software"), to deal in -the Software without restriction, including without limitation the rights to -use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies -of the Software, and to permit persons to whom the Software is furnished to do -so, subject to the following conditions: - -The above copyright notice and this permission notice shall be included in all -copies or substantial portions of the Software. - -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN -THE SOFTWARE. - --------------------------------------------------- -Library: tzinfo v1.2.5 -Url: https://github.com/tzinfo/tzinfo -License: MIT - -Copyright (c) 2005-2018 Philip Ross - -Permission is hereby granted, free of charge, to any person obtaining a copy of -this software and associated documentation files (the "Software"), to deal in -the Software without restriction, including without limitation the rights to -use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies -of the Software, and to permit persons to whom the Software is furnished to do -so, subject to the following conditions: - -The above copyright notice and this permission notice shall be included in all -copies or substantial portions of the Software. - -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN -THE SOFTWARE. - --------------------------------------------------- -Library: unf v0.1.4 -Url: https://github.com/knu/ruby-unf -License: BSD-2-Clause - -Copyright (c) 2011, 2012 Akinori MUSHA - -All rights reserved. - -Redistribution and use in source and binary forms, with or without -modification, are permitted provided that the following conditions -are met: -1. Redistributions of source code must retain the above copyright - notice, this list of conditions and the following disclaimer. -2. Redistributions in binary form must reproduce the above copyright - notice, this list of conditions and the following disclaimer in the - documentation and/or other materials provided with the distribution. - -THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND -ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE -IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE -ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE -FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL -DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS -OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) -HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT -LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY -OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF -SUCH DAMAGE. - --------------------------------------------------- -Library: unsafe-fences v1.0 -Url: https://github.com/headius/unsafe-fences -License: Apache-2.0 - - - Apache License - Version 2.0, January 2004 - http://www.apache.org/licenses/ - - TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION - - 1. Definitions. - - "License" shall mean the terms and conditions for use, reproduction, - and distribution as defined by Sections 1 through 9 of this document. - - "Licensor" shall mean the copyright owner or entity authorized by - the copyright owner that is granting the License. - - "Legal Entity" shall mean the union of the acting entity and all - other entities that control, are controlled by, or are under common - control with that entity. For the purposes of this definition, - "control" means (i) the power, direct or indirect, to cause the - direction or management of such entity, whether by contract or - otherwise, or (ii) ownership of fifty percent (50%) or more of the - outstanding shares, or (iii) beneficial ownership of such entity. - - "You" (or "Your") shall mean an individual or Legal Entity - exercising permissions granted by this License. - - "Source" form shall mean the preferred form for making modifications, - including but not limited to software source code, documentation - source, and configuration files. - - "Object" form shall mean any form resulting from mechanical - transformation or translation of a Source form, including but - not limited to compiled object code, generated documentation, - and conversions to other media types. - - "Work" shall mean the work of authorship, whether in Source or - Object form, made available under the License, as indicated by a - copyright notice that is included in or attached to the work - (an example is provided in the Appendix below). - - "Derivative Works" shall mean any work, whether in Source or Object - form, that is based on (or derived from) the Work and for which the - editorial revisions, annotations, elaborations, or other modifications - represent, as a whole, an original work of authorship. For the purposes - of this License, Derivative Works shall not include works that remain - separable from, or merely link (or bind by name) to the interfaces of, - the Work and Derivative Works thereof. - - "Contribution" shall mean any work of authorship, including - the original version of the Work and any modifications or additions - to that Work or Derivative Works thereof, that is intentionally - submitted to Licensor for inclusion in the Work by the copyright owner - or by an individual or Legal Entity authorized to submit on behalf of - the copyright owner. For the purposes of this definition, "submitted" - means any form of electronic, verbal, or written communication sent - to the Licensor or its representatives, including but not limited to - communication on electronic mailing lists, source code control systems, - and issue tracking systems that are managed by, or on behalf of, the - Licensor for the purpose of discussing and improving the Work, but - excluding communication that is conspicuously marked or otherwise - designated in writing by the copyright owner as "Not a Contribution." - - "Contributor" shall mean Licensor and any individual or Legal Entity - on behalf of whom a Contribution has been received by Licensor and - subsequently incorporated within the Work. - - 2. Grant of Copyright License. Subject to the terms and conditions of - this License, each Contributor hereby grants to You a perpetual, - worldwide, non-exclusive, no-charge, royalty-free, irrevocable - copyright license to reproduce, prepare Derivative Works of, - publicly display, publicly perform, sublicense, and distribute the - Work and such Derivative Works in Source or Object form. - - 3. Grant of Patent License. Subject to the terms and conditions of - this License, each Contributor hereby grants to You a perpetual, - worldwide, non-exclusive, no-charge, royalty-free, irrevocable - (except as stated in this section) patent license to make, have made, - use, offer to sell, sell, import, and otherwise transfer the Work, - where such license applies only to those patent claims licensable - by such Contributor that are necessarily infringed by their - Contribution(s) alone or by combination of their Contribution(s) - with the Work to which such Contribution(s) was submitted. If You - institute patent litigation against any entity (including a - cross-claim or counterclaim in a lawsuit) alleging that the Work - or a Contribution incorporated within the Work constitutes direct - or contributory patent infringement, then any patent licenses - granted to You under this License for that Work shall terminate - as of the date such litigation is filed. - - 4. Redistribution. You may reproduce and distribute copies of the - Work or Derivative Works thereof in any medium, with or without - modifications, and in Source or Object form, provided that You - meet the following conditions: - - (a) You must give any other recipients of the Work or - Derivative Works a copy of this License; and - - (b) You must cause any modified files to carry prominent notices - stating that You changed the files; and - - (c) You must retain, in the Source form of any Derivative Works - that You distribute, all copyright, patent, trademark, and - attribution notices from the Source form of the Work, - excluding those notices that do not pertain to any part of - the Derivative Works; and - - (d) If the Work includes a "NOTICE" text file as part of its - distribution, then any Derivative Works that You distribute must - include a readable copy of the attribution notices contained - within such NOTICE file, excluding those notices that do not - pertain to any part of the Derivative Works, in at least one - of the following places: within a NOTICE text file distributed - as part of the Derivative Works; within the Source form or - documentation, if provided along with the Derivative Works; or, - within a display generated by the Derivative Works, if and - wherever such third-party notices normally appear. The contents - of the NOTICE file are for informational purposes only and - do not modify the License. You may add Your own attribution - notices within Derivative Works that You distribute, alongside - or as an addendum to the NOTICE text from the Work, provided - that such additional attribution notices cannot be construed - as modifying the License. - - You may add Your own copyright statement to Your modifications and - may provide additional or different license terms and conditions - for use, reproduction, or distribution of Your modifications, or - for any such Derivative Works as a whole, provided Your use, - reproduction, and distribution of the Work otherwise complies with - the conditions stated in this License. - - 5. Submission of Contributions. Unless You explicitly state otherwise, - any Contribution intentionally submitted for inclusion in the Work - by You to the Licensor shall be under the terms and conditions of - this License, without any additional terms or conditions. - Notwithstanding the above, nothing herein shall supersede or modify - the terms of any separate license agreement you may have executed - with Licensor regarding such Contributions. - - 6. Trademarks. This License does not grant permission to use the trade - names, trademarks, service marks, or product names of the Licensor, - except as required for reasonable and customary use in describing the - origin of the Work and reproducing the content of the NOTICE file. - - 7. Disclaimer of Warranty. Unless required by applicable law or - agreed to in writing, Licensor provides the Work (and each - Contributor provides its Contributions) on an "AS IS" BASIS, - WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or - implied, including, without limitation, any warranties or conditions - of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A - PARTICULAR PURPOSE. You are solely responsible for determining the - appropriateness of using or redistributing the Work and assume any - risks associated with Your exercise of permissions under this License. - - 8. Limitation of Liability. In no event and under no legal theory, - whether in tort (including negligence), contract, or otherwise, - unless required by applicable law (such as deliberate and grossly - negligent acts) or agreed to in writing, shall any Contributor be - liable to You for damages, including any direct, indirect, special, - incidental, or consequential damages of any character arising as a - result of this License or out of the use or inability to use the - Work (including but not limited to damages for loss of goodwill, - work stoppage, computer failure or malfunction, or any and all - other commercial damages or losses), even if such Contributor - has been advised of the possibility of such damages. - - 9. Accepting Warranty or Additional Liability. While redistributing - the Work or Derivative Works thereof, You may choose to offer, - and charge a fee for, acceptance of support, warranty, indemnity, - or other liability obligations and/or rights consistent with this - License. However, in accepting such obligations, You may act only - on Your own behalf and on Your sole responsibility, not on behalf - of any other Contributor, and only if You agree to indemnify, - defend, and hold each Contributor harmless for any liability - incurred by, or claims asserted against, such Contributor by reason - of your accepting any such warranty or additional liability. - - END OF TERMS AND CONDITIONS - - APPENDIX: How to apply the Apache License to your work. - - To apply the Apache License to your work, attach the following - boilerplate notice, with the fields enclosed by brackets "[]" - replaced with your own identifying information. (Don't include - the brackets!) The text should be enclosed in the appropriate - comment syntax for the file format. We also recommend that a - file or class name and description of purpose be included on the - same "printed page" as the copyright notice for easier - identification within third-party archives. - - Copyright [yyyy] [name of copyright owner] - - Licensed 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. - --------------------------------------------------- -Library: webhdfs v0.8.0 -Url: https://github.com/kzk/webhdfs -License: Apache-2.0 - -Copyright (C) 2012 Fluentd Project - - Licensed 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. - --------------------------------------------------- -Library: webmock v1.21.0 -Url: https://github.com/bblimke/webmock -License: MIT - -Copyright (c) 2009-2010 Bartosz Blimke - -Permission is hereby granted, free of charge, to any person obtaining -a copy of this software and associated documentation files (the -"Software"), to deal in the Software without restriction, including -without limitation the rights to use, copy, modify, merge, publish, -distribute, sublicense, and/or sell copies of the Software, and to -permit persons to whom the Software is furnished to do so, subject to -the following conditions: - -The above copyright notice and this permission notice shall be -included in all copies or substantial portions of the Software. - -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, -EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF -MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND -NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE -LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION -OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION -WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. - --------------------------------------------------- -Library: webrick v1.3.1 -Url: https://github.com/ruby/webrick -License: BSD-2-Clause - -Copyright (C) 1993-2013 Yukihiro Matsumoto. All rights reserved. - -Redistribution and use in source and binary forms, with or without -modification, are permitted provided that the following conditions -are met: -1. Redistributions of source code must retain the above copyright -notice, this list of conditions and the following disclaimer. -2. Redistributions in binary form must reproduce the above copyright -notice, this list of conditions and the following disclaimer in the -documentation and/or other materials provided with the distribution. - -THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND -ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE -IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE -ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE -FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL -DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS -OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) -HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT -LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY -OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF -SUCH DAMAGE. - --------------------------------------------------- -Library: xml-simple v1.1.5 -Url: https://github.com/maik/xml-simple -License: BSD-2-Clause - -Readme.md: - -XmlSimple is Copyright (c) 2003-2017 Maik Schmidt. It is free software, and may -be redistributed under the terms specified in the COPYING file of the current -Ruby distribution. - -Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: - -1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. -2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. -THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. diff --git a/logstash-core/lib/logstash/dependency_report.rb b/logstash-core/lib/logstash/dependency_report.rb index 6e92d2036..c0535aba9 100644 --- a/logstash-core/lib/logstash/dependency_report.rb +++ b/logstash-core/lib/logstash/dependency_report.rb @@ -13,6 +13,10 @@ class LogStash::DependencyReport < Clamp::Command option [ "--csv" ], "OUTPUT_PATH", "The path to write the dependency report in csv format.", :required => true, :attribute_name => :output_path + OTHER_DEPENDENCIES = [ + ["jruby", "", "http://jruby.org", "EPL-2.0"] + ] + def execute require "csv" @@ -24,6 +28,8 @@ class LogStash::DependencyReport < Clamp::Command gems.each { |d| csv << d } puts "Finding gem embedded java/jar dependencies" jars.each { |d| csv << d } + puts "Adding non-gem non-jar dependencies (such as jruby distribution)" + OTHER_DEPENDENCIES.each { |d| csv << d } end puts "Wrote temporary ruby deps CSV to #{ruby_output_path}" diff --git a/logstash-core/logstash-core.gemspec b/logstash-core/logstash-core.gemspec index 4d0adeb21..03748524e 100644 --- a/logstash-core/logstash-core.gemspec +++ b/logstash-core/logstash-core.gemspec @@ -54,6 +54,7 @@ Gem::Specification.new do |gem| gem.add_runtime_dependency "gems", "~> 1" #(MIT license) gem.add_runtime_dependency "concurrent-ruby", "~> 1" gem.add_runtime_dependency "rack", '~> 2' + gem.add_runtime_dependency "mustermann", '~> 1.0.3' gem.add_runtime_dependency "sinatra", '~> 2' gem.add_runtime_dependency 'puma', '~> 4' gem.add_runtime_dependency "jruby-openssl", "~> 0.10" # >= 0.9.13 Required to support TLSv1.2 diff --git a/tools/dependencies-report/src/main/resources/licenseMapping.csv b/tools/dependencies-report/src/main/resources/licenseMapping.csv index 2e7f43d42..043d5a9ba 100644 --- a/tools/dependencies-report/src/main/resources/licenseMapping.csv +++ b/tools/dependencies-report/src/main/resources/licenseMapping.csv @@ -1,188 +1,142 @@ dependency,dependencyUrl,licenseOverride -"addressable:2.3.8",https://github.com/sporkmonger/addressable,Apache-2.0 -"asm:6.0",http://asm.objectweb.org,BSD-3-Clause -"atomic:1.1.99",http://github.com/ruby-concurrency/atomic,Apache-2.0 -"avl_tree:1.2.1",https://github.com/nahi/avl_tree,BSD-2-Clause-FreeBSD -"awesome_print:1.7.0",https://github.com/awesome-print/awesome_print,MIT -"aws-sdk-core:2.11.111",http://github.com/aws/aws-sdk-ruby,Apache-2.0 -"aws-sdk-resources:2.11.111",http://github.com/aws/aws-sdk-ruby,Apache-2.0 -"aws-sdk-v1:1.67.0",http://aws.amazon.com/sdkforruby,Apache-2.0 -"aws-sdk:2.11.111",http://github.com/aws/aws-sdk-ruby,Apache-2.0 -"aws-sigv4:1.0.3",http://github.com/aws/aws-sdk-ruby,Apache-2.0 -"backports:3.11.3",http://github.com/marcandre/backports,MIT -"bindata:2.4.3",http://github.com/dmendel/bindata,BSD-2-Clause -"bouncycastle",https://www.bouncycastle.org,MIT -"buftok:0.2.0",https://github.com/sferik/buftok,MIT -"builder:3.2.3",http://onestepback.org,MIT -"bundler:1.9.10",https://bundler.io/,MIT -"bytelist:",http://github.com/jruby/bytelist,EPL-1.0 -"cabin:0.9.0",https://github.com/jordansissel/ruby-cabin,Apache-2.0 -"childprocess:0.9.0",http://github.com/enkessler/childprocess,MIT -"chronic_duration:0.10.6",https://github.com/hpoydar/chronic_duration,MIT -"clamp:0.6.5",http://github.com/mdub/clamp,MIT -"coderay:1.1.2",http://coderay.rubychan.de,MIT -"com.fasterxml.jackson.core:jackson-annotations:2.9.5",https://github.com/FasterXML/jackson-annotations,Apache-2.0 -"com.fasterxml.jackson.core:jackson-core:2.9.5",https://github.com/FasterXML/jackson-core,Apache-2.0 -"com.fasterxml.jackson.core:jackson-databind:2.9.5",https://github.com/FasterXML/jackson-databind,Apache-2.0 -"com.fasterxml.jackson.dataformat:jackson-dataformat-cbor:2.9.5",https://github.com/FasterXML/jackson-dataformats-binary,Apache-2.0 -"com.fasterxml.jackson.module:jackson-module-afterburner:2.9.5",https://github.com/FasterXML/jackson-modules-base,Apache-2.0 -"com.github.jnr:jnr-unixsocket:","https://github.com/jnr/jnr-unixsocket",Apache-2.0 -"com.github.jnr:jnr-x86asm:","https://github.com/jnr/jnr-x86asm",MIT -"com.google.code.findbugs:jsr305:1.3.9",http://findbugs.sourceforge.net,Apache-2.0 -"com.google.errorprone:error_prone_annotations:2.0.18",https://github.com/google/error-prone,Apache-2.0 -"com.google.googlejavaformat:google-java-format:1.1",https://github.com/google/google-java-format,Apache-2.0 -"com.google.guava:guava:22.0",https://github.com/google/guava,Apache-2.0 -"com.google.j2objc:j2objc-annotations:1.1",https://github.com/google/j2objc/,Apache-2.0 -"commons-codec:commons-codec:1.10.0",http://commons.apache.org/proper/commons-codec/,Apache-2.0 -"commons-codec:commons-codec:1.11",http://commons.apache.org/proper/commons-codec/,Apache-2.0 -"commons-logging:commons-logging:1.2.0",http://commons.apache.org/proper/commons-logging/,Apache-2.0 -"concurrent-ruby:1.0.5",http://www.concurrent-ruby.com,MIT -"controls.js:",https://github.com/controlsjs/controls.js,GPL-3.0-only -"crack:0.4.3",http://github.com/jnunemaker/crack,MIT -"diff-lcs:1.3",https://github.com/halostatue/diff-lcs,MIT -"domain_name:0.5.20180417",https://github.com/knu/ruby-domain_name,BSD-2-Clause -"dotenv:2.5.0",https://github.com/bkeepers/dotenv,MIT -"edn:1.1.1",https://github.com/relevance/edn-ruby,MIT -"elasticsearch-api:5.0.5",https://github.com/elastic/elasticsearch-ruby,Apache-2.0 -"elasticsearch-transport:5.0.5",https://github.com/elastic/elasticsearch-ruby,Apache-2.0 -"elasticsearch:5.0.5",https://github.com/elastic/elasticsearch-ruby,Apache-2.0 -"equalizer:0.0.10",https://github.com/dkubb/equalizer,MIT -"faraday:0.9.2",https://github.com/lostisland/faraday,MIT -"ffi:1.9.25",https://github.com/ffi/ffi,BSD-3-CLAUSE -"filesize:0.0.4",https://github.com/dominikh,MIT -"filewatch:0.9.0",https://github.com/jordansissel/ruby-filewatch,MIT -"ftw:0.0.48",https://github.com/jordansissel/ruby-ftw,Apache-2.0 -"gelf:3.0.0",https://github.com/graylog-labs/gelf-rb,MIT -"gelfd:0.2.0",https://github.com/lusis/gelfd,Apache-2.0 -"gems:0.8.3",https://github.com/rubygems/gems,MIT -"gmetric:0.1.3",https://github.com/igrigorik/gmetric,MIT -"gradle.plugin.com.github.jk1:gradle-license-report:0.7.1",https://github.com/jk1/Gradle-License-Report,Apache-2.0 -"gserver:0.0.1",https://github.com/ruby/gserver/blob,Ruby -"hitimes:1.3.0",https://github.com/copiousfreetime/hitimes,ISC -"http-cookie:1.0.3",https://github.com/sparklemotion/http-cookie,MIT -"http-form_data:1.0.1",https://github.com/httprb/form_data,MIT -"http:0.9.9",https://github.com/httprb/http,MIT -"http_parser.rb:0.6.0",https://github.com/tmm1/http_parser.rb,MIT -"i18n:0.6.9",https://github.com/svenfuchs/i18n,MIT -"insist:1.0.0",https://github.com/jordansissel/ruby-insist,Apache-2.0 -"invokebinder:1.7",https://github.com/headius/invokebinder,Apache-2.0 -"jar-dependencies:0.3.12",https://github.com/mkristian/jar-dependencies,MIT -"jay-yydebug:",https://github.com/jruby/jay-yydebug,EPL-2.0|GPL-2.0|LGPL-2.1 -"jcodings:1.0.18",https://github.com/jruby/jcodings,MIT -"jdbc-derby:10.12.1.1",https://github.com/jruby/activerecord-jdbc-adapter,Apache-2.0 -"jffi:1.2.16",https://github.com/jnr/jffi,Apache-2.0|LGPL-3.0 -"jitescript:0.4.1",https://github.com/qmx/jitescript,Apache-2.0 -"jline2:2.1.1",https://github.com/jline/jline2,BSD-2-Clause -"jls-grok:0.11.5",https://github.com/jordansissel/ruby-grok,Apache-2.0 -"jls-lumberjack:0.0.26",https://github.com/elastic/ruby-lumberjack,Apache-2.0 -"jmespath:1.4.0",https://github.com/jmespath/jmespath.rb,Apache-2.0 -"jnr-constants:0.9.9",https://github.com/jnr/jnr-constants,Apache-2.0|LGPL-3.0 -"jnr-enxio:0.16",https://github.com/jnr/jnr-enxio,Apache-2.0|LGPL-3.0 -"jnr-ffi:2.1.7",https://github.com/jnr/jnr-ffi,Apache-2.0|LGPL-3.0 -"jnr-netdb:1.1.6",https://github.com/jnr/jnr-netdb,Apache-2.0 -"jnr-posix:3.0.41",https://github.com/jnr/jnr-posix,EPL-2.0|GPL-2.0|LGPL-2.1dependency,dependencyUrl,licenseOverride -"joda-time","http://www.joda.org/joda-time/",Apache-2.0 -"joni","https://github.com/jruby/joni/",MIT -"jrjackson:0.4.6",https://github.com/guyboertje/jrjackson,Apache-2.0 -"jruby-openssl:0.10.1","https://github.com/jruby/jruby-openssl/",EPL-1.0 -"jruby-readline","https://github.com/jruby/jruby-readline",EPL-1.0 -"jruby-stdin-channel:0.2.0","https://github.com/colinsurprenant/jruby-stdin-channel",Apache-2.0 -"json-generator","https://github.com/tmattia/json-generator/",MIT -"json:1.8.6",http://json-jruby.rubyforge.org/,Ruby -"jzlib","http://www.jcraft.com/jzlib/",BSD -"lru_redux:1.1.0","https://github.com/SamSaffron/lru_redux/",MIT -"mail:2.6.6","https://github.com/mikel/mail/",MIT -"manticore:0.6.4","https://github.com/cheald/manticore/",MIT -"march_hare:3.1.1","https://github.com/ruby-amqp/march_hare/",MIT -"memoizable:0.4.2","https://github.com/dkubb/memoizable/",MIT -"method_source:0.8.2","https://github.com/banister/method_source/",MIT -"metriks:0.9.9.8","https://github.com/eric/metriks/",MIT -"mime-types:2.6.2",https://github.com/mime-types/ruby-mime-types/,MIT -"minitar:0.6.1",https://github.com/halostatue/minitar/,RUBY|BSD-2-Clause -"msgpack:1.2.4","https://github.com/msgpack/msgpack-ruby",Apache-2.0 -"multi_json:1.13.1","https://github.com/intridea/multi_json",MIT -"multipart-post:2.0.0","https://github.com/nicksieger/multipart-post",MIT -"murmurhash3:0.1.6","https://github.com/funny-falcon/",MIT -"mustache:0.99.8","https://github.com/mustache/mustache",MIT -"nailgun","http://martiansoftware.com/nailgun",Apache-2.0 -"naught:1.1.0","https://github.com/avdi/naught/",MIT -"nokogiri:1.8.4","http://nokogiri.org/",MIT -"numerizer:0.1.1","https://github.com/jduff/numerizer/",MIT -"openssl_pkcs8_pure:0.0.0.2",http://github.com/cielavenir/openssl_pkcs8_pure,Ruby -"options",https://github.com/headius/options,Apache-2.0 -"org.apache.logging.log4j:log4j-1.2-api:2.6.2","https://logging.apache.org/log4j",Apache-2.0 -"org.apache.logging.log4j:log4j-api:2.6.2","https://logging.apache.org/log4j",Apache-2.0 -"org.apache.logging.log4j:log4j-api:2.8.2",https://logging.apache.org/log4j/2.x/index.html,Apache-2.0 -"org.apache.logging.log4j:log4j-api:2.9.1",https://logging.apache.org/log4j/2.x/index.html,Apache-2.0 -"org.apache.logging.log4j:log4j-core:2.8.2",https://logging.apache.org/log4j/2.x/index.html,Apache-2.0 -"org.apache.logging.log4j:log4j-core:2.9.1",https://logging.apache.org/log4j/2.x/index.html,Apache-2.0 -"org.apache.logging.log4j:log4j-slf4j-impl:2.8.2",https://logging.apache.org/log4j/2.x/index.html,Apache-2.0 -"org.apache.logging.log4j:log4j-slf4j-impl:2.9.1",https://logging.apache.org/log4j/2.x/index.html,Apache-2.0 -"org.codehaus.janino:commons-compiler:3.0.8",https://github.com/janino-compiler/janino,BSD-3-Clause -"org.codehaus.janino:janino:3.0.8",https://github.com/janino-compiler/janino,BSD-3-Clause -"org.codehaus.mojo:animal-sniffer-annotations:1.14",https://www.mojohaus.org/animal-sniffer/animal-sniffer-annotations/,MIT -"org.eclipse.core:org.eclipse.core.commands:3.6.0",http://www.eclipse.org,EPL-1.0 -"org.eclipse.core:org.eclipse.core.contenttype:3.4.100",http://www.eclipse.org,EPL-1.0 -"org.eclipse.core:org.eclipse.core.expressions:3.4.300",http://www.eclipse.org,EPL-1.0 -"org.eclipse.core:org.eclipse.core.filesystem:1.3.100",http://www.eclipse.org,EPL-1.0 -"org.eclipse.core:org.eclipse.core.jobs:3.5.100",http://www.eclipse.org,EPL-1.0 -"org.eclipse.core:org.eclipse.core.resources:3.7.100",http://www.eclipse.org,EPL-1.0 -"org.eclipse.core:org.eclipse.core.runtime:3.7.0",http://www.eclipse.org,EPL-1.0 -"org.eclipse.equinox:org.eclipse.equinox.app:1.3.100",http://www.eclipse.org/platform,EPL-1.0 -"org.eclipse.equinox:org.eclipse.equinox.common:3.6.0",http://www.eclipse.org/platform,EPL-1.0 -"org.eclipse.equinox:org.eclipse.equinox.preferences:3.4.1",http://www.eclipse.org/platform,EPL-1.0 -"org.eclipse.equinox:org.eclipse.equinox.registry:3.5.101",http://www.eclipse.org/platform,EPL-1.0 -"org.eclipse.jdt:org.eclipse.jdt.core:3.10.0",http://www.eclipse.org/jdt,EPL-1.0 -"org.eclipse.osgi:org.eclipse.osgi:3.7.1",http://www.eclipse.org/jdt,EPL-1.0 -"org.eclipse.text:org.eclipse.text:3.5.101",http://www.eclipse.org/jdt,EPL-1.0 -"org.jruby:jruby-complete:9.1.13.0",http://jruby.org/,EPL-2.0 -"org.slf4j:slf4j-api:1.7.25",http://www.slf4j.org/,MIT -"paquet:0.2.1",https://github.com/elastic/logstash,Apache-2.0 -"pleaserun:0.0.30",https://github.com/jordansissel/pleaserun,Apache-2.0 -"polyglot:0.3.5",http://github.com/cjheath/polyglot,MIT -"poseidon:0.0.5",https://github.com/bpot/poseidon,MIT -"prototype.js:",http://prototypejs.org,MIT TODO: Another jruby dependency that is not shipped with it -"pry:0.10.4",http://pryrepl.org,MIT -"psych:2.2.4",https://github.com/ruby/psych,MIT -"public_suffix:1.4.6",https://simonecarletti.com/code/publicsuffix-ruby,MIT -"puma:2.16.0",http://puma.io,BSD-3-Clause -"racc:",https://github.com/tenderlove/racc, TODO: https://github.com/tenderlove/racc/blob/master/COPYING vs https://github.com/jruby/jruby/blob/master/COPYING#L89 -"rack-protection:1.5.5",http://github.com/rkh/rack-protection,MIT -"rack:1.6.6",http://rack.github.io/,MIT -"rake:10.4.2",https://github.com/ruby/rake,MIT -"redis:3.3.5",https://github.com/redis/redis-rb,MIT -"rspec-core:3.7.1",https://github.com/rspec/rspec-core,MIT -"rspec-expectations:3.7.0",https://github.com/rspec/rspec-expectations,MIT -"rspec-mocks:3.7.0",https://github.com/rspec/rspec-mocks,MIT -"rspec-sequencing:0.1.0",https://github.com/elastic/rspec-sequencing,Apache-2.0 -"rspec-support:3.7.1",https://github.com/rspec/rspec-support,MIT -"rspec-wait:0.0.9",https://github.com/laserlemon/rspec-wait,MIT -"rspec:3.7.0",https://github.com/rspec/rspec,MIT -"ruby-progressbar:1.8.3",https://github.com/jfelchner/ruby-progressbar,MIT -"rubyzip:1.2.1",https://github.com/rubyzip/rubyzip,BSD-2-Clause-FreeBSD -"rufus-scheduler:3.0.9",http://github.com/jmettraux/rufus-scheduler,MIT -"rumbster:1.1.0",https://github.com/aesterline/rumbster,Apache-2.0 -"safe_yaml:1.0.4",https://github.com/dtao/safe_yaml,MIT -"sequel:5.11.0",https://github.com/jeremyevans/sequel,MIT -"simple_oauth:0.3.1",https://github.com/laserlemon/simple_oauth,MIT -"sinatra:1.4.8",https://github.com/sinatra/sinatra,MIT -"slop:3.6.0",https://github.com/leejarvis/slop,MIT -"snakeyaml:1.18",https://bitbucket.org/asomov/snakeyaml/,Apache-2.0 -"snappy-jars:1.1.0.1.2",https://github.com/doxavore/snappy-jars,Apache-2.0 -"snappy:0.0.12",https://github.com/miyucy/snappy,MIT -"snmp:1.2.0",https://github.com/hallidave/ruby-snmp,MIT -"spoon:0.0.6",https://github.com/headius/spoon,Apache-2.0 -"stud:0.0.23",https://github.com/jordansissel/ruby-stud,Apache-2.0 -"thread_safe:0.3.6",https://github.com/ruby-concurrency/thread_safe,Apache-2.0 -"tilt:2.0.8",https://github.com/rtomayko/tilt,MIT -"timecop:0.9.1",https://github.com/travisjeffery/timecop,MIT -"treetop:1.4.15",https://github.com/cjheath/treetop,MIT -"twitter:5.15.0",https://github.com/sferik/twitter,MIT -"tzinfo-data:1.2018.5",https://github.com/tzinfo/tzinfo-data,MIT -"tzinfo:1.2.5",https://github.com/tzinfo/tzinfo,MIT,Philip Ross -"unf:0.1.4",https://github.com/knu/ruby-unf,BSD-2-Clause -"unsafe-fences:1.0",https://github.com/headius/unsafe-fences,Apache-2.0 -"webhdfs:0.8.0",https://github.com/kzk/webhdfs,Apache-2.0 -"webmock:1.21.0",https://github.com/bblimke/webmock,MIT -"webrick:1.3.1",https://github.com/ruby/webrick,BSD-2-Clause -"xml-simple:1.1.5",https://github.com/maik/xml-simple,BSD-2-Clause +"addressable:",https://github.com/sporkmonger/addressable,Apache-2.0 +"atomic:",http://github.com/ruby-concurrency/atomic,Apache-2.0 +"avl_tree:",https://github.com/nahi/avl_tree,BSD-2-Clause-FreeBSD +"avro:",https://github.com/apache/avro/tree/master/lang/ruby,Apache-2.0 +"awesome_print:",https://github.com/awesome-print/awesome_print,MIT +"aws-eventstream:",https://github.com/aws/aws-sdk-ruby/tree/master/gems/aws-eventstream,Apache-2.0 +"aws-sdk-core:",http://github.com/aws/aws-sdk-ruby,Apache-2.0 +"aws-sdk-resources:",http://github.com/aws/aws-sdk-ruby,Apache-2.0 +"aws-sdk-v1:",http://aws.amazon.com/sdkforruby,Apache-2.0 +"aws-sdk:",http://github.com/aws/aws-sdk-ruby,Apache-2.0 +"aws-sigv4:",http://github.com/aws/aws-sdk-ruby,Apache-2.0 +"back_pressure:",https://github.com/yaauie/ruby_back_pressure,Apache-2.0 +"bindata:",http://github.com/dmendel/bindata,BSD-2-Clause +"buftok:",https://github.com/sferik/buftok,MIT +"builder:",http://onestepback.org,MIT +"bundler:",https://bundler.io/,MIT +"cabin:",https://github.com/jordansissel/ruby-cabin,Apache-2.0 +"chronic_duration:",https://github.com/hpoydar/chronic_duration,MIT +"clamp:",http://github.com/mdub/clamp,MIT +"coderay:",http://coderay.rubychan.de,MIT +"com.fasterxml.jackson.core:jackson-annotations:",https://github.com/FasterXML/jackson-annotations,Apache-2.0 +"com.fasterxml.jackson.core:jackson-databind:",https://github.com/FasterXML/jackson-databind,Apache-2.0 +"com.fasterxml.jackson.core:jackson-core:",https://github.com/FasterXML/jackson-core,Apache-2.0 +"com.fasterxml.jackson.dataformat:jackson-dataformat-cbor:",https://github.com/FasterXML/jackson-dataformats-binary,Apache-2.0 +"com.fasterxml.jackson.module:jackson-module-afterburner:",https://github.com/FasterXML/jackson-modules-base,Apache-2.0 +"com.google.code.findbugs:jsr305:",http://findbugs.sourceforge.net,Apache-2.0 +"com.google.errorprone:error_prone_annotations:",https://github.com/google/error-prone,Apache-2.0 +"com.google.googlejavaformat:google-java-format:",https://github.com/google/google-java-format,Apache-2.0 +"com.google.guava:guava:",https://github.com/google/guava,Apache-2.0 +"com.google.j2objc:j2objc-annotations:",https://github.com/google/j2objc/,Apache-2.0 +"commons-codec:commons-codec:",http://commons.apache.org/proper/commons-codec/,Apache-2.0 +"commons-codec:commons-codec:",http://commons.apache.org/proper/commons-codec/,Apache-2.0 +"commons-logging:commons-logging:",http://commons.apache.org/proper/commons-logging/,Apache-2.0 +"concurrent-ruby:",http://www.concurrent-ruby.com,MIT +"dalli:",https://github.com/petergoldstein/dalli,MIT +"domain_name:",https://github.com/knu/ruby-domain_name,BSD-2-Clause +"dotenv:",https://github.com/bkeepers/dotenv,MIT +"edn:",https://github.com/relevance/edn-ruby,MIT +"elasticsearch-api:",https://github.com/elastic/elasticsearch-ruby,Apache-2.0 +"elasticsearch-transport:",https://github.com/elastic/elasticsearch-ruby,Apache-2.0 +"elasticsearch:",https://github.com/elastic/elasticsearch-ruby,Apache-2.0 +"equalizer:",https://github.com/dkubb/equalizer,MIT +"faraday:",https://github.com/lostisland/faraday,MIT +"ffi:",https://github.com/ffi/ffi,BSD-3-CLAUSE +"filesize:",https://github.com/dominikh,MIT +"gelfd2:",https://github.com/ptqa/gelfd2,Apache-2.0 +"gems:",https://github.com/rubygems/gems,MIT +"gene_pool:",https://github.com/bpardee/gene_pool,MIT +"gradle.plugin.com.github.jk1:gradle-license-report:",https://github.com/jk1/Gradle-License-Report,Apache-2.0 +"hitimes:",https://github.com/copiousfreetime/hitimes,ISC +"http-cookie:",https://github.com/sparklemotion/http-cookie,MIT +"http-form_data:",https://github.com/httprb/form_data,MIT +"http:",https://github.com/httprb/http,MIT +"http_parser.rb:",https://github.com/tmm1/http_parser.rb,MIT +"i18n:",https://github.com/svenfuchs/i18n,MIT +"insist:",https://github.com/jordansissel/ruby-insist,Apache-2.0 +"jar-dependencies:",https://github.com/mkristian/jar-dependencies,MIT +"jls-grok:",https://github.com/jordansissel/ruby-grok,Apache-2.0 +"jls-lumberjack:",https://github.com/elastic/ruby-lumberjack,Apache-2.0 +"jmespath:",https://github.com/jmespath/jmespath.rb,Apache-2.0 +"jrjackson:",https://github.com/guyboertje/jrjackson,Apache-2.0 +"jruby:",https://jruby.org,EPL-2.0 +"jruby-jms:",https://github.com/reidmorrison/jruby-jms,Apache-2.0 +"jruby-openssl:","https://github.com/jruby/jruby-openssl/",EPL-1.0 +"jruby-stdin-channel:","https://github.com/colinsurprenant/jruby-stdin-channel",Apache-2.0 +"json:",http://json-jruby.rubyforge.org/,Ruby +"lru_redux:","https://github.com/SamSaffron/lru_redux/",MIT +"mail:","https://github.com/mikel/mail/",MIT +"manticore:","https://github.com/cheald/manticore/",MIT +"march_hare:","https://github.com/ruby-amqp/march_hare/",MIT +"memoizable:","https://github.com/dkubb/memoizable/",MIT +"method_source:","https://github.com/banister/method_source/",MIT +"metriks:","https://github.com/eric/metriks/",MIT +"mime-types:",https://github.com/mime-types/ruby-mime-types/,MIT +"minitar:",https://github.com/halostatue/minitar/,RUBY|BSD-2-Clause +"msgpack:","https://github.com/msgpack/msgpack-ruby",Apache-2.0 +"multi_json:","https://github.com/intridea/multi_json",MIT +"multipart-post:","https://github.com/nicksieger/multipart-post",MIT +"murmurhash3:","https://github.com/funny-falcon/",MIT +"mustermann:","https://github.com/sinatra/mustermann",MIT +"mustache:","https://github.com/mustache/mustache",MIT +"naught:","https://github.com/avdi/naught/",MIT +"nio4r:","https://github.com/socketry/nio4r",MIT +"nokogiri:","http://nokogiri.org/",MIT +"numerizer:","https://github.com/jduff/numerizer/",MIT +"openssl_pkcs8_pure:",http://github.com/cielavenir/openssl_pkcs8_pure,Ruby +"org.apache.logging.log4j:log4j-api:",https://logging.apache.org/log4j/2.x/index.html,Apache-2.0 +"org.apache.logging.log4j:log4j-core:",https://logging.apache.org/log4j/2.x/index.html,Apache-2.0 +"org.apache.logging.log4j:log4j-slf4j-impl:",https://logging.apache.org/log4j/2.x/index.html,Apache-2.0 +"org.codehaus.janino:commons-compiler:",https://github.com/janino-compiler/janino,BSD-3-Clause +"org.codehaus.janino:janino:",https://github.com/janino-compiler/janino,BSD-3-Clause +"org.codehaus.mojo:animal-sniffer-annotations:",https://www.mojohaus.org/animal-sniffer/animal-sniffer-annotations/,MIT +"org.eclipse.core:org.eclipse.core.commands:",http://www.eclipse.org,EPL-1.0 +"org.eclipse.core:org.eclipse.core.contenttype:",http://www.eclipse.org,EPL-1.0 +"org.eclipse.core:org.eclipse.core.expressions:",http://www.eclipse.org,EPL-1.0 +"org.eclipse.core:org.eclipse.core.filesystem:",http://www.eclipse.org,EPL-1.0 +"org.eclipse.core:org.eclipse.core.jobs:",http://www.eclipse.org,EPL-1.0 +"org.eclipse.core:org.eclipse.core.resources:",http://www.eclipse.org,EPL-1.0 +"org.eclipse.core:org.eclipse.core.runtime:",http://www.eclipse.org,EPL-1.0 +"org.eclipse.equinox:org.eclipse.equinox.app:",http://www.eclipse.org/platform,EPL-1.0 +"org.eclipse.equinox:org.eclipse.equinox.common:",http://www.eclipse.org/platform,EPL-1.0 +"org.eclipse.equinox:org.eclipse.equinox.preferences:",http://www.eclipse.org/platform,EPL-1.0 +"org.eclipse.equinox:org.eclipse.equinox.registry:",http://www.eclipse.org/platform,EPL-1.0 +"org.eclipse.jdt:org.eclipse.jdt.core:",http://www.eclipse.org/jdt,EPL-1.0 +"org.eclipse.osgi:org.eclipse.osgi:",http://www.eclipse.org/jdt,EPL-1.0 +"org.eclipse.text:org.eclipse.text:",http://www.eclipse.org/jdt,EPL-1.0 +"org.javassist:javassist:",https://github.com/jboss-javassist/javassist,Apache-2.0 +"org.jruby:jruby-complete:",http://jruby.org/,EPL-2.0 +"org.reflections:reflections:",https://github.com/ronmamo/reflections,BSD-2-Clause +"org.slf4j:slf4j-api:",http://www.slf4j.org/,MIT +"paquet:",https://github.com/elastic/logstash,Apache-2.0 +"pleaserun:",https://github.com/jordansissel/pleaserun,Apache-2.0 +"polyglot:",http://github.com/cjheath/polyglot,MIT +"pry:",http://pryrepl.org,MIT +"public_suffix:",https://simonecarletti.com/code/publicsuffix-ruby,MIT +"puma:",http://puma.io,BSD-3-Clause +"rack-protection:",http://github.com/rkh/rack-protection,MIT +"rack:",http://rack.github.io/,MIT +"rake:",https://github.com/ruby/rake,MIT +"redis:",https://github.com/redis/redis-rb,MIT +"ruby-progressbar:",https://github.com/jfelchner/ruby-progressbar,MIT +"rubyzip:",https://github.com/rubyzip/rubyzip,BSD-2-Clause-FreeBSD +"rufus-scheduler:",http://github.com/jmettraux/rufus-scheduler,MIT +"semantic_logger:",https://github.com/rocketjob/semantic_logger,Apache-2.0 +"sequel:",https://github.com/jeremyevans/sequel,MIT +"simple_oauth:",https://github.com/laserlemon/simple_oauth,MIT +"sinatra:",https://github.com/sinatra/sinatra,MIT +"snappy-jars:",https://github.com/doxavore/snappy-jars,Apache-2.0 +"snappy:",https://github.com/miyucy/snappy,MIT +"snmp:",https://github.com/hallidave/ruby-snmp,MIT +"spoon:",https://github.com/headius/spoon,Apache-2.0 +"stud:",https://github.com/jordansissel/ruby-stud,Apache-2.0 +"thread_safe:",https://github.com/ruby-concurrency/thread_safe,Apache-2.0 +"tilt:",https://github.com/rtomayko/tilt,MIT +"treetop:",https://github.com/cjheath/treetop,MIT +"twitter:",https://github.com/sferik/twitter,MIT +"tzinfo-data:",https://github.com/tzinfo/tzinfo-data,MIT +"tzinfo:",https://github.com/tzinfo/tzinfo,MIT,Philip Ross +"unf:",https://github.com/knu/ruby-unf,BSD-2-Clause +"webhdfs:",https://github.com/kzk/webhdfs,Apache-2.0 +"xml-simple:",https://github.com/maik/xml-simple,BSD-2-Clause diff --git a/tools/dependencies-report/src/main/resources/notices/a.txt b/tools/dependencies-report/src/main/resources/notices/a.txt new file mode 100644 index 000000000..49517220f --- /dev/null +++ b/tools/dependencies-report/src/main/resources/notices/a.txt @@ -0,0 +1,57 @@ +asm +backports +bouncycastle +bytelist +childprocess +chronic_duration +com.github.jnr:jnr-unixsocket +com.github.jnr:jnr-x86asm +controls.js +crack +diff-lcs +filewatch +ftw +gelf +gelfd +gmetric +gserver +invokebinder +jay-yydebug +jcodings +jdbc-derby +jffi +jitescript +jline2 +jnr-constants +jnr-enxio +jnr-ffi +jnr-netdb +jnr-posix +joda-time +joni +jruby-readline +json-generator +jzlib +nailgun +numerizer +options +org.apache.logging.log4j:log4j-1.2-api +poseidon +prototype.js +psych +racc +rspec +rspec-core +rspec-expectations +rspec-mocks +rspec-sequencing +rspec-support +rspec-wait +rumbster +safe_yaml +slop +snakeyaml +timecop +unsafe-fences +webmock +webrick diff --git a/tools/dependencies-report/src/main/resources/notices/addressable-2.3.8-NOTICE.txt b/tools/dependencies-report/src/main/resources/notices/addressable-NOTICE.txt similarity index 100% rename from tools/dependencies-report/src/main/resources/notices/addressable-2.3.8-NOTICE.txt rename to tools/dependencies-report/src/main/resources/notices/addressable-NOTICE.txt diff --git a/tools/dependencies-report/src/main/resources/notices/asm-6.0-NOTICE.txt b/tools/dependencies-report/src/main/resources/notices/asm-6.0-NOTICE.txt deleted file mode 100644 index 631ee53c5..000000000 --- a/tools/dependencies-report/src/main/resources/notices/asm-6.0-NOTICE.txt +++ /dev/null @@ -1,27 +0,0 @@ -ASM: a very small and fast Java bytecode manipulation framework -Copyright (c) 2000-2011 INRIA, France Telecom -All rights reserved. - -Redistribution and use in source and binary forms, with or without -modification, are permitted provided that the following conditions -are met: -1. Redistributions of source code must retain the above copyright - notice, this list of conditions and the following disclaimer. -2. Redistributions in binary form must reproduce the above copyright - notice, this list of conditions and the following disclaimer in the - documentation and/or other materials provided with the distribution. -3. Neither the name of the copyright holders nor the names of its - contributors may be used to endorse or promote products derived from - this software without specific prior written permission. - -THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" -AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE -IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE -ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE -LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR -CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF -SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS -INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN -CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) -ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF -THE POSSIBILITY OF SUCH DAMAGE. \ No newline at end of file diff --git a/tools/dependencies-report/src/main/resources/notices/atomic-1.1.99-NOTICE.txt b/tools/dependencies-report/src/main/resources/notices/atomic-NOTICE.txt similarity index 100% rename from tools/dependencies-report/src/main/resources/notices/atomic-1.1.99-NOTICE.txt rename to tools/dependencies-report/src/main/resources/notices/atomic-NOTICE.txt diff --git a/tools/dependencies-report/src/main/resources/notices/avl_tree-1.2.1-NOTICE.txt b/tools/dependencies-report/src/main/resources/notices/avl_tree-NOTICE.txt similarity index 100% rename from tools/dependencies-report/src/main/resources/notices/avl_tree-1.2.1-NOTICE.txt rename to tools/dependencies-report/src/main/resources/notices/avl_tree-NOTICE.txt diff --git a/tools/dependencies-report/src/main/resources/notices/avro-NOTICE.txt b/tools/dependencies-report/src/main/resources/notices/avro-NOTICE.txt new file mode 100644 index 000000000..859ea81d7 --- /dev/null +++ b/tools/dependencies-report/src/main/resources/notices/avro-NOTICE.txt @@ -0,0 +1,6 @@ +Apache Avro +Copyright 2010-2015 The Apache Software Foundation + +This product includes software developed at +The Apache Software Foundation (https://www.apache.org/). + diff --git a/tools/dependencies-report/src/main/resources/notices/awesome_print-1.7.0-NOTICE.txt b/tools/dependencies-report/src/main/resources/notices/awesome_print-NOTICE.txt similarity index 100% rename from tools/dependencies-report/src/main/resources/notices/awesome_print-1.7.0-NOTICE.txt rename to tools/dependencies-report/src/main/resources/notices/awesome_print-NOTICE.txt diff --git a/tools/dependencies-report/src/main/resources/notices/aws-eventstream-NOTICE.txt b/tools/dependencies-report/src/main/resources/notices/aws-eventstream-NOTICE.txt new file mode 100644 index 000000000..83755fd9a --- /dev/null +++ b/tools/dependencies-report/src/main/resources/notices/aws-eventstream-NOTICE.txt @@ -0,0 +1,2 @@ +AWS SDK for Ruby +Copyright 2015 Amazon.com, Inc. or its affiliates. All Rights Reserved. diff --git a/tools/dependencies-report/src/main/resources/notices/aws-sdk-2.11.111-NOTICE.txt b/tools/dependencies-report/src/main/resources/notices/aws-sdk-NOTICE.txt similarity index 100% rename from tools/dependencies-report/src/main/resources/notices/aws-sdk-2.11.111-NOTICE.txt rename to tools/dependencies-report/src/main/resources/notices/aws-sdk-NOTICE.txt diff --git a/tools/dependencies-report/src/main/resources/notices/aws-sdk-core-2.11.111-NOTICE.txt b/tools/dependencies-report/src/main/resources/notices/aws-sdk-core-NOTICE.txt similarity index 100% rename from tools/dependencies-report/src/main/resources/notices/aws-sdk-core-2.11.111-NOTICE.txt rename to tools/dependencies-report/src/main/resources/notices/aws-sdk-core-NOTICE.txt diff --git a/tools/dependencies-report/src/main/resources/notices/aws-sdk-resources-2.11.111-NOTICE.txt b/tools/dependencies-report/src/main/resources/notices/aws-sdk-resources-NOTICE.txt similarity index 100% rename from tools/dependencies-report/src/main/resources/notices/aws-sdk-resources-2.11.111-NOTICE.txt rename to tools/dependencies-report/src/main/resources/notices/aws-sdk-resources-NOTICE.txt diff --git a/tools/dependencies-report/src/main/resources/notices/aws-sdk-v1-1.67.0-NOTICE.txt b/tools/dependencies-report/src/main/resources/notices/aws-sdk-v1-NOTICE.txt similarity index 100% rename from tools/dependencies-report/src/main/resources/notices/aws-sdk-v1-1.67.0-NOTICE.txt rename to tools/dependencies-report/src/main/resources/notices/aws-sdk-v1-NOTICE.txt diff --git a/tools/dependencies-report/src/main/resources/notices/aws-sigv4-1.0.3-NOTICE.txt b/tools/dependencies-report/src/main/resources/notices/aws-sigv4-NOTICE.txt similarity index 100% rename from tools/dependencies-report/src/main/resources/notices/aws-sigv4-1.0.3-NOTICE.txt rename to tools/dependencies-report/src/main/resources/notices/aws-sigv4-NOTICE.txt diff --git a/tools/dependencies-report/src/main/resources/notices/options-NOTICE.txt b/tools/dependencies-report/src/main/resources/notices/back_pressure-NOTICE.txt similarity index 74% rename from tools/dependencies-report/src/main/resources/notices/options-NOTICE.txt rename to tools/dependencies-report/src/main/resources/notices/back_pressure-NOTICE.txt index b9015b394..124d6a7cc 100644 --- a/tools/dependencies-report/src/main/resources/notices/options-NOTICE.txt +++ b/tools/dependencies-report/src/main/resources/notices/back_pressure-NOTICE.txt @@ -1,10 +1,10 @@ -source: https://github.com/headius/options/blob/options-1.4/src/main/java/com/headius/options/Option.java#L1-L13 +Copyright [yyyy] [name of copyright owner] Licensed 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 + 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, diff --git a/tools/dependencies-report/src/main/resources/notices/backports-3.11.3-NOTICE.txt b/tools/dependencies-report/src/main/resources/notices/backports-3.11.3-NOTICE.txt deleted file mode 100644 index 4b67862a4..000000000 --- a/tools/dependencies-report/src/main/resources/notices/backports-3.11.3-NOTICE.txt +++ /dev/null @@ -1,20 +0,0 @@ -Copyright (c) 2009 Marc-Andre Lafortune - -Permission is hereby granted, free of charge, to any person obtaining -a copy of this software and associated documentation files (the -"Software"), to deal in the Software without restriction, including -without limitation the rights to use, copy, modify, merge, publish, -distribute, sublicense, and/or sell copies of the Software, and to -permit persons to whom the Software is furnished to do so, subject to -the following conditions: - -The above copyright notice and this permission notice shall be -included in all copies or substantial portions of the Software. - -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, -EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF -MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND -NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE -LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION -OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION -WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. diff --git a/tools/dependencies-report/src/main/resources/notices/bindata-2.4.3-NOTICE.txt b/tools/dependencies-report/src/main/resources/notices/bindata-NOTICE.txt similarity index 100% rename from tools/dependencies-report/src/main/resources/notices/bindata-2.4.3-NOTICE.txt rename to tools/dependencies-report/src/main/resources/notices/bindata-NOTICE.txt diff --git a/tools/dependencies-report/src/main/resources/notices/buftok-0.2.0-NOTICE.txt b/tools/dependencies-report/src/main/resources/notices/buftok-NOTICE.txt similarity index 100% rename from tools/dependencies-report/src/main/resources/notices/buftok-0.2.0-NOTICE.txt rename to tools/dependencies-report/src/main/resources/notices/buftok-NOTICE.txt diff --git a/tools/dependencies-report/src/main/resources/notices/builder-3.2.3-NOTICE.txt b/tools/dependencies-report/src/main/resources/notices/builder-NOTICE.txt similarity index 100% rename from tools/dependencies-report/src/main/resources/notices/builder-3.2.3-NOTICE.txt rename to tools/dependencies-report/src/main/resources/notices/builder-NOTICE.txt diff --git a/tools/dependencies-report/src/main/resources/notices/bundler-1.9.10-NOTICE.txt b/tools/dependencies-report/src/main/resources/notices/bundler-NOTICE.txt similarity index 100% rename from tools/dependencies-report/src/main/resources/notices/bundler-1.9.10-NOTICE.txt rename to tools/dependencies-report/src/main/resources/notices/bundler-NOTICE.txt diff --git a/tools/dependencies-report/src/main/resources/notices/cabin-0.9.0-NOTICE.txt b/tools/dependencies-report/src/main/resources/notices/cabin-NOTICE.txt similarity index 100% rename from tools/dependencies-report/src/main/resources/notices/cabin-0.9.0-NOTICE.txt rename to tools/dependencies-report/src/main/resources/notices/cabin-NOTICE.txt diff --git a/tools/dependencies-report/src/main/resources/notices/chronic_duration-0.10.6-NOTICE.txt b/tools/dependencies-report/src/main/resources/notices/chronic_duration-NOTICE.txt similarity index 100% rename from tools/dependencies-report/src/main/resources/notices/chronic_duration-0.10.6-NOTICE.txt rename to tools/dependencies-report/src/main/resources/notices/chronic_duration-NOTICE.txt diff --git a/tools/dependencies-report/src/main/resources/notices/clamp-0.6.5-NOTICE.txt b/tools/dependencies-report/src/main/resources/notices/clamp-NOTICE.txt similarity index 100% rename from tools/dependencies-report/src/main/resources/notices/clamp-0.6.5-NOTICE.txt rename to tools/dependencies-report/src/main/resources/notices/clamp-NOTICE.txt diff --git a/tools/dependencies-report/src/main/resources/notices/coderay-1.1.2-NOTICE.txt b/tools/dependencies-report/src/main/resources/notices/coderay-NOTICE.txt similarity index 100% rename from tools/dependencies-report/src/main/resources/notices/coderay-1.1.2-NOTICE.txt rename to tools/dependencies-report/src/main/resources/notices/coderay-NOTICE.txt diff --git a/tools/dependencies-report/src/main/resources/notices/com.fasterxml.jackson.core!jackson-annotations-2.9.5-NOTICE.txt b/tools/dependencies-report/src/main/resources/notices/com.fasterxml.jackson.core!jackson-annotations-NOTICE.txt similarity index 100% rename from tools/dependencies-report/src/main/resources/notices/com.fasterxml.jackson.core!jackson-annotations-2.9.5-NOTICE.txt rename to tools/dependencies-report/src/main/resources/notices/com.fasterxml.jackson.core!jackson-annotations-NOTICE.txt diff --git a/tools/dependencies-report/src/main/resources/notices/com.fasterxml.jackson.core!jackson-core-2.9.5-NOTICE.txt b/tools/dependencies-report/src/main/resources/notices/com.fasterxml.jackson.core!jackson-core-NOTICE.txt similarity index 100% rename from tools/dependencies-report/src/main/resources/notices/com.fasterxml.jackson.core!jackson-core-2.9.5-NOTICE.txt rename to tools/dependencies-report/src/main/resources/notices/com.fasterxml.jackson.core!jackson-core-NOTICE.txt diff --git a/tools/dependencies-report/src/main/resources/notices/com.fasterxml.jackson.core!jackson-databind-2.9.5-NOTICE.txt b/tools/dependencies-report/src/main/resources/notices/com.fasterxml.jackson.core!jackson-databind-NOTICE.txt similarity index 100% rename from tools/dependencies-report/src/main/resources/notices/com.fasterxml.jackson.core!jackson-databind-2.9.5-NOTICE.txt rename to tools/dependencies-report/src/main/resources/notices/com.fasterxml.jackson.core!jackson-databind-NOTICE.txt diff --git a/tools/dependencies-report/src/main/resources/notices/com.fasterxml.jackson.dataformat!jackson-dataformat-cbor-2.9.5-NOTICE.txt b/tools/dependencies-report/src/main/resources/notices/com.fasterxml.jackson.dataformat!jackson-dataformat-cbor-NOTICE.txt similarity index 100% rename from tools/dependencies-report/src/main/resources/notices/com.fasterxml.jackson.dataformat!jackson-dataformat-cbor-2.9.5-NOTICE.txt rename to tools/dependencies-report/src/main/resources/notices/com.fasterxml.jackson.dataformat!jackson-dataformat-cbor-NOTICE.txt diff --git a/tools/dependencies-report/src/main/resources/notices/com.fasterxml.jackson.module!jackson-module-afterburner-2.9.5-NOTICE.txt b/tools/dependencies-report/src/main/resources/notices/com.fasterxml.jackson.module!jackson-module-afterburner-NOTICE.txt similarity index 100% rename from tools/dependencies-report/src/main/resources/notices/com.fasterxml.jackson.module!jackson-module-afterburner-2.9.5-NOTICE.txt rename to tools/dependencies-report/src/main/resources/notices/com.fasterxml.jackson.module!jackson-module-afterburner-NOTICE.txt diff --git a/tools/dependencies-report/src/main/resources/notices/com.google.code.findbugs!jsr305-1.3.9-NOTICE.txt b/tools/dependencies-report/src/main/resources/notices/com.google.code.findbugs!jsr305-NOTICE.txt similarity index 100% rename from tools/dependencies-report/src/main/resources/notices/com.google.code.findbugs!jsr305-1.3.9-NOTICE.txt rename to tools/dependencies-report/src/main/resources/notices/com.google.code.findbugs!jsr305-NOTICE.txt diff --git a/tools/dependencies-report/src/main/resources/notices/com.google.errorprone!error_prone_annotations-2.0.18-NOTICE.txt b/tools/dependencies-report/src/main/resources/notices/com.google.errorprone!error_prone_annotations-NOTICE.txt similarity index 100% rename from tools/dependencies-report/src/main/resources/notices/com.google.errorprone!error_prone_annotations-2.0.18-NOTICE.txt rename to tools/dependencies-report/src/main/resources/notices/com.google.errorprone!error_prone_annotations-NOTICE.txt diff --git a/tools/dependencies-report/src/main/resources/notices/com.google.googlejavaformat!google-java-format-1.1-NOTICE.txt b/tools/dependencies-report/src/main/resources/notices/com.google.googlejavaformat!google-java-format-NOTICE.txt similarity index 100% rename from tools/dependencies-report/src/main/resources/notices/com.google.googlejavaformat!google-java-format-1.1-NOTICE.txt rename to tools/dependencies-report/src/main/resources/notices/com.google.googlejavaformat!google-java-format-NOTICE.txt diff --git a/tools/dependencies-report/src/main/resources/notices/com.google.guava!guava-22.0-NOTICE.txt b/tools/dependencies-report/src/main/resources/notices/com.google.guava!guava-NOTICE.txt similarity index 100% rename from tools/dependencies-report/src/main/resources/notices/com.google.guava!guava-22.0-NOTICE.txt rename to tools/dependencies-report/src/main/resources/notices/com.google.guava!guava-NOTICE.txt diff --git a/tools/dependencies-report/src/main/resources/notices/com.google.j2objc!j2objc-annotations-1.1-NOTICE.txt b/tools/dependencies-report/src/main/resources/notices/com.google.j2objc!j2objc-annotations-NOTICE.txt similarity index 100% rename from tools/dependencies-report/src/main/resources/notices/com.google.j2objc!j2objc-annotations-1.1-NOTICE.txt rename to tools/dependencies-report/src/main/resources/notices/com.google.j2objc!j2objc-annotations-NOTICE.txt diff --git a/tools/dependencies-report/src/main/resources/notices/commons-codec!commons-codec-1.11-NOTICE.txt b/tools/dependencies-report/src/main/resources/notices/commons-codec!commons-codec-1.11-NOTICE.txt deleted file mode 100644 index 186b540cc..000000000 --- a/tools/dependencies-report/src/main/resources/notices/commons-codec!commons-codec-1.11-NOTICE.txt +++ /dev/null @@ -1,220 +0,0 @@ -Apache Commons Codec -Copyright 2002-2017 The Apache Software Foundation - -This product includes software developed at -The Apache Software Foundation (http://www.apache.org/). - -src/test/org/apache/commons/codec/language/DoubleMetaphoneTest.java -contains test data from http://aspell.net/test/orig/batch0.tab. -Copyright (C) 2002 Kevin Atkinson (kevina@gnu.org) - -=============================================================================== - -The content of package org.apache.commons.codec.language.bm has been translated -from the original php source code available at http://stevemorse.org/phoneticinfo.htm -with permission from the original authors. -Original source copyright: -Copyright (c) 2008 Alexander Beider & Stephen P. Morse. - - - Apache License - Version 2.0, January 2004 - http://www.apache.org/licenses/ - - TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION - - 1. Definitions. - - "License" shall mean the terms and conditions for use, reproduction, - and distribution as defined by Sections 1 through 9 of this document. - - "Licensor" shall mean the copyright owner or entity authorized by - the copyright owner that is granting the License. - - "Legal Entity" shall mean the union of the acting entity and all - other entities that control, are controlled by, or are under common - control with that entity. For the purposes of this definition, - "control" means (i) the power, direct or indirect, to cause the - direction or management of such entity, whether by contract or - otherwise, or (ii) ownership of fifty percent (50%) or more of the - outstanding shares, or (iii) beneficial ownership of such entity. - - "You" (or "Your") shall mean an individual or Legal Entity - exercising permissions granted by this License. - - "Source" form shall mean the preferred form for making modifications, - including but not limited to software source code, documentation - source, and configuration files. - - "Object" form shall mean any form resulting from mechanical - transformation or translation of a Source form, including but - not limited to compiled object code, generated documentation, - and conversions to other media types. - - "Work" shall mean the work of authorship, whether in Source or - Object form, made available under the License, as indicated by a - copyright notice that is included in or attached to the work - (an example is provided in the Appendix below). - - "Derivative Works" shall mean any work, whether in Source or Object - form, that is based on (or derived from) the Work and for which the - editorial revisions, annotations, elaborations, or other modifications - represent, as a whole, an original work of authorship. For the purposes - of this License, Derivative Works shall not include works that remain - separable from, or merely link (or bind by name) to the interfaces of, - the Work and Derivative Works thereof. - - "Contribution" shall mean any work of authorship, including - the original version of the Work and any modifications or additions - to that Work or Derivative Works thereof, that is intentionally - submitted to Licensor for inclusion in the Work by the copyright owner - or by an individual or Legal Entity authorized to submit on behalf of - the copyright owner. For the purposes of this definition, "submitted" - means any form of electronic, verbal, or written communication sent - to the Licensor or its representatives, including but not limited to - communication on electronic mailing lists, source code control systems, - and issue tracking systems that are managed by, or on behalf of, the - Licensor for the purpose of discussing and improving the Work, but - excluding communication that is conspicuously marked or otherwise - designated in writing by the copyright owner as "Not a Contribution." - - "Contributor" shall mean Licensor and any individual or Legal Entity - on behalf of whom a Contribution has been received by Licensor and - subsequently incorporated within the Work. - - 2. Grant of Copyright License. Subject to the terms and conditions of - this License, each Contributor hereby grants to You a perpetual, - worldwide, non-exclusive, no-charge, royalty-free, irrevocable - copyright license to reproduce, prepare Derivative Works of, - publicly display, publicly perform, sublicense, and distribute the - Work and such Derivative Works in Source or Object form. - - 3. Grant of Patent License. Subject to the terms and conditions of - this License, each Contributor hereby grants to You a perpetual, - worldwide, non-exclusive, no-charge, royalty-free, irrevocable - (except as stated in this section) patent license to make, have made, - use, offer to sell, sell, import, and otherwise transfer the Work, - where such license applies only to those patent claims licensable - by such Contributor that are necessarily infringed by their - Contribution(s) alone or by combination of their Contribution(s) - with the Work to which such Contribution(s) was submitted. If You - institute patent litigation against any entity (including a - cross-claim or counterclaim in a lawsuit) alleging that the Work - or a Contribution incorporated within the Work constitutes direct - or contributory patent infringement, then any patent licenses - granted to You under this License for that Work shall terminate - as of the date such litigation is filed. - - 4. Redistribution. You may reproduce and distribute copies of the - Work or Derivative Works thereof in any medium, with or without - modifications, and in Source or Object form, provided that You - meet the following conditions: - - (a) You must give any other recipients of the Work or - Derivative Works a copy of this License; and - - (b) You must cause any modified files to carry prominent notices - stating that You changed the files; and - - (c) You must retain, in the Source form of any Derivative Works - that You distribute, all copyright, patent, trademark, and - attribution notices from the Source form of the Work, - excluding those notices that do not pertain to any part of - the Derivative Works; and - - (d) If the Work includes a "NOTICE" text file as part of its - distribution, then any Derivative Works that You distribute must - include a readable copy of the attribution notices contained - within such NOTICE file, excluding those notices that do not - pertain to any part of the Derivative Works, in at least one - of the following places: within a NOTICE text file distributed - as part of the Derivative Works; within the Source form or - documentation, if provided along with the Derivative Works; or, - within a display generated by the Derivative Works, if and - wherever such third-party notices normally appear. The contents - of the NOTICE file are for informational purposes only and - do not modify the License. You may add Your own attribution - notices within Derivative Works that You distribute, alongside - or as an addendum to the NOTICE text from the Work, provided - that such additional attribution notices cannot be construed - as modifying the License. - - You may add Your own copyright statement to Your modifications and - may provide additional or different license terms and conditions - for use, reproduction, or distribution of Your modifications, or - for any such Derivative Works as a whole, provided Your use, - reproduction, and distribution of the Work otherwise complies with - the conditions stated in this License. - - 5. Submission of Contributions. Unless You explicitly state otherwise, - any Contribution intentionally submitted for inclusion in the Work - by You to the Licensor shall be under the terms and conditions of - this License, without any additional terms or conditions. - Notwithstanding the above, nothing herein shall supersede or modify - the terms of any separate license agreement you may have executed - with Licensor regarding such Contributions. - - 6. Trademarks. This License does not grant permission to use the trade - names, trademarks, service marks, or product names of the Licensor, - except as required for reasonable and customary use in describing the - origin of the Work and reproducing the content of the NOTICE file. - - 7. Disclaimer of Warranty. Unless required by applicable law or - agreed to in writing, Licensor provides the Work (and each - Contributor provides its Contributions) on an "AS IS" BASIS, - WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or - implied, including, without limitation, any warranties or conditions - of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A - PARTICULAR PURPOSE. You are solely responsible for determining the - appropriateness of using or redistributing the Work and assume any - risks associated with Your exercise of permissions under this License. - - 8. Limitation of Liability. In no event and under no legal theory, - whether in tort (including negligence), contract, or otherwise, - unless required by applicable law (such as deliberate and grossly - negligent acts) or agreed to in writing, shall any Contributor be - liable to You for damages, including any direct, indirect, special, - incidental, or consequential damages of any character arising as a - result of this License or out of the use or inability to use the - Work (including but not limited to damages for loss of goodwill, - work stoppage, computer failure or malfunction, or any and all - other commercial damages or losses), even if such Contributor - has been advised of the possibility of such damages. - - 9. Accepting Warranty or Additional Liability. While redistributing - the Work or Derivative Works thereof, You may choose to offer, - and charge a fee for, acceptance of support, warranty, indemnity, - or other liability obligations and/or rights consistent with this - License. However, in accepting such obligations, You may act only - on Your own behalf and on Your sole responsibility, not on behalf - of any other Contributor, and only if You agree to indemnify, - defend, and hold each Contributor harmless for any liability - incurred by, or claims asserted against, such Contributor by reason - of your accepting any such warranty or additional liability. - - END OF TERMS AND CONDITIONS - - APPENDIX: How to apply the Apache License to your work. - - To apply the Apache License to your work, attach the following - boilerplate notice, with the fields enclosed by brackets "[]" - replaced with your own identifying information. (Don't include - the brackets!) The text should be enclosed in the appropriate - comment syntax for the file format. We also recommend that a - file or class name and description of purpose be included on the - same "printed page" as the copyright notice for easier - identification within third-party archives. - - Copyright [yyyy] [name of copyright owner] - - Licensed 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. \ No newline at end of file diff --git a/tools/dependencies-report/src/main/resources/notices/commons-codec!commons-codec-1.10.0-NOTICE.txt b/tools/dependencies-report/src/main/resources/notices/commons-codec!commons-codec-NOTICE.txt similarity index 100% rename from tools/dependencies-report/src/main/resources/notices/commons-codec!commons-codec-1.10.0-NOTICE.txt rename to tools/dependencies-report/src/main/resources/notices/commons-codec!commons-codec-NOTICE.txt diff --git a/tools/dependencies-report/src/main/resources/notices/commons-logging!commons-logging-1.2.0-NOTICE.txt b/tools/dependencies-report/src/main/resources/notices/commons-logging!commons-logging-NOTICE.txt similarity index 100% rename from tools/dependencies-report/src/main/resources/notices/commons-logging!commons-logging-1.2.0-NOTICE.txt rename to tools/dependencies-report/src/main/resources/notices/commons-logging!commons-logging-NOTICE.txt diff --git a/tools/dependencies-report/src/main/resources/notices/concurrent-ruby-1.0.5-NOTICE.txt b/tools/dependencies-report/src/main/resources/notices/concurrent-ruby-NOTICE.txt similarity index 100% rename from tools/dependencies-report/src/main/resources/notices/concurrent-ruby-1.0.5-NOTICE.txt rename to tools/dependencies-report/src/main/resources/notices/concurrent-ruby-NOTICE.txt diff --git a/tools/dependencies-report/src/main/resources/notices/controls.js-NOTICE.txt b/tools/dependencies-report/src/main/resources/notices/controls.js-NOTICE.txt deleted file mode 100644 index 929c05d72..000000000 --- a/tools/dependencies-report/src/main/resources/notices/controls.js-NOTICE.txt +++ /dev/null @@ -1 +0,0 @@ -404: Not Found diff --git a/tools/dependencies-report/src/main/resources/notices/crack-0.4.3-NOTICE.txt b/tools/dependencies-report/src/main/resources/notices/dalli-NOTICE.txt similarity index 95% rename from tools/dependencies-report/src/main/resources/notices/crack-0.4.3-NOTICE.txt rename to tools/dependencies-report/src/main/resources/notices/dalli-NOTICE.txt index fbbebe148..51c00933c 100644 --- a/tools/dependencies-report/src/main/resources/notices/crack-0.4.3-NOTICE.txt +++ b/tools/dependencies-report/src/main/resources/notices/dalli-NOTICE.txt @@ -1,4 +1,4 @@ -Copyright (c) 2009 John Nunemaker +Copyright (c) Peter M. Goldstein, Mike Perham Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the diff --git a/tools/dependencies-report/src/main/resources/notices/diff-lcs-1.3-NOTICE.txt b/tools/dependencies-report/src/main/resources/notices/diff-lcs-1.3-NOTICE.txt deleted file mode 100644 index c0ffb22b7..000000000 --- a/tools/dependencies-report/src/main/resources/notices/diff-lcs-1.3-NOTICE.txt +++ /dev/null @@ -1,19 +0,0 @@ -Copyright 2004–2013 Austin Ziegler. - -Permission is hereby granted, free of charge, to any person obtaining a copy of -this software and associated documentation files (the "Software"), to deal in -the Software without restriction, including without limitation the rights to -use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies -of the Software, and to permit persons to whom the Software is furnished to do -so, subject to the following conditions: - -The above copyright notice and this permission notice shall be included in all -copies or substantial portions of the Software. - -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE -SOFTWARE. \ No newline at end of file diff --git a/tools/dependencies-report/src/main/resources/notices/domain_name-0.5.20180417-NOTICE.txt b/tools/dependencies-report/src/main/resources/notices/domain_name-NOTICE.txt similarity index 100% rename from tools/dependencies-report/src/main/resources/notices/domain_name-0.5.20180417-NOTICE.txt rename to tools/dependencies-report/src/main/resources/notices/domain_name-NOTICE.txt diff --git a/tools/dependencies-report/src/main/resources/notices/dotenv-2.5.0-NOTICE.txt b/tools/dependencies-report/src/main/resources/notices/dotenv-NOTICE.txt similarity index 100% rename from tools/dependencies-report/src/main/resources/notices/dotenv-2.5.0-NOTICE.txt rename to tools/dependencies-report/src/main/resources/notices/dotenv-NOTICE.txt diff --git a/tools/dependencies-report/src/main/resources/notices/edn-1.1.1-NOTICE.txt b/tools/dependencies-report/src/main/resources/notices/edn-NOTICE.txt similarity index 100% rename from tools/dependencies-report/src/main/resources/notices/edn-1.1.1-NOTICE.txt rename to tools/dependencies-report/src/main/resources/notices/edn-NOTICE.txt diff --git a/tools/dependencies-report/src/main/resources/notices/elasticsearch-5.0.5-NOTICE.txt b/tools/dependencies-report/src/main/resources/notices/elasticsearch-NOTICE.txt similarity index 100% rename from tools/dependencies-report/src/main/resources/notices/elasticsearch-5.0.5-NOTICE.txt rename to tools/dependencies-report/src/main/resources/notices/elasticsearch-NOTICE.txt diff --git a/tools/dependencies-report/src/main/resources/notices/elasticsearch-api-5.0.5-NOTICE.txt b/tools/dependencies-report/src/main/resources/notices/elasticsearch-api-NOTICE.txt similarity index 100% rename from tools/dependencies-report/src/main/resources/notices/elasticsearch-api-5.0.5-NOTICE.txt rename to tools/dependencies-report/src/main/resources/notices/elasticsearch-api-NOTICE.txt diff --git a/tools/dependencies-report/src/main/resources/notices/elasticsearch-transport-5.0.5-NOTICE.txt b/tools/dependencies-report/src/main/resources/notices/elasticsearch-transport-NOTICE.txt similarity index 100% rename from tools/dependencies-report/src/main/resources/notices/elasticsearch-transport-5.0.5-NOTICE.txt rename to tools/dependencies-report/src/main/resources/notices/elasticsearch-transport-NOTICE.txt diff --git a/tools/dependencies-report/src/main/resources/notices/equalizer-0.0.10-NOTICE.txt b/tools/dependencies-report/src/main/resources/notices/equalizer-NOTICE.txt similarity index 100% rename from tools/dependencies-report/src/main/resources/notices/equalizer-0.0.10-NOTICE.txt rename to tools/dependencies-report/src/main/resources/notices/equalizer-NOTICE.txt diff --git a/tools/dependencies-report/src/main/resources/notices/faraday-0.9.2-NOTICE.txt b/tools/dependencies-report/src/main/resources/notices/faraday-NOTICE.txt similarity index 100% rename from tools/dependencies-report/src/main/resources/notices/faraday-0.9.2-NOTICE.txt rename to tools/dependencies-report/src/main/resources/notices/faraday-NOTICE.txt diff --git a/tools/dependencies-report/src/main/resources/notices/ffi-1.9.25-NOTICE.txt b/tools/dependencies-report/src/main/resources/notices/ffi-NOTICE.txt similarity index 100% rename from tools/dependencies-report/src/main/resources/notices/ffi-1.9.25-NOTICE.txt rename to tools/dependencies-report/src/main/resources/notices/ffi-NOTICE.txt diff --git a/tools/dependencies-report/src/main/resources/notices/filesize-0.0.4-NOTICE.txt b/tools/dependencies-report/src/main/resources/notices/filesize-NOTICE.txt similarity index 100% rename from tools/dependencies-report/src/main/resources/notices/filesize-0.0.4-NOTICE.txt rename to tools/dependencies-report/src/main/resources/notices/filesize-NOTICE.txt diff --git a/tools/dependencies-report/src/main/resources/notices/filewatch-0.9.0-NOTICE.txt b/tools/dependencies-report/src/main/resources/notices/filewatch-0.9.0-NOTICE.txt deleted file mode 100644 index 663792949..000000000 --- a/tools/dependencies-report/src/main/resources/notices/filewatch-0.9.0-NOTICE.txt +++ /dev/null @@ -1,3 +0,0 @@ -https://github.com/jordansissel/ruby-filewatch/blob/master/LICENSE - -License is MIT (very permissive). diff --git a/tools/dependencies-report/src/main/resources/notices/ftw-0.0.48-NOTICE.txt b/tools/dependencies-report/src/main/resources/notices/ftw-0.0.48-NOTICE.txt deleted file mode 100644 index d94e000d4..000000000 --- a/tools/dependencies-report/src/main/resources/notices/ftw-0.0.48-NOTICE.txt +++ /dev/null @@ -1,3 +0,0 @@ -source: https://github.com/jordansissel/ruby-ftw/blob/master/ftw.gemspec#L19 - -Apache License (2.0) \ No newline at end of file diff --git a/tools/dependencies-report/src/main/resources/notices/gelf-3.0.0-NOTICE.txt b/tools/dependencies-report/src/main/resources/notices/gelf-3.0.0-NOTICE.txt deleted file mode 100644 index fe6c6e577..000000000 --- a/tools/dependencies-report/src/main/resources/notices/gelf-3.0.0-NOTICE.txt +++ /dev/null @@ -1,22 +0,0 @@ -source: https://github.com/graylog-labs/gelf-rb/blob/v3.0.0/LICENSE - -Copyright (c) 2010-2016 Lennart Koopmann, Alexey Palazhchenko - -Permission is hereby granted, free of charge, to any person obtaining -a copy of this software and associated documentation files (the -"Software"), to deal in the Software without restriction, including -without limitation the rights to use, copy, modify, merge, publish, -distribute, sublicense, and/or sell copies of the Software, and to -permit persons to whom the Software is furnished to do so, subject to -the following conditions: - -The above copyright notice and this permission notice shall be -included in all copies or substantial portions of the Software. - -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, -EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF -MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND -NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE -LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION -OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION -WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. diff --git a/tools/dependencies-report/src/main/resources/notices/gelfd-0.2.0-NOTICE.txt b/tools/dependencies-report/src/main/resources/notices/gelfd2-NOTICE.txt similarity index 90% rename from tools/dependencies-report/src/main/resources/notices/gelfd-0.2.0-NOTICE.txt rename to tools/dependencies-report/src/main/resources/notices/gelfd2-NOTICE.txt index b0b282e64..3d140d170 100644 --- a/tools/dependencies-report/src/main/resources/notices/gelfd-0.2.0-NOTICE.txt +++ b/tools/dependencies-report/src/main/resources/notices/gelfd2-NOTICE.txt @@ -1,5 +1,3 @@ -source: https://github.com/lusis/gelfd/blob/master/LICENSE - Copyright 2011-2013 John E. Vincent and contributors. Licensed under the Apache License, Version 2.0 (the "License"); @@ -13,4 +11,3 @@ 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. - diff --git a/tools/dependencies-report/src/main/resources/notices/gems-0.8.3-NOTICE.txt b/tools/dependencies-report/src/main/resources/notices/gems-NOTICE.txt similarity index 100% rename from tools/dependencies-report/src/main/resources/notices/gems-0.8.3-NOTICE.txt rename to tools/dependencies-report/src/main/resources/notices/gems-NOTICE.txt diff --git a/tools/dependencies-report/src/main/resources/notices/childprocess-0.9.0-NOTICE.txt b/tools/dependencies-report/src/main/resources/notices/gene_pool-NOTICE.txt similarity index 96% rename from tools/dependencies-report/src/main/resources/notices/childprocess-0.9.0-NOTICE.txt rename to tools/dependencies-report/src/main/resources/notices/gene_pool-NOTICE.txt index 50cfbaec2..a51d36247 100644 --- a/tools/dependencies-report/src/main/resources/notices/childprocess-0.9.0-NOTICE.txt +++ b/tools/dependencies-report/src/main/resources/notices/gene_pool-NOTICE.txt @@ -1,4 +1,4 @@ -Copyright (c) 2010-2015 Jari Bakken +Copyright (c) 2010-2011 Brad Pardee Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the diff --git a/tools/dependencies-report/src/main/resources/notices/gmetric-0.1.3-NOTICE.txt b/tools/dependencies-report/src/main/resources/notices/gmetric-0.1.3-NOTICE.txt deleted file mode 100644 index da1b45b15..000000000 --- a/tools/dependencies-report/src/main/resources/notices/gmetric-0.1.3-NOTICE.txt +++ /dev/null @@ -1,3 +0,0 @@ -source: https://github.com/igrigorik/gmetric/blob/master/README.md - -The MIT License, Copyright (c) 2009 Ilya Grigorik diff --git a/tools/dependencies-report/src/main/resources/notices/gradle.plugin.com.github.jk1!gradle-license-report-0.7.1-NOTICE.txt b/tools/dependencies-report/src/main/resources/notices/gradle.plugin.com.github.jk1!gradle-license-report-NOTICE.txt similarity index 100% rename from tools/dependencies-report/src/main/resources/notices/gradle.plugin.com.github.jk1!gradle-license-report-0.7.1-NOTICE.txt rename to tools/dependencies-report/src/main/resources/notices/gradle.plugin.com.github.jk1!gradle-license-report-NOTICE.txt diff --git a/tools/dependencies-report/src/main/resources/notices/gserver-0.0.1-NOTICE.txt b/tools/dependencies-report/src/main/resources/notices/gserver-0.0.1-NOTICE.txt deleted file mode 100644 index d38b8ff5b..000000000 --- a/tools/dependencies-report/src/main/resources/notices/gserver-0.0.1-NOTICE.txt +++ /dev/null @@ -1,58 +0,0 @@ -Source: https://github.com/ruby/gserver/blob/v0.0.1/LICENSE.txt - -Ruby is copyrighted free software by Yukihiro Matsumoto . -You can redistribute it and/or modify it under either the terms of the -2-clause BSDL (see the file BSDL), or the conditions below: - - 1. You may make and give away verbatim copies of the source form of the - software without restriction, provided that you duplicate all of the - original copyright notices and associated disclaimers. - - 2. You may modify your copy of the software in any way, provided that - you do at least ONE of the following: - - a) place your modifications in the Public Domain or otherwise - make them Freely Available, such as by posting said - modifications to Usenet or an equivalent medium, or by allowing - the author to include your modifications in the software. - - b) use the modified software only within your corporation or - organization. - - c) give non-standard binaries non-standard names, with - instructions on where to get the original software distribution. - - d) make other distribution arrangements with the author. - - 3. You may distribute the software in object code or binary form, - provided that you do at least ONE of the following: - - a) distribute the binaries and library files of the software, - together with instructions (in the manual page or equivalent) - on where to get the original distribution. - - b) accompany the distribution with the machine-readable source of - the software. - - c) give non-standard binaries non-standard names, with - instructions on where to get the original software distribution. - - d) make other distribution arrangements with the author. - - 4. You may modify and include the part of the software into any other - software (possibly commercial). But some files in the distribution - are not written by the author, so that they are not under these terms. - - For the list of those files and their copying conditions, see the - file LEGAL. - - 5. The scripts and library files supplied as input to or produced as - output from the software do not automatically fall under the - copyright of the software, but belong to whomever generated them, - and may be sold commercially, and may be aggregated with this - software. - - 6. THIS SOFTWARE IS PROVIDED "AS IS" AND WITHOUT ANY EXPRESS OR - IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED - WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR - PURPOSE. diff --git a/tools/dependencies-report/src/main/resources/notices/hitimes-1.3.0-NOTICE.txt b/tools/dependencies-report/src/main/resources/notices/hitimes-NOTICE.txt similarity index 100% rename from tools/dependencies-report/src/main/resources/notices/hitimes-1.3.0-NOTICE.txt rename to tools/dependencies-report/src/main/resources/notices/hitimes-NOTICE.txt diff --git a/tools/dependencies-report/src/main/resources/notices/http-0.9.9-NOTICE.txt b/tools/dependencies-report/src/main/resources/notices/http-NOTICE.txt similarity index 100% rename from tools/dependencies-report/src/main/resources/notices/http-0.9.9-NOTICE.txt rename to tools/dependencies-report/src/main/resources/notices/http-NOTICE.txt diff --git a/tools/dependencies-report/src/main/resources/notices/http-cookie-1.0.3-NOTICE.txt b/tools/dependencies-report/src/main/resources/notices/http-cookie-NOTICE.txt similarity index 100% rename from tools/dependencies-report/src/main/resources/notices/http-cookie-1.0.3-NOTICE.txt rename to tools/dependencies-report/src/main/resources/notices/http-cookie-NOTICE.txt diff --git a/tools/dependencies-report/src/main/resources/notices/http-form_data-1.0.1-NOTICE.txt b/tools/dependencies-report/src/main/resources/notices/http-form_data-NOTICE.txt similarity index 100% rename from tools/dependencies-report/src/main/resources/notices/http-form_data-1.0.1-NOTICE.txt rename to tools/dependencies-report/src/main/resources/notices/http-form_data-NOTICE.txt diff --git a/tools/dependencies-report/src/main/resources/notices/http_parser.rb-0.6.0-NOTICE.txt b/tools/dependencies-report/src/main/resources/notices/http_parser.rb-NOTICE.txt similarity index 100% rename from tools/dependencies-report/src/main/resources/notices/http_parser.rb-0.6.0-NOTICE.txt rename to tools/dependencies-report/src/main/resources/notices/http_parser.rb-NOTICE.txt diff --git a/tools/dependencies-report/src/main/resources/notices/i18n-0.6.9-NOTICE.txt b/tools/dependencies-report/src/main/resources/notices/i18n-NOTICE.txt similarity index 100% rename from tools/dependencies-report/src/main/resources/notices/i18n-0.6.9-NOTICE.txt rename to tools/dependencies-report/src/main/resources/notices/i18n-NOTICE.txt diff --git a/tools/dependencies-report/src/main/resources/notices/insist-1.0.0-NOTICE.txt b/tools/dependencies-report/src/main/resources/notices/insist-NOTICE.txt similarity index 100% rename from tools/dependencies-report/src/main/resources/notices/insist-1.0.0-NOTICE.txt rename to tools/dependencies-report/src/main/resources/notices/insist-NOTICE.txt diff --git a/tools/dependencies-report/src/main/resources/notices/invokebinder-1.7-NOTICE.txt b/tools/dependencies-report/src/main/resources/notices/invokebinder-1.7-NOTICE.txt deleted file mode 100644 index 8c32d8814..000000000 --- a/tools/dependencies-report/src/main/resources/notices/invokebinder-1.7-NOTICE.txt +++ /dev/null @@ -1,15 +0,0 @@ -source: https://github.com/headius/invokebinder/search?q=copyright - -Copyright 2012-2014 headius. - -Licensed 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. \ No newline at end of file diff --git a/tools/dependencies-report/src/main/resources/notices/jar-dependencies-0.3.12-NOTICE.txt b/tools/dependencies-report/src/main/resources/notices/jar-dependencies-NOTICE.txt similarity index 100% rename from tools/dependencies-report/src/main/resources/notices/jar-dependencies-0.3.12-NOTICE.txt rename to tools/dependencies-report/src/main/resources/notices/jar-dependencies-NOTICE.txt diff --git a/tools/dependencies-report/src/main/resources/notices/jay-yydebug-NOTICE.txt b/tools/dependencies-report/src/main/resources/notices/jay-NOTICE.txt similarity index 100% rename from tools/dependencies-report/src/main/resources/notices/jay-yydebug-NOTICE.txt rename to tools/dependencies-report/src/main/resources/notices/jay-NOTICE.txt diff --git a/tools/dependencies-report/src/main/resources/notices/jcodings-1.0.18-NOTICE.txt b/tools/dependencies-report/src/main/resources/notices/jcodings-1.0.18-NOTICE.txt deleted file mode 100644 index c70f00c0c..000000000 --- a/tools/dependencies-report/src/main/resources/notices/jcodings-1.0.18-NOTICE.txt +++ /dev/null @@ -1,19 +0,0 @@ -source: https://github.com/jruby/jcodings/blob/master/LICENSE.txt - -Permission is hereby granted, free of charge, to any person obtaining a copy of -this software and associated documentation files (the "Software"), to deal in -the Software without restriction, including without limitation the rights to -use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies -of the Software, and to permit persons to whom the Software is furnished to do -so, subject to the following conditions: - -The above copyright notice and this permission notice shall be included in all -copies or substantial portions of the Software. - -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE -SOFTWARE. diff --git a/tools/dependencies-report/src/main/resources/notices/jdbc-derby-10.12.1.1-NOTICE.txt b/tools/dependencies-report/src/main/resources/notices/jdbc-derby-10.12.1.1-NOTICE.txt deleted file mode 100644 index c8f9117ec..000000000 --- a/tools/dependencies-report/src/main/resources/notices/jdbc-derby-10.12.1.1-NOTICE.txt +++ /dev/null @@ -1,203 +0,0 @@ -source: https://github.com/jruby/activerecord-jdbc-adapter/blob/master/jdbc-derby/LICENSE.txt - - Apache License - Version 2.0, January 2004 - http://www.apache.org/licenses/ - - TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION - - 1. Definitions. - - "License" shall mean the terms and conditions for use, reproduction, - and distribution as defined by Sections 1 through 9 of this document. - - "Licensor" shall mean the copyright owner or entity authorized by - the copyright owner that is granting the License. - - "Legal Entity" shall mean the union of the acting entity and all - other entities that control, are controlled by, or are under common - control with that entity. For the purposes of this definition, - "control" means (i) the power, direct or indirect, to cause the - direction or management of such entity, whether by contract or - otherwise, or (ii) ownership of fifty percent (50%) or more of the - outstanding shares, or (iii) beneficial ownership of such entity. - - "You" (or "Your") shall mean an individual or Legal Entity - exercising permissions granted by this License. - - "Source" form shall mean the preferred form for making modifications, - including but not limited to software source code, documentation - source, and configuration files. - - "Object" form shall mean any form resulting from mechanical - transformation or translation of a Source form, including but - not limited to compiled object code, generated documentation, - and conversions to other media types. - - "Work" shall mean the work of authorship, whether in Source or - Object form, made available under the License, as indicated by a - copyright notice that is included in or attached to the work - (an example is provided in the Appendix below). - - "Derivative Works" shall mean any work, whether in Source or Object - form, that is based on (or derived from) the Work and for which the - editorial revisions, annotations, elaborations, or other modifications - represent, as a whole, an original work of authorship. For the purposes - of this License, Derivative Works shall not include works that remain - separable from, or merely link (or bind by name) to the interfaces of, - the Work and Derivative Works thereof. - - "Contribution" shall mean any work of authorship, including - the original version of the Work and any modifications or additions - to that Work or Derivative Works thereof, that is intentionally - submitted to Licensor for inclusion in the Work by the copyright owner - or by an individual or Legal Entity authorized to submit on behalf of - the copyright owner. For the purposes of this definition, "submitted" - means any form of electronic, verbal, or written communication sent - to the Licensor or its representatives, including but not limited to - communication on electronic mailing lists, source code control systems, - and issue tracking systems that are managed by, or on behalf of, the - Licensor for the purpose of discussing and improving the Work, but - excluding communication that is conspicuously marked or otherwise - designated in writing by the copyright owner as "Not a Contribution." - - "Contributor" shall mean Licensor and any individual or Legal Entity - on behalf of whom a Contribution has been received by Licensor and - subsequently incorporated within the Work. - - 2. Grant of Copyright License. Subject to the terms and conditions of - this License, each Contributor hereby grants to You a perpetual, - worldwide, non-exclusive, no-charge, royalty-free, irrevocable - copyright license to reproduce, prepare Derivative Works of, - publicly display, publicly perform, sublicense, and distribute the - Work and such Derivative Works in Source or Object form. - - 3. Grant of Patent License. Subject to the terms and conditions of - this License, each Contributor hereby grants to You a perpetual, - worldwide, non-exclusive, no-charge, royalty-free, irrevocable - (except as stated in this section) patent license to make, have made, - use, offer to sell, sell, import, and otherwise transfer the Work, - where such license applies only to those patent claims licensable - by such Contributor that are necessarily infringed by their - Contribution(s) alone or by combination of their Contribution(s) - with the Work to which such Contribution(s) was submitted. If You - institute patent litigation against any entity (including a - cross-claim or counterclaim in a lawsuit) alleging that the Work - or a Contribution incorporated within the Work constitutes direct - or contributory patent infringement, then any patent licenses - granted to You under this License for that Work shall terminate - as of the date such litigation is filed. - - 4. Redistribution. You may reproduce and distribute copies of the - Work or Derivative Works thereof in any medium, with or without - modifications, and in Source or Object form, provided that You - meet the following conditions: - - (a) You must give any other recipients of the Work or - Derivative Works a copy of this License; and - - (b) You must cause any modified files to carry prominent notices - stating that You changed the files; and - - (c) You must retain, in the Source form of any Derivative Works - that You distribute, all copyright, patent, trademark, and - attribution notices from the Source form of the Work, - excluding those notices that do not pertain to any part of - the Derivative Works; and - - (d) If the Work includes a "NOTICE" text file as part of its - distribution, then any Derivative Works that You distribute must - include a readable copy of the attribution notices contained - within such NOTICE file, excluding those notices that do not - pertain to any part of the Derivative Works, in at least one - of the following places: within a NOTICE text file distributed - as part of the Derivative Works; within the Source form or - documentation, if provided along with the Derivative Works; or, - within a display generated by the Derivative Works, if and - wherever such third-party notices normally appear. The contents - of the NOTICE file are for informational purposes only and - do not modify the License. You may add Your own attribution - notices within Derivative Works that You distribute, alongside - or as an addendum to the NOTICE text from the Work, provided - that such additional attribution notices cannot be construed - as modifying the License. - - You may add Your own copyright statement to Your modifications and - may provide additional or different license terms and conditions - for use, reproduction, or distribution of Your modifications, or - for any such Derivative Works as a whole, provided Your use, - reproduction, and distribution of the Work otherwise complies with - the conditions stated in this License. - - 5. Submission of Contributions. Unless You explicitly state otherwise, - any Contribution intentionally submitted for inclusion in the Work - by You to the Licensor shall be under the terms and conditions of - this License, without any additional terms or conditions. - Notwithstanding the above, nothing herein shall supersede or modify - the terms of any separate license agreement you may have executed - with Licensor regarding such Contributions. - - 6. Trademarks. This License does not grant permission to use the trade - names, trademarks, service marks, or product names of the Licensor, - except as required for reasonable and customary use in describing the - origin of the Work and reproducing the content of the NOTICE file. - - 7. Disclaimer of Warranty. Unless required by applicable law or - agreed to in writing, Licensor provides the Work (and each - Contributor provides its Contributions) on an "AS IS" BASIS, - WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or - implied, including, without limitation, any warranties or conditions - of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A - PARTICULAR PURPOSE. You are solely responsible for determining the - appropriateness of using or redistributing the Work and assume any - risks associated with Your exercise of permissions under this License. - - 8. Limitation of Liability. In no event and under no legal theory, - whether in tort (including negligence), contract, or otherwise, - unless required by applicable law (such as deliberate and grossly - negligent acts) or agreed to in writing, shall any Contributor be - liable to You for damages, including any direct, indirect, special, - incidental, or consequential damages of any character arising as a - result of this License or out of the use or inability to use the - Work (including but not limited to damages for loss of goodwill, - work stoppage, computer failure or malfunction, or any and all - other commercial damages or losses), even if such Contributor - has been advised of the possibility of such damages. - - 9. Accepting Warranty or Additional Liability. While redistributing - the Work or Derivative Works thereof, You may choose to offer, - and charge a fee for, acceptance of support, warranty, indemnity, - or other liability obligations and/or rights consistent with this - License. However, in accepting such obligations, You may act only - on Your own behalf and on Your sole responsibility, not on behalf - of any other Contributor, and only if You agree to indemnify, - defend, and hold each Contributor harmless for any liability - incurred by, or claims asserted against, such Contributor by reason - of your accepting any such warranty or additional liability. - - END OF TERMS AND CONDITIONS - - APPENDIX: How to apply the Apache License to your work. - - To apply the Apache License to your work, attach the following - boilerplate notice, with the fields enclosed by brackets "[]" - replaced with your own identifying information. (Don't include - the brackets!) The text should be enclosed in the appropriate - comment syntax for the file format. We also recommend that a - file or class name and description of purpose be included on the - same "printed page" as the copyright notice for easier - identification within third-party archives. - - Copyright [yyyy] [name of copyright owner] - - Licensed 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. diff --git a/tools/dependencies-report/src/main/resources/notices/jffi-1.2.16-NOTICE.txt b/tools/dependencies-report/src/main/resources/notices/jffi-1.2.16-NOTICE.txt deleted file mode 100644 index aba0602f1..000000000 --- a/tools/dependencies-report/src/main/resources/notices/jffi-1.2.16-NOTICE.txt +++ /dev/null @@ -1,27 +0,0 @@ -source: https://github.com/jnr/jffi/blob/master/LICENSE - -Licensed 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. - - - Alternatively, you can redistribute it and/or modify it under - the terms of the GNU Lesser General Public License as published by - the Free Software Foundation, either version 3 of the License, or - (at your option) any later version. - - This code is distributed in the hope that it will be useful, but WITHOUT - ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License - version 3 for more details. - - You should have received a copy of the GNU Lesser General Public License - version 3 along with this work. If not, see . diff --git a/tools/dependencies-report/src/main/resources/notices/jitescript-0.4.1-NOTICE.txt b/tools/dependencies-report/src/main/resources/notices/jitescript-0.4.1-NOTICE.txt deleted file mode 100644 index 783fa6f2e..000000000 --- a/tools/dependencies-report/src/main/resources/notices/jitescript-0.4.1-NOTICE.txt +++ /dev/null @@ -1,179 +0,0 @@ - source: https://github.com/qmx/jitescript/blob/master/LICENSE - - Apache License - Version 2.0, January 2004 - http://www.apache.org/licenses/ - - TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION - - 1. Definitions. - - "License" shall mean the terms and conditions for use, reproduction, - and distribution as defined by Sections 1 through 9 of this document. - - "Licensor" shall mean the copyright owner or entity authorized by - the copyright owner that is granting the License. - - "Legal Entity" shall mean the union of the acting entity and all - other entities that control, are controlled by, or are under common - control with that entity. For the purposes of this definition, - "control" means (i) the power, direct or indirect, to cause the - direction or management of such entity, whether by contract or - otherwise, or (ii) ownership of fifty percent (50%) or more of the - outstanding shares, or (iii) beneficial ownership of such entity. - - "You" (or "Your") shall mean an individual or Legal Entity - exercising permissions granted by this License. - - "Source" form shall mean the preferred form for making modifications, - including but not limited to software source code, documentation - source, and configuration files. - - "Object" form shall mean any form resulting from mechanical - transformation or translation of a Source form, including but - not limited to compiled object code, generated documentation, - and conversions to other media types. - - "Work" shall mean the work of authorship, whether in Source or - Object form, made available under the License, as indicated by a - copyright notice that is included in or attached to the work - (an example is provided in the Appendix below). - - "Derivative Works" shall mean any work, whether in Source or Object - form, that is based on (or derived from) the Work and for which the - editorial revisions, annotations, elaborations, or other modifications - represent, as a whole, an original work of authorship. For the purposes - of this License, Derivative Works shall not include works that remain - separable from, or merely link (or bind by name) to the interfaces of, - the Work and Derivative Works thereof. - - "Contribution" shall mean any work of authorship, including - the original version of the Work and any modifications or additions - to that Work or Derivative Works thereof, that is intentionally - submitted to Licensor for inclusion in the Work by the copyright owner - or by an individual or Legal Entity authorized to submit on behalf of - the copyright owner. For the purposes of this definition, "submitted" - means any form of electronic, verbal, or written communication sent - to the Licensor or its representatives, including but not limited to - communication on electronic mailing lists, source code control systems, - and issue tracking systems that are managed by, or on behalf of, the - Licensor for the purpose of discussing and improving the Work, but - excluding communication that is conspicuously marked or otherwise - designated in writing by the copyright owner as "Not a Contribution." - - "Contributor" shall mean Licensor and any individual or Legal Entity - on behalf of whom a Contribution has been received by Licensor and - subsequently incorporated within the Work. - - 2. Grant of Copyright License. Subject to the terms and conditions of - this License, each Contributor hereby grants to You a perpetual, - worldwide, non-exclusive, no-charge, royalty-free, irrevocable - copyright license to reproduce, prepare Derivative Works of, - publicly display, publicly perform, sublicense, and distribute the - Work and such Derivative Works in Source or Object form. - - 3. Grant of Patent License. Subject to the terms and conditions of - this License, each Contributor hereby grants to You a perpetual, - worldwide, non-exclusive, no-charge, royalty-free, irrevocable - (except as stated in this section) patent license to make, have made, - use, offer to sell, sell, import, and otherwise transfer the Work, - where such license applies only to those patent claims licensable - by such Contributor that are necessarily infringed by their - Contribution(s) alone or by combination of their Contribution(s) - with the Work to which such Contribution(s) was submitted. If You - institute patent litigation against any entity (including a - cross-claim or counterclaim in a lawsuit) alleging that the Work - or a Contribution incorporated within the Work constitutes direct - or contributory patent infringement, then any patent licenses - granted to You under this License for that Work shall terminate - as of the date such litigation is filed. - - 4. Redistribution. You may reproduce and distribute copies of the - Work or Derivative Works thereof in any medium, with or without - modifications, and in Source or Object form, provided that You - meet the following conditions: - - (a) You must give any other recipients of the Work or - Derivative Works a copy of this License; and - - (b) You must cause any modified files to carry prominent notices - stating that You changed the files; and - - (c) You must retain, in the Source form of any Derivative Works - that You distribute, all copyright, patent, trademark, and - attribution notices from the Source form of the Work, - excluding those notices that do not pertain to any part of - the Derivative Works; and - - (d) If the Work includes a "NOTICE" text file as part of its - distribution, then any Derivative Works that You distribute must - include a readable copy of the attribution notices contained - within such NOTICE file, excluding those notices that do not - pertain to any part of the Derivative Works, in at least one - of the following places: within a NOTICE text file distributed - as part of the Derivative Works; within the Source form or - documentation, if provided along with the Derivative Works; or, - within a display generated by the Derivative Works, if and - wherever such third-party notices normally appear. The contents - of the NOTICE file are for informational purposes only and - do not modify the License. You may add Your own attribution - notices within Derivative Works that You distribute, alongside - or as an addendum to the NOTICE text from the Work, provided - that such additional attribution notices cannot be construed - as modifying the License. - - You may add Your own copyright statement to Your modifications and - may provide additional or different license terms and conditions - for use, reproduction, or distribution of Your modifications, or - for any such Derivative Works as a whole, provided Your use, - reproduction, and distribution of the Work otherwise complies with - the conditions stated in this License. - - 5. Submission of Contributions. Unless You explicitly state otherwise, - any Contribution intentionally submitted for inclusion in the Work - by You to the Licensor shall be under the terms and conditions of - this License, without any additional terms or conditions. - Notwithstanding the above, nothing herein shall supersede or modify - the terms of any separate license agreement you may have executed - with Licensor regarding such Contributions. - - 6. Trademarks. This License does not grant permission to use the trade - names, trademarks, service marks, or product names of the Licensor, - except as required for reasonable and customary use in describing the - origin of the Work and reproducing the content of the NOTICE file. - - 7. Disclaimer of Warranty. Unless required by applicable law or - agreed to in writing, Licensor provides the Work (and each - Contributor provides its Contributions) on an "AS IS" BASIS, - WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or - implied, including, without limitation, any warranties or conditions - of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A - PARTICULAR PURPOSE. You are solely responsible for determining the - appropriateness of using or redistributing the Work and assume any - risks associated with Your exercise of permissions under this License. - - 8. Limitation of Liability. In no event and under no legal theory, - whether in tort (including negligence), contract, or otherwise, - unless required by applicable law (such as deliberate and grossly - negligent acts) or agreed to in writing, shall any Contributor be - liable to You for damages, including any direct, indirect, special, - incidental, or consequential damages of any character arising as a - result of this License or out of the use or inability to use the - Work (including but not limited to damages for loss of goodwill, - work stoppage, computer failure or malfunction, or any and all - other commercial damages or losses), even if such Contributor - has been advised of the possibility of such damages. - - 9. Accepting Warranty or Additional Liability. While redistributing - the Work or Derivative Works thereof, You may choose to offer, - and charge a fee for, acceptance of support, warranty, indemnity, - or other liability obligations and/or rights consistent with this - License. However, in accepting such obligations, You may act only - on Your own behalf and on Your sole responsibility, not on behalf - of any other Contributor, and only if You agree to indemnify, - defend, and hold each Contributor harmless for any liability - incurred by, or claims asserted against, such Contributor by reason - of your accepting any such warranty or additional liability. - - END OF TERMS AND CONDITIONS - diff --git a/tools/dependencies-report/src/main/resources/notices/jline2-2.1.1-NOTICE.txt b/tools/dependencies-report/src/main/resources/notices/jline2-2.1.1-NOTICE.txt deleted file mode 100644 index 747e6c777..000000000 --- a/tools/dependencies-report/src/main/resources/notices/jline2-2.1.1-NOTICE.txt +++ /dev/null @@ -1,36 +0,0 @@ -source: https://github.com/jline/jline2/blob/master/LICENSE.txt - -Copyright (c) 2002-2016, the original author or authors. -All rights reserved. - -http://www.opensource.org/licenses/bsd-license.php - -Redistribution and use in source and binary forms, with or -without modification, are permitted provided that the following -conditions are met: - -Redistributions of source code must retain the above copyright -notice, this list of conditions and the following disclaimer. - -Redistributions in binary form must reproduce the above copyright -notice, this list of conditions and the following disclaimer -in the documentation and/or other materials provided with -the distribution. - -Neither the name of JLine nor the names of its contributors -may be used to endorse or promote products derived from this -software without specific prior written permission. - -THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS -"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, -BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY -AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO -EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE -FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, -OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, -PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, -DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED -AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT -LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING -IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED -OF THE POSSIBILITY OF SUCH DAMAGE. diff --git a/tools/dependencies-report/src/main/resources/notices/jls-grok-0.11.5-NOTICE.txt b/tools/dependencies-report/src/main/resources/notices/jls-grok-NOTICE.txt similarity index 100% rename from tools/dependencies-report/src/main/resources/notices/jls-grok-0.11.5-NOTICE.txt rename to tools/dependencies-report/src/main/resources/notices/jls-grok-NOTICE.txt diff --git a/tools/dependencies-report/src/main/resources/notices/jls-lumberjack-0.0.26-NOTICE.txt b/tools/dependencies-report/src/main/resources/notices/jls-lumberjack-NOTICE.txt similarity index 100% rename from tools/dependencies-report/src/main/resources/notices/jls-lumberjack-0.0.26-NOTICE.txt rename to tools/dependencies-report/src/main/resources/notices/jls-lumberjack-NOTICE.txt diff --git a/tools/dependencies-report/src/main/resources/notices/jmespath-1.4.0-NOTICE.txt b/tools/dependencies-report/src/main/resources/notices/jmespath-NOTICE.txt similarity index 100% rename from tools/dependencies-report/src/main/resources/notices/jmespath-1.4.0-NOTICE.txt rename to tools/dependencies-report/src/main/resources/notices/jmespath-NOTICE.txt diff --git a/tools/dependencies-report/src/main/resources/notices/jnr-unixsocket-NOTICE.txt b/tools/dependencies-report/src/main/resources/notices/jnr-NOTICE.txt similarity index 100% rename from tools/dependencies-report/src/main/resources/notices/jnr-unixsocket-NOTICE.txt rename to tools/dependencies-report/src/main/resources/notices/jnr-NOTICE.txt diff --git a/tools/dependencies-report/src/main/resources/notices/jnr-constants-0.9.9-NOTICE.txt b/tools/dependencies-report/src/main/resources/notices/jnr-constants-0.9.9-NOTICE.txt deleted file mode 100644 index d012a0922..000000000 --- a/tools/dependencies-report/src/main/resources/notices/jnr-constants-0.9.9-NOTICE.txt +++ /dev/null @@ -1,27 +0,0 @@ -source: https://github.com/jnr/jnr-constants/blob/jnr-constants-0.9.9/LICENSE - -Licensed 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. - - - Alternatively, you can redistribute it and/or modify it under - the terms of the GNU Lesser General Public License as published by - the Free Software Foundation, either version 3 of the License, or - (at your option) any later version. - - This code is distributed in the hope that it will be useful, but WITHOUT - ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License - version 3 for more details. - - You should have received a copy of the GNU Lesser General Public License - version 3 along with this work. If not, see . diff --git a/tools/dependencies-report/src/main/resources/notices/jnr-enxio-0.16-NOTICE.txt b/tools/dependencies-report/src/main/resources/notices/jnr-enxio-0.16-NOTICE.txt deleted file mode 100644 index 913ff5665..000000000 --- a/tools/dependencies-report/src/main/resources/notices/jnr-enxio-0.16-NOTICE.txt +++ /dev/null @@ -1,13 +0,0 @@ -source: https://github.com/jnr/jnr-enxio/blob/jnr-enxio-0.16/LICENSE - -Licensed 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. diff --git a/tools/dependencies-report/src/main/resources/notices/jnr-ffi-2.1.7-NOTICE.txt b/tools/dependencies-report/src/main/resources/notices/jnr-ffi-2.1.7-NOTICE.txt deleted file mode 100644 index 1c207c9fb..000000000 --- a/tools/dependencies-report/src/main/resources/notices/jnr-ffi-2.1.7-NOTICE.txt +++ /dev/null @@ -1,27 +0,0 @@ -source: https://github.com/jnr/jnr-ffi/blob/master/LICENSE - -Licensed 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. - - - Alternatively, you can redistribute it and/or modify it under - the terms of the GNU Lesser General Public License as published by - the Free Software Foundation, either version 3 of the License, or - (at your option) any later version. - - This code is distributed in the hope that it will be useful, but WITHOUT - ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License - version 3 for more details. - - You should have received a copy of the GNU Lesser General Public License - version 3 along with this work. If not, see . diff --git a/tools/dependencies-report/src/main/resources/notices/jnr-netdb-1.1.6-NOTICE.txt b/tools/dependencies-report/src/main/resources/notices/jnr-netdb-1.1.6-NOTICE.txt deleted file mode 100644 index 3416bc1ee..000000000 --- a/tools/dependencies-report/src/main/resources/notices/jnr-netdb-1.1.6-NOTICE.txt +++ /dev/null @@ -1,13 +0,0 @@ -source: https://github.com/jnr/jnr-netdb/blob/master/LICENSE - -Licensed 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. diff --git a/tools/dependencies-report/src/main/resources/notices/jnr-posix-3.0.41-NOTICE.txt b/tools/dependencies-report/src/main/resources/notices/jnr-posix-3.0.41-NOTICE.txt deleted file mode 100644 index 16e6629ea..000000000 --- a/tools/dependencies-report/src/main/resources/notices/jnr-posix-3.0.41-NOTICE.txt +++ /dev/null @@ -1,2488 +0,0 @@ -source: https://github.com/jnr/jnr-posix/blob/master/LICENSE.txt - -jnr-posix is released under a tri EPL/GPL/LGPL license. You can use it, -redistribute it and/or modify it under the terms of the: - - Eclipse Public License version 1.0 - GNU General Public License version 2 - GNU Lesser General Public License version 2.1 - -The complete text of the Eclipse Public License is as follows: - - Eclipse Public License - v 1.0 - - THE ACCOMPANYING PROGRAM IS PROVIDED UNDER THE TERMS OF THIS ECLIPSE - PUBLIC LICENSE ("AGREEMENT"). ANY USE, REPRODUCTION OR DISTRIBUTION - OF THE PROGRAM CONSTITUTES RECIPIENT'S ACCEPTANCE OF THIS AGREEMENT. - - 1. DEFINITIONS - - "Contribution" means: - - a) in the case of the initial Contributor, the initial code and - documentation distributed under this Agreement, and - - b) in the case of each subsequent Contributor: - - i) changes to the Program, and - - ii) additions to the Program; - where such changes and/or additions to the Program - originate from and are distributed by that particular - Contributor. A Contribution 'originates' from a - Contributor if it was added to the Program by such - Contributor itself or anyone acting on such - Contributor's behalf. Contributions do not include - additions to the Program which: (i) are separate modules - of software distributed in conjunction with the Program - under their own license agreement, and (ii) are not - derivative works of the Program. - - "Contributor" means any person or entity that distributes the Program. - - "Licensed Patents" mean patent claims licensable by a Contributor - which are necessarily infringed by the use or sale of its - Contribution alone or when combined with the Program. - - "Program" means the Contributions distributed in accordance with - this Agreement. - - "Recipient" means anyone who receives the Program under this - Agreement, including all Contributors. - - 2. GRANT OF RIGHTS - - a) Subject to the terms of this Agreement, each Contributor - hereby grants Recipient a non-exclusive, worldwide, - royalty-free copyright license to reproduce, prepare - derivative works of, publicly display, publicly perform, - distribute and sublicense the Contribution of such - Contributor, if any, and such derivative works, in source - code and object code form. - - b) Subject to the terms of this Agreement, each Contributor - hereby grants Recipient a non-exclusive, worldwide, - royalty-free patent license under Licensed Patents to make, - use, sell, offer to sell, import and otherwise transfer the - Contribution of such Contributor, if any, in source code and - object code form. This patent license shall apply to the - combination of the Contribution and the Program if, at the - time the Contribution is added by the Contributor, such - addition of the Contribution causes such combination to be - covered by the Licensed Patents. The patent license shall not - apply to any other combinations which include the - Contribution. No hardware per se is licensed hereunder. - - c) Recipient understands that although each Contributor grants - the licenses to its Contributions set forth herein, no - assurances are provided by any Contributor that the Program - does not infringe the patent or other intellectual property - rights of any other entity. Each Contributor disclaims any - liability to Recipient for claims brought by any other entity - based on infringement of intellectual property rights or - otherwise. As a condition to exercising the rights and - licenses granted hereunder, each Recipient hereby assumes - sole responsibility to secure any other intellectual property - rights needed, if any. For example, if a third party patent - license is required to allow Recipient to distribute the - Program, it is Recipient's responsibility to acquire that - license before distributing the Program. - - d) Each Contributor represents that to its knowledge it has - sufficient copyright rights in its Contribution, if any, to - grant the copyright license set forth in this Agreement. - - 3. REQUIREMENTS - - A Contributor may choose to distribute the Program in object code - form under its own license agreement, provided that: - - a) it complies with the terms and conditions of this Agreement; and - - b) its license agreement: - - i) effectively disclaims on behalf of all Contributors all - warranties and conditions, express and implied, including - warranties or conditions of title and non-infringement, - and implied warranties or conditions of merchantability - and fitness for a particular purpose; - - ii) effectively excludes on behalf of all Contributors all - liability for damages, including direct, indirect, - special, incidental and consequential damages, such as - lost profits; - - iii) states that any provisions which differ from this - Agreement are offered by that Contributor alone and not - by any other party; and - - iv) states that source code for the Program is available - from such Contributor, and informs licensees how to - obtain it in a reasonable manner on or through a medium - customarily used for software exchange. - - When the Program is made available in source code form: - - a) it must be made available under this Agreement; and - - b) a copy of this Agreement must be included with each copy of - the Program. - - Contributors may not remove or alter any copyright notices contained - within the Program. - - Each Contributor must identify itself as the originator of its - Contribution, if any, in a manner that reasonably allows subsequent - Recipients to identify the originator of the Contribution. - - 4. COMMERCIAL DISTRIBUTION - - Commercial distributors of software may accept certain - responsibilities with respect to end users, business partners and - the like. While this license is intended to facilitate the - commercial use of the Program, the Contributor who includes the - Program in a commercial product offering should do so in a manner - which does not create potential liability for other Contributors. - Therefore, if a Contributor includes the Program in a commercial - product offering, such Contributor ("Commercial Contributor") hereby - agrees to defend and indemnify every other Contributor ("Indemnified - Contributor") against any losses, damages and costs (collectively - "Losses") arising from claims, lawsuits and other legal actions - brought by a third party against the Indemnified Contributor to the - extent caused by the acts or omissions of such Commercial - Contributor in connection with its distribution of the Program in a - commercial product offering. The obligations in this section do not - apply to any claims or Losses relating to any actual or alleged - intellectual property infringement. In order to qualify, an - Indemnified Contributor must: a) promptly notify the Commercial - Contributor in writing of such claim, and b) allow the Commercial - Contributor to control, and cooperate with the Commercial - Contributor in, the defense and any related settlement negotiations. - The Indemnified Contributor may participate in any such claim at its - own expense. - - For example, a Contributor might include the Program in a commercial - product offering, Product X. That Contributor is then a Commercial - Contributor. If that Commercial Contributor then makes performance - claims, or offers warranties related to Product X, those performance - claims and warranties are such Commercial Contributor's - responsibility alone. Under this section, the Commercial Contributor - would have to defend claims against the other Contributors related - to those performance claims and warranties, and if a court requires - any other Contributor to pay any damages as a result, the Commercial - Contributor must pay those damages. - - 5. NO WARRANTY - - EXCEPT AS EXPRESSLY SET FORTH IN THIS AGREEMENT, THE PROGRAM IS - PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF - ANY KIND, EITHER EXPRESS OR IMPLIED INCLUDING, WITHOUT LIMITATION, - ANY WARRANTIES OR CONDITIONS OF TITLE, NON-INFRINGEMENT, - MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE. Each Recipient - is solely responsible for determining the appropriateness of using - and distributing the Program and assumes all risks associated with - its exercise of rights under this Agreement , including but not - limited to the risks and costs of program errors, compliance with - applicable laws, damage to or loss of data, programs or equipment, - and unavailability or interruption of operations. - - 6. DISCLAIMER OF LIABILITY - - EXCEPT AS EXPRESSLY SET FORTH IN THIS AGREEMENT, NEITHER RECIPIENT - NOR ANY CONTRIBUTORS SHALL HAVE ANY LIABILITY FOR ANY DIRECT, - INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES - (INCLUDING WITHOUT LIMITATION LOST PROFITS), HOWEVER CAUSED AND ON - ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR - TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF - THE USE OR DISTRIBUTION OF THE PROGRAM OR THE EXERCISE OF ANY RIGHTS - GRANTED HEREUNDER, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH - DAMAGES. - - 7. GENERAL - - If any provision of this Agreement is invalid or unenforceable under - applicable law, it shall not affect the validity or enforceability - of the remainder of the terms of this Agreement, and without further - action by the parties hereto, such provision shall be reformed to - the minimum extent necessary to make such provision valid and - enforceable. - - If Recipient institutes patent litigation against any entity - (including a cross-claim or counterclaim in a lawsuit) alleging that - the Program itself (excluding combinations of the Program with other - software or hardware) infringes such Recipient's patent(s), then - such Recipient's rights granted under Section 2(b) shall terminate - as of the date such litigation is filed. - - All Recipient's rights under this Agreement shall terminate if it - fails to comply with any of the material terms or conditions of this - Agreement and does not cure such failure in a reasonable period of - time after becoming aware of such noncompliance. If all Recipient's - rights under this Agreement terminate, Recipient agrees to cease use - and distribution of the Program as soon as reasonably practicable. - However, Recipient's obligations under this Agreement and any - licenses granted by Recipient relating to the Program shall continue - and survive. - - Everyone is permitted to copy and distribute copies of this - Agreement, but in order to avoid inconsistency the Agreement is - copyrighted and may only be modified in the following manner. The - Agreement Steward reserves the right to publish new versions - (including revisions) of this Agreement from time to time. No one - other than the Agreement Steward has the right to modify this - Agreement. The Eclipse Foundation is the initial Agreement Steward. - The Eclipse Foundation may assign the responsibility to serve as the - Agreement Steward to a suitable separate entity. Each new version of - the Agreement will be given a distinguishing version number. The - Program (including Contributions) may always be distributed subject - to the version of the Agreement under which it was received. In - addition, after a new version of the Agreement is published, - Contributor may elect to distribute the Program (including its - Contributions) under the new version. Except as expressly stated in - Sections 2(a) and 2(b) above, Recipient receives no rights or - licenses to the intellectual property of any Contributor under this - Agreement, whether expressly, by implication, estoppel or otherwise. - All rights in the Program not expressly granted under this Agreement - are reserved. - - This Agreement is governed by the laws of the State of New York and - the intellectual property laws of the United States of America. No - party to this Agreement will bring a legal action under this - Agreement more than one year after the cause of action arose. Each - party waives its rights to a jury trial in any resulting litigation. - -The complete text of the Common Public License is as follows: - - Common Public License - v 1.0 - - THE ACCOMPANYING PROGRAM IS PROVIDED UNDER THE TERMS OF THIS COMMON - PUBLIC LICENSE ("AGREEMENT"). ANY USE, REPRODUCTION OR DISTRIBUTION OF - THE PROGRAM CONSTITUTES RECIPIENT'S ACCEPTANCE OF THIS AGREEMENT. - - 1. DEFINITIONS - - "Contribution" means: - - a) in the case of the initial Contributor, the initial code and - documentation distributed under this Agreement, and - - b) in the case of each subsequent Contributor: - - i) changes to the Program, and - - ii) additions to the Program; - - where such changes and/or additions to the Program originate - from and are distributed by that particular Contributor. A - Contribution 'originates' from a Contributor if it was added to the - Program by such Contributor itself or anyone acting on such - Contributor's behalf. Contributions do not include additions to the - Program which: (i) are separate modules of software distributed in - conjunction with the Program under their own license agreement, - and (ii) are not derivative works of the Program. - - "Contributor" means any person or entity that distributes the Program. - - "Licensed Patents " mean patent claims licensable by a Contributor - which are necessarily infringed by the use or sale of its Contribution - alone or when combined with the Program. - - "Program" means the Contributions distributed in accordance with this Agreement. - - "Recipient" means anyone who receives the Program under this - Agreement, including all Contributors. - - 2. GRANT OF RIGHTS - - a) Subject to the terms of this Agreement, each Contributor - hereby grants Recipient a non-exclusive, worldwide, royalty-free - copyright license to reproduce, prepare derivative works of, publicly - display, publicly perform, distribute and sublicense the Contribution - of such Contributor, if any, and such derivative works, in source code - and object code form. - - b) Subject to the terms of this Agreement, each Contributor - hereby grants Recipient a non-exclusive, worldwide, royalty-free - patent license under Licensed Patents to make, use, sell, offer to - sell, import and otherwise transfer the Contribution of such - Contributor, if any, in source code and object code form. This patent - license shall apply to the combination of the Contribution and the - Program if, at the time the Contribution is added by the Contributor, - such addition of the Contribution causes such combination to be - covered by the Licensed Patents. The patent license shall not apply to - any other combinations which include the Contribution. No hardware per - se is licensed hereunder. - - c) Recipient understands that although each Contributor grants - the licenses to its Contributions set forth herein, no assurances are - provided by any Contributor that the Program does not infringe the - patent or other intellectual property rights of any other entity. Each - Contributor disclaims any liability to Recipient for claims brought by - any other entity based on infringement of intellectual property rights - or otherwise. As a condition to exercising the rights and licenses - granted hereunder, each Recipient hereby assumes sole responsibility - to secure any other intellectual property rights needed, if any. For - example, if a third party patent license is required to allow - Recipient to distribute the Program, it is Recipient's responsibility - to acquire that license before distributing the Program. - - d) Each Contributor represents that to its knowledge it has - sufficient copyright rights in its Contribution, if any, to grant the - copyright license set forth in this Agreement. - - 3. REQUIREMENTS - - A Contributor may choose to distribute the Program in object code form - under its own license agreement, provided that: - - a) it complies with the terms and conditions of this Agreement; - and - - b) its license agreement: - - i) effectively disclaims on behalf of all Contributors all - warranties and conditions, express and implied, including warranties - or conditions of title and non-infringement, and implied warranties or - conditions of merchantability and fitness for a particular purpose; - - ii) effectively excludes on behalf of all Contributors all - liability for damages, including direct, indirect, special, incidental - and consequential damages, such as lost profits; - - iii) states that any provisions which differ from this Agreement - are offered by that Contributor alone and not by any other party; and - - iv) states that source code for the Program is available from - such Contributor, and informs licensees how to obtain it in a - reasonable manner on or through a medium customarily used for software - exchange. - - When the Program is made available in source code form: - - a) it must be made available under this Agreement; and - - b) a copy of this Agreement must be included with each copy of - the Program. - - Contributors may not remove or alter any copyright notices contained - within the Program. - - Each Contributor must identify itself as the originator of its - Contribution, if any, in a manner that reasonably allows subsequent - Recipients to identify the originator of the Contribution. - - 4. COMMERCIAL DISTRIBUTION - - Commercial distributors of software may accept certain - responsibilities with respect to end users, business partners and the - like. While this license is intended to facilitate the commercial use - of the Program, the Contributor who includes the Program in a - commercial product offering should do so in a manner which does not - create potential liability for other Contributors. Therefore, if a - Contributor includes the Program in a commercial product offering, - such Contributor ("Commercial Contributor") hereby agrees to defend - and indemnify every other Contributor ("Indemnified Contributor") - against any losses, damages and costs (collectively "Losses") arising - from claims, lawsuits and other legal actions brought by a third party - against the Indemnified Contributor to the extent caused by the acts - or omissions of such Commercial Contributor in connection with its - distribution of the Program in a commercial product offering. The - obligations in this section do not apply to any claims or Losses - relating to any actual or alleged intellectual property - infringement. In order to qualify, an Indemnified Contributor must: a) - promptly notify the Commercial Contributor in writing of such claim, - and b) allow the Commercial Contributor to control, and cooperate with - the Commercial Contributor in, the defense and any related settlement - negotiations. The Indemnified Contributor may participate in any such - claim at its own expense. - - For example, a Contributor might include the Program in a commercial - product offering, Product X. That Contributor is then a Commercial - Contributor. If that Commercial Contributor then makes performance - claims, or offers warranties related to Product X, those performance - claims and warranties are such Commercial Contributor's responsibility - alone. Under this section, the Commercial Contributor would have to - defend claims against the other Contributors related to those - performance claims and warranties, and if a court requires any other - Contributor to pay any damages as a result, the Commercial Contributor - must pay those damages. - - 5. NO WARRANTY - - EXCEPT AS EXPRESSLY SET FORTH IN THIS AGREEMENT, THE PROGRAM IS - PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - KIND, EITHER EXPRESS OR IMPLIED INCLUDING, WITHOUT LIMITATION, ANY - WARRANTIES OR CONDITIONS OF TITLE, NON-INFRINGEMENT, MERCHANTABILITY - OR FITNESS FOR A PARTICULAR PURPOSE. Each Recipient is solely - responsible for determining the appropriateness of using and - distributing the Program and assumes all risks associated with its - exercise of rights under this Agreement, including but not limited to - the risks and costs of program errors, compliance with applicable - laws, damage to or loss of data, programs or equipment, and - unavailability or interruption of operations. - - 6. DISCLAIMER OF LIABILITY - - EXCEPT AS EXPRESSLY SET FORTH IN THIS AGREEMENT, NEITHER RECIPIENT NOR - ANY CONTRIBUTORS SHALL HAVE ANY LIABILITY FOR ANY DIRECT, INDIRECT, - INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING - WITHOUT LIMITATION LOST PROFITS), HOWEVER CAUSED AND ON ANY THEORY OF - LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING - NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OR - DISTRIBUTION OF THE PROGRAM OR THE EXERCISE OF ANY RIGHTS GRANTED - HEREUNDER, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGES. - - 7. GENERAL - - If any provision of this Agreement is invalid or unenforceable under - applicable law, it shall not affect the validity or enforceability of - the remainder of the terms of this Agreement, and without further - action by the parties hereto, such provision shall be reformed to the - minimum extent necessary to make such provision valid and enforceable. - - If Recipient institutes patent litigation against a Contributor with - respect to a patent applicable to software (including a cross-claim or - counterclaim in a lawsuit), then any patent licenses granted by that - Contributor to such Recipient under this Agreement shall terminate as - of the date such litigation is filed. In addition, if Recipient - institutes patent litigation against any entity (including a - cross-claim or counterclaim in a lawsuit) alleging that the Program - itself (excluding combinations of the Program with other software or - hardware) infringes such Recipient's patent(s), then such Recipient's - rights granted under Section 2(b) shall terminate as of the date such - litigation is filed. - - All Recipient's rights under this Agreement shall terminate if it - fails to comply with any of the material terms or conditions of this - Agreement and does not cure such failure in a reasonable period of - time after becoming aware of such noncompliance. If all Recipient's - rights under this Agreement terminate, Recipient agrees to cease use - and distribution of the Program as soon as reasonably - practicable. However, Recipient's obligations under this Agreement and - any licenses granted by Recipient relating to the Program shall - continue and survive. - - Everyone is permitted to copy and distribute copies of this Agreement, - but in order to avoid inconsistency the Agreement is copyrighted and - may only be modified in the following manner. The Agreement Steward - reserves the right to publish new versions (including revisions) of - this Agreement from time to time. No one other than the Agreement - Steward has the right to modify this Agreement. IBM is the initial - Agreement Steward. IBM may assign the responsibility to serve as the - Agreement Steward to a suitable separate entity. Each new version of - the Agreement will be given a distinguishing version number. The - Program (including Contributions) may always be distributed subject to - the version of the Agreement under which it was received. In addition, - after a new version of the Agreement is published, Contributor may - elect to distribute the Program (including its Contributions) under - the new version. Except as expressly stated in Sections 2(a) and 2(b) - above, Recipient receives no rights or licenses to the intellectual - property of any Contributor under this Agreement, whether expressly, - by implication, estoppel or otherwise. All rights in the Program not - expressly granted under this Agreement are reserved. - - This Agreement is governed by the laws of the State of New York and - the intellectual property laws of the United States of America. No - party to this Agreement will bring a legal action under this Agreement - more than one year after the cause of action arose. Each party waives - its rights to a jury trial in any resulting litigation. - -The complete text of the GNU General Public License v2 is as follows: - - GNU GENERAL PUBLIC LICENSE - Version 2, June 1991 - - Copyright (C) 1989, 1991 Free Software Foundation, Inc. - 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - Everyone is permitted to copy and distribute verbatim copies - of this license document, but changing it is not allowed. - - Preamble - - The licenses for most software are designed to take away your - freedom to share and change it. By contrast, the GNU General Public - License is intended to guarantee your freedom to share and change free - software--to make sure the software is free for all its users. This - General Public License applies to most of the Free Software - Foundation's software and to any other program whose authors commit to - using it. (Some other Free Software Foundation software is covered by - the GNU Library General Public License instead.) You can apply it to - your programs, too. - - When we speak of free software, we are referring to freedom, not - price. Our General Public Licenses are designed to make sure that you - have the freedom to distribute copies of free software (and charge for - this service if you wish), that you receive source code or can get it - if you want it, that you can change the software or use pieces of it - in new free programs; and that you know you can do these things. - - To protect your rights, we need to make restrictions that forbid - anyone to deny you these rights or to ask you to surrender the rights. - These restrictions translate to certain responsibilities for you if you - distribute copies of the software, or if you modify it. - - For example, if you distribute copies of such a program, whether - gratis or for a fee, you must give the recipients all the rights that - you have. You must make sure that they, too, receive or can get the - source code. And you must show them these terms so they know their - rights. - - We protect your rights with two steps: (1) copyright the software, and - (2) offer you this license which gives you legal permission to copy, - distribute and/or modify the software. - - Also, for each author's protection and ours, we want to make certain - that everyone understands that there is no warranty for this free - software. If the software is modified by someone else and passed on, we - want its recipients to know that what they have is not the original, so - that any problems introduced by others will not reflect on the original - authors' reputations. - - Finally, any free program is threatened constantly by software - patents. We wish to avoid the danger that redistributors of a free - program will individually obtain patent licenses, in effect making the - program proprietary. To prevent this, we have made it clear that any - patent must be licensed for everyone's free use or not licensed at all. - - The precise terms and conditions for copying, distribution and - modification follow. - - GNU GENERAL PUBLIC LICENSE - TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION - - 0. This License applies to any program or other work which contains - a notice placed by the copyright holder saying it may be distributed - under the terms of this General Public License. The "Program", below, - refers to any such program or work, and a "work based on the Program" - means either the Program or any derivative work under copyright law: - that is to say, a work containing the Program or a portion of it, - either verbatim or with modifications and/or translated into another - language. (Hereinafter, translation is included without limitation in - the term "modification".) Each licensee is addressed as "you". - - Activities other than copying, distribution and modification are not - covered by this License; they are outside its scope. The act of - running the Program is not restricted, and the output from the Program - is covered only if its contents constitute a work based on the - Program (independent of having been made by running the Program). - Whether that is true depends on what the Program does. - - 1. You may copy and distribute verbatim copies of the Program's - source code as you receive it, in any medium, provided that you - conspicuously and appropriately publish on each copy an appropriate - copyright notice and disclaimer of warranty; keep intact all the - notices that refer to this License and to the absence of any warranty; - and give any other recipients of the Program a copy of this License - along with the Program. - - You may charge a fee for the physical act of transferring a copy, and - you may at your option offer warranty protection in exchange for a fee. - - 2. You may modify your copy or copies of the Program or any portion - of it, thus forming a work based on the Program, and copy and - distribute such modifications or work under the terms of Section 1 - above, provided that you also meet all of these conditions: - - a) You must cause the modified files to carry prominent notices - stating that you changed the files and the date of any change. - - b) You must cause any work that you distribute or publish, that in - whole or in part contains or is derived from the Program or any - part thereof, to be licensed as a whole at no charge to all third - parties under the terms of this License. - - c) If the modified program normally reads commands interactively - when run, you must cause it, when started running for such - interactive use in the most ordinary way, to print or display an - announcement including an appropriate copyright notice and a - notice that there is no warranty (or else, saying that you provide - a warranty) and that users may redistribute the program under - these conditions, and telling the user how to view a copy of this - License. (Exception: if the Program itself is interactive but - does not normally print such an announcement, your work based on - the Program is not required to print an announcement.) - - These requirements apply to the modified work as a whole. If - identifiable sections of that work are not derived from the Program, - and can be reasonably considered independent and separate works in - themselves, then this License, and its terms, do not apply to those - sections when you distribute them as separate works. But when you - distribute the same sections as part of a whole which is a work based - on the Program, the distribution of the whole must be on the terms of - this License, whose permissions for other licensees extend to the - entire whole, and thus to each and every part regardless of who wrote it. - - Thus, it is not the intent of this section to claim rights or contest - your rights to work written entirely by you; rather, the intent is to - exercise the right to control the distribution of derivative or - collective works based on the Program. - - In addition, mere aggregation of another work not based on the Program - with the Program (or with a work based on the Program) on a volume of - a storage or distribution medium does not bring the other work under - the scope of this License. - - 3. You may copy and distribute the Program (or a work based on it, - under Section 2) in object code or executable form under the terms of - Sections 1 and 2 above provided that you also do one of the following: - - a) Accompany it with the complete corresponding machine-readable - source code, which must be distributed under the terms of Sections - 1 and 2 above on a medium customarily used for software interchange; or, - - b) Accompany it with a written offer, valid for at least three - years, to give any third party, for a charge no more than your - cost of physically performing source distribution, a complete - machine-readable copy of the corresponding source code, to be - distributed under the terms of Sections 1 and 2 above on a medium - customarily used for software interchange; or, - - c) Accompany it with the information you received as to the offer - to distribute corresponding source code. (This alternative is - allowed only for noncommercial distribution and only if you - received the program in object code or executable form with such - an offer, in accord with Subsection b above.) - - The source code for a work means the preferred form of the work for - making modifications to it. For an executable work, complete source - code means all the source code for all modules it contains, plus any - associated interface definition files, plus the scripts used to - control compilation and installation of the executable. However, as a - special exception, the source code distributed need not include - anything that is normally distributed (in either source or binary - form) with the major components (compiler, kernel, and so on) of the - operating system on which the executable runs, unless that component - itself accompanies the executable. - - If distribution of executable or object code is made by offering - access to copy from a designated place, then offering equivalent - access to copy the source code from the same place counts as - distribution of the source code, even though third parties are not - compelled to copy the source along with the object code. - - 4. You may not copy, modify, sublicense, or distribute the Program - except as expressly provided under this License. Any attempt - otherwise to copy, modify, sublicense or distribute the Program is - void, and will automatically terminate your rights under this License. - However, parties who have received copies, or rights, from you under - this License will not have their licenses terminated so long as such - parties remain in full compliance. - - 5. You are not required to accept this License, since you have not - signed it. However, nothing else grants you permission to modify or - distribute the Program or its derivative works. These actions are - prohibited by law if you do not accept this License. Therefore, by - modifying or distributing the Program (or any work based on the - Program), you indicate your acceptance of this License to do so, and - all its terms and conditions for copying, distributing or modifying - the Program or works based on it. - - 6. Each time you redistribute the Program (or any work based on the - Program), the recipient automatically receives a license from the - original licensor to copy, distribute or modify the Program subject to - these terms and conditions. You may not impose any further - restrictions on the recipients' exercise of the rights granted herein. - You are not responsible for enforcing compliance by third parties to - this License. - - 7. If, as a consequence of a court judgment or allegation of patent - infringement or for any other reason (not limited to patent issues), - conditions are imposed on you (whether by court order, agreement or - otherwise) that contradict the conditions of this License, they do not - excuse you from the conditions of this License. If you cannot - distribute so as to satisfy simultaneously your obligations under this - License and any other pertinent obligations, then as a consequence you - may not distribute the Program at all. For example, if a patent - license would not permit royalty-free redistribution of the Program by - all those who receive copies directly or indirectly through you, then - the only way you could satisfy both it and this License would be to - refrain entirely from distribution of the Program. - - If any portion of this section is held invalid or unenforceable under - any particular circumstance, the balance of the section is intended to - apply and the section as a whole is intended to apply in other - circumstances. - - It is not the purpose of this section to induce you to infringe any - patents or other property right claims or to contest validity of any - such claims; this section has the sole purpose of protecting the - integrity of the free software distribution system, which is - implemented by public license practices. Many people have made - generous contributions to the wide range of software distributed - through that system in reliance on consistent application of that - system; it is up to the author/donor to decide if he or she is willing - to distribute software through any other system and a licensee cannot - impose that choice. - - This section is intended to make thoroughly clear what is believed to - be a consequence of the rest of this License. - - 8. If the distribution and/or use of the Program is restricted in - certain countries either by patents or by copyrighted interfaces, the - original copyright holder who places the Program under this License - may add an explicit geographical distribution limitation excluding - those countries, so that distribution is permitted only in or among - countries not thus excluded. In such case, this License incorporates - the limitation as if written in the body of this License. - - 9. The Free Software Foundation may publish revised and/or new versions - of the General Public License from time to time. Such new versions will - be similar in spirit to the present version, but may differ in detail to - address new problems or concerns. - - Each version is given a distinguishing version number. If the Program - specifies a version number of this License which applies to it and "any - later version", you have the option of following the terms and conditions - either of that version or of any later version published by the Free - Software Foundation. If the Program does not specify a version number of - this License, you may choose any version ever published by the Free Software - Foundation. - - 10. If you wish to incorporate parts of the Program into other free - programs whose distribution conditions are different, write to the author - to ask for permission. For software which is copyrighted by the Free - Software Foundation, write to the Free Software Foundation; we sometimes - make exceptions for this. Our decision will be guided by the two goals - of preserving the free status of all derivatives of our free software and - of promoting the sharing and reuse of software generally. - - NO WARRANTY - - 11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY - FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN - OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES - PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED - OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF - MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS - TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE - PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING, - REPAIR OR CORRECTION. - - 12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING - WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR - REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, - INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING - OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED - TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY - YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER - PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE - POSSIBILITY OF SUCH DAMAGES. - - END OF TERMS AND CONDITIONS - -The complete text of the GNU Lesser General Public License 2.1 is as follows: - - GNU LESSER GENERAL PUBLIC LICENSE - Version 2.1, February 1999 - - Copyright (C) 1991, 1999 Free Software Foundation, Inc. - 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - Everyone is permitted to copy and distribute verbatim copies - of this license document, but changing it is not allowed. - - [This is the first released version of the Lesser GPL. It also counts - as the successor of the GNU Library Public License, version 2, hence - the version number 2.1.] - - Preamble - - The licenses for most software are designed to take away your - freedom to share and change it. By contrast, the GNU General Public - Licenses are intended to guarantee your freedom to share and change - free software--to make sure the software is free for all its users. - - This license, the Lesser General Public License, applies to some - specially designated software packages--typically libraries--of the - Free Software Foundation and other authors who decide to use it. You - can use it too, but we suggest you first think carefully about whether - this license or the ordinary General Public License is the better - strategy to use in any particular case, based on the explanations below. - - When we speak of free software, we are referring to freedom of use, - not price. Our General Public Licenses are designed to make sure that - you have the freedom to distribute copies of free software (and charge - for this service if you wish); that you receive source code or can get - it if you want it; that you can change the software and use pieces of - it in new free programs; and that you are informed that you can do - these things. - - To protect your rights, we need to make restrictions that forbid - distributors to deny you these rights or to ask you to surrender these - rights. These restrictions translate to certain responsibilities for - you if you distribute copies of the library or if you modify it. - - For example, if you distribute copies of the library, whether gratis - or for a fee, you must give the recipients all the rights that we gave - you. You must make sure that they, too, receive or can get the source - code. If you link other code with the library, you must provide - complete object files to the recipients, so that they can relink them - with the library after making changes to the library and recompiling - it. And you must show them these terms so they know their rights. - - We protect your rights with a two-step method: (1) we copyright the - library, and (2) we offer you this license, which gives you legal - permission to copy, distribute and/or modify the library. - - To protect each distributor, we want to make it very clear that - there is no warranty for the free library. Also, if the library is - modified by someone else and passed on, the recipients should know - that what they have is not the original version, so that the original - author's reputation will not be affected by problems that might be - introduced by others. - - Finally, software patents pose a constant threat to the existence of - any free program. We wish to make sure that a company cannot - effectively restrict the users of a free program by obtaining a - restrictive license from a patent holder. Therefore, we insist that - any patent license obtained for a version of the library must be - consistent with the full freedom of use specified in this license. - - Most GNU software, including some libraries, is covered by the - ordinary GNU General Public License. This license, the GNU Lesser - General Public License, applies to certain designated libraries, and - is quite different from the ordinary General Public License. We use - this license for certain libraries in order to permit linking those - libraries into non-free programs. - - When a program is linked with a library, whether statically or using - a shared library, the combination of the two is legally speaking a - combined work, a derivative of the original library. The ordinary - General Public License therefore permits such linking only if the - entire combination fits its criteria of freedom. The Lesser General - Public License permits more lax criteria for linking other code with - the library. - - We call this license the "Lesser" General Public License because it - does Less to protect the user's freedom than the ordinary General - Public License. It also provides other free software developers Less - of an advantage over competing non-free programs. These disadvantages - are the reason we use the ordinary General Public License for many - libraries. However, the Lesser license provides advantages in certain - special circumstances. - - For example, on rare occasions, there may be a special need to - encourage the widest possible use of a certain library, so that it becomes - a de-facto standard. To achieve this, non-free programs must be - allowed to use the library. A more frequent case is that a free - library does the same job as widely used non-free libraries. In this - case, there is little to gain by limiting the free library to free - software only, so we use the Lesser General Public License. - - In other cases, permission to use a particular library in non-free - programs enables a greater number of people to use a large body of - free software. For example, permission to use the GNU C Library in - non-free programs enables many more people to use the whole GNU - operating system, as well as its variant, the GNU/Linux operating - system. - - Although the Lesser General Public License is Less protective of the - users' freedom, it does ensure that the user of a program that is - linked with the Library has the freedom and the wherewithal to run - that program using a modified version of the Library. - - The precise terms and conditions for copying, distribution and - modification follow. Pay close attention to the difference between a - "work based on the library" and a "work that uses the library". The - former contains code derived from the library, whereas the latter must - be combined with the library in order to run. - - GNU LESSER GENERAL PUBLIC LICENSE - TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION - - 0. This License Agreement applies to any software library or other - program which contains a notice placed by the copyright holder or - other authorized party saying it may be distributed under the terms of - this Lesser General Public License (also called "this License"). - Each licensee is addressed as "you". - - A "library" means a collection of software functions and/or data - prepared so as to be conveniently linked with application programs - (which use some of those functions and data) to form executables. - - The "Library", below, refers to any such software library or work - which has been distributed under these terms. A "work based on the - Library" means either the Library or any derivative work under - copyright law: that is to say, a work containing the Library or a - portion of it, either verbatim or with modifications and/or translated - straightforwardly into another language. (Hereinafter, translation is - included without limitation in the term "modification".) - - "Source code" for a work means the preferred form of the work for - making modifications to it. For a library, complete source code means - all the source code for all modules it contains, plus any associated - interface definition files, plus the scripts used to control compilation - and installation of the library. - - Activities other than copying, distribution and modification are not - covered by this License; they are outside its scope. The act of - running a program using the Library is not restricted, and output from - such a program is covered only if its contents constitute a work based - on the Library (independent of the use of the Library in a tool for - writing it). Whether that is true depends on what the Library does - and what the program that uses the Library does. - - 1. You may copy and distribute verbatim copies of the Library's - complete source code as you receive it, in any medium, provided that - you conspicuously and appropriately publish on each copy an - appropriate copyright notice and disclaimer of warranty; keep intact - all the notices that refer to this License and to the absence of any - warranty; and distribute a copy of this License along with the - Library. - - You may charge a fee for the physical act of transferring a copy, - and you may at your option offer warranty protection in exchange for a - fee. - - 2. You may modify your copy or copies of the Library or any portion - of it, thus forming a work based on the Library, and copy and - distribute such modifications or work under the terms of Section 1 - above, provided that you also meet all of these conditions: - - a) The modified work must itself be a software library. - - b) You must cause the files modified to carry prominent notices - stating that you changed the files and the date of any change. - - c) You must cause the whole of the work to be licensed at no - charge to all third parties under the terms of this License. - - d) If a facility in the modified Library refers to a function or a - table of data to be supplied by an application program that uses - the facility, other than as an argument passed when the facility - is invoked, then you must make a good faith effort to ensure that, - in the event an application does not supply such function or - table, the facility still operates, and performs whatever part of - its purpose remains meaningful. - - (For example, a function in a library to compute square roots has - a purpose that is entirely well-defined independent of the - application. Therefore, Subsection 2d requires that any - application-supplied function or table used by this function must - be optional: if the application does not supply it, the square - root function must still compute square roots.) - - These requirements apply to the modified work as a whole. If - identifiable sections of that work are not derived from the Library, - and can be reasonably considered independent and separate works in - themselves, then this License, and its terms, do not apply to those - sections when you distribute them as separate works. But when you - distribute the same sections as part of a whole which is a work based - on the Library, the distribution of the whole must be on the terms of - this License, whose permissions for other licensees extend to the - entire whole, and thus to each and every part regardless of who wrote - it. - - Thus, it is not the intent of this section to claim rights or contest - your rights to work written entirely by you; rather, the intent is to - exercise the right to control the distribution of derivative or - collective works based on the Library. - - In addition, mere aggregation of another work not based on the Library - with the Library (or with a work based on the Library) on a volume of - a storage or distribution medium does not bring the other work under - the scope of this License. - - 3. You may opt to apply the terms of the ordinary GNU General Public - License instead of this License to a given copy of the Library. To do - this, you must alter all the notices that refer to this License, so - that they refer to the ordinary GNU General Public License, version 2, - instead of to this License. (If a newer version than version 2 of the - ordinary GNU General Public License has appeared, then you can specify - that version instead if you wish.) Do not make any other change in - these notices. - - Once this change is made in a given copy, it is irreversible for - that copy, so the ordinary GNU General Public License applies to all - subsequent copies and derivative works made from that copy. - - This option is useful when you wish to copy part of the code of - the Library into a program that is not a library. - - 4. You may copy and distribute the Library (or a portion or - derivative of it, under Section 2) in object code or executable form - under the terms of Sections 1 and 2 above provided that you accompany - it with the complete corresponding machine-readable source code, which - must be distributed under the terms of Sections 1 and 2 above on a - medium customarily used for software interchange. - - If distribution of object code is made by offering access to copy - from a designated place, then offering equivalent access to copy the - source code from the same place satisfies the requirement to - distribute the source code, even though third parties are not - compelled to copy the source along with the object code. - - 5. A program that contains no derivative of any portion of the - Library, but is designed to work with the Library by being compiled or - linked with it, is called a "work that uses the Library". Such a - work, in isolation, is not a derivative work of the Library, and - therefore falls outside the scope of this License. - - However, linking a "work that uses the Library" with the Library - creates an executable that is a derivative of the Library (because it - contains portions of the Library), rather than a "work that uses the - library". The executable is therefore covered by this License. - Section 6 states terms for distribution of such executables. - - When a "work that uses the Library" uses material from a header file - that is part of the Library, the object code for the work may be a - derivative work of the Library even though the source code is not. - Whether this is true is especially significant if the work can be - linked without the Library, or if the work is itself a library. The - threshold for this to be true is not precisely defined by law. - - If such an object file uses only numerical parameters, data - structure layouts and accessors, and small macros and small inline - functions (ten lines or less in length), then the use of the object - file is unrestricted, regardless of whether it is legally a derivative - work. (Executables containing this object code plus portions of the - Library will still fall under Section 6.) - - Otherwise, if the work is a derivative of the Library, you may - distribute the object code for the work under the terms of Section 6. - Any executables containing that work also fall under Section 6, - whether or not they are linked directly with the Library itself. - - 6. As an exception to the Sections above, you may also combine or - link a "work that uses the Library" with the Library to produce a - work containing portions of the Library, and distribute that work - under terms of your choice, provided that the terms permit - modification of the work for the customer's own use and reverse - engineering for debugging such modifications. - - You must give prominent notice with each copy of the work that the - Library is used in it and that the Library and its use are covered by - this License. You must supply a copy of this License. If the work - during execution displays copyright notices, you must include the - copyright notice for the Library among them, as well as a reference - directing the user to the copy of this License. Also, you must do one - of these things: - - a) Accompany the work with the complete corresponding - machine-readable source code for the Library including whatever - changes were used in the work (which must be distributed under - Sections 1 and 2 above); and, if the work is an executable linked - with the Library, with the complete machine-readable "work that - uses the Library", as object code and/or source code, so that the - user can modify the Library and then relink to produce a modified - executable containing the modified Library. (It is understood - that the user who changes the contents of definitions files in the - Library will not necessarily be able to recompile the application - to use the modified definitions.) - - b) Use a suitable shared library mechanism for linking with the - Library. A suitable mechanism is one that (1) uses at run time a - copy of the library already present on the user's computer system, - rather than copying library functions into the executable, and (2) - will operate properly with a modified version of the library, if - the user installs one, as long as the modified version is - interface-compatible with the version that the work was made with. - - c) Accompany the work with a written offer, valid for at - least three years, to give the same user the materials - specified in Subsection 6a, above, for a charge no more - than the cost of performing this distribution. - - d) If distribution of the work is made by offering access to copy - from a designated place, offer equivalent access to copy the above - specified materials from the same place. - - e) Verify that the user has already received a copy of these - materials or that you have already sent this user a copy. - - For an executable, the required form of the "work that uses the - Library" must include any data and utility programs needed for - reproducing the executable from it. However, as a special exception, - the materials to be distributed need not include anything that is - normally distributed (in either source or binary form) with the major - components (compiler, kernel, and so on) of the operating system on - which the executable runs, unless that component itself accompanies - the executable. - - It may happen that this requirement contradicts the license - restrictions of other proprietary libraries that do not normally - accompany the operating system. Such a contradiction means you cannot - use both them and the Library together in an executable that you - distribute. - - 7. You may place library facilities that are a work based on the - Library side-by-side in a single library together with other library - facilities not covered by this License, and distribute such a combined - library, provided that the separate distribution of the work based on - the Library and of the other library facilities is otherwise - permitted, and provided that you do these two things: - - a) Accompany the combined library with a copy of the same work - based on the Library, uncombined with any other library - facilities. This must be distributed under the terms of the - Sections above. - - b) Give prominent notice with the combined library of the fact - that part of it is a work based on the Library, and explaining - where to find the accompanying uncombined form of the same work. - - 8. You may not copy, modify, sublicense, link with, or distribute - the Library except as expressly provided under this License. Any - attempt otherwise to copy, modify, sublicense, link with, or - distribute the Library is void, and will automatically terminate your - rights under this License. However, parties who have received copies, - or rights, from you under this License will not have their licenses - terminated so long as such parties remain in full compliance. - - 9. You are not required to accept this License, since you have not - signed it. However, nothing else grants you permission to modify or - distribute the Library or its derivative works. These actions are - prohibited by law if you do not accept this License. Therefore, by - modifying or distributing the Library (or any work based on the - Library), you indicate your acceptance of this License to do so, and - all its terms and conditions for copying, distributing or modifying - the Library or works based on it. - - 10. Each time you redistribute the Library (or any work based on the - Library), the recipient automatically receives a license from the - original licensor to copy, distribute, link with or modify the Library - subject to these terms and conditions. You may not impose any further - restrictions on the recipients' exercise of the rights granted herein. - You are not responsible for enforcing compliance by third parties with - this License. - - 11. If, as a consequence of a court judgment or allegation of patent - infringement or for any other reason (not limited to patent issues), - conditions are imposed on you (whether by court order, agreement or - otherwise) that contradict the conditions of this License, they do not - excuse you from the conditions of this License. If you cannot - distribute so as to satisfy simultaneously your obligations under this - License and any other pertinent obligations, then as a consequence you - may not distribute the Library at all. For example, if a patent - license would not permit royalty-free redistribution of the Library by - all those who receive copies directly or indirectly through you, then - the only way you could satisfy both it and this License would be to - refrain entirely from distribution of the Library. - - If any portion of this section is held invalid or unenforceable under any - particular circumstance, the balance of the section is intended to apply, - and the section as a whole is intended to apply in other circumstances. - - It is not the purpose of this section to induce you to infringe any - patents or other property right claims or to contest validity of any - such claims; this section has the sole purpose of protecting the - integrity of the free software distribution system which is - implemented by public license practices. Many people have made - generous contributions to the wide range of software distributed - through that system in reliance on consistent application of that - system; it is up to the author/donor to decide if he or she is willing - to distribute software through any other system and a licensee cannot - impose that choice. - - This section is intended to make thoroughly clear what is believed to - be a consequence of the rest of this License. - - 12. If the distribution and/or use of the Library is restricted in - certain countries either by patents or by copyrighted interfaces, the - original copyright holder who places the Library under this License may add - an explicit geographical distribution limitation excluding those countries, - so that distribution is permitted only in or among countries not thus - excluded. In such case, this License incorporates the limitation as if - written in the body of this License. - - 13. The Free Software Foundation may publish revised and/or new - versions of the Lesser General Public License from time to time. - Such new versions will be similar in spirit to the present version, - but may differ in detail to address new problems or concerns. - - Each version is given a distinguishing version number. If the Library - specifies a version number of this License which applies to it and - "any later version", you have the option of following the terms and - conditions either of that version or of any later version published by - the Free Software Foundation. If the Library does not specify a - license version number, you may choose any version ever published by - the Free Software Foundation. - - 14. If you wish to incorporate parts of the Library into other free - programs whose distribution conditions are incompatible with these, - write to the author to ask for permission. For software which is - copyrighted by the Free Software Foundation, write to the Free - Software Foundation; we sometimes make exceptions for this. Our - decision will be guided by the two goals of preserving the free status - of all derivatives of our free software and of promoting the sharing - and reuse of software generally. - - NO WARRANTY - - 15. BECAUSE THE LIBRARY IS LICENSED FREE OF CHARGE, THERE IS NO - WARRANTY FOR THE LIBRARY, TO THE EXTENT PERMITTED BY APPLICABLE LAW. - EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR - OTHER PARTIES PROVIDE THE LIBRARY "AS IS" WITHOUT WARRANTY OF ANY - KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE - IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR - PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE - LIBRARY IS WITH YOU. SHOULD THE LIBRARY PROVE DEFECTIVE, YOU ASSUME - THE COST OF ALL NECESSARY SERVICING, REPAIR OR CORRECTION. - - 16. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN - WRITING WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY - AND/OR REDISTRIBUTE THE LIBRARY AS PERMITTED ABOVE, BE LIABLE TO YOU - FOR DAMAGES, INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR - CONSEQUENTIAL DAMAGES ARISING OUT OF THE USE OR INABILITY TO USE THE - LIBRARY (INCLUDING BUT NOT LIMITED TO LOSS OF DATA OR DATA BEING - RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD PARTIES OR A - FAILURE OF THE LIBRARY TO OPERATE WITH ANY OTHER SOFTWARE), EVEN IF - SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH - DAMAGES. - - END OF TERMS AND CONDITIONS - - How to Apply These Terms to Your New Libraries - - If you develop a new library, and you want it to be of the greatest - possible use to the public, we recommend making it free software that - everyone can redistribute and change. You can do so by permitting - redistribution under these terms (or, alternatively, under the terms of the - ordinary General Public License). - - To apply these terms, attach the following notices to the library. It is - safest to attach them to the start of each source file to most effectively - convey the exclusion of warranty; and each file should have at least the - "copyright" line and a pointer to where the full notice is found. - - - Copyright (C) - - This library is free software; you can redistribute it and/or - modify it under the terms of the GNU Lesser General Public - License as published by the Free Software Foundation; either - version 2.1 of the License, or (at your option) any later version. - - This library is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - Lesser General Public License for more details. - - You should have received a copy of the GNU Lesser General Public - License along with this library; if not, write to the Free Software - Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - - Also add information on how to contact you by electronic and paper mail. - - You should also get your employer (if you work as a programmer) or your - school, if any, to sign a "copyright disclaimer" for the library, if - necessary. Here is a sample; alter the names: - - Yoyodyne, Inc., hereby disclaims all copyright interest in the - library `Frob' (a library for tweaking knobs) written by James Random Hacker. - - , 1 April 1990 - Ty Coon, President of Vice - - That's all there is to it! - -The following licenses cover code other than JRuby which is included with JRuby. - -Licenses listed below include: - -* GNU General Public License version 3 -* Apache 2.0 License -* BSD License -* Apache Software License Version 1.1 -* MIT License - -The complete text of the GNU General Public License version 3 is as follows: - - GNU GENERAL PUBLIC LICENSE - Version 3, 29 June 2007 - - Copyright (C) 2007 Free Software Foundation, Inc. - Everyone is permitted to copy and distribute verbatim copies - of this license document, but changing it is not allowed. - - Preamble - - The GNU General Public License is a free, copyleft license for - software and other kinds of works. - - The licenses for most software and other practical works are designed - to take away your freedom to share and change the works. By contrast, - the GNU General Public License is intended to guarantee your freedom to - share and change all versions of a program--to make sure it remains free - software for all its users. We, the Free Software Foundation, use the - GNU General Public License for most of our software; it applies also to - any other work released this way by its authors. You can apply it to - your programs, too. - - When we speak of free software, we are referring to freedom, not - price. Our General Public Licenses are designed to make sure that you - have the freedom to distribute copies of free software (and charge for - them if you wish), that you receive source code or can get it if you - want it, that you can change the software or use pieces of it in new - free programs, and that you know you can do these things. - - To protect your rights, we need to prevent others from denying you - these rights or asking you to surrender the rights. Therefore, you have - certain responsibilities if you distribute copies of the software, or if - you modify it: responsibilities to respect the freedom of others. - - For example, if you distribute copies of such a program, whether - gratis or for a fee, you must pass on to the recipients the same - freedoms that you received. You must make sure that they, too, receive - or can get the source code. And you must show them these terms so they - know their rights. - - Developers that use the GNU GPL protect your rights with two steps: - (1) assert copyright on the software, and (2) offer you this License - giving you legal permission to copy, distribute and/or modify it. - - For the developers' and authors' protection, the GPL clearly explains - that there is no warranty for this free software. For both users' and - authors' sake, the GPL requires that modified versions be marked as - changed, so that their problems will not be attributed erroneously to - authors of previous versions. - - Some devices are designed to deny users access to install or run - modified versions of the software inside them, although the manufacturer - can do so. This is fundamentally incompatible with the aim of - protecting users' freedom to change the software. The systematic - pattern of such abuse occurs in the area of products for individuals to - use, which is precisely where it is most unacceptable. Therefore, we - have designed this version of the GPL to prohibit the practice for those - products. If such problems arise substantially in other domains, we - stand ready to extend this provision to those domains in future versions - of the GPL, as needed to protect the freedom of users. - - Finally, every program is threatened constantly by software patents. - States should not allow patents to restrict development and use of - software on general-purpose computers, but in those that do, we wish to - avoid the special danger that patents applied to a free program could - make it effectively proprietary. To prevent this, the GPL assures that - patents cannot be used to render the program non-free. - - The precise terms and conditions for copying, distribution and - modification follow. - - TERMS AND CONDITIONS - - 0. Definitions. - - "This License" refers to version 3 of the GNU General Public License. - - "Copyright" also means copyright-like laws that apply to other kinds of - works, such as semiconductor masks. - - "The Program" refers to any copyrightable work licensed under this - License. Each licensee is addressed as "you". "Licensees" and - "recipients" may be individuals or organizations. - - To "modify" a work means to copy from or adapt all or part of the work - in a fashion requiring copyright permission, other than the making of an - exact copy. The resulting work is called a "modified version" of the - earlier work or a work "based on" the earlier work. - - A "covered work" means either the unmodified Program or a work based - on the Program. - - To "propagate" a work means to do anything with it that, without - permission, would make you directly or secondarily liable for - infringement under applicable copyright law, except executing it on a - computer or modifying a private copy. Propagation includes copying, - distribution (with or without modification), making available to the - public, and in some countries other activities as well. - - To "convey" a work means any kind of propagation that enables other - parties to make or receive copies. Mere interaction with a user through - a computer network, with no transfer of a copy, is not conveying. - - An interactive user interface displays "Appropriate Legal Notices" - to the extent that it includes a convenient and prominently visible - feature that (1) displays an appropriate copyright notice, and (2) - tells the user that there is no warranty for the work (except to the - extent that warranties are provided), that licensees may convey the - work under this License, and how to view a copy of this License. If - the interface presents a list of user commands or options, such as a - menu, a prominent item in the list meets this criterion. - - 1. Source Code. - - The "source code" for a work means the preferred form of the work - for making modifications to it. "Object code" means any non-source - form of a work. - - A "Standard Interface" means an interface that either is an official - standard defined by a recognized standards body, or, in the case of - interfaces specified for a particular programming language, one that - is widely used among developers working in that language. - - The "System Libraries" of an executable work include anything, other - than the work as a whole, that (a) is included in the normal form of - packaging a Major Component, but which is not part of that Major - Component, and (b) serves only to enable use of the work with that - Major Component, or to implement a Standard Interface for which an - implementation is available to the public in source code form. A - "Major Component", in this context, means a major essential component - (kernel, window system, and so on) of the specific operating system - (if any) on which the executable work runs, or a compiler used to - produce the work, or an object code interpreter used to run it. - - The "Corresponding Source" for a work in object code form means all - the source code needed to generate, install, and (for an executable - work) run the object code and to modify the work, including scripts to - control those activities. However, it does not include the work's - System Libraries, or general-purpose tools or generally available free - programs which are used unmodified in performing those activities but - which are not part of the work. For example, Corresponding Source - includes interface definition files associated with source files for - the work, and the source code for shared libraries and dynamically - linked subprograms that the work is specifically designed to require, - such as by intimate data communication or control flow between those - subprograms and other parts of the work. - - The Corresponding Source need not include anything that users - can regenerate automatically from other parts of the Corresponding - Source. - - The Corresponding Source for a work in source code form is that - same work. - - 2. Basic Permissions. - - All rights granted under this License are granted for the term of - copyright on the Program, and are irrevocable provided the stated - conditions are met. This License explicitly affirms your unlimited - permission to run the unmodified Program. The output from running a - covered work is covered by this License only if the output, given its - content, constitutes a covered work. This License acknowledges your - rights of fair use or other equivalent, as provided by copyright law. - - You may make, run and propagate covered works that you do not - convey, without conditions so long as your license otherwise remains - in force. You may convey covered works to others for the sole purpose - of having them make modifications exclusively for you, or provide you - with facilities for running those works, provided that you comply with - the terms of this License in conveying all material for which you do - not control copyright. Those thus making or running the covered works - for you must do so exclusively on your behalf, under your direction - and control, on terms that prohibit them from making any copies of - your copyrighted material outside their relationship with you. - - Conveying under any other circumstances is permitted solely under - the conditions stated below. Sublicensing is not allowed; section 10 - makes it unnecessary. - - 3. Protecting Users' Legal Rights From Anti-Circumvention Law. - - No covered work shall be deemed part of an effective technological - measure under any applicable law fulfilling obligations under article - 11 of the WIPO copyright treaty adopted on 20 December 1996, or - similar laws prohibiting or restricting circumvention of such - measures. - - When you convey a covered work, you waive any legal power to forbid - circumvention of technological measures to the extent such circumvention - is effected by exercising rights under this License with respect to - the covered work, and you disclaim any intention to limit operation or - modification of the work as a means of enforcing, against the work's - users, your or third parties' legal rights to forbid circumvention of - technological measures. - - 4. Conveying Verbatim Copies. - - You may convey verbatim copies of the Program's source code as you - receive it, in any medium, provided that you conspicuously and - appropriately publish on each copy an appropriate copyright notice; - keep intact all notices stating that this License and any - non-permissive terms added in accord with section 7 apply to the code; - keep intact all notices of the absence of any warranty; and give all - recipients a copy of this License along with the Program. - - You may charge any price or no price for each copy that you convey, - and you may offer support or warranty protection for a fee. - - 5. Conveying Modified Source Versions. - - You may convey a work based on the Program, or the modifications to - produce it from the Program, in the form of source code under the - terms of section 4, provided that you also meet all of these conditions: - - a) The work must carry prominent notices stating that you modified - it, and giving a relevant date. - - b) The work must carry prominent notices stating that it is - released under this License and any conditions added under section - 7. This requirement modifies the requirement in section 4 to - "keep intact all notices". - - c) You must license the entire work, as a whole, under this - License to anyone who comes into possession of a copy. This - License will therefore apply, along with any applicable section 7 - additional terms, to the whole of the work, and all its parts, - regardless of how they are packaged. This License gives no - permission to license the work in any other way, but it does not - invalidate such permission if you have separately received it. - - d) If the work has interactive user interfaces, each must display - Appropriate Legal Notices; however, if the Program has interactive - interfaces that do not display Appropriate Legal Notices, your - work need not make them do so. - - A compilation of a covered work with other separate and independent - works, which are not by their nature extensions of the covered work, - and which are not combined with it such as to form a larger program, - in or on a volume of a storage or distribution medium, is called an - "aggregate" if the compilation and its resulting copyright are not - used to limit the access or legal rights of the compilation's users - beyond what the individual works permit. Inclusion of a covered work - in an aggregate does not cause this License to apply to the other - parts of the aggregate. - - 6. Conveying Non-Source Forms. - - You may convey a covered work in object code form under the terms - of sections 4 and 5, provided that you also convey the - machine-readable Corresponding Source under the terms of this License, - in one of these ways: - - a) Convey the object code in, or embodied in, a physical product - (including a physical distribution medium), accompanied by the - Corresponding Source fixed on a durable physical medium - customarily used for software interchange. - - b) Convey the object code in, or embodied in, a physical product - (including a physical distribution medium), accompanied by a - written offer, valid for at least three years and valid for as - long as you offer spare parts or customer support for that product - model, to give anyone who possesses the object code either (1) a - copy of the Corresponding Source for all the software in the - product that is covered by this License, on a durable physical - medium customarily used for software interchange, for a price no - more than your reasonable cost of physically performing this - conveying of source, or (2) access to copy the - Corresponding Source from a network server at no charge. - - c) Convey individual copies of the object code with a copy of the - written offer to provide the Corresponding Source. This - alternative is allowed only occasionally and noncommercially, and - only if you received the object code with such an offer, in accord - with subsection 6b. - - d) Convey the object code by offering access from a designated - place (gratis or for a charge), and offer equivalent access to the - Corresponding Source in the same way through the same place at no - further charge. You need not require recipients to copy the - Corresponding Source along with the object code. If the place to - copy the object code is a network server, the Corresponding Source - may be on a different server (operated by you or a third party) - that supports equivalent copying facilities, provided you maintain - clear directions next to the object code saying where to find the - Corresponding Source. Regardless of what server hosts the - Corresponding Source, you remain obligated to ensure that it is - available for as long as needed to satisfy these requirements. - - e) Convey the object code using peer-to-peer transmission, provided - you inform other peers where the object code and Corresponding - Source of the work are being offered to the general public at no - charge under subsection 6d. - - A separable portion of the object code, whose source code is excluded - from the Corresponding Source as a System Library, need not be - included in conveying the object code work. - - A "User Product" is either (1) a "consumer product", which means any - tangible personal property which is normally used for personal, family, - or household purposes, or (2) anything designed or sold for incorporation - into a dwelling. In determining whether a product is a consumer product, - doubtful cases shall be resolved in favor of coverage. For a particular - product received by a particular user, "normally used" refers to a - typical or common use of that class of product, regardless of the status - of the particular user or of the way in which the particular user - actually uses, or expects or is expected to use, the product. A product - is a consumer product regardless of whether the product has substantial - commercial, industrial or non-consumer uses, unless such uses represent - the only significant mode of use of the product. - - "Installation Information" for a User Product means any methods, - procedures, authorization keys, or other information required to install - and execute modified versions of a covered work in that User Product from - a modified version of its Corresponding Source. The information must - suffice to ensure that the continued functioning of the modified object - code is in no case prevented or interfered with solely because - modification has been made. - - If you convey an object code work under this section in, or with, or - specifically for use in, a User Product, and the conveying occurs as - part of a transaction in which the right of possession and use of the - User Product is transferred to the recipient in perpetuity or for a - fixed term (regardless of how the transaction is characterized), the - Corresponding Source conveyed under this section must be accompanied - by the Installation Information. But this requirement does not apply - if neither you nor any third party retains the ability to install - modified object code on the User Product (for example, the work has - been installed in ROM). - - The requirement to provide Installation Information does not include a - requirement to continue to provide support service, warranty, or updates - for a work that has been modified or installed by the recipient, or for - the User Product in which it has been modified or installed. Access to a - network may be denied when the modification itself materially and - adversely affects the operation of the network or violates the rules and - protocols for communication across the network. - - Corresponding Source conveyed, and Installation Information provided, - in accord with this section must be in a format that is publicly - documented (and with an implementation available to the public in - source code form), and must require no special password or key for - unpacking, reading or copying. - - 7. Additional Terms. - - "Additional permissions" are terms that supplement the terms of this - License by making exceptions from one or more of its conditions. - Additional permissions that are applicable to the entire Program shall - be treated as though they were included in this License, to the extent - that they are valid under applicable law. If additional permissions - apply only to part of the Program, that part may be used separately - under those permissions, but the entire Program remains governed by - this License without regard to the additional permissions. - - When you convey a copy of a covered work, you may at your option - remove any additional permissions from that copy, or from any part of - it. (Additional permissions may be written to require their own - removal in certain cases when you modify the work.) You may place - additional permissions on material, added by you to a covered work, - for which you have or can give appropriate copyright permission. - - Notwithstanding any other provision of this License, for material you - add to a covered work, you may (if authorized by the copyright holders of - that material) supplement the terms of this License with terms: - - a) Disclaiming warranty or limiting liability differently from the - terms of sections 15 and 16 of this License; or - - b) Requiring preservation of specified reasonable legal notices or - author attributions in that material or in the Appropriate Legal - Notices displayed by works containing it; or - - c) Prohibiting misrepresentation of the origin of that material, or - requiring that modified versions of such material be marked in - reasonable ways as different from the original version; or - - d) Limiting the use for publicity purposes of names of licensors or - authors of the material; or - - e) Declining to grant rights under trademark law for use of some - trade names, trademarks, or service marks; or - - f) Requiring indemnification of licensors and authors of that - material by anyone who conveys the material (or modified versions of - it) with contractual assumptions of liability to the recipient, for - any liability that these contractual assumptions directly impose on - those licensors and authors. - - All other non-permissive additional terms are considered "further - restrictions" within the meaning of section 10. If the Program as you - received it, or any part of it, contains a notice stating that it is - governed by this License along with a term that is a further - restriction, you may remove that term. If a license document contains - a further restriction but permits relicensing or conveying under this - License, you may add to a covered work material governed by the terms - of that license document, provided that the further restriction does - not survive such relicensing or conveying. - - If you add terms to a covered work in accord with this section, you - must place, in the relevant source files, a statement of the - additional terms that apply to those files, or a notice indicating - where to find the applicable terms. - - Additional terms, permissive or non-permissive, may be stated in the - form of a separately written license, or stated as exceptions; - the above requirements apply either way. - - 8. Termination. - - You may not propagate or modify a covered work except as expressly - provided under this License. Any attempt otherwise to propagate or - modify it is void, and will automatically terminate your rights under - this License (including any patent licenses granted under the third - paragraph of section 11). - - However, if you cease all violation of this License, then your - license from a particular copyright holder is reinstated (a) - provisionally, unless and until the copyright holder explicitly and - finally terminates your license, and (b) permanently, if the copyright - holder fails to notify you of the violation by some reasonable means - prior to 60 days after the cessation. - - Moreover, your license from a particular copyright holder is - reinstated permanently if the copyright holder notifies you of the - violation by some reasonable means, this is the first time you have - received notice of violation of this License (for any work) from that - copyright holder, and you cure the violation prior to 30 days after - your receipt of the notice. - - Termination of your rights under this section does not terminate the - licenses of parties who have received copies or rights from you under - this License. If your rights have been terminated and not permanently - reinstated, you do not qualify to receive new licenses for the same - material under section 10. - - 9. Acceptance Not Required for Having Copies. - - You are not required to accept this License in order to receive or - run a copy of the Program. Ancillary propagation of a covered work - occurring solely as a consequence of using peer-to-peer transmission - to receive a copy likewise does not require acceptance. However, - nothing other than this License grants you permission to propagate or - modify any covered work. These actions infringe copyright if you do - not accept this License. Therefore, by modifying or propagating a - covered work, you indicate your acceptance of this License to do so. - - 10. Automatic Licensing of Downstream Recipients. - - Each time you convey a covered work, the recipient automatically - receives a license from the original licensors, to run, modify and - propagate that work, subject to this License. You are not responsible - for enforcing compliance by third parties with this License. - - An "entity transaction" is a transaction transferring control of an - organization, or substantially all assets of one, or subdividing an - organization, or merging organizations. If propagation of a covered - work results from an entity transaction, each party to that - transaction who receives a copy of the work also receives whatever - licenses to the work the party's predecessor in interest had or could - give under the previous paragraph, plus a right to possession of the - Corresponding Source of the work from the predecessor in interest, if - the predecessor has it or can get it with reasonable efforts. - - You may not impose any further restrictions on the exercise of the - rights granted or affirmed under this License. For example, you may - not impose a license fee, royalty, or other charge for exercise of - rights granted under this License, and you may not initiate litigation - (including a cross-claim or counterclaim in a lawsuit) alleging that - any patent claim is infringed by making, using, selling, offering for - sale, or importing the Program or any portion of it. - - 11. Patents. - - A "contributor" is a copyright holder who authorizes use under this - License of the Program or a work on which the Program is based. The - work thus licensed is called the contributor's "contributor version". - - A contributor's "essential patent claims" are all patent claims - owned or controlled by the contributor, whether already acquired or - hereafter acquired, that would be infringed by some manner, permitted - by this License, of making, using, or selling its contributor version, - but do not include claims that would be infringed only as a - consequence of further modification of the contributor version. For - purposes of this definition, "control" includes the right to grant - patent sublicenses in a manner consistent with the requirements of - this License. - - Each contributor grants you a non-exclusive, worldwide, royalty-free - patent license under the contributor's essential patent claims, to - make, use, sell, offer for sale, import and otherwise run, modify and - propagate the contents of its contributor version. - - In the following three paragraphs, a "patent license" is any express - agreement or commitment, however denominated, not to enforce a patent - (such as an express permission to practice a patent or covenant not to - sue for patent infringement). To "grant" such a patent license to a - party means to make such an agreement or commitment not to enforce a - patent against the party. - - If you convey a covered work, knowingly relying on a patent license, - and the Corresponding Source of the work is not available for anyone - to copy, free of charge and under the terms of this License, through a - publicly available network server or other readily accessible means, - then you must either (1) cause the Corresponding Source to be so - available, or (2) arrange to deprive yourself of the benefit of the - patent license for this particular work, or (3) arrange, in a manner - consistent with the requirements of this License, to extend the patent - license to downstream recipients. "Knowingly relying" means you have - actual knowledge that, but for the patent license, your conveying the - covered work in a country, or your recipient's use of the covered work - in a country, would infringe one or more identifiable patents in that - country that you have reason to believe are valid. - - If, pursuant to or in connection with a single transaction or - arrangement, you convey, or propagate by procuring conveyance of, a - covered work, and grant a patent license to some of the parties - receiving the covered work authorizing them to use, propagate, modify - or convey a specific copy of the covered work, then the patent license - you grant is automatically extended to all recipients of the covered - work and works based on it. - - A patent license is "discriminatory" if it does not include within - the scope of its coverage, prohibits the exercise of, or is - conditioned on the non-exercise of one or more of the rights that are - specifically granted under this License. You may not convey a covered - work if you are a party to an arrangement with a third party that is - in the business of distributing software, under which you make payment - to the third party based on the extent of your activity of conveying - the work, and under which the third party grants, to any of the - parties who would receive the covered work from you, a discriminatory - patent license (a) in connection with copies of the covered work - conveyed by you (or copies made from those copies), or (b) primarily - for and in connection with specific products or compilations that - contain the covered work, unless you entered into that arrangement, - or that patent license was granted, prior to 28 March 2007. - - Nothing in this License shall be construed as excluding or limiting - any implied license or other defenses to infringement that may - otherwise be available to you under applicable patent law. - - 12. No Surrender of Others' Freedom. - - If conditions are imposed on you (whether by court order, agreement or - otherwise) that contradict the conditions of this License, they do not - excuse you from the conditions of this License. If you cannot convey a - covered work so as to satisfy simultaneously your obligations under this - License and any other pertinent obligations, then as a consequence you may - not convey it at all. For example, if you agree to terms that obligate you - to collect a royalty for further conveying from those to whom you convey - the Program, the only way you could satisfy both those terms and this - License would be to refrain entirely from conveying the Program. - - 13. Use with the GNU Affero General Public License. - - Notwithstanding any other provision of this License, you have - permission to link or combine any covered work with a work licensed - under version 3 of the GNU Affero General Public License into a single - combined work, and to convey the resulting work. The terms of this - License will continue to apply to the part which is the covered work, - but the special requirements of the GNU Affero General Public License, - section 13, concerning interaction through a network will apply to the - combination as such. - - 14. Revised Versions of this License. - - The Free Software Foundation may publish revised and/or new versions of - the GNU General Public License from time to time. Such new versions will - be similar in spirit to the present version, but may differ in detail to - address new problems or concerns. - - Each version is given a distinguishing version number. If the - Program specifies that a certain numbered version of the GNU General - Public License "or any later version" applies to it, you have the - option of following the terms and conditions either of that numbered - version or of any later version published by the Free Software - Foundation. If the Program does not specify a version number of the - GNU General Public License, you may choose any version ever published - by the Free Software Foundation. - - If the Program specifies that a proxy can decide which future - versions of the GNU General Public License can be used, that proxy's - public statement of acceptance of a version permanently authorizes you - to choose that version for the Program. - - Later license versions may give you additional or different - permissions. However, no additional obligations are imposed on any - author or copyright holder as a result of your choosing to follow a - later version. - - 15. Disclaimer of Warranty. - - THERE IS NO WARRANTY FOR THE PROGRAM, TO THE EXTENT PERMITTED BY - APPLICABLE LAW. EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT - HOLDERS AND/OR OTHER PARTIES PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY - OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, - THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR - PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE PROGRAM - IS WITH YOU. SHOULD THE PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF - ALL NECESSARY SERVICING, REPAIR OR CORRECTION. - - 16. Limitation of Liability. - - IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING - WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MODIFIES AND/OR CONVEYS - THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY - GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE - USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED TO LOSS OF - DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD - PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER PROGRAMS), - EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF - SUCH DAMAGES. - - 17. Interpretation of Sections 15 and 16. - - If the disclaimer of warranty and limitation of liability provided - above cannot be given local legal effect according to their terms, - reviewing courts shall apply local law that most closely approximates - an absolute waiver of all civil liability in connection with the - Program, unless a warranty or assumption of liability accompanies a - copy of the Program in return for a fee. - - END OF TERMS AND CONDITIONS - - How to Apply These Terms to Your New Programs - - If you develop a new program, and you want it to be of the greatest - possible use to the public, the best way to achieve this is to make it - free software which everyone can redistribute and change under these terms. - - To do so, attach the following notices to the program. It is safest - to attach them to the start of each source file to most effectively - state the exclusion of warranty; and each file should have at least - the "copyright" line and a pointer to where the full notice is found. - - - Copyright (C) - - This program is free software: you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation, either version 3 of the License, or - (at your option) any later version. - - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program. If not, see . - - Also add information on how to contact you by electronic and paper mail. - - If the program does terminal interaction, make it output a short - notice like this when it starts in an interactive mode: - - Copyright (C) - This program comes with ABSOLUTELY NO WARRANTY; for details type `show w'. - This is free software, and you are welcome to redistribute it - under certain conditions; type `show c' for details. - - The hypothetical commands `show w' and `show c' should show the appropriate - parts of the General Public License. Of course, your program's commands - might be different; for a GUI interface, you would use an "about box". - - You should also get your employer (if you work as a programmer) or school, - if any, to sign a "copyright disclaimer" for the program, if necessary. - For more information on this, and how to apply and follow the GNU GPL, see - . - - The GNU General Public License does not permit incorporating your program - into proprietary programs. If your program is a subroutine library, you - may consider it more useful to permit linking proprietary applications with - the library. If this is what you want to do, use the GNU Lesser General - Public License instead of this License. But first, please read - . - -The complete text of the Apache 2.0 License is as follows: - - Apache License - Version 2.0, January 2004 - http://www.apache.org/licenses/ - - TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION - - 1. Definitions. - - "License" shall mean the terms and conditions for use, reproduction, - and distribution as defined by Sections 1 through 9 of this document. - - "Licensor" shall mean the copyright owner or entity authorized by - the copyright owner that is granting the License. - - "Legal Entity" shall mean the union of the acting entity and all - other entities that control, are controlled by, or are under common - control with that entity. For the purposes of this definition, - "control" means (i) the power, direct or indirect, to cause the - direction or management of such entity, whether by contract or - otherwise, or (ii) ownership of fifty percent (50%) or more of the - outstanding shares, or (iii) beneficial ownership of such entity. - - "You" (or "Your") shall mean an individual or Legal Entity - exercising permissions granted by this License. - - "Source" form shall mean the preferred form for making modifications, - including but not limited to software source code, documentation - source, and configuration files. - - "Object" form shall mean any form resulting from mechanical - transformation or translation of a Source form, including but - not limited to compiled object code, generated documentation, - and conversions to other media types. - - "Work" shall mean the work of authorship, whether in Source or - Object form, made available under the License, as indicated by a - copyright notice that is included in or attached to the work - (an example is provided in the Appendix below). - - "Derivative Works" shall mean any work, whether in Source or Object - form, that is based on (or derived from) the Work and for which the - editorial revisions, annotations, elaborations, or other modifications - represent, as a whole, an original work of authorship. For the purposes - of this License, Derivative Works shall not include works that remain - separable from, or merely link (or bind by name) to the interfaces of, - the Work and Derivative Works thereof. - - "Contribution" shall mean any work of authorship, including - the original version of the Work and any modifications or additions - to that Work or Derivative Works thereof, that is intentionally - submitted to Licensor for inclusion in the Work by the copyright owner - or by an individual or Legal Entity authorized to submit on behalf of - the copyright owner. For the purposes of this definition, "submitted" - means any form of electronic, verbal, or written communication sent - to the Licensor or its representatives, including but not limited to - communication on electronic mailing lists, source code control systems, - and issue tracking systems that are managed by, or on behalf of, the - Licensor for the purpose of discussing and improving the Work, but - excluding communication that is conspicuously marked or otherwise - designated in writing by the copyright owner as "Not a Contribution." - - "Contributor" shall mean Licensor and any individual or Legal Entity - on behalf of whom a Contribution has been received by Licensor and - subsequently incorporated within the Work. - - 2. Grant of Copyright License. Subject to the terms and conditions of - this License, each Contributor hereby grants to You a perpetual, - worldwide, non-exclusive, no-charge, royalty-free, irrevocable - copyright license to reproduce, prepare Derivative Works of, - publicly display, publicly perform, sublicense, and distribute the - Work and such Derivative Works in Source or Object form. - - 3. Grant of Patent License. Subject to the terms and conditions of - this License, each Contributor hereby grants to You a perpetual, - worldwide, non-exclusive, no-charge, royalty-free, irrevocable - (except as stated in this section) patent license to make, have made, - use, offer to sell, sell, import, and otherwise transfer the Work, - where such license applies only to those patent claims licensable - by such Contributor that are necessarily infringed by their - Contribution(s) alone or by combination of their Contribution(s) - with the Work to which such Contribution(s) was submitted. If You - institute patent litigation against any entity (including a - cross-claim or counterclaim in a lawsuit) alleging that the Work - or a Contribution incorporated within the Work constitutes direct - or contributory patent infringement, then any patent licenses - granted to You under this License for that Work shall terminate - as of the date such litigation is filed. - - 4. Redistribution. You may reproduce and distribute copies of the - Work or Derivative Works thereof in any medium, with or without - modifications, and in Source or Object form, provided that You - meet the following conditions: - - (a) You must give any other recipients of the Work or - Derivative Works a copy of this License; and - - (b) You must cause any modified files to carry prominent notices - stating that You changed the files; and - - (c) You must retain, in the Source form of any Derivative Works - that You distribute, all copyright, patent, trademark, and - attribution notices from the Source form of the Work, - excluding those notices that do not pertain to any part of - the Derivative Works; and - - (d) If the Work includes a "NOTICE" text file as part of its - distribution, then any Derivative Works that You distribute must - include a readable copy of the attribution notices contained - within such NOTICE file, excluding those notices that do not - pertain to any part of the Derivative Works, in at least one - of the following places: within a NOTICE text file distributed - as part of the Derivative Works; within the Source form or - documentation, if provided along with the Derivative Works; or, - within a display generated by the Derivative Works, if and - wherever such third-party notices normally appear. The contents - of the NOTICE file are for informational purposes only and - do not modify the License. You may add Your own attribution - notices within Derivative Works that You distribute, alongside - or as an addendum to the NOTICE text from the Work, provided - that such additional attribution notices cannot be construed - as modifying the License. - - You may add Your own copyright statement to Your modifications and - may provide additional or different license terms and conditions - for use, reproduction, or distribution of Your modifications, or - for any such Derivative Works as a whole, provided Your use, - reproduction, and distribution of the Work otherwise complies with - the conditions stated in this License. - - 5. Submission of Contributions. Unless You explicitly state otherwise, - any Contribution intentionally submitted for inclusion in the Work - by You to the Licensor shall be under the terms and conditions of - this License, without any additional terms or conditions. - Notwithstanding the above, nothing herein shall supersede or modify - the terms of any separate license agreement you may have executed - with Licensor regarding such Contributions. - - 6. Trademarks. This License does not grant permission to use the trade - names, trademarks, service marks, or product names of the Licensor, - except as required for reasonable and customary use in describing the - origin of the Work and reproducing the content of the NOTICE file. - - 7. Disclaimer of Warranty. Unless required by applicable law or - agreed to in writing, Licensor provides the Work (and each - Contributor provides its Contributions) on an "AS IS" BASIS, - WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or - implied, including, without limitation, any warranties or conditions - of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A - PARTICULAR PURPOSE. You are solely responsible for determining the - appropriateness of using or redistributing the Work and assume any - risks associated with Your exercise of permissions under this License. - - 8. Limitation of Liability. In no event and under no legal theory, - whether in tort (including negligence), contract, or otherwise, - unless required by applicable law (such as deliberate and grossly - negligent acts) or agreed to in writing, shall any Contributor be - liable to You for damages, including any direct, indirect, special, - incidental, or consequential damages of any character arising as a - result of this License or out of the use or inability to use the - Work (including but not limited to damages for loss of goodwill, - work stoppage, computer failure or malfunction, or any and all - other commercial damages or losses), even if such Contributor - has been advised of the possibility of such damages. - - 9. Accepting Warranty or Additional Liability. While redistributing - the Work or Derivative Works thereof, You may choose to offer, - and charge a fee for, acceptance of support, warranty, indemnity, - or other liability obligations and/or rights consistent with this - License. However, in accepting such obligations, You may act only - on Your own behalf and on Your sole responsibility, not on behalf - of any other Contributor, and only if You agree to indemnify, - defend, and hold each Contributor harmless for any liability - incurred by, or claims asserted against, such Contributor by reason - of your accepting any such warranty or additional liability. - - END OF TERMS AND CONDITIONS - - APPENDIX: How to apply the Apache License to your work. - - To apply the Apache License to your work, attach the following - boilerplate notice, with the fields enclosed by brackets "[]" - replaced with your own identifying information. (Don't include - the brackets!) The text should be enclosed in the appropriate - comment syntax for the file format. We also recommend that a - file or class name and description of purpose be included on the - same "printed page" as the copyright notice for easier - identification within third-party archives. - - Copyright [yyyy] [name of copyright owner] - - Licensed 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. - -The complete text of the BSD license can be is as follows: - - Copyright (c) The Regents of the University of California. - All rights reserved. - - Redistribution and use in source and binary forms, with or without - modification, are permitted provided that the following conditions - are met: - 1. Redistributions of source code must retain the above copyright - notice, this list of conditions and the following disclaimer. - 2. Redistributions in binary form must reproduce the above copyright - notice, this list of conditions and the following disclaimer in the - documentation and/or other materials provided with the distribution. - 3. Neither the name of the University nor the names of its contributors - may be used to endorse or promote products derived from this software - without specific prior written permission. - - THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND - ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE - ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE - FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL - DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS - OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) - HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT - LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY - OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF - SUCH DAMAGE. - -The complete text of the Apache Software License Version 1.1 is as follows: - - /* - * ================================================================ - * The Apache Software License, Version 1.1 - * ================================================================ - * - * Copyright (C) 2000-2002 The Apache Software Foundation. All - * rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following - * conditions are met: - * - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in - * the documentation and/or other materials provided with the - * distribution. - * - * 3. The end-user documentation included with the redistribution, if - * any, must include the following acknowledgment: "This product - * includes software developed by the Apache Software Foundation - * (http://www.apache.org/)." Alternately, this acknowledgment may - * appear in the software itself, if and wherever such third-party - * acknowledgments normally appear. - * - * 4. The names "Ant" and "Apache Software Foundation" must not be - * used to endorse or promote products derived from this software - * without prior written permission. For written permission, please - * contact apache@apache.org. - * - * 5. Products derived from this software may not be called "Apache", - * nor may "Apache" appear in their name, without prior written - * permission of the Apache Software Foundation. - * - * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED - * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES - * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE - * DISCLAIMED. IN NO EVENT SHALL THE APACHE SOFTWARE FOUNDATION - * OR ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT - * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, - * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON - * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR - * TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT - * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY - * OF SUCH DAMAGE. - * - * This software consists of voluntary contributions made by many - * individuals on behalf of the Apache Software Foundation. For more - * information on the Apache Software Foundation, please see - * . - * - */ - -The complete text of the MIT license is as follows: - - Permission is hereby granted, free of charge, to any person - obtaining a copy of this software and associated documentation - files (the “Software”), to deal in the Software without - restriction, including without limitation the rights to use, - copy, modify, merge, publish, distribute, sublicense, and/or sell - copies of the Software, and to permit persons to whom the - Software is furnished to do so, subject to the following - conditions: - - The above copyright notice and this permission notice shall be - included in all copies or substantial portions of the Software. - - THE SOFTWARE IS PROVIDED “AS IS”, WITHOUT WARRANTY OF ANY KIND, - EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES - OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND - NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT - HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, - WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING - FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR - OTHER DEALINGS IN THE SOFTWARE. - -The complete text of the Eclipse Public License v1.0 is as follows: - - Eclipse Public License - v 1.0 - - THE ACCOMPANYING PROGRAM IS PROVIDED UNDER THE TERMS OF THIS ECLIPSE PUBLIC - LICENSE ("AGREEMENT"). ANY USE, REPRODUCTION OR DISTRIBUTION OF THE PROGRAM - CONSTITUTES RECIPIENT’S ACCEPTANCE OF THIS AGREEMENT. - - 1. DEFINITIONS - - "Contribution" means: - - a) in the case of the initial Contributor, the initial code and documentation - distributed under this Agreement, and - b) in the case of each subsequent Contributor: - - i) changes to the Program, and - - ii) additions to the Program; - - where such changes and/or additions to the Program originate from and are - distributed by that particular Contributor. A Contribution 'originates' from a - Contributor if it was added to the Program by such Contributor itself or anyone - acting on such Contributor’s behalf. Contributions do not include additions to - the Program which: (i) are separate modules of software distributed in - conjunction with the Program under their own license agreement, and (ii) are not - derivative works of the Program. - - "Contributor" means any person or entity that distributes the Program. - - "Licensed Patents " mean patent claims licensable by a Contributor which are - necessarily infringed by the use or sale of its Contribution alone or when - combined with the Program. - - "Program" means the Contributions distributed in accordance with this Agreement. - - "Recipient" means anyone who receives the Program under this Agreement, - including all Contributors. - - 2. GRANT OF RIGHTS - - a) Subject to the terms of this Agreement, each Contributor hereby grants - Recipient a non-exclusive, worldwide, royalty-free copyright license to - reproduce, prepare derivative works of, publicly display, publicly perform, - distribute and sublicense the Contribution of such Contributor, if any, and such - derivative works, in source code and object code form. - - b) Subject to the terms of this Agreement, each Contributor hereby grants - Recipient a non-exclusive, worldwide, royalty-free patent license under Licensed - Patents to make, use, sell, offer to sell, import and otherwise transfer the - Contribution of such Contributor, if any, in source code and object code form. - This patent license shall apply to the combination of the Contribution and the - Program if, at the time the Contribution is added by the Contributor, such - addition of the Contribution causes such combination to be covered by the - Licensed Patents. The patent license shall not apply to any other combinations - which include the Contribution. No hardware per se is licensed hereunder. - - c) Recipient understands that although each Contributor grants the licenses to - its Contributions set forth herein, no assurances are provided by any - Contributor that the Program does not infringe the patent or other intellectual - property rights of any other entity. Each Contributor disclaims any liability to - Recipient for claims brought by any other entity based on infringement of - intellectual property rights or otherwise. As a condition to exercising the - rights and licenses granted hereunder, each Recipient hereby assumes sole - responsibility to secure any other intellectual property rights needed, if any. - For example, if a third party patent license is required to allow Recipient to - distribute the Program, it is Recipient’s responsibility to acquire that license - before distributing the Program. - - d) Each Contributor represents that to its knowledge it has sufficient copyright - rights in its Contribution, if any, to grant the copyright license set forth in - this Agreement. - - 3. REQUIREMENTS - - A Contributor may choose to distribute the Program in object code form under its - own license agreement, provided that: - - a) it complies with the terms and conditions of this Agreement; and - - b) its license agreement: - - i) effectively disclaims on behalf of all Contributors all warranties and - conditions, express and implied, including warranties or conditions of title and - non-infringement, and implied warranties or conditions of merchantability and - fitness for a particular purpose; - - ii) effectively excludes on behalf of all Contributors all liability for - damages, including direct, indirect, special, incidental and consequential - damages, such as lost profits; - - iii) states that any provisions which differ from this Agreement are offered by - that Contributor alone and not by any other party; and - - iv) states that source code for the Program is available from such Contributor, - and informs licensees how to obtain it in a reasonable manner on or through a - medium customarily used for software exchange. - - When the Program is made available in source code form: - - a) it must be made available under this Agreement; and - b) a copy of this Agreement must be included with each copy of the Program. - - Contributors may not remove or alter any copyright notices contained within the - Program. - - Each Contributor must identify itself as the originator of its Contribution, if - any, in a manner that reasonably allows subsequent Recipients to identify the - originator of the Contribution. - - 4. COMMERCIAL DISTRIBUTION - - Commercial distributors of software may accept certain responsibilities with - respect to end users, business partners and the like. While this license is - intended to facilitate the commercial use of the Program, the Contributor who - includes the Program in a commercial product offering should do so in a manner - which does not create potential liability for other Contributors. Therefore, if - a Contributor includes the Program in a commercial product offering, such - Contributor ("Commercial Contributor") hereby agrees to defend and indemnify - every other Contributor ("Indemnified Contributor") against any losses, damages - and costs (collectively "Losses") arising from claims, lawsuits and other legal - actions brought by a third party against the Indemnified Contributor to the - extent caused by the acts or omissions of such Commercial Contributor in - connection with its distribution of the Program in a commercial product - offering. The obligations in this section do not apply to any claims or Losses - relating to any actual or alleged intellectual property infringement. In order - to qualify, an Indemnified Contributor must: a) promptly notify the Commercial - Contributor in writing of such claim, and b) allow the Commercial Contributor to - control, and cooperate with the Commercial Contributor in, the defense and any - related settlement negotiations. The Indemnified Contributor may participate in - any such claim at its own expense. - - For example, a Contributor might include the Program in a commercial product - offering, Product X. That Contributor is then a Commercial Contributor. If that - Commercial Contributor then makes performance claims, or offers warranties - related to Product X, those performance claims and warranties are such - Commercial Contributor’s responsibility alone. Under this section, the - Commercial Contributor would have to defend claims against the other - Contributors related to those performance claims and warranties, and if a court - requires any other Contributor to pay any damages as a result, the Commercial - Contributor must pay those damages. - - 5. NO WARRANTY - - EXCEPT AS EXPRESSLY SET FORTH IN THIS AGREEMENT, THE PROGRAM IS PROVIDED ON AN - "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, EITHER EXPRESS OR - IMPLIED INCLUDING, WITHOUT LIMITATION, ANY WARRANTIES OR CONDITIONS OF TITLE, - NON-INFRINGEMENT, MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE. Each - Recipient is solely responsible for determining the appropriateness of using and - distributing the Program and assumes all risks associated with its exercise of - rights under this Agreement , including but not limited to the risks and costs - of program errors, compliance with applicable laws, damage to or loss of data, - programs or equipment, and unavailability or interruption of operations. - - 6. DISCLAIMER OF LIABILITY - - EXCEPT AS EXPRESSLY SET FORTH IN THIS AGREEMENT, NEITHER RECIPIENT NOR ANY - CONTRIBUTORS SHALL HAVE ANY LIABILITY FOR ANY DIRECT, INDIRECT, INCIDENTAL, - SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING WITHOUT LIMITATION LOST - PROFITS), HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, - STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY - OUT OF THE USE OR DISTRIBUTION OF THE PROGRAM OR THE EXERCISE OF ANY RIGHTS - GRANTED HEREUNDER, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGES. - - 7. GENERAL - - If any provision of this Agreement is invalid or unenforceable under applicable - law, it shall not affect the validity or enforceability of the remainder of the - terms of this Agreement, and without further action by the parties hereto, such - provision shall be reformed to the minimum extent necessary to make such - provision valid and enforceable. - - If Recipient institutes patent litigation against any entity (including a - cross-claim or counterclaim in a lawsuit) alleging that the Program itself - (excluding combinations of the Program with other software or hardware) - infringes such Recipient’s patent(s), then such Recipient’s rights granted under - Section 2(b) shall terminate as of the date such litigation is filed. - - All Recipient’s rights under this Agreement shall terminate if it fails to - comply with any of the material terms or conditions of this Agreement and does - not cure such failure in a reasonable period of time after becoming aware of - such noncompliance. If all Recipient’s rights under this Agreement terminate, - Recipient agrees to cease use and distribution of the Program as soon as - reasonably practicable. However, Recipient’s obligations under this Agreement - and any licenses granted by Recipient relating to the Program shall continue and - survive. - - Everyone is permitted to copy and distribute copies of this Agreement, but in - order to avoid inconsistency the Agreement is copyrighted and may only be - modified in the following manner. The Agreement Steward reserves the right to - publish new versions (including revisions) of this Agreement from time to time. - No one other than the Agreement Steward has the right to modify this Agreement. - The Eclipse Foundation is the initial Agreement Steward. The Eclipse Foundation - may assign the responsibility to serve as the Agreement Steward to a suitable - separate entity. Each new version of the Agreement will be given a - distinguishing version number. The Program (including Contributions) may always - be distributed subject to the version of the Agreement under which it was - received. In addition, after a new version of the Agreement is published, - Contributor may elect to distribute the Program (including its Contributions) - under the new version. Except as expressly stated in Sections 2(a) and 2(b) - above, Recipient receives no rights or licenses to the intellectual property of - any Contributor under this Agreement, whether expressly, by implication, - estoppel or otherwise. All rights in the Program not expressly granted under - this Agreement are reserved. - - This Agreement is governed by the laws of the State of New York and the - intellectual property laws of the United States of America. No party to this - Agreement will bring a legal action under this Agreement more than one year - after the cause of action arose. Each party waives its rights to a jury trial in - any resulting litigation. diff --git a/tools/dependencies-report/src/main/resources/notices/jnr-x86asm-NOTICE.txt b/tools/dependencies-report/src/main/resources/notices/jnr-x86asm-NOTICE.txt deleted file mode 100644 index 87ace0005..000000000 --- a/tools/dependencies-report/src/main/resources/notices/jnr-x86asm-NOTICE.txt +++ /dev/null @@ -1,25 +0,0 @@ -source: https://github.com/jnr/jnr-x86asm/blob/1.0.2/LICENSE - - Copyright (C) 2010 Wayne Meissner - Copyright (c) 2008-2009, Petr Kobalicek - - Permission is hereby granted, free of charge, to any person - obtaining a copy of this software and associated documentation - files (the "Software"), to deal in the Software without - restriction, including without limitation the rights to use, - copy, modify, merge, publish, distribute, sublicense, and/or sell - copies of the Software, and to permit persons to whom the - Software is furnished to do so, subject to the following - conditions: - - The above copyright notice and this permission notice shall be - included in all copies or substantial portions of the Software. - - THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, - EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES - OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND - NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT - HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, - WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING - FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR - OTHER DEALINGS IN THE SOFTWARE. diff --git a/tools/dependencies-report/src/main/resources/notices/joda-time-NOTICE.txt b/tools/dependencies-report/src/main/resources/notices/joda-NOTICE.txt similarity index 100% rename from tools/dependencies-report/src/main/resources/notices/joda-time-NOTICE.txt rename to tools/dependencies-report/src/main/resources/notices/joda-NOTICE.txt diff --git a/tools/dependencies-report/src/main/resources/notices/joni-NOTICE.txt b/tools/dependencies-report/src/main/resources/notices/joni-NOTICE.txt deleted file mode 100644 index 7eb6908d6..000000000 --- a/tools/dependencies-report/src/main/resources/notices/joni-NOTICE.txt +++ /dev/null @@ -1,23 +0,0 @@ -source: https://github.com/jruby/joni/blob/joni-2.1.16/LICENSE - -MIT License - -Copyright (c) 2017 JRuby Team - -Permission is hereby granted, free of charge, to any person obtaining a copy -of this software and associated documentation files (the "Software"), to deal -in the Software without restriction, including without limitation the rights -to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -copies of the Software, and to permit persons to whom the Software is -furnished to do so, subject to the following conditions: - -The above copyright notice and this permission notice shall be included in all -copies or substantial portions of the Software. - -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE -SOFTWARE. \ No newline at end of file diff --git a/tools/dependencies-report/src/main/resources/notices/jrjackson-0.4.6-NOTICE.txt b/tools/dependencies-report/src/main/resources/notices/jrjackson-NOTICE.txt similarity index 100% rename from tools/dependencies-report/src/main/resources/notices/jrjackson-0.4.6-NOTICE.txt rename to tools/dependencies-report/src/main/resources/notices/jrjackson-NOTICE.txt diff --git a/tools/dependencies-report/src/main/resources/notices/jruby-9.1.14.0-NOTICE.txt b/tools/dependencies-report/src/main/resources/notices/jruby-9.1.14.0-NOTICE.txt deleted file mode 100644 index b2d729c89..000000000 --- a/tools/dependencies-report/src/main/resources/notices/jruby-9.1.14.0-NOTICE.txt +++ /dev/null @@ -1,342 +0,0 @@ -source: https://github.com/jruby/jruby/blob/9.1.14.0/COPYING#L1-L340 - -JRuby is Copyright (c) 2007-2017 The JRuby project, and is released -under a tri EPL/GPL/LGPL license. You can use it, redistribute it -and/or modify it under the terms of the: - - Eclipse Public License version 1.0 - OR - GNU General Public License version 2 - OR - GNU Lesser General Public License version 2.1 - -bytelist (http://github.com/jruby/bytelist), -jnr-posix (https://github.com/jnr/jnr-posix), -jruby-openssl (https://github.com/jruby/jruby-openssl), -jruby-readline (https://github.com/jruby/jruby-readline), -psych (https://github.com/ruby/psych), -yydebug (http://svn.codehaus.org/jruby/trunk/jay/yydebug) -are released under the same copyright/license. - -Some additional libraries distributed with JRuby are not covered by -JRuby's licence. Most of these libraries and their licenses are listed -below. Also see LICENSE.RUBY for most files found in lib/ruby/stdlib. - - bench/rails/public/javascripts/* are distributed under the MIT - license, and have the following copyrights: - - controls.js is Copyright: - (c) 2005-2008 Thomas Fuchs (http://script.aculo.us, http://mir.aculo.us) - (c) 2005-2007 Ivan Krstic (http://blogs.law.harvard.edu/ivan) - (c) 2005-2007 Jon Tirsen (http://www.tirsen.com) - - dragdrop.js is Copyright: - (c) 2005-2008 Thomas Fuchs (http://script.aculo.us, http://mir.aculo.us) - (c) 2005-2007 Sammi Williams (http://www.oriontransfer.co.nz, sammi@oriontransfer.co.nz) - - effect.js is Copyright (c) 2005-2008 Thomas Fuchs. - - prototype.js is Copyright (c) 2005-2007 Sam Stephenson. - - asm (http://asm.objectweb.org) is distributed under the BSD license and is - - Copyright (c) 2000-2011 INRIA, France Telecom - All rights reserved. - - jline2 (https://github.com/jline/jline2) is distributed under the BSD license: - - Copyright (c) 2002-2012, the original author or authors. - All rights reserved. - - jzlib (http://www.jcraft.com/jzlib/) is distributed under the BSD license: - - Copyright (c) 2000-2011 ymnk, JCraft,Inc. All rights reserved. - - The "rake" library (http://rake.rubyforge.org/) is distributed under - the MIT license, and has the following copyright: - - Copyright (c) 2003, 2004 Jim Weirich - - jcodings (http://github.com/jruby/jcodings) and - joni (http://github.com/jruby/joni) are distributed - under the MIT license without copyright. - - Bouncycastle is released under the MIT license: - - Copyright (c) 2000 - 2006 The Legion Of The Bouncy Castle. - - jnr-x86asm (https://github.com/jnr/jnr-x86asm) is distributed under the MIT - license with the following copyright: - - Copyright (C) 2010 Wayne Meissner - Copyright (c) 2008-2009, Petr Kobalicek - - The following libraries are redistributed under the Apache Software - License v2.0, available below. - invokebinder (https://github.com/headius/invokebinder) - jffi (https://github.com/jnr/jffi) - jitescript (https://github.com/qmx/jitescript) - jnr-constants (http://github.com/jnr/jnr-constants) - jnr-enxio (https://github.com/jnr/jnr-enxio) - jnr-ffi (https://github.com/jnr/jnr-jffi) - jnr-netdb (http://github.com/jnr/jnr-netdb) - jnr-unixsocket (https://github.com/jnr/jnr-unixsocket) - joda-time (http://joda-time.sourceforge.net) - maven (http://maven.apache.org/) - nailgun (http://martiansoftware.com/nailgun) - options (https://github.com/headius/options) - snakeyaml (https://github.com/asomov/snakeyaml) - unsafe-fences (https://github.com/headius/unsafe-fences) - - racc (runtime only, https://github.com/tenderlove/racc) is - distributed under the same license terms as the Ruby standard - library. This includes all files under lib/ruby/stdlib/racc. - See LICENSE.RUBY. - - json-generator and json-parser (https://github.com/flori/json) native - extenstions under the same license terms as the Ruby standard library. - See LICENSE.RUBY - -The complete text of the Eclipse Public License is as follows: - - Eclipse Public License - v 1.0 - - THE ACCOMPANYING PROGRAM IS PROVIDED UNDER THE TERMS OF THIS ECLIPSE - PUBLIC LICENSE ("AGREEMENT"). ANY USE, REPRODUCTION OR DISTRIBUTION - OF THE PROGRAM CONSTITUTES RECIPIENT'S ACCEPTANCE OF THIS AGREEMENT. - - 1. DEFINITIONS - - "Contribution" means: - - a) in the case of the initial Contributor, the initial code and - documentation distributed under this Agreement, and - - b) in the case of each subsequent Contributor: - - i) changes to the Program, and - - ii) additions to the Program; - where such changes and/or additions to the Program - originate from and are distributed by that particular - Contributor. A Contribution 'originates' from a - Contributor if it was added to the Program by such - Contributor itself or anyone acting on such - Contributor's behalf. Contributions do not include - additions to the Program which: (i) are separate modules - of software distributed in conjunction with the Program - under their own license agreement, and (ii) are not - derivative works of the Program. - - "Contributor" means any person or entity that distributes the Program. - - "Licensed Patents" mean patent claims licensable by a Contributor - which are necessarily infringed by the use or sale of its - Contribution alone or when combined with the Program. - - "Program" means the Contributions distributed in accordance with - this Agreement. - - "Recipient" means anyone who receives the Program under this - Agreement, including all Contributors. - - 2. GRANT OF RIGHTS - - a) Subject to the terms of this Agreement, each Contributor - hereby grants Recipient a non-exclusive, worldwide, - royalty-free copyright license to reproduce, prepare - derivative works of, publicly display, publicly perform, - distribute and sublicense the Contribution of such - Contributor, if any, and such derivative works, in source - code and object code form. - - b) Subject to the terms of this Agreement, each Contributor - hereby grants Recipient a non-exclusive, worldwide, - royalty-free patent license under Licensed Patents to make, - use, sell, offer to sell, import and otherwise transfer the - Contribution of such Contributor, if any, in source code and - object code form. This patent license shall apply to the - combination of the Contribution and the Program if, at the - time the Contribution is added by the Contributor, such - addition of the Contribution causes such combination to be - covered by the Licensed Patents. The patent license shall not - apply to any other combinations which include the - Contribution. No hardware per se is licensed hereunder. - - c) Recipient understands that although each Contributor grants - the licenses to its Contributions set forth herein, no - assurances are provided by any Contributor that the Program - does not infringe the patent or other intellectual property - rights of any other entity. Each Contributor disclaims any - liability to Recipient for claims brought by any other entity - based on infringement of intellectual property rights or - otherwise. As a condition to exercising the rights and - licenses granted hereunder, each Recipient hereby assumes - sole responsibility to secure any other intellectual property - rights needed, if any. For example, if a third party patent - license is required to allow Recipient to distribute the - Program, it is Recipient's responsibility to acquire that - license before distributing the Program. - - d) Each Contributor represents that to its knowledge it has - sufficient copyright rights in its Contribution, if any, to - grant the copyright license set forth in this Agreement. - - 3. REQUIREMENTS - - A Contributor may choose to distribute the Program in object code - form under its own license agreement, provided that: - - a) it complies with the terms and conditions of this Agreement; and - - b) its license agreement: - - i) effectively disclaims on behalf of all Contributors all - warranties and conditions, express and implied, including - warranties or conditions of title and non-infringement, - and implied warranties or conditions of merchantability - and fitness for a particular purpose; - - ii) effectively excludes on behalf of all Contributors all - liability for damages, including direct, indirect, - special, incidental and consequential damages, such as - lost profits; - - iii) states that any provisions which differ from this - Agreement are offered by that Contributor alone and not - by any other party; and - - iv) states that source code for the Program is available - from such Contributor, and informs licensees how to - obtain it in a reasonable manner on or through a medium - customarily used for software exchange. - - When the Program is made available in source code form: - - a) it must be made available under this Agreement; and - - b) a copy of this Agreement must be included with each copy of - the Program. - - Contributors may not remove or alter any copyright notices contained - within the Program. - - Each Contributor must identify itself as the originator of its - Contribution, if any, in a manner that reasonably allows subsequent - Recipients to identify the originator of the Contribution. - - 4. COMMERCIAL DISTRIBUTION - - Commercial distributors of software may accept certain - responsibilities with respect to end users, business partners and - the like. While this license is intended to facilitate the - commercial use of the Program, the Contributor who includes the - Program in a commercial product offering should do so in a manner - which does not create potential liability for other Contributors. - Therefore, if a Contributor includes the Program in a commercial - product offering, such Contributor ("Commercial Contributor") hereby - agrees to defend and indemnify every other Contributor ("Indemnified - Contributor") against any losses, damages and costs (collectively - "Losses") arising from claims, lawsuits and other legal actions - brought by a third party against the Indemnified Contributor to the - extent caused by the acts or omissions of such Commercial - Contributor in connection with its distribution of the Program in a - commercial product offering. The obligations in this section do not - apply to any claims or Losses relating to any actual or alleged - intellectual property infringement. In order to qualify, an - Indemnified Contributor must: a) promptly notify the Commercial - Contributor in writing of such claim, and b) allow the Commercial - Contributor to control, and cooperate with the Commercial - Contributor in, the defense and any related settlement negotiations. - The Indemnified Contributor may participate in any such claim at its - own expense. - - For example, a Contributor might include the Program in a commercial - product offering, Product X. That Contributor is then a Commercial - Contributor. If that Commercial Contributor then makes performance - claims, or offers warranties related to Product X, those performance - claims and warranties are such Commercial Contributor's - responsibility alone. Under this section, the Commercial Contributor - would have to defend claims against the other Contributors related - to those performance claims and warranties, and if a court requires - any other Contributor to pay any damages as a result, the Commercial - Contributor must pay those damages. - - 5. NO WARRANTY - - EXCEPT AS EXPRESSLY SET FORTH IN THIS AGREEMENT, THE PROGRAM IS - PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF - ANY KIND, EITHER EXPRESS OR IMPLIED INCLUDING, WITHOUT LIMITATION, - ANY WARRANTIES OR CONDITIONS OF TITLE, NON-INFRINGEMENT, - MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE. Each Recipient - is solely responsible for determining the appropriateness of using - and distributing the Program and assumes all risks associated with - its exercise of rights under this Agreement , including but not - limited to the risks and costs of program errors, compliance with - applicable laws, damage to or loss of data, programs or equipment, - and unavailability or interruption of operations. - - 6. DISCLAIMER OF LIABILITY - - EXCEPT AS EXPRESSLY SET FORTH IN THIS AGREEMENT, NEITHER RECIPIENT - NOR ANY CONTRIBUTORS SHALL HAVE ANY LIABILITY FOR ANY DIRECT, - INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES - (INCLUDING WITHOUT LIMITATION LOST PROFITS), HOWEVER CAUSED AND ON - ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR - TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF - THE USE OR DISTRIBUTION OF THE PROGRAM OR THE EXERCISE OF ANY RIGHTS - GRANTED HEREUNDER, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH - DAMAGES. - - 7. GENERAL - - If any provision of this Agreement is invalid or unenforceable under - applicable law, it shall not affect the validity or enforceability - of the remainder of the terms of this Agreement, and without further - action by the parties hereto, such provision shall be reformed to - the minimum extent necessary to make such provision valid and - enforceable. - - If Recipient institutes patent litigation against any entity - (including a cross-claim or counterclaim in a lawsuit) alleging that - the Program itself (excluding combinations of the Program with other - software or hardware) infringes such Recipient's patent(s), then - such Recipient's rights granted under Section 2(b) shall terminate - as of the date such litigation is filed. - - All Recipient's rights under this Agreement shall terminate if it - fails to comply with any of the material terms or conditions of this - Agreement and does not cure such failure in a reasonable period of - time after becoming aware of such noncompliance. If all Recipient's - rights under this Agreement terminate, Recipient agrees to cease use - and distribution of the Program as soon as reasonably practicable. - However, Recipient's obligations under this Agreement and any - licenses granted by Recipient relating to the Program shall continue - and survive. - - Everyone is permitted to copy and distribute copies of this - Agreement, but in order to avoid inconsistency the Agreement is - copyrighted and may only be modified in the following manner. The - Agreement Steward reserves the right to publish new versions - (including revisions) of this Agreement from time to time. No one - other than the Agreement Steward has the right to modify this - Agreement. The Eclipse Foundation is the initial Agreement Steward. - The Eclipse Foundation may assign the responsibility to serve as the - Agreement Steward to a suitable separate entity. Each new version of - the Agreement will be given a distinguishing version number. The - Program (including Contributions) may always be distributed subject - to the version of the Agreement under which it was received. In - addition, after a new version of the Agreement is published, - Contributor may elect to distribute the Program (including its - Contributions) under the new version. Except as expressly stated in - Sections 2(a) and 2(b) above, Recipient receives no rights or - licenses to the intellectual property of any Contributor under this - Agreement, whether expressly, by implication, estoppel or otherwise. - All rights in the Program not expressly granted under this Agreement - are reserved. - - This Agreement is governed by the laws of the State of New York and - the intellectual property laws of the United States of America. No - party to this Agreement will bring a legal action under this - Agreement more than one year after the cause of action arose. Each - party waives its rights to a jury trial in any resulting litigation. \ No newline at end of file diff --git a/tools/dependencies-report/src/main/resources/notices/bytelist-NOTICE.txt b/tools/dependencies-report/src/main/resources/notices/jruby-NOTICE.txt similarity index 72% rename from tools/dependencies-report/src/main/resources/notices/bytelist-NOTICE.txt rename to tools/dependencies-report/src/main/resources/notices/jruby-NOTICE.txt index a9fdfc945..e1f33ed12 100644 --- a/tools/dependencies-report/src/main/resources/notices/bytelist-NOTICE.txt +++ b/tools/dependencies-report/src/main/resources/notices/jruby-NOTICE.txt @@ -1,399 +1,262 @@ -JRuby is Copyright (c) 2007-2013 The JRuby project, and is released +JRuby is Copyright (c) 2007-2018 The JRuby project, and is released under a tri EPL/GPL/LGPL license. You can use it, redistribute it and/or modify it under the terms of the: - Eclipse Public License version 1.0 + Eclipse Public License version 2.0 + OR GNU General Public License version 2 + OR GNU Lesser General Public License version 2.1 +bytelist (http://github.com/jruby/bytelist), +jnr-posix (https://github.com/jnr/jnr-posix), +jruby-openssl (https://github.com/jruby/jruby-openssl), +jruby-readline (https://github.com/jruby/jruby-readline), +psych (https://github.com/ruby/psych), +yydebug (https://github.com/jruby/jay-yydebug/) +are released under the same copyright/license. + +Some additional libraries distributed with JRuby are not covered by +JRuby's licence. Most of these libraries and their licenses are listed +below. Also see LICENSE.RUBY for most files found in lib/ruby/stdlib. + + asm (http://asm.objectweb.org) is distributed under the BSD license and is + + Copyright (c) 2000-2011 INRIA, France Telecom + All rights reserved. + + jline2 (https://github.com/jline/jline2) is distributed under the BSD license: + + Copyright (c) 2002-2012, the original author or authors. + All rights reserved. + + jzlib (http://www.jcraft.com/jzlib/) is distributed under the BSD license: + + Copyright (c) 2000-2011 ymnk, JCraft,Inc. All rights reserved. + + The "rake" library (https://github.com/ruby/rake) is distributed under + the MIT license, and has the following copyright: + + Copyright (c) 2003, 2004 Jim Weirich + + jcodings (http://github.com/jruby/jcodings) and + joni (http://github.com/jruby/joni) are distributed + under the MIT license without copyright. + + Bouncycastle is released under the MIT license: + + Copyright (c) 2000 - 2006 The Legion Of The Bouncy Castle. + + jnr-x86asm (https://github.com/jnr/jnr-x86asm) is distributed under the MIT + license with the following copyright: + + Copyright (C) 2010 Wayne Meissner + Copyright (c) 2008-2009, Petr Kobalicek + + The following libraries are redistributed under the Apache Software + License v2.0, available below. + invokebinder (https://github.com/headius/invokebinder) + jffi (https://github.com/jnr/jffi) + jitescript (https://github.com/qmx/jitescript) + jnr-constants (http://github.com/jnr/jnr-constants) + jnr-enxio (https://github.com/jnr/jnr-enxio) + jnr-ffi (https://github.com/jnr/jnr-jffi) + jnr-netdb (http://github.com/jnr/jnr-netdb) + jnr-unixsocket (https://github.com/jnr/jnr-unixsocket) + joda-time (http://joda-time.sourceforge.net) + maven (http://maven.apache.org/) + nailgun (http://martiansoftware.com/nailgun) + options (https://github.com/headius/options) + snakeyaml (https://github.com/asomov/snakeyaml) + unsafe-fences (https://github.com/headius/unsafe-fences) + + racc (runtime only, https://github.com/tenderlove/racc) is + distributed under the same license terms as the Ruby standard + library. This includes all files under lib/ruby/stdlib/racc. + See LICENSE.RUBY. + + json-generator and json-parser (https://github.com/flori/json) native + extenstions under the same license terms as the Ruby standard library. + See LICENSE.RUBY + The complete text of the Eclipse Public License is as follows: - Eclipse Public License - v 1.0 + Eclipse Public License - v 2.0 - THE ACCOMPANYING PROGRAM IS PROVIDED UNDER THE TERMS OF THIS ECLIPSE - PUBLIC LICENSE ("AGREEMENT"). ANY USE, REPRODUCTION OR DISTRIBUTION - OF THE PROGRAM CONSTITUTES RECIPIENT'S ACCEPTANCE OF THIS AGREEMENT. + THE ACCOMPANYING PROGRAM IS PROVIDED UNDER THE TERMS OF THIS ECLIPSE + PUBLIC LICENSE ("AGREEMENT"). ANY USE, REPRODUCTION OR DISTRIBUTION + OF THE PROGRAM CONSTITUTES RECIPIENT'S ACCEPTANCE OF THIS AGREEMENT. 1. DEFINITIONS "Contribution" means: - a) in the case of the initial Contributor, the initial code and - documentation distributed under this Agreement, and + a) in the case of the initial Contributor, the initial content + Distributed under this Agreement, and - b) in the case of each subsequent Contributor: + b) in the case of each subsequent Contributor: + i) changes to the Program, and + ii) additions to the Program; + where such changes and/or additions to the Program originate from + and are Distributed by that particular Contributor. A Contribution + "originates" from a Contributor if it was added to the Program by + such Contributor itself or anyone acting on such Contributor's behalf. + Contributions do not include changes or additions to the Program that + are not Modified Works. - i) changes to the Program, and + "Contributor" means any person or entity that Distributes the Program. - ii) additions to the Program; - where such changes and/or additions to the Program - originate from and are distributed by that particular - Contributor. A Contribution 'originates' from a - Contributor if it was added to the Program by such - Contributor itself or anyone acting on such - Contributor's behalf. Contributions do not include - additions to the Program which: (i) are separate modules - of software distributed in conjunction with the Program - under their own license agreement, and (ii) are not - derivative works of the Program. + "Licensed Patents" mean patent claims licensable by a Contributor which + are necessarily infringed by the use or sale of its Contribution alone + or when combined with the Program. - "Contributor" means any person or entity that distributes the Program. + "Program" means the Contributions Distributed in accordance with this + Agreement. - "Licensed Patents" mean patent claims licensable by a Contributor - which are necessarily infringed by the use or sale of its - Contribution alone or when combined with the Program. + "Recipient" means anyone who receives the Program under this Agreement + or any Secondary License (as applicable), including Contributors. - "Program" means the Contributions distributed in accordance with - this Agreement. + "Derivative Works" shall mean any work, whether in Source Code or other + form, that is based on (or derived from) the Program and for which the + editorial revisions, annotations, elaborations, or other modifications + represent, as a whole, an original work of authorship. - "Recipient" means anyone who receives the Program under this - Agreement, including all Contributors. + "Modified Works" shall mean any work in Source Code or other form that + results from an addition to, deletion from, or modification of the + contents of the Program, including, for purposes of clarity any new file + in Source Code form that contains any contents of the Program. Modified + Works shall not include works that contain only declarations, + interfaces, types, classes, structures, or files of the Program solely + in each case in order to link to, bind by name, or subclass the Program + or Modified Works thereof. + + "Distribute" means the acts of a) distributing or b) making available + in any manner that enables the transfer of a copy. + + "Source Code" means the form of a Program preferred for making + modifications, including but not limited to software source code, + documentation source, and configuration files. + + "Secondary License" means either the GNU General Public License, + Version 2.0, or any later versions of that license, including any + exceptions or additional permissions as identified by the initial + Contributor. 2. GRANT OF RIGHTS - a) Subject to the terms of this Agreement, each Contributor - hereby grants Recipient a non-exclusive, worldwide, - royalty-free copyright license to reproduce, prepare - derivative works of, publicly display, publicly perform, - distribute and sublicense the Contribution of such - Contributor, if any, and such derivative works, in source - code and object code form. + a) Subject to the terms of this Agreement, each Contributor hereby + grants Recipient a non-exclusive, worldwide, royalty-free copyright + license to reproduce, prepare Derivative Works of, publicly display, + publicly perform, Distribute and sublicense the Contribution of such + Contributor, if any, and such Derivative Works. - b) Subject to the terms of this Agreement, each Contributor - hereby grants Recipient a non-exclusive, worldwide, - royalty-free patent license under Licensed Patents to make, - use, sell, offer to sell, import and otherwise transfer the - Contribution of such Contributor, if any, in source code and - object code form. This patent license shall apply to the - combination of the Contribution and the Program if, at the - time the Contribution is added by the Contributor, such - addition of the Contribution causes such combination to be - covered by the Licensed Patents. The patent license shall not - apply to any other combinations which include the - Contribution. No hardware per se is licensed hereunder. + b) Subject to the terms of this Agreement, each Contributor hereby + grants Recipient a non-exclusive, worldwide, royalty-free patent + license under Licensed Patents to make, use, sell, offer to sell, + import and otherwise transfer the Contribution of such Contributor, + if any, in Source Code or other form. This patent license shall + apply to the combination of the Contribution and the Program if, at + the time the Contribution is added by the Contributor, such addition + of the Contribution causes such combination to be covered by the + Licensed Patents. The patent license shall not apply to any other + combinations which include the Contribution. No hardware per se is + licensed hereunder. - c) Recipient understands that although each Contributor grants - the licenses to its Contributions set forth herein, no - assurances are provided by any Contributor that the Program - does not infringe the patent or other intellectual property - rights of any other entity. Each Contributor disclaims any - liability to Recipient for claims brought by any other entity - based on infringement of intellectual property rights or - otherwise. As a condition to exercising the rights and - licenses granted hereunder, each Recipient hereby assumes - sole responsibility to secure any other intellectual property - rights needed, if any. For example, if a third party patent - license is required to allow Recipient to distribute the - Program, it is Recipient's responsibility to acquire that - license before distributing the Program. + c) Recipient understands that although each Contributor grants the + licenses to its Contributions set forth herein, no assurances are + provided by any Contributor that the Program does not infringe the + patent or other intellectual property rights of any other entity. + Each Contributor disclaims any liability to Recipient for claims + brought by any other entity based on infringement of intellectual + property rights or otherwise. As a condition to exercising the + rights and licenses granted hereunder, each Recipient hereby + assumes sole responsibility to secure any other intellectual + property rights needed, if any. For example, if a third party + patent license is required to allow Recipient to Distribute the + Program, it is Recipient's responsibility to acquire that license + before distributing the Program. - d) Each Contributor represents that to its knowledge it has - sufficient copyright rights in its Contribution, if any, to - grant the copyright license set forth in this Agreement. + d) Each Contributor represents that to its knowledge it has + sufficient copyright rights in its Contribution, if any, to grant + the copyright license set forth in this Agreement. + + e) Notwithstanding the terms of any Secondary License, no + Contributor makes additional grants to any Recipient (other than + those set forth in this Agreement) as a result of such Recipient's + receipt of the Program under the terms of a Secondary License + (if permitted under the terms of Section 3). 3. REQUIREMENTS - A Contributor may choose to distribute the Program in object code - form under its own license agreement, provided that: + 3.1 If a Contributor Distributes the Program in any form, then: - a) it complies with the terms and conditions of this Agreement; and + a) the Program must also be made available as Source Code, in + accordance with section 3.2, and the Contributor must accompany + the Program with a statement that the Source Code for the Program + is available under this Agreement, and informs Recipients how to + obtain it in a reasonable manner on or through a medium customarily + used for software exchange; and - b) its license agreement: + b) the Contributor may Distribute the Program under a license + different than this Agreement, provided that such license: + i) effectively disclaims on behalf of all other Contributors all + warranties and conditions, express and implied, including + warranties or conditions of title and non-infringement, and + implied warranties or conditions of merchantability and fitness + for a particular purpose; - i) effectively disclaims on behalf of all Contributors all - warranties and conditions, express and implied, including - warranties or conditions of title and non-infringement, - and implied warranties or conditions of merchantability - and fitness for a particular purpose; + ii) effectively excludes on behalf of all other Contributors all + liability for damages, including direct, indirect, special, + incidental and consequential damages, such as lost profits; - ii) effectively excludes on behalf of all Contributors all - liability for damages, including direct, indirect, - special, incidental and consequential damages, such as - lost profits; + iii) does not attempt to limit or alter the recipients' rights + in the Source Code under section 3.2; and - iii) states that any provisions which differ from this - Agreement are offered by that Contributor alone and not - by any other party; and + iv) requires any subsequent distribution of the Program by any + party to be under a license that satisfies the requirements + of this section 3. - iv) states that source code for the Program is available - from such Contributor, and informs licensees how to - obtain it in a reasonable manner on or through a medium - customarily used for software exchange. + 3.2 When the Program is Distributed as Source Code: - When the Program is made available in source code form: + a) it must be made available under this Agreement, or if the + Program (i) is combined with other material in a separate file or + files made available under a Secondary License, and (ii) the initial + Contributor attached to the Source Code the notice described in + Exhibit A of this Agreement, then the Program may be made available + under the terms of such Secondary Licenses, and - a) it must be made available under this Agreement; and + b) a copy of this Agreement must be included with each copy of + the Program. - b) a copy of this Agreement must be included with each copy of - the Program. - - Contributors may not remove or alter any copyright notices contained - within the Program. - - Each Contributor must identify itself as the originator of its - Contribution, if any, in a manner that reasonably allows subsequent - Recipients to identify the originator of the Contribution. + 3.3 Contributors may not remove or alter any copyright, patent, + trademark, attribution notices, disclaimers of warranty, or limitations + of liability ("notices") contained within the Program from any copy of + the Program which they Distribute, provided that Contributors may add + their own appropriate notices. 4. COMMERCIAL DISTRIBUTION - Commercial distributors of software may accept certain - responsibilities with respect to end users, business partners and - the like. While this license is intended to facilitate the - commercial use of the Program, the Contributor who includes the - Program in a commercial product offering should do so in a manner - which does not create potential liability for other Contributors. - Therefore, if a Contributor includes the Program in a commercial - product offering, such Contributor ("Commercial Contributor") hereby - agrees to defend and indemnify every other Contributor ("Indemnified - Contributor") against any losses, damages and costs (collectively - "Losses") arising from claims, lawsuits and other legal actions - brought by a third party against the Indemnified Contributor to the - extent caused by the acts or omissions of such Commercial - Contributor in connection with its distribution of the Program in a - commercial product offering. The obligations in this section do not + Commercial distributors of software may accept certain responsibilities + with respect to end users, business partners and the like. While this + license is intended to facilitate the commercial use of the Program, + the Contributor who includes the Program in a commercial product + offering should do so in a manner which does not create potential + liability for other Contributors. Therefore, if a Contributor includes + the Program in a commercial product offering, such Contributor + ("Commercial Contributor") hereby agrees to defend and indemnify every + other Contributor ("Indemnified Contributor") against any losses, + damages and costs (collectively "Losses") arising from claims, lawsuits + and other legal actions brought by a third party against the Indemnified + Contributor to the extent caused by the acts or omissions of such + Commercial Contributor in connection with its distribution of the Program + in a commercial product offering. The obligations in this section do not apply to any claims or Losses relating to any actual or alleged - intellectual property infringement. In order to qualify, an - Indemnified Contributor must: a) promptly notify the Commercial - Contributor in writing of such claim, and b) allow the Commercial - Contributor to control, and cooperate with the Commercial - Contributor in, the defense and any related settlement negotiations. - The Indemnified Contributor may participate in any such claim at its - own expense. - - For example, a Contributor might include the Program in a commercial - product offering, Product X. That Contributor is then a Commercial - Contributor. If that Commercial Contributor then makes performance - claims, or offers warranties related to Product X, those performance - claims and warranties are such Commercial Contributor's - responsibility alone. Under this section, the Commercial Contributor - would have to defend claims against the other Contributors related - to those performance claims and warranties, and if a court requires - any other Contributor to pay any damages as a result, the Commercial - Contributor must pay those damages. - - 5. NO WARRANTY - - EXCEPT AS EXPRESSLY SET FORTH IN THIS AGREEMENT, THE PROGRAM IS - PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF - ANY KIND, EITHER EXPRESS OR IMPLIED INCLUDING, WITHOUT LIMITATION, - ANY WARRANTIES OR CONDITIONS OF TITLE, NON-INFRINGEMENT, - MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE. Each Recipient - is solely responsible for determining the appropriateness of using - and distributing the Program and assumes all risks associated with - its exercise of rights under this Agreement , including but not - limited to the risks and costs of program errors, compliance with - applicable laws, damage to or loss of data, programs or equipment, - and unavailability or interruption of operations. - - 6. DISCLAIMER OF LIABILITY - - EXCEPT AS EXPRESSLY SET FORTH IN THIS AGREEMENT, NEITHER RECIPIENT - NOR ANY CONTRIBUTORS SHALL HAVE ANY LIABILITY FOR ANY DIRECT, - INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES - (INCLUDING WITHOUT LIMITATION LOST PROFITS), HOWEVER CAUSED AND ON - ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR - TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF - THE USE OR DISTRIBUTION OF THE PROGRAM OR THE EXERCISE OF ANY RIGHTS - GRANTED HEREUNDER, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH - DAMAGES. - - 7. GENERAL - - If any provision of this Agreement is invalid or unenforceable under - applicable law, it shall not affect the validity or enforceability - of the remainder of the terms of this Agreement, and without further - action by the parties hereto, such provision shall be reformed to - the minimum extent necessary to make such provision valid and - enforceable. - - If Recipient institutes patent litigation against any entity - (including a cross-claim or counterclaim in a lawsuit) alleging that - the Program itself (excluding combinations of the Program with other - software or hardware) infringes such Recipient's patent(s), then - such Recipient's rights granted under Section 2(b) shall terminate - as of the date such litigation is filed. - - All Recipient's rights under this Agreement shall terminate if it - fails to comply with any of the material terms or conditions of this - Agreement and does not cure such failure in a reasonable period of - time after becoming aware of such noncompliance. If all Recipient's - rights under this Agreement terminate, Recipient agrees to cease use - and distribution of the Program as soon as reasonably practicable. - However, Recipient's obligations under this Agreement and any - licenses granted by Recipient relating to the Program shall continue - and survive. - - Everyone is permitted to copy and distribute copies of this - Agreement, but in order to avoid inconsistency the Agreement is - copyrighted and may only be modified in the following manner. The - Agreement Steward reserves the right to publish new versions - (including revisions) of this Agreement from time to time. No one - other than the Agreement Steward has the right to modify this - Agreement. The Eclipse Foundation is the initial Agreement Steward. - The Eclipse Foundation may assign the responsibility to serve as the - Agreement Steward to a suitable separate entity. Each new version of - the Agreement will be given a distinguishing version number. The - Program (including Contributions) may always be distributed subject - to the version of the Agreement under which it was received. In - addition, after a new version of the Agreement is published, - Contributor may elect to distribute the Program (including its - Contributions) under the new version. Except as expressly stated in - Sections 2(a) and 2(b) above, Recipient receives no rights or - licenses to the intellectual property of any Contributor under this - Agreement, whether expressly, by implication, estoppel or otherwise. - All rights in the Program not expressly granted under this Agreement - are reserved. - - This Agreement is governed by the laws of the State of New York and - the intellectual property laws of the United States of America. No - party to this Agreement will bring a legal action under this - Agreement more than one year after the cause of action arose. Each - party waives its rights to a jury trial in any resulting litigation. - -The complete text of the Common Public License is as follows: - - Common Public License - v 1.0 - - THE ACCOMPANYING PROGRAM IS PROVIDED UNDER THE TERMS OF THIS COMMON - PUBLIC LICENSE ("AGREEMENT"). ANY USE, REPRODUCTION OR DISTRIBUTION OF - THE PROGRAM CONSTITUTES RECIPIENT'S ACCEPTANCE OF THIS AGREEMENT. - - 1. DEFINITIONS - - "Contribution" means: - - a) in the case of the initial Contributor, the initial code and - documentation distributed under this Agreement, and - - b) in the case of each subsequent Contributor: - - i) changes to the Program, and - - ii) additions to the Program; - - where such changes and/or additions to the Program originate - from and are distributed by that particular Contributor. A - Contribution 'originates' from a Contributor if it was added to the - Program by such Contributor itself or anyone acting on such - Contributor's behalf. Contributions do not include additions to the - Program which: (i) are separate modules of software distributed in - conjunction with the Program under their own license agreement, - and (ii) are not derivative works of the Program. - - "Contributor" means any person or entity that distributes the Program. - - "Licensed Patents " mean patent claims licensable by a Contributor - which are necessarily infringed by the use or sale of its Contribution - alone or when combined with the Program. - - "Program" means the Contributions distributed in accordance with this Agreement. - - "Recipient" means anyone who receives the Program under this - Agreement, including all Contributors. - - 2. GRANT OF RIGHTS - - a) Subject to the terms of this Agreement, each Contributor - hereby grants Recipient a non-exclusive, worldwide, royalty-free - copyright license to reproduce, prepare derivative works of, publicly - display, publicly perform, distribute and sublicense the Contribution - of such Contributor, if any, and such derivative works, in source code - and object code form. - - b) Subject to the terms of this Agreement, each Contributor - hereby grants Recipient a non-exclusive, worldwide, royalty-free - patent license under Licensed Patents to make, use, sell, offer to - sell, import and otherwise transfer the Contribution of such - Contributor, if any, in source code and object code form. This patent - license shall apply to the combination of the Contribution and the - Program if, at the time the Contribution is added by the Contributor, - such addition of the Contribution causes such combination to be - covered by the Licensed Patents. The patent license shall not apply to - any other combinations which include the Contribution. No hardware per - se is licensed hereunder. - - c) Recipient understands that although each Contributor grants - the licenses to its Contributions set forth herein, no assurances are - provided by any Contributor that the Program does not infringe the - patent or other intellectual property rights of any other entity. Each - Contributor disclaims any liability to Recipient for claims brought by - any other entity based on infringement of intellectual property rights - or otherwise. As a condition to exercising the rights and licenses - granted hereunder, each Recipient hereby assumes sole responsibility - to secure any other intellectual property rights needed, if any. For - example, if a third party patent license is required to allow - Recipient to distribute the Program, it is Recipient's responsibility - to acquire that license before distributing the Program. - - d) Each Contributor represents that to its knowledge it has - sufficient copyright rights in its Contribution, if any, to grant the - copyright license set forth in this Agreement. - - 3. REQUIREMENTS - - A Contributor may choose to distribute the Program in object code form - under its own license agreement, provided that: - - a) it complies with the terms and conditions of this Agreement; - and - - b) its license agreement: - - i) effectively disclaims on behalf of all Contributors all - warranties and conditions, express and implied, including warranties - or conditions of title and non-infringement, and implied warranties or - conditions of merchantability and fitness for a particular purpose; - - ii) effectively excludes on behalf of all Contributors all - liability for damages, including direct, indirect, special, incidental - and consequential damages, such as lost profits; - - iii) states that any provisions which differ from this Agreement - are offered by that Contributor alone and not by any other party; and - - iv) states that source code for the Program is available from - such Contributor, and informs licensees how to obtain it in a - reasonable manner on or through a medium customarily used for software - exchange. - - When the Program is made available in source code form: - - a) it must be made available under this Agreement; and - - b) a copy of this Agreement must be included with each copy of - the Program. - - Contributors may not remove or alter any copyright notices contained - within the Program. - - Each Contributor must identify itself as the originator of its - Contribution, if any, in a manner that reasonably allows subsequent - Recipients to identify the originator of the Contribution. - - 4. COMMERCIAL DISTRIBUTION - - Commercial distributors of software may accept certain - responsibilities with respect to end users, business partners and the - like. While this license is intended to facilitate the commercial use - of the Program, the Contributor who includes the Program in a - commercial product offering should do so in a manner which does not - create potential liability for other Contributors. Therefore, if a - Contributor includes the Program in a commercial product offering, - such Contributor ("Commercial Contributor") hereby agrees to defend - and indemnify every other Contributor ("Indemnified Contributor") - against any losses, damages and costs (collectively "Losses") arising - from claims, lawsuits and other legal actions brought by a third party - against the Indemnified Contributor to the extent caused by the acts - or omissions of such Commercial Contributor in connection with its - distribution of the Program in a commercial product offering. The - obligations in this section do not apply to any claims or Losses - relating to any actual or alleged intellectual property - infringement. In order to qualify, an Indemnified Contributor must: a) - promptly notify the Commercial Contributor in writing of such claim, - and b) allow the Commercial Contributor to control, and cooperate with - the Commercial Contributor in, the defense and any related settlement - negotiations. The Indemnified Contributor may participate in any such - claim at its own expense. + intellectual property infringement. In order to qualify, an Indemnified + Contributor must: a) promptly notify the Commercial Contributor in + writing of such claim, and b) allow the Commercial Contributor to control, + and cooperate with the Commercial Contributor in, the defense and any + related settlement negotiations. The Indemnified Contributor may + participate in any such claim at its own expense. For example, a Contributor might include the Program in a commercial product offering, Product X. That Contributor is then a Commercial @@ -401,35 +264,36 @@ The complete text of the Common Public License is as follows: claims, or offers warranties related to Product X, those performance claims and warranties are such Commercial Contributor's responsibility alone. Under this section, the Commercial Contributor would have to - defend claims against the other Contributors related to those - performance claims and warranties, and if a court requires any other - Contributor to pay any damages as a result, the Commercial Contributor - must pay those damages. + defend claims against the other Contributors related to those performance + claims and warranties, and if a court requires any other Contributor to + pay any damages as a result, the Commercial Contributor must pay + those damages. 5. NO WARRANTY - EXCEPT AS EXPRESSLY SET FORTH IN THIS AGREEMENT, THE PROGRAM IS - PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - KIND, EITHER EXPRESS OR IMPLIED INCLUDING, WITHOUT LIMITATION, ANY - WARRANTIES OR CONDITIONS OF TITLE, NON-INFRINGEMENT, MERCHANTABILITY - OR FITNESS FOR A PARTICULAR PURPOSE. Each Recipient is solely - responsible for determining the appropriateness of using and - distributing the Program and assumes all risks associated with its - exercise of rights under this Agreement, including but not limited to - the risks and costs of program errors, compliance with applicable - laws, damage to or loss of data, programs or equipment, and - unavailability or interruption of operations. + EXCEPT AS EXPRESSLY SET FORTH IN THIS AGREEMENT, AND TO THE EXTENT + PERMITTED BY APPLICABLE LAW, THE PROGRAM IS PROVIDED ON AN "AS IS" + BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, EITHER EXPRESS OR + IMPLIED INCLUDING, WITHOUT LIMITATION, ANY WARRANTIES OR CONDITIONS OF + TITLE, NON-INFRINGEMENT, MERCHANTABILITY OR FITNESS FOR A PARTICULAR + PURPOSE. Each Recipient is solely responsible for determining the + appropriateness of using and distributing the Program and assumes all + risks associated with its exercise of rights under this Agreement, + including but not limited to the risks and costs of program errors, + compliance with applicable laws, damage to or loss of data, programs + or equipment, and unavailability or interruption of operations. 6. DISCLAIMER OF LIABILITY - EXCEPT AS EXPRESSLY SET FORTH IN THIS AGREEMENT, NEITHER RECIPIENT NOR - ANY CONTRIBUTORS SHALL HAVE ANY LIABILITY FOR ANY DIRECT, INDIRECT, - INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING - WITHOUT LIMITATION LOST PROFITS), HOWEVER CAUSED AND ON ANY THEORY OF - LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING - NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OR - DISTRIBUTION OF THE PROGRAM OR THE EXERCISE OF ANY RIGHTS GRANTED - HEREUNDER, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGES. + EXCEPT AS EXPRESSLY SET FORTH IN THIS AGREEMENT, AND TO THE EXTENT + PERMITTED BY APPLICABLE LAW, NEITHER RECIPIENT NOR ANY CONTRIBUTORS + SHALL HAVE ANY LIABILITY FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING WITHOUT LIMITATION LOST + PROFITS), HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + ARISING IN ANY WAY OUT OF THE USE OR DISTRIBUTION OF THE PROGRAM OR THE + EXERCISE OF ANY RIGHTS GRANTED HEREUNDER, EVEN IF ADVISED OF THE + POSSIBILITY OF SUCH DAMAGES. 7. GENERAL @@ -439,15 +303,10 @@ The complete text of the Common Public License is as follows: action by the parties hereto, such provision shall be reformed to the minimum extent necessary to make such provision valid and enforceable. - If Recipient institutes patent litigation against a Contributor with - respect to a patent applicable to software (including a cross-claim or - counterclaim in a lawsuit), then any patent licenses granted by that - Contributor to such Recipient under this Agreement shall terminate as - of the date such litigation is filed. In addition, if Recipient - institutes patent litigation against any entity (including a - cross-claim or counterclaim in a lawsuit) alleging that the Program - itself (excluding combinations of the Program with other software or - hardware) infringes such Recipient's patent(s), then such Recipient's + If Recipient institutes patent litigation against any entity + (including a cross-claim or counterclaim in a lawsuit) alleging that the + Program itself (excluding combinations of the Program with other software + or hardware) infringes such Recipient's patent(s), then such Recipient's rights granted under Section 2(b) shall terminate as of the date such litigation is filed. @@ -456,35 +315,49 @@ The complete text of the Common Public License is as follows: Agreement and does not cure such failure in a reasonable period of time after becoming aware of such noncompliance. If all Recipient's rights under this Agreement terminate, Recipient agrees to cease use - and distribution of the Program as soon as reasonably - practicable. However, Recipient's obligations under this Agreement and - any licenses granted by Recipient relating to the Program shall - continue and survive. + and distribution of the Program as soon as reasonably practicable. + However, Recipient's obligations under this Agreement and any licenses + granted by Recipient relating to the Program shall continue and survive. Everyone is permitted to copy and distribute copies of this Agreement, but in order to avoid inconsistency the Agreement is copyrighted and may only be modified in the following manner. The Agreement Steward reserves the right to publish new versions (including revisions) of this Agreement from time to time. No one other than the Agreement - Steward has the right to modify this Agreement. IBM is the initial - Agreement Steward. IBM may assign the responsibility to serve as the - Agreement Steward to a suitable separate entity. Each new version of - the Agreement will be given a distinguishing version number. The - Program (including Contributions) may always be distributed subject to - the version of the Agreement under which it was received. In addition, - after a new version of the Agreement is published, Contributor may - elect to distribute the Program (including its Contributions) under - the new version. Except as expressly stated in Sections 2(a) and 2(b) - above, Recipient receives no rights or licenses to the intellectual - property of any Contributor under this Agreement, whether expressly, - by implication, estoppel or otherwise. All rights in the Program not - expressly granted under this Agreement are reserved. + Steward has the right to modify this Agreement. The Eclipse Foundation + is the initial Agreement Steward. The Eclipse Foundation may assign the + responsibility to serve as the Agreement Steward to a suitable separate + entity. Each new version of the Agreement will be given a distinguishing + version number. The Program (including Contributions) may always be + Distributed subject to the version of the Agreement under which it was + received. In addition, after a new version of the Agreement is published, + Contributor may elect to Distribute the Program (including its + Contributions) under the new version. - This Agreement is governed by the laws of the State of New York and - the intellectual property laws of the United States of America. No - party to this Agreement will bring a legal action under this Agreement - more than one year after the cause of action arose. Each party waives - its rights to a jury trial in any resulting litigation. + Except as expressly stated in Sections 2(a) and 2(b) above, Recipient + receives no rights or licenses to the intellectual property of any + Contributor under this Agreement, whether expressly, by implication, + estoppel or otherwise. All rights in the Program not expressly granted + under this Agreement are reserved. Nothing in this Agreement is intended + to be enforceable by any entity that is not a Contributor or Recipient. + No third-party beneficiary rights are created under this Agreement. + + Exhibit A - Form of Secondary Licenses Notice + + "This Source Code may also be made available under the following + Secondary Licenses when the conditions for such availability set forth + in the Eclipse Public License, v. 2.0 are satisfied: {name license(s), + version(s), and exceptions or additional permissions here}." + + Simply including a copy of this Agreement, including this Exhibit A + is not sufficient to license the Source Code under Secondary Licenses. + + If it is not possible or desirable to put the notice in a particular + file, then You may include the notice in a location (such as a LICENSE + file in a relevant directory) where a recipient would be likely to + look for such a notice. + + You may add additional accurate notices of copyright ownership. The complete text of the GNU General Public License v2 is as follows: @@ -1281,7 +1154,6 @@ Licenses listed below include: * GNU General Public License version 3 * Apache 2.0 License * BSD License -* Apache Software License Version 1.1 * MIT License The complete text of the GNU General Public License version 3 is as follows: @@ -2167,9 +2039,6 @@ The complete text of the Apache 2.0 License is as follows: The complete text of the BSD license can be is as follows: - Copyright (c) The Regents of the University of California. - All rights reserved. - Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: @@ -2182,75 +2051,17 @@ The complete text of the BSD license can be is as follows: may be used to endorse or promote products derived from this software without specific prior written permission. - THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND - ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE - ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE - FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL - DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS - OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) - HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT - LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY - OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF - SUCH DAMAGE. - -The complete text of the Apache Software License Version 1.1 is as follows: - - /* - * ================================================================ - * The Apache Software License, Version 1.1 - * ================================================================ - * - * Copyright (C) 2000-2002 The Apache Software Foundation. All - * rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following - * conditions are met: - * - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in - * the documentation and/or other materials provided with the - * distribution. - * - * 3. The end-user documentation included with the redistribution, if - * any, must include the following acknowledgment: "This product - * includes software developed by the Apache Software Foundation - * (http://www.apache.org/)." Alternately, this acknowledgment may - * appear in the software itself, if and wherever such third-party - * acknowledgments normally appear. - * - * 4. The names "Ant" and "Apache Software Foundation" must not be - * used to endorse or promote products derived from this software - * without prior written permission. For written permission, please - * contact apache@apache.org. - * - * 5. Products derived from this software may not be called "Apache", - * nor may "Apache" appear in their name, without prior written - * permission of the Apache Software Foundation. - * - * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED - * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES - * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE - * DISCLAIMED. IN NO EVENT SHALL THE APACHE SOFTWARE FOUNDATION - * OR ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT - * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, - * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON - * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR - * TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT - * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY - * OF SUCH DAMAGE. - * - * This software consists of voluntary contributions made by many - * individuals on behalf of the Apache Software Foundation. For more - * information on the Apache Software Foundation, please see - * . - * - */ + ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE + LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF + THE POSSIBILITY OF SUCH DAMAGE. The complete text of the MIT license is as follows: @@ -2275,213 +2086,374 @@ The complete text of the MIT license is as follows: FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. -The complete text of the Eclipse Public License v1.0 is as follows: +The complete text of the GPL v2, and classpath exception: - Eclipse Public License - v 1.0 - - THE ACCOMPANYING PROGRAM IS PROVIDED UNDER THE TERMS OF THIS ECLIPSE PUBLIC - LICENSE ("AGREEMENT"). ANY USE, REPRODUCTION OR DISTRIBUTION OF THE PROGRAM - CONSTITUTES RECIPIENT’S ACCEPTANCE OF THIS AGREEMENT. - - 1. DEFINITIONS - - "Contribution" means: - - a) in the case of the initial Contributor, the initial code and documentation - distributed under this Agreement, and - b) in the case of each subsequent Contributor: - - i) changes to the Program, and - - ii) additions to the Program; - - where such changes and/or additions to the Program originate from and are - distributed by that particular Contributor. A Contribution 'originates' from a - Contributor if it was added to the Program by such Contributor itself or anyone - acting on such Contributor’s behalf. Contributions do not include additions to - the Program which: (i) are separate modules of software distributed in - conjunction with the Program under their own license agreement, and (ii) are not - derivative works of the Program. - - "Contributor" means any person or entity that distributes the Program. - - "Licensed Patents " mean patent claims licensable by a Contributor which are - necessarily infringed by the use or sale of its Contribution alone or when - combined with the Program. - - "Program" means the Contributions distributed in accordance with this Agreement. - - "Recipient" means anyone who receives the Program under this Agreement, - including all Contributors. - - 2. GRANT OF RIGHTS - - a) Subject to the terms of this Agreement, each Contributor hereby grants - Recipient a non-exclusive, worldwide, royalty-free copyright license to - reproduce, prepare derivative works of, publicly display, publicly perform, - distribute and sublicense the Contribution of such Contributor, if any, and such - derivative works, in source code and object code form. - - b) Subject to the terms of this Agreement, each Contributor hereby grants - Recipient a non-exclusive, worldwide, royalty-free patent license under Licensed - Patents to make, use, sell, offer to sell, import and otherwise transfer the - Contribution of such Contributor, if any, in source code and object code form. - This patent license shall apply to the combination of the Contribution and the - Program if, at the time the Contribution is added by the Contributor, such - addition of the Contribution causes such combination to be covered by the - Licensed Patents. The patent license shall not apply to any other combinations - which include the Contribution. No hardware per se is licensed hereunder. - - c) Recipient understands that although each Contributor grants the licenses to - its Contributions set forth herein, no assurances are provided by any - Contributor that the Program does not infringe the patent or other intellectual - property rights of any other entity. Each Contributor disclaims any liability to - Recipient for claims brought by any other entity based on infringement of - intellectual property rights or otherwise. As a condition to exercising the - rights and licenses granted hereunder, each Recipient hereby assumes sole - responsibility to secure any other intellectual property rights needed, if any. - For example, if a third party patent license is required to allow Recipient to - distribute the Program, it is Recipient’s responsibility to acquire that license - before distributing the Program. - - d) Each Contributor represents that to its knowledge it has sufficient copyright - rights in its Contribution, if any, to grant the copyright license set forth in - this Agreement. - - 3. REQUIREMENTS - - A Contributor may choose to distribute the Program in object code form under its - own license agreement, provided that: - - a) it complies with the terms and conditions of this Agreement; and - - b) its license agreement: - - i) effectively disclaims on behalf of all Contributors all warranties and - conditions, express and implied, including warranties or conditions of title and - non-infringement, and implied warranties or conditions of merchantability and - fitness for a particular purpose; - - ii) effectively excludes on behalf of all Contributors all liability for - damages, including direct, indirect, special, incidental and consequential - damages, such as lost profits; - - iii) states that any provisions which differ from this Agreement are offered by - that Contributor alone and not by any other party; and - - iv) states that source code for the Program is available from such Contributor, - and informs licensees how to obtain it in a reasonable manner on or through a - medium customarily used for software exchange. - - When the Program is made available in source code form: - - a) it must be made available under this Agreement; and - b) a copy of this Agreement must be included with each copy of the Program. - - Contributors may not remove or alter any copyright notices contained within the - Program. - - Each Contributor must identify itself as the originator of its Contribution, if - any, in a manner that reasonably allows subsequent Recipients to identify the - originator of the Contribution. - - 4. COMMERCIAL DISTRIBUTION - - Commercial distributors of software may accept certain responsibilities with - respect to end users, business partners and the like. While this license is - intended to facilitate the commercial use of the Program, the Contributor who - includes the Program in a commercial product offering should do so in a manner - which does not create potential liability for other Contributors. Therefore, if - a Contributor includes the Program in a commercial product offering, such - Contributor ("Commercial Contributor") hereby agrees to defend and indemnify - every other Contributor ("Indemnified Contributor") against any losses, damages - and costs (collectively "Losses") arising from claims, lawsuits and other legal - actions brought by a third party against the Indemnified Contributor to the - extent caused by the acts or omissions of such Commercial Contributor in - connection with its distribution of the Program in a commercial product - offering. The obligations in this section do not apply to any claims or Losses - relating to any actual or alleged intellectual property infringement. In order - to qualify, an Indemnified Contributor must: a) promptly notify the Commercial - Contributor in writing of such claim, and b) allow the Commercial Contributor to - control, and cooperate with the Commercial Contributor in, the defense and any - related settlement negotiations. The Indemnified Contributor may participate in - any such claim at its own expense. - - For example, a Contributor might include the Program in a commercial product - offering, Product X. That Contributor is then a Commercial Contributor. If that - Commercial Contributor then makes performance claims, or offers warranties - related to Product X, those performance claims and warranties are such - Commercial Contributor’s responsibility alone. Under this section, the - Commercial Contributor would have to defend claims against the other - Contributors related to those performance claims and warranties, and if a court - requires any other Contributor to pay any damages as a result, the Commercial - Contributor must pay those damages. - - 5. NO WARRANTY - - EXCEPT AS EXPRESSLY SET FORTH IN THIS AGREEMENT, THE PROGRAM IS PROVIDED ON AN - "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, EITHER EXPRESS OR - IMPLIED INCLUDING, WITHOUT LIMITATION, ANY WARRANTIES OR CONDITIONS OF TITLE, - NON-INFRINGEMENT, MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE. Each - Recipient is solely responsible for determining the appropriateness of using and - distributing the Program and assumes all risks associated with its exercise of - rights under this Agreement , including but not limited to the risks and costs - of program errors, compliance with applicable laws, damage to or loss of data, - programs or equipment, and unavailability or interruption of operations. - - 6. DISCLAIMER OF LIABILITY - - EXCEPT AS EXPRESSLY SET FORTH IN THIS AGREEMENT, NEITHER RECIPIENT NOR ANY - CONTRIBUTORS SHALL HAVE ANY LIABILITY FOR ANY DIRECT, INDIRECT, INCIDENTAL, - SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING WITHOUT LIMITATION LOST - PROFITS), HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, - STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY - OUT OF THE USE OR DISTRIBUTION OF THE PROGRAM OR THE EXERCISE OF ANY RIGHTS - GRANTED HEREUNDER, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGES. - - 7. GENERAL - - If any provision of this Agreement is invalid or unenforceable under applicable - law, it shall not affect the validity or enforceability of the remainder of the - terms of this Agreement, and without further action by the parties hereto, such - provision shall be reformed to the minimum extent necessary to make such - provision valid and enforceable. - - If Recipient institutes patent litigation against any entity (including a - cross-claim or counterclaim in a lawsuit) alleging that the Program itself - (excluding combinations of the Program with other software or hardware) - infringes such Recipient’s patent(s), then such Recipient’s rights granted under - Section 2(b) shall terminate as of the date such litigation is filed. - - All Recipient’s rights under this Agreement shall terminate if it fails to - comply with any of the material terms or conditions of this Agreement and does - not cure such failure in a reasonable period of time after becoming aware of - such noncompliance. If all Recipient’s rights under this Agreement terminate, - Recipient agrees to cease use and distribution of the Program as soon as - reasonably practicable. However, Recipient’s obligations under this Agreement - and any licenses granted by Recipient relating to the Program shall continue and - survive. - - Everyone is permitted to copy and distribute copies of this Agreement, but in - order to avoid inconsistency the Agreement is copyrighted and may only be - modified in the following manner. The Agreement Steward reserves the right to - publish new versions (including revisions) of this Agreement from time to time. - No one other than the Agreement Steward has the right to modify this Agreement. - The Eclipse Foundation is the initial Agreement Steward. The Eclipse Foundation - may assign the responsibility to serve as the Agreement Steward to a suitable - separate entity. Each new version of the Agreement will be given a - distinguishing version number. The Program (including Contributions) may always - be distributed subject to the version of the Agreement under which it was - received. In addition, after a new version of the Agreement is published, - Contributor may elect to distribute the Program (including its Contributions) - under the new version. Except as expressly stated in Sections 2(a) and 2(b) - above, Recipient receives no rights or licenses to the intellectual property of - any Contributor under this Agreement, whether expressly, by implication, - estoppel or otherwise. All rights in the Program not expressly granted under - this Agreement are reserved. - - This Agreement is governed by the laws of the State of New York and the - intellectual property laws of the United States of America. No party to this - Agreement will bring a legal action under this Agreement more than one year - after the cause of action arose. Each party waives its rights to a jury trial in - any resulting litigation. +The GNU General Public License (GPL) + +Version 2, June 1991 + +Copyright (C) 1989, 1991 Free Software Foundation, Inc. +59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + +Everyone is permitted to copy and distribute verbatim copies of this license +document, but changing it is not allowed. + +Preamble + +The licenses for most software are designed to take away your freedom to share +and change it. By contrast, the GNU General Public License is intended to +guarantee your freedom to share and change free software--to make sure the +software is free for all its users. This General Public License applies to +most of the Free Software Foundation's software and to any other program whose +authors commit to using it. (Some other Free Software Foundation software is +covered by the GNU Library General Public License instead.) You can apply it to +your programs, too. + +When we speak of free software, we are referring to freedom, not price. Our +General Public Licenses are designed to make sure that you have the freedom to +distribute copies of free software (and charge for this service if you wish), +that you receive source code or can get it if you want it, that you can change +the software or use pieces of it in new free programs; and that you know you +can do these things. + +To protect your rights, we need to make restrictions that forbid anyone to deny +you these rights or to ask you to surrender the rights. These restrictions +translate to certain responsibilities for you if you distribute copies of the +software, or if you modify it. + +For example, if you distribute copies of such a program, whether gratis or for +a fee, you must give the recipients all the rights that you have. You must +make sure that they, too, receive or can get the source code. And you must +show them these terms so they know their rights. + +We protect your rights with two steps: (1) copyright the software, and (2) +offer you this license which gives you legal permission to copy, distribute +and/or modify the software. + +Also, for each author's protection and ours, we want to make certain that +everyone understands that there is no warranty for this free software. If the +software is modified by someone else and passed on, we want its recipients to +know that what they have is not the original, so that any problems introduced +by others will not reflect on the original authors' reputations. + +Finally, any free program is threatened constantly by software patents. We +wish to avoid the danger that redistributors of a free program will +individually obtain patent licenses, in effect making the program proprietary. +To prevent this, we have made it clear that any patent must be licensed for +everyone's free use or not licensed at all. + +The precise terms and conditions for copying, distribution and modification +follow. + +TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION + +0. This License applies to any program or other work which contains a notice +placed by the copyright holder saying it may be distributed under the terms of +this General Public License. The "Program", below, refers to any such program +or work, and a "work based on the Program" means either the Program or any +derivative work under copyright law: that is to say, a work containing the +Program or a portion of it, either verbatim or with modifications and/or +translated into another language. (Hereinafter, translation is included +without limitation in the term "modification".) Each licensee is addressed as +"you". + +Activities other than copying, distribution and modification are not covered by +this License; they are outside its scope. The act of running the Program is +not restricted, and the output from the Program is covered only if its contents +constitute a work based on the Program (independent of having been made by +running the Program). Whether that is true depends on what the Program does. + +1. You may copy and distribute verbatim copies of the Program's source code as +you receive it, in any medium, provided that you conspicuously and +appropriately publish on each copy an appropriate copyright notice and +disclaimer of warranty; keep intact all the notices that refer to this License +and to the absence of any warranty; and give any other recipients of the +Program a copy of this License along with the Program. + +You may charge a fee for the physical act of transferring a copy, and you may +at your option offer warranty protection in exchange for a fee. + +2. You may modify your copy or copies of the Program or any portion of it, thus +forming a work based on the Program, and copy and distribute such modifications +or work under the terms of Section 1 above, provided that you also meet all of +these conditions: + + a) You must cause the modified files to carry prominent notices stating + that you changed the files and the date of any change. + + b) You must cause any work that you distribute or publish, that in whole or + in part contains or is derived from the Program or any part thereof, to be + licensed as a whole at no charge to all third parties under the terms of + this License. + + c) If the modified program normally reads commands interactively when run, + you must cause it, when started running for such interactive use in the + most ordinary way, to print or display an announcement including an + appropriate copyright notice and a notice that there is no warranty (or + else, saying that you provide a warranty) and that users may redistribute + the program under these conditions, and telling the user how to view a copy + of this License. (Exception: if the Program itself is interactive but does + not normally print such an announcement, your work based on the Program is + not required to print an announcement.) + +These requirements apply to the modified work as a whole. If identifiable +sections of that work are not derived from the Program, and can be reasonably +considered independent and separate works in themselves, then this License, and +its terms, do not apply to those sections when you distribute them as separate +works. But when you distribute the same sections as part of a whole which is a +work based on the Program, the distribution of the whole must be on the terms +of this License, whose permissions for other licensees extend to the entire +whole, and thus to each and every part regardless of who wrote it. + +Thus, it is not the intent of this section to claim rights or contest your +rights to work written entirely by you; rather, the intent is to exercise the +right to control the distribution of derivative or collective works based on +the Program. + +In addition, mere aggregation of another work not based on the Program with the +Program (or with a work based on the Program) on a volume of a storage or +distribution medium does not bring the other work under the scope of this +License. + +3. You may copy and distribute the Program (or a work based on it, under +Section 2) in object code or executable form under the terms of Sections 1 and +2 above provided that you also do one of the following: + + a) Accompany it with the complete corresponding machine-readable source + code, which must be distributed under the terms of Sections 1 and 2 above + on a medium customarily used for software interchange; or, + + b) Accompany it with a written offer, valid for at least three years, to + give any third party, for a charge no more than your cost of physically + performing source distribution, a complete machine-readable copy of the + corresponding source code, to be distributed under the terms of Sections 1 + and 2 above on a medium customarily used for software interchange; or, + + c) Accompany it with the information you received as to the offer to + distribute corresponding source code. (This alternative is allowed only + for noncommercial distribution and only if you received the program in + object code or executable form with such an offer, in accord with + Subsection b above.) + +The source code for a work means the preferred form of the work for making +modifications to it. For an executable work, complete source code means all +the source code for all modules it contains, plus any associated interface +definition files, plus the scripts used to control compilation and installation +of the executable. However, as a special exception, the source code +distributed need not include anything that is normally distributed (in either +source or binary form) with the major components (compiler, kernel, and so on) +of the operating system on which the executable runs, unless that component +itself accompanies the executable. + +If distribution of executable or object code is made by offering access to copy +from a designated place, then offering equivalent access to copy the source +code from the same place counts as distribution of the source code, even though +third parties are not compelled to copy the source along with the object code. + +4. You may not copy, modify, sublicense, or distribute the Program except as +expressly provided under this License. Any attempt otherwise to copy, modify, +sublicense or distribute the Program is void, and will automatically terminate +your rights under this License. However, parties who have received copies, or +rights, from you under this License will not have their licenses terminated so +long as such parties remain in full compliance. + +5. You are not required to accept this License, since you have not signed it. +However, nothing else grants you permission to modify or distribute the Program +or its derivative works. These actions are prohibited by law if you do not +accept this License. Therefore, by modifying or distributing the Program (or +any work based on the Program), you indicate your acceptance of this License to +do so, and all its terms and conditions for copying, distributing or modifying +the Program or works based on it. + +6. Each time you redistribute the Program (or any work based on the Program), +the recipient automatically receives a license from the original licensor to +copy, distribute or modify the Program subject to these terms and conditions. +You may not impose any further restrictions on the recipients' exercise of the +rights granted herein. You are not responsible for enforcing compliance by +third parties to this License. + +7. If, as a consequence of a court judgment or allegation of patent +infringement or for any other reason (not limited to patent issues), conditions +are imposed on you (whether by court order, agreement or otherwise) that +contradict the conditions of this License, they do not excuse you from the +conditions of this License. If you cannot distribute so as to satisfy +simultaneously your obligations under this License and any other pertinent +obligations, then as a consequence you may not distribute the Program at all. +For example, if a patent license would not permit royalty-free redistribution +of the Program by all those who receive copies directly or indirectly through +you, then the only way you could satisfy both it and this License would be to +refrain entirely from distribution of the Program. + +If any portion of this section is held invalid or unenforceable under any +particular circumstance, the balance of the section is intended to apply and +the section as a whole is intended to apply in other circumstances. + +It is not the purpose of this section to induce you to infringe any patents or +other property right claims or to contest validity of any such claims; this +section has the sole purpose of protecting the integrity of the free software +distribution system, which is implemented by public license practices. Many +people have made generous contributions to the wide range of software +distributed through that system in reliance on consistent application of that +system; it is up to the author/donor to decide if he or she is willing to +distribute software through any other system and a licensee cannot impose that +choice. + +This section is intended to make thoroughly clear what is believed to be a +consequence of the rest of this License. + +8. If the distribution and/or use of the Program is restricted in certain +countries either by patents or by copyrighted interfaces, the original +copyright holder who places the Program under this License may add an explicit +geographical distribution limitation excluding those countries, so that +distribution is permitted only in or among countries not thus excluded. In +such case, this License incorporates the limitation as if written in the body +of this License. + +9. The Free Software Foundation may publish revised and/or new versions of the +General Public License from time to time. Such new versions will be similar in +spirit to the present version, but may differ in detail to address new problems +or concerns. + +Each version is given a distinguishing version number. If the Program +specifies a version number of this License which applies to it and "any later +version", you have the option of following the terms and conditions either of +that version or of any later version published by the Free Software Foundation. +If the Program does not specify a version number of this License, you may +choose any version ever published by the Free Software Foundation. + +10. If you wish to incorporate parts of the Program into other free programs +whose distribution conditions are different, write to the author to ask for +permission. For software which is copyrighted by the Free Software Foundation, +write to the Free Software Foundation; we sometimes make exceptions for this. +Our decision will be guided by the two goals of preserving the free status of +all derivatives of our free software and of promoting the sharing and reuse of +software generally. + +NO WARRANTY + +11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY FOR +THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN OTHERWISE +STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES PROVIDE THE +PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED OR IMPLIED, +INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND +FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND +PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE PROGRAM PROVE DEFECTIVE, +YOU ASSUME THE COST OF ALL NECESSARY SERVICING, REPAIR OR CORRECTION. + +12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING WILL +ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR REDISTRIBUTE THE +PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY +GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE USE OR +INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED TO LOSS OF DATA OR DATA +BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD PARTIES OR A +FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER PROGRAMS), EVEN IF SUCH HOLDER +OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGES. + +END OF TERMS AND CONDITIONS + +How to Apply These Terms to Your New Programs + +If you develop a new program, and you want it to be of the greatest possible +use to the public, the best way to achieve this is to make it free software +which everyone can redistribute and change under these terms. + +To do so, attach the following notices to the program. It is safest to attach +them to the start of each source file to most effectively convey the exclusion +of warranty; and each file should have at least the "copyright" line and a +pointer to where the full notice is found. + + One line to give the program's name and a brief idea of what it does. + + Copyright (C) + + This program is free software; you can redistribute it and/or modify it + under the terms of the GNU General Public License as published by the Free + Software Foundation; either version 2 of the License, or (at your option) + any later version. + + This program is distributed in the hope that it will be useful, but WITHOUT + ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + more details. + + You should have received a copy of the GNU General Public License along + with this program; if not, write to the Free Software Foundation, Inc., 59 + Temple Place, Suite 330, Boston, MA 02111-1307 USA + +Also add information on how to contact you by electronic and paper mail. + +If the program is interactive, make it output a short notice like this when it +starts in an interactive mode: + + Gnomovision version 69, Copyright (C) year name of author Gnomovision comes + with ABSOLUTELY NO WARRANTY; for details type 'show w'. This is free + software, and you are welcome to redistribute it under certain conditions; + type 'show c' for details. + +The hypothetical commands 'show w' and 'show c' should show the appropriate +parts of the General Public License. Of course, the commands you use may be +called something other than 'show w' and 'show c'; they could even be +mouse-clicks or menu items--whatever suits your program. + +You should also get your employer (if you work as a programmer) or your school, +if any, to sign a "copyright disclaimer" for the program, if necessary. Here +is a sample; alter the names: + + Yoyodyne, Inc., hereby disclaims all copyright interest in the program + 'Gnomovision' (which makes passes at compilers) written by James Hacker. + + signature of Ty Coon, 1 April 1989 + + Ty Coon, President of Vice + +This General Public License does not permit incorporating your program into +proprietary programs. If your program is a subroutine library, you may +consider it more useful to permit linking proprietary applications with the +library. If this is what you want to do, use the GNU Library General Public +License instead of this License. + +"CLASSPATH" EXCEPTION TO THE GPL + +Certain source files distributed by Oracle America and/or its affiliates are +subject to the following clarification and special exception to the GPL, but +only where Oracle has expressly included in the particular source file's header +the words "Oracle designates this particular file as subject to the "Classpath" +exception as provided by Oracle in the LICENSE file that accompanied this code." + + Linking this library statically or dynamically with other modules is making + a combined work based on this library. Thus, the terms and conditions of + the GNU General Public License cover the whole combination. + + As a special exception, the copyright holders of this library give you + permission to link this library with independent modules to produce an + executable, regardless of the license terms of these independent modules, + and to copy and distribute the resulting executable under terms of your + choice, provided that you also meet, for each linked independent module, + the terms and conditions of the license of that module. An independent + module is a module which is not derived from or based on this library. If + you modify this library, you may extend this exception to your version of + the library, but you are not obligated to do so. If you do not wish to do + so, delete this exception statement from your version. + +The full text of the zlib licence: + +Copyright (C) 1995-2013 Jean-loup Gailly and Mark Adler + +This software is provided 'as-is', without any express or implied +warranty. In no event will the authors be held liable for any damages +arising from the use of this software. + +Permission is granted to anyone to use this software for any purpose, +including commercial applications, and to alter it and redistribute it +freely, subject to the following restrictions: + +1. The origin of this software must not be misrepresented; you must not + claim that you wrote the original software. If you use this software + in a product, an acknowledgment in the product documentation would be + appreciated but is not required. +2. Altered source versions must be plainly marked as such, and must not be + misrepresented as being the original software. +3. This notice may not be removed or altered from any source distribution. + +Jean-loup Gailly Mark Adler +jloup@gzip.org madler@alumni.caltech.edu diff --git a/tools/dependencies-report/src/main/resources/notices/rumbster-1.1.0-NOTICE.txt b/tools/dependencies-report/src/main/resources/notices/jruby-jms-NOTICE.txt similarity index 87% rename from tools/dependencies-report/src/main/resources/notices/rumbster-1.1.0-NOTICE.txt rename to tools/dependencies-report/src/main/resources/notices/jruby-jms-NOTICE.txt index 0aed17823..91166f048 100644 --- a/tools/dependencies-report/src/main/resources/notices/rumbster-1.1.0-NOTICE.txt +++ b/tools/dependencies-report/src/main/resources/notices/jruby-jms-NOTICE.txt @@ -1,4 +1,4 @@ -Copyright (c) 2011 Adam Esterline. See LICENSE.txt for further details. +Copyright 2008, 2009, 2010, 2011 J. Reid Morrison, Inc. Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. diff --git a/tools/dependencies-report/src/main/resources/notices/jruby-openssl-0.10.1-NOTICE.txt b/tools/dependencies-report/src/main/resources/notices/jruby-openssl-NOTICE.txt similarity index 100% rename from tools/dependencies-report/src/main/resources/notices/jruby-openssl-0.10.1-NOTICE.txt rename to tools/dependencies-report/src/main/resources/notices/jruby-openssl-NOTICE.txt diff --git a/tools/dependencies-report/src/main/resources/notices/jruby-readline-NOTICE.txt b/tools/dependencies-report/src/main/resources/notices/jruby-readline-NOTICE.txt deleted file mode 100644 index 97f4b8df7..000000000 --- a/tools/dependencies-report/src/main/resources/notices/jruby-readline-NOTICE.txt +++ /dev/null @@ -1,32 +0,0 @@ -source: https://github.com/jruby/jruby-readline/blob/1.2.2/License.txt - -JRuby-OpenSSL is distributed under the same license as JRuby (http://www.jruby.org/). - -Version: EPL 1.0/GPL 2.0/LGPL 2.1 - -The contents of this file are subject to the Common Public -License Version 1.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.eclipse.org/legal/cpl-v10.html - -Software distributed under the License is distributed on an "AS -IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or -implied. See the License for the specific language governing -rights and limitations under the License. - -Copyright (C) 2007 Ola Bini - -Alternatively, the contents of this file may be used under the terms of -either of the GNU General Public License Version 2 or later (the "GPL"), -or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), -in which case the provisions of the GPL or the LGPL are applicable instead -of those above. If you wish to allow use of your version of this file only -under the terms of either the GPL or the LGPL, and not to allow others to -use your version of this file under the terms of the EPL, indicate your -decision by deleting the provisions above and replace them with the notice -and other provisions required by the GPL or the LGPL. If you do not delete -the provisions above, a recipient may use your version of this file under -the terms of any one of the EPL, the GPL or the LGPL. - -JRuby-OpenSSL includes software by the Legion of the Bouncy Castle -(http://bouncycastle.org/license.html). \ No newline at end of file diff --git a/tools/dependencies-report/src/main/resources/notices/jruby-stdin-channel-0.2.0-NOTICE.txt b/tools/dependencies-report/src/main/resources/notices/jruby-stdin-channel-NOTICE.txt similarity index 100% rename from tools/dependencies-report/src/main/resources/notices/jruby-stdin-channel-0.2.0-NOTICE.txt rename to tools/dependencies-report/src/main/resources/notices/jruby-stdin-channel-NOTICE.txt diff --git a/tools/dependencies-report/src/main/resources/notices/json-1.8.6-NOTICE.txt b/tools/dependencies-report/src/main/resources/notices/json-1.8.6-NOTICE.txt deleted file mode 100644 index b1e8df126..000000000 --- a/tools/dependencies-report/src/main/resources/notices/json-1.8.6-NOTICE.txt +++ /dev/null @@ -1,3 +0,0 @@ -source: https://github.com/flori/json/blob/v1.8.6/README.md#license - -Ruby License, see https://www.ruby-lang.org/en/about/license.txt. \ No newline at end of file diff --git a/tools/dependencies-report/src/main/resources/notices/json-generator-NOTICE.txt b/tools/dependencies-report/src/main/resources/notices/json-NOTICE.txt similarity index 100% rename from tools/dependencies-report/src/main/resources/notices/json-generator-NOTICE.txt rename to tools/dependencies-report/src/main/resources/notices/json-NOTICE.txt diff --git a/tools/dependencies-report/src/main/resources/notices/jzlib-NOTICE.txt b/tools/dependencies-report/src/main/resources/notices/jzlib-NOTICE.txt deleted file mode 100644 index ce8a1dee7..000000000 --- a/tools/dependencies-report/src/main/resources/notices/jzlib-NOTICE.txt +++ /dev/null @@ -1,27 +0,0 @@ -source: https://github.com/ymnk/jzlib/blob/1.1.3/LICENSE.txt#L5-L29 - -Copyright (c) 2000-2011 ymnk, JCraft,Inc. All rights reserved. - -Redistribution and use in source and binary forms, with or without -modification, are permitted provided that the following conditions are met: - - 1. Redistributions of source code must retain the above copyright notice, - this list of conditions and the following disclaimer. - - 2. Redistributions in binary form must reproduce the above copyright - notice, this list of conditions and the following disclaimer in - the documentation and/or other materials provided with the distribution. - - 3. The names of the authors may not be used to endorse or promote products - derived from this software without specific prior written permission. - -THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED WARRANTIES, -INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND -FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL JCRAFT, -INC. OR ANY CONTRIBUTORS TO THIS SOFTWARE BE LIABLE FOR ANY DIRECT, INDIRECT, -INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT -LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, -OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF -LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING -NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, -EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. \ No newline at end of file diff --git a/tools/dependencies-report/src/main/resources/notices/lru_redux-1.1.0-NOTICE.txt b/tools/dependencies-report/src/main/resources/notices/lru_redux-NOTICE.txt similarity index 100% rename from tools/dependencies-report/src/main/resources/notices/lru_redux-1.1.0-NOTICE.txt rename to tools/dependencies-report/src/main/resources/notices/lru_redux-NOTICE.txt diff --git a/tools/dependencies-report/src/main/resources/notices/mail-2.6.6-NOTICE.txt b/tools/dependencies-report/src/main/resources/notices/mail-NOTICE.txt similarity index 100% rename from tools/dependencies-report/src/main/resources/notices/mail-2.6.6-NOTICE.txt rename to tools/dependencies-report/src/main/resources/notices/mail-NOTICE.txt diff --git a/tools/dependencies-report/src/main/resources/notices/manticore-0.6.4-NOTICE.txt b/tools/dependencies-report/src/main/resources/notices/manticore-NOTICE.txt similarity index 100% rename from tools/dependencies-report/src/main/resources/notices/manticore-0.6.4-NOTICE.txt rename to tools/dependencies-report/src/main/resources/notices/manticore-NOTICE.txt diff --git a/tools/dependencies-report/src/main/resources/notices/march_hare-3.1.1-NOTICE.txt b/tools/dependencies-report/src/main/resources/notices/march_hare-NOTICE.txt similarity index 100% rename from tools/dependencies-report/src/main/resources/notices/march_hare-3.1.1-NOTICE.txt rename to tools/dependencies-report/src/main/resources/notices/march_hare-NOTICE.txt diff --git a/tools/dependencies-report/src/main/resources/notices/memoizable-0.4.2-NOTICE.txt b/tools/dependencies-report/src/main/resources/notices/memoizable-NOTICE.txt similarity index 100% rename from tools/dependencies-report/src/main/resources/notices/memoizable-0.4.2-NOTICE.txt rename to tools/dependencies-report/src/main/resources/notices/memoizable-NOTICE.txt diff --git a/tools/dependencies-report/src/main/resources/notices/method_source-0.8.2-NOTICE.txt b/tools/dependencies-report/src/main/resources/notices/method_source-NOTICE.txt similarity index 100% rename from tools/dependencies-report/src/main/resources/notices/method_source-0.8.2-NOTICE.txt rename to tools/dependencies-report/src/main/resources/notices/method_source-NOTICE.txt diff --git a/tools/dependencies-report/src/main/resources/notices/metriks-0.9.9.8-NOTICE.txt b/tools/dependencies-report/src/main/resources/notices/metriks-NOTICE.txt similarity index 100% rename from tools/dependencies-report/src/main/resources/notices/metriks-0.9.9.8-NOTICE.txt rename to tools/dependencies-report/src/main/resources/notices/metriks-NOTICE.txt diff --git a/tools/dependencies-report/src/main/resources/notices/mime-types-2.6.2-NOTICE.txt b/tools/dependencies-report/src/main/resources/notices/mime-types-NOTICE.txt similarity index 100% rename from tools/dependencies-report/src/main/resources/notices/mime-types-2.6.2-NOTICE.txt rename to tools/dependencies-report/src/main/resources/notices/mime-types-NOTICE.txt diff --git a/tools/dependencies-report/src/main/resources/notices/minitar-0.6.1-NOTICE.txt b/tools/dependencies-report/src/main/resources/notices/minitar-NOTICE.txt similarity index 100% rename from tools/dependencies-report/src/main/resources/notices/minitar-0.6.1-NOTICE.txt rename to tools/dependencies-report/src/main/resources/notices/minitar-NOTICE.txt diff --git a/tools/dependencies-report/src/main/resources/notices/msgpack-1.2.4-NOTICE.txt b/tools/dependencies-report/src/main/resources/notices/msgpack-NOTICE.txt similarity index 100% rename from tools/dependencies-report/src/main/resources/notices/msgpack-1.2.4-NOTICE.txt rename to tools/dependencies-report/src/main/resources/notices/msgpack-NOTICE.txt diff --git a/tools/dependencies-report/src/main/resources/notices/multi_json-1.13.1-NOTICE.txt b/tools/dependencies-report/src/main/resources/notices/multi_json-NOTICE.txt similarity index 100% rename from tools/dependencies-report/src/main/resources/notices/multi_json-1.13.1-NOTICE.txt rename to tools/dependencies-report/src/main/resources/notices/multi_json-NOTICE.txt diff --git a/tools/dependencies-report/src/main/resources/notices/multipart-post-2.0.0-NOTICE.txt b/tools/dependencies-report/src/main/resources/notices/multipart-post-NOTICE.txt similarity index 100% rename from tools/dependencies-report/src/main/resources/notices/multipart-post-2.0.0-NOTICE.txt rename to tools/dependencies-report/src/main/resources/notices/multipart-post-NOTICE.txt diff --git a/tools/dependencies-report/src/main/resources/notices/murmurhash3-0.1.6-NOTICE.txt b/tools/dependencies-report/src/main/resources/notices/murmurhash3-NOTICE.txt similarity index 100% rename from tools/dependencies-report/src/main/resources/notices/murmurhash3-0.1.6-NOTICE.txt rename to tools/dependencies-report/src/main/resources/notices/murmurhash3-NOTICE.txt diff --git a/tools/dependencies-report/src/main/resources/notices/mustache-0.99.8-NOTICE.txt b/tools/dependencies-report/src/main/resources/notices/mustache-NOTICE.txt similarity index 100% rename from tools/dependencies-report/src/main/resources/notices/mustache-0.99.8-NOTICE.txt rename to tools/dependencies-report/src/main/resources/notices/mustache-NOTICE.txt diff --git a/tools/dependencies-report/src/main/resources/notices/rspec-3.7.0-NOTICE.txt b/tools/dependencies-report/src/main/resources/notices/mustermann-NOTICE.txt similarity index 76% rename from tools/dependencies-report/src/main/resources/notices/rspec-3.7.0-NOTICE.txt rename to tools/dependencies-report/src/main/resources/notices/mustermann-NOTICE.txt index ef0df45a0..bc53b031f 100644 --- a/tools/dependencies-report/src/main/resources/notices/rspec-3.7.0-NOTICE.txt +++ b/tools/dependencies-report/src/main/resources/notices/mustermann-NOTICE.txt @@ -1,10 +1,9 @@ -Copyright © 2009 Chad Humphries, David Chelimsky -Copyright © 2006 David Chelimsky, The RSpec Development Team -Copyright © 2005 Steven Baker +Copyright (c) 2013-2017 Konstantin Haase +Copyright (c) 2016-2017 Zachary Scott Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation -files (the “Software”), to deal in the Software without +files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the @@ -14,7 +13,7 @@ conditions: The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. -THE SOFTWARE IS PROVIDED “AS IS”, WITHOUT WARRANTY OF ANY KIND, +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT diff --git a/tools/dependencies-report/src/main/resources/notices/nailgun-NOTICE.txt b/tools/dependencies-report/src/main/resources/notices/nailgun-NOTICE.txt deleted file mode 100644 index 84d3b7235..000000000 --- a/tools/dependencies-report/src/main/resources/notices/nailgun-NOTICE.txt +++ /dev/null @@ -1,5 +0,0 @@ -source: https://github.com/facebook/nailgun/blob/nailgun-all-0.9.3/LICENSE.txt - -Nailgun Copyright © 2004-2012, Martian Software, Inc. - -Apache License \ No newline at end of file diff --git a/tools/dependencies-report/src/main/resources/notices/naught-1.1.0-NOTICE.txt b/tools/dependencies-report/src/main/resources/notices/naught-NOTICE.txt similarity index 100% rename from tools/dependencies-report/src/main/resources/notices/naught-1.1.0-NOTICE.txt rename to tools/dependencies-report/src/main/resources/notices/naught-NOTICE.txt diff --git a/tools/dependencies-report/src/main/resources/notices/bouncycastle-NOTICE.txt b/tools/dependencies-report/src/main/resources/notices/nio4r-NOTICE.txt similarity index 89% rename from tools/dependencies-report/src/main/resources/notices/bouncycastle-NOTICE.txt rename to tools/dependencies-report/src/main/resources/notices/nio4r-NOTICE.txt index c445a93a0..ce4682240 100644 --- a/tools/dependencies-report/src/main/resources/notices/bouncycastle-NOTICE.txt +++ b/tools/dependencies-report/src/main/resources/notices/nio4r-NOTICE.txt @@ -1,7 +1,10 @@ -Copyright (c) 2000 - 2018 The Legion of the Bouncy Castle Inc. (https://www.bouncycastle.org) +Released under the MIT license. + +Copyright, 2019, by Tony Arcieri. +Copyright, 2019, by Samuel G. D. Williams. Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. \ No newline at end of file +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. diff --git a/tools/dependencies-report/src/main/resources/notices/nokogiri-1.8.4-NOTICE.txt b/tools/dependencies-report/src/main/resources/notices/nokogiri-NOTICE.txt similarity index 100% rename from tools/dependencies-report/src/main/resources/notices/nokogiri-1.8.4-NOTICE.txt rename to tools/dependencies-report/src/main/resources/notices/nokogiri-NOTICE.txt diff --git a/tools/dependencies-report/src/main/resources/notices/numerizer-0.1.1-NOTICE.txt b/tools/dependencies-report/src/main/resources/notices/numerizer-NOTICE.txt similarity index 100% rename from tools/dependencies-report/src/main/resources/notices/numerizer-0.1.1-NOTICE.txt rename to tools/dependencies-report/src/main/resources/notices/numerizer-NOTICE.txt diff --git a/tools/dependencies-report/src/main/resources/notices/openssl_pkcs8_pure-0.0.0.2-NOTICE.txt b/tools/dependencies-report/src/main/resources/notices/openssl_pkcs8_pure-NOTICE.txt similarity index 100% rename from tools/dependencies-report/src/main/resources/notices/openssl_pkcs8_pure-0.0.0.2-NOTICE.txt rename to tools/dependencies-report/src/main/resources/notices/openssl_pkcs8_pure-NOTICE.txt diff --git a/tools/dependencies-report/src/main/resources/notices/org.apache.logging.log4j!log4j-api-2.9.1-NOTICE.txt b/tools/dependencies-report/src/main/resources/notices/org.apache.logging.log4j!log4j-api-NOTICE.txt similarity index 100% rename from tools/dependencies-report/src/main/resources/notices/org.apache.logging.log4j!log4j-api-2.9.1-NOTICE.txt rename to tools/dependencies-report/src/main/resources/notices/org.apache.logging.log4j!log4j-api-NOTICE.txt diff --git a/tools/dependencies-report/src/main/resources/notices/org.apache.logging.log4j!log4j-core-2.9.1-NOTICE.txt b/tools/dependencies-report/src/main/resources/notices/org.apache.logging.log4j!log4j-core-NOTICE.txt similarity index 100% rename from tools/dependencies-report/src/main/resources/notices/org.apache.logging.log4j!log4j-core-2.9.1-NOTICE.txt rename to tools/dependencies-report/src/main/resources/notices/org.apache.logging.log4j!log4j-core-NOTICE.txt diff --git a/tools/dependencies-report/src/main/resources/notices/org.apache.logging.log4j!log4j-slf4j-impl-2.9.1-NOTICE.txt b/tools/dependencies-report/src/main/resources/notices/org.apache.logging.log4j!log4j-slf4j-impl-NOTICE.txt similarity index 100% rename from tools/dependencies-report/src/main/resources/notices/org.apache.logging.log4j!log4j-slf4j-impl-2.9.1-NOTICE.txt rename to tools/dependencies-report/src/main/resources/notices/org.apache.logging.log4j!log4j-slf4j-impl-NOTICE.txt diff --git a/tools/dependencies-report/src/main/resources/notices/org.codehaus.janino!commons-compiler-3.0.8-NOTICE.txt b/tools/dependencies-report/src/main/resources/notices/org.codehaus.janino!commons-compiler-NOTICE.txt similarity index 100% rename from tools/dependencies-report/src/main/resources/notices/org.codehaus.janino!commons-compiler-3.0.8-NOTICE.txt rename to tools/dependencies-report/src/main/resources/notices/org.codehaus.janino!commons-compiler-NOTICE.txt diff --git a/tools/dependencies-report/src/main/resources/notices/org.codehaus.janino!janino-3.0.8-NOTICE.txt b/tools/dependencies-report/src/main/resources/notices/org.codehaus.janino!janino-NOTICE.txt similarity index 100% rename from tools/dependencies-report/src/main/resources/notices/org.codehaus.janino!janino-3.0.8-NOTICE.txt rename to tools/dependencies-report/src/main/resources/notices/org.codehaus.janino!janino-NOTICE.txt diff --git a/tools/dependencies-report/src/main/resources/notices/org.codehaus.mojo!animal-sniffer-annotations-1.14-NOTICE.txt b/tools/dependencies-report/src/main/resources/notices/org.codehaus.mojo!animal-sniffer-annotations-NOTICE.txt similarity index 100% rename from tools/dependencies-report/src/main/resources/notices/org.codehaus.mojo!animal-sniffer-annotations-1.14-NOTICE.txt rename to tools/dependencies-report/src/main/resources/notices/org.codehaus.mojo!animal-sniffer-annotations-NOTICE.txt diff --git a/tools/dependencies-report/src/main/resources/notices/org.eclipse.core!org.eclipse.core.commands-3.6.0-NOTICE.txt b/tools/dependencies-report/src/main/resources/notices/org.eclipse.core!org.eclipse.core.commands-NOTICE.txt similarity index 100% rename from tools/dependencies-report/src/main/resources/notices/org.eclipse.core!org.eclipse.core.commands-3.6.0-NOTICE.txt rename to tools/dependencies-report/src/main/resources/notices/org.eclipse.core!org.eclipse.core.commands-NOTICE.txt diff --git a/tools/dependencies-report/src/main/resources/notices/org.eclipse.core!org.eclipse.core.contenttype-3.4.100-NOTICE.txt b/tools/dependencies-report/src/main/resources/notices/org.eclipse.core!org.eclipse.core.contenttype-NOTICE.txt similarity index 100% rename from tools/dependencies-report/src/main/resources/notices/org.eclipse.core!org.eclipse.core.contenttype-3.4.100-NOTICE.txt rename to tools/dependencies-report/src/main/resources/notices/org.eclipse.core!org.eclipse.core.contenttype-NOTICE.txt diff --git a/tools/dependencies-report/src/main/resources/notices/org.eclipse.core!org.eclipse.core.expressions-3.4.300-NOTICE.txt b/tools/dependencies-report/src/main/resources/notices/org.eclipse.core!org.eclipse.core.expressions-NOTICE.txt similarity index 100% rename from tools/dependencies-report/src/main/resources/notices/org.eclipse.core!org.eclipse.core.expressions-3.4.300-NOTICE.txt rename to tools/dependencies-report/src/main/resources/notices/org.eclipse.core!org.eclipse.core.expressions-NOTICE.txt diff --git a/tools/dependencies-report/src/main/resources/notices/org.eclipse.core!org.eclipse.core.filesystem-1.3.100-NOTICE.txt b/tools/dependencies-report/src/main/resources/notices/org.eclipse.core!org.eclipse.core.filesystem-NOTICE.txt similarity index 100% rename from tools/dependencies-report/src/main/resources/notices/org.eclipse.core!org.eclipse.core.filesystem-1.3.100-NOTICE.txt rename to tools/dependencies-report/src/main/resources/notices/org.eclipse.core!org.eclipse.core.filesystem-NOTICE.txt diff --git a/tools/dependencies-report/src/main/resources/notices/org.eclipse.core!org.eclipse.core.jobs-3.5.100-NOTICE.txt b/tools/dependencies-report/src/main/resources/notices/org.eclipse.core!org.eclipse.core.jobs-NOTICE.txt similarity index 100% rename from tools/dependencies-report/src/main/resources/notices/org.eclipse.core!org.eclipse.core.jobs-3.5.100-NOTICE.txt rename to tools/dependencies-report/src/main/resources/notices/org.eclipse.core!org.eclipse.core.jobs-NOTICE.txt diff --git a/tools/dependencies-report/src/main/resources/notices/org.eclipse.core!org.eclipse.core.resources-3.7.100-NOTICE.txt b/tools/dependencies-report/src/main/resources/notices/org.eclipse.core!org.eclipse.core.resources-NOTICE.txt similarity index 100% rename from tools/dependencies-report/src/main/resources/notices/org.eclipse.core!org.eclipse.core.resources-3.7.100-NOTICE.txt rename to tools/dependencies-report/src/main/resources/notices/org.eclipse.core!org.eclipse.core.resources-NOTICE.txt diff --git a/tools/dependencies-report/src/main/resources/notices/org.eclipse.core!org.eclipse.core.runtime-3.7.0-NOTICE.txt b/tools/dependencies-report/src/main/resources/notices/org.eclipse.core!org.eclipse.core.runtime-NOTICE.txt similarity index 100% rename from tools/dependencies-report/src/main/resources/notices/org.eclipse.core!org.eclipse.core.runtime-3.7.0-NOTICE.txt rename to tools/dependencies-report/src/main/resources/notices/org.eclipse.core!org.eclipse.core.runtime-NOTICE.txt diff --git a/tools/dependencies-report/src/main/resources/notices/org.eclipse.equinox!org.eclipse.equinox.app-1.3.100-NOTICE.txt b/tools/dependencies-report/src/main/resources/notices/org.eclipse.equinox!org.eclipse.equinox.app-NOTICE.txt similarity index 100% rename from tools/dependencies-report/src/main/resources/notices/org.eclipse.equinox!org.eclipse.equinox.app-1.3.100-NOTICE.txt rename to tools/dependencies-report/src/main/resources/notices/org.eclipse.equinox!org.eclipse.equinox.app-NOTICE.txt diff --git a/tools/dependencies-report/src/main/resources/notices/org.eclipse.equinox!org.eclipse.equinox.common-3.6.0-NOTICE.txt b/tools/dependencies-report/src/main/resources/notices/org.eclipse.equinox!org.eclipse.equinox.common-NOTICE.txt similarity index 100% rename from tools/dependencies-report/src/main/resources/notices/org.eclipse.equinox!org.eclipse.equinox.common-3.6.0-NOTICE.txt rename to tools/dependencies-report/src/main/resources/notices/org.eclipse.equinox!org.eclipse.equinox.common-NOTICE.txt diff --git a/tools/dependencies-report/src/main/resources/notices/org.eclipse.equinox!org.eclipse.equinox.preferences-3.4.1-NOTICE.txt b/tools/dependencies-report/src/main/resources/notices/org.eclipse.equinox!org.eclipse.equinox.preferences-NOTICE.txt similarity index 100% rename from tools/dependencies-report/src/main/resources/notices/org.eclipse.equinox!org.eclipse.equinox.preferences-3.4.1-NOTICE.txt rename to tools/dependencies-report/src/main/resources/notices/org.eclipse.equinox!org.eclipse.equinox.preferences-NOTICE.txt diff --git a/tools/dependencies-report/src/main/resources/notices/org.eclipse.equinox!org.eclipse.equinox.registry-3.5.101-NOTICE.txt b/tools/dependencies-report/src/main/resources/notices/org.eclipse.equinox!org.eclipse.equinox.registry-NOTICE.txt similarity index 100% rename from tools/dependencies-report/src/main/resources/notices/org.eclipse.equinox!org.eclipse.equinox.registry-3.5.101-NOTICE.txt rename to tools/dependencies-report/src/main/resources/notices/org.eclipse.equinox!org.eclipse.equinox.registry-NOTICE.txt diff --git a/tools/dependencies-report/src/main/resources/notices/org.eclipse.jdt!org.eclipse.jdt.core-3.10.0-NOTICE.txt b/tools/dependencies-report/src/main/resources/notices/org.eclipse.jdt!org.eclipse.jdt.core-NOTICE.txt similarity index 100% rename from tools/dependencies-report/src/main/resources/notices/org.eclipse.jdt!org.eclipse.jdt.core-3.10.0-NOTICE.txt rename to tools/dependencies-report/src/main/resources/notices/org.eclipse.jdt!org.eclipse.jdt.core-NOTICE.txt diff --git a/tools/dependencies-report/src/main/resources/notices/org.eclipse.osgi!org.eclipse.osgi-3.7.1-NOTICE.txt b/tools/dependencies-report/src/main/resources/notices/org.eclipse.osgi!org.eclipse.osgi-NOTICE.txt similarity index 100% rename from tools/dependencies-report/src/main/resources/notices/org.eclipse.osgi!org.eclipse.osgi-3.7.1-NOTICE.txt rename to tools/dependencies-report/src/main/resources/notices/org.eclipse.osgi!org.eclipse.osgi-NOTICE.txt diff --git a/tools/dependencies-report/src/main/resources/notices/org.eclipse.text!org.eclipse.text-3.5.101-NOTICE.txt b/tools/dependencies-report/src/main/resources/notices/org.eclipse.text!org.eclipse.text-NOTICE.txt similarity index 100% rename from tools/dependencies-report/src/main/resources/notices/org.eclipse.text!org.eclipse.text-3.5.101-NOTICE.txt rename to tools/dependencies-report/src/main/resources/notices/org.eclipse.text!org.eclipse.text-NOTICE.txt diff --git a/tools/dependencies-report/src/main/resources/notices/org.javassist!javassist-NOTICE.txt b/tools/dependencies-report/src/main/resources/notices/org.javassist!javassist-NOTICE.txt new file mode 100644 index 000000000..d73ba6b9e --- /dev/null +++ b/tools/dependencies-report/src/main/resources/notices/org.javassist!javassist-NOTICE.txt @@ -0,0 +1,3 @@ +Copyright (C) 1999-2019 by Shigeru Chiba, All rights reserved. + +This software is distributed under the Mozilla Public License Version 1.1, the GNU Lesser General Public License Version 2.1 or later, or the Apache License Version 2.0. diff --git a/tools/dependencies-report/src/main/resources/notices/org.jruby!jruby-complete-9.1.13.0-NOTICE.txt b/tools/dependencies-report/src/main/resources/notices/org.jruby!jruby-complete-NOTICE.txt similarity index 100% rename from tools/dependencies-report/src/main/resources/notices/org.jruby!jruby-complete-9.1.13.0-NOTICE.txt rename to tools/dependencies-report/src/main/resources/notices/org.jruby!jruby-complete-NOTICE.txt diff --git a/tools/dependencies-report/src/main/resources/notices/org.reflections!reflections-NOTICE.txt b/tools/dependencies-report/src/main/resources/notices/org.reflections!reflections-NOTICE.txt new file mode 100644 index 000000000..77f62ea0f --- /dev/null +++ b/tools/dependencies-report/src/main/resources/notices/org.reflections!reflections-NOTICE.txt @@ -0,0 +1,15 @@ + DO WHAT THE FUCK YOU WANT TO PUBLIC LICENSE + Version 2, December 2004 + + Copyright (C) 2004 Sam Hocevar + + Everyone is permitted to copy and distribute verbatim or modified + copies of this license document, and changing it is allowed as long + as the name is changed. + + DO WHAT THE FUCK YOU WANT TO PUBLIC LICENSE + TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION + + 0. You just DO WHAT THE FUCK YOU WANT TO. + +Also licensed under BSD-2-Clause according to https://github.com/ronmamo/reflections/blob/0.9.11/pom.xml#L20-L22 diff --git a/tools/dependencies-report/src/main/resources/notices/org.slf4j!slf4j-api-1.7.25-NOTICE.txt b/tools/dependencies-report/src/main/resources/notices/org.slf4j!slf4j-api-NOTICE.txt similarity index 100% rename from tools/dependencies-report/src/main/resources/notices/org.slf4j!slf4j-api-1.7.25-NOTICE.txt rename to tools/dependencies-report/src/main/resources/notices/org.slf4j!slf4j-api-NOTICE.txt diff --git a/tools/dependencies-report/src/main/resources/notices/paquet-0.2.1-NOTICE.txt b/tools/dependencies-report/src/main/resources/notices/paquet-NOTICE.txt similarity index 100% rename from tools/dependencies-report/src/main/resources/notices/paquet-0.2.1-NOTICE.txt rename to tools/dependencies-report/src/main/resources/notices/paquet-NOTICE.txt diff --git a/tools/dependencies-report/src/main/resources/notices/pleaserun-0.0.30-NOTICE.txt b/tools/dependencies-report/src/main/resources/notices/pleaserun-NOTICE.txt similarity index 100% rename from tools/dependencies-report/src/main/resources/notices/pleaserun-0.0.30-NOTICE.txt rename to tools/dependencies-report/src/main/resources/notices/pleaserun-NOTICE.txt diff --git a/tools/dependencies-report/src/main/resources/notices/polyglot-0.3.5-NOTICE.txt b/tools/dependencies-report/src/main/resources/notices/polyglot-NOTICE.txt similarity index 100% rename from tools/dependencies-report/src/main/resources/notices/polyglot-0.3.5-NOTICE.txt rename to tools/dependencies-report/src/main/resources/notices/polyglot-NOTICE.txt diff --git a/tools/dependencies-report/src/main/resources/notices/poseidon-0.0.5-NOTICE.txt b/tools/dependencies-report/src/main/resources/notices/poseidon-0.0.5-NOTICE.txt deleted file mode 100644 index 391c8de27..000000000 --- a/tools/dependencies-report/src/main/resources/notices/poseidon-0.0.5-NOTICE.txt +++ /dev/null @@ -1,22 +0,0 @@ -Copyright (c) 2013 Bob Potter - -MIT License - -Permission is hereby granted, free of charge, to any person obtaining -a copy of this software and associated documentation files (the -"Software"), to deal in the Software without restriction, including -without limitation the rights to use, copy, modify, merge, publish, -distribute, sublicense, and/or sell copies of the Software, and to -permit persons to whom the Software is furnished to do so, subject to -the following conditions: - -The above copyright notice and this permission notice shall be -included in all copies or substantial portions of the Software. - -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, -EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF -MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND -NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE -LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION -OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION -WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. \ No newline at end of file diff --git a/tools/dependencies-report/src/main/resources/notices/prototype.js-NOTICE.txt b/tools/dependencies-report/src/main/resources/notices/prototype.js-NOTICE.txt deleted file mode 100644 index 30404ce4c..000000000 --- a/tools/dependencies-report/src/main/resources/notices/prototype.js-NOTICE.txt +++ /dev/null @@ -1 +0,0 @@ -TODO \ No newline at end of file diff --git a/tools/dependencies-report/src/main/resources/notices/pry-0.10.4-NOTICE.txt b/tools/dependencies-report/src/main/resources/notices/pry-NOTICE.txt similarity index 100% rename from tools/dependencies-report/src/main/resources/notices/pry-0.10.4-NOTICE.txt rename to tools/dependencies-report/src/main/resources/notices/pry-NOTICE.txt diff --git a/tools/dependencies-report/src/main/resources/notices/psych-2.2.4-NOTICE.txt b/tools/dependencies-report/src/main/resources/notices/psych-2.2.4-NOTICE.txt deleted file mode 100644 index 6055da4db..000000000 --- a/tools/dependencies-report/src/main/resources/notices/psych-2.2.4-NOTICE.txt +++ /dev/null @@ -1,7 +0,0 @@ -Copyright 2009 Aaron Patterson, et al. - -Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the 'Software'), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: - -The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. - -THE SOFTWARE IS PROVIDED 'AS IS', WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. \ No newline at end of file diff --git a/tools/dependencies-report/src/main/resources/notices/public_suffix-1.4.6-NOTICE.txt b/tools/dependencies-report/src/main/resources/notices/public_suffix-NOTICE.txt similarity index 100% rename from tools/dependencies-report/src/main/resources/notices/public_suffix-1.4.6-NOTICE.txt rename to tools/dependencies-report/src/main/resources/notices/public_suffix-NOTICE.txt diff --git a/tools/dependencies-report/src/main/resources/notices/puma-2.16.0-NOTICE.txt b/tools/dependencies-report/src/main/resources/notices/puma-NOTICE.txt similarity index 100% rename from tools/dependencies-report/src/main/resources/notices/puma-2.16.0-NOTICE.txt rename to tools/dependencies-report/src/main/resources/notices/puma-NOTICE.txt diff --git a/tools/dependencies-report/src/main/resources/notices/racc-NOTICE.txt b/tools/dependencies-report/src/main/resources/notices/racc-NOTICE.txt deleted file mode 100644 index d7d4db9e8..000000000 --- a/tools/dependencies-report/src/main/resources/notices/racc-NOTICE.txt +++ /dev/null @@ -1,8 +0,0 @@ -TODO - - - -Racc is distributed under the terms of the GNU Lesser General -Public License version 2. Note that you do NOT need to follow -LGPL for your own parser (racc outputs). You can distribute those -files under any licenses you want.Racc is \ No newline at end of file diff --git a/tools/dependencies-report/src/main/resources/notices/rack-1.6.6-NOTICE.txt b/tools/dependencies-report/src/main/resources/notices/rack-NOTICE.txt similarity index 100% rename from tools/dependencies-report/src/main/resources/notices/rack-1.6.6-NOTICE.txt rename to tools/dependencies-report/src/main/resources/notices/rack-NOTICE.txt diff --git a/tools/dependencies-report/src/main/resources/notices/rack-protection-1.5.5-NOTICE.txt b/tools/dependencies-report/src/main/resources/notices/rack-protection-NOTICE.txt similarity index 100% rename from tools/dependencies-report/src/main/resources/notices/rack-protection-1.5.5-NOTICE.txt rename to tools/dependencies-report/src/main/resources/notices/rack-protection-NOTICE.txt diff --git a/tools/dependencies-report/src/main/resources/notices/rake-10.4.2-NOTICE.txt b/tools/dependencies-report/src/main/resources/notices/rake-NOTICE.txt similarity index 100% rename from tools/dependencies-report/src/main/resources/notices/rake-10.4.2-NOTICE.txt rename to tools/dependencies-report/src/main/resources/notices/rake-NOTICE.txt diff --git a/tools/dependencies-report/src/main/resources/notices/redis-3.3.5-NOTICE.txt b/tools/dependencies-report/src/main/resources/notices/redis-NOTICE.txt similarity index 100% rename from tools/dependencies-report/src/main/resources/notices/redis-3.3.5-NOTICE.txt rename to tools/dependencies-report/src/main/resources/notices/redis-NOTICE.txt diff --git a/tools/dependencies-report/src/main/resources/notices/rspec-core-3.7.1-NOTICE.txt b/tools/dependencies-report/src/main/resources/notices/rspec-core-3.7.1-NOTICE.txt deleted file mode 100644 index 76dc17d73..000000000 --- a/tools/dependencies-report/src/main/resources/notices/rspec-core-3.7.1-NOTICE.txt +++ /dev/null @@ -1,26 +0,0 @@ -The MIT License (MIT) -===================== - -* Copyright © 2012 Chad Humphries, David Chelimsky, Myron Marston -* Copyright © 2009 Chad Humphries, David Chelimsky -* Copyright © 2006 David Chelimsky, The RSpec Development Team -* Copyright © 2005 Steven Baker - -Permission is hereby granted, free of charge, to any person obtaining -a copy of this software and associated documentation files (the -"Software"), to deal in the Software without restriction, including -without limitation the rights to use, copy, modify, merge, publish, -distribute, sublicense, and/or sell copies of the Software, and to -permit persons to whom the Software is furnished to do so, subject to -the following conditions: - -The above copyright notice and this permission notice shall be -included in all copies or substantial portions of the Software. - -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, -EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF -MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. -IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY -CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, -TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE -SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. diff --git a/tools/dependencies-report/src/main/resources/notices/rspec-expectations-3.7.0-NOTICE.txt b/tools/dependencies-report/src/main/resources/notices/rspec-expectations-3.7.0-NOTICE.txt deleted file mode 100644 index dae02d8a7..000000000 --- a/tools/dependencies-report/src/main/resources/notices/rspec-expectations-3.7.0-NOTICE.txt +++ /dev/null @@ -1,25 +0,0 @@ -The MIT License (MIT) -===================== - -* Copyright © 2012 David Chelimsky, Myron Marston -* Copyright © 2006 David Chelimsky, The RSpec Development Team -* Copyright © 2005 Steven Baker - -Permission is hereby granted, free of charge, to any person obtaining -a copy of this software and associated documentation files (the -"Software"), to deal in the Software without restriction, including -without limitation the rights to use, copy, modify, merge, publish, -distribute, sublicense, and/or sell copies of the Software, and to -permit persons to whom the Software is furnished to do so, subject to -the following conditions: - -The above copyright notice and this permission notice shall be -included in all copies or substantial portions of the Software. - -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, -EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF -MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. -IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY -CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, -TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE -SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. diff --git a/tools/dependencies-report/src/main/resources/notices/rspec-mocks-3.7.0-NOTICE.txt b/tools/dependencies-report/src/main/resources/notices/rspec-mocks-3.7.0-NOTICE.txt deleted file mode 100644 index dae02d8a7..000000000 --- a/tools/dependencies-report/src/main/resources/notices/rspec-mocks-3.7.0-NOTICE.txt +++ /dev/null @@ -1,25 +0,0 @@ -The MIT License (MIT) -===================== - -* Copyright © 2012 David Chelimsky, Myron Marston -* Copyright © 2006 David Chelimsky, The RSpec Development Team -* Copyright © 2005 Steven Baker - -Permission is hereby granted, free of charge, to any person obtaining -a copy of this software and associated documentation files (the -"Software"), to deal in the Software without restriction, including -without limitation the rights to use, copy, modify, merge, publish, -distribute, sublicense, and/or sell copies of the Software, and to -permit persons to whom the Software is furnished to do so, subject to -the following conditions: - -The above copyright notice and this permission notice shall be -included in all copies or substantial portions of the Software. - -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, -EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF -MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. -IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY -CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, -TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE -SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. diff --git a/tools/dependencies-report/src/main/resources/notices/rspec-sequencing-0.1.0-NOTICE.txt b/tools/dependencies-report/src/main/resources/notices/rspec-sequencing-0.1.0-NOTICE.txt deleted file mode 100644 index 5446bebe6..000000000 --- a/tools/dependencies-report/src/main/resources/notices/rspec-sequencing-0.1.0-NOTICE.txt +++ /dev/null @@ -1,202 +0,0 @@ -Copyright (c) 2016 Elasticsearch - - Apache License - Version 2.0, January 2004 - http://www.apache.org/licenses/ - - TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION - - 1. Definitions. - - "License" shall mean the terms and conditions for use, reproduction, - and distribution as defined by Sections 1 through 9 of this document. - - "Licensor" shall mean the copyright owner or entity authorized by - the copyright owner that is granting the License. - - "Legal Entity" shall mean the union of the acting entity and all - other entities that control, are controlled by, or are under common - control with that entity. For the purposes of this definition, - "control" means (i) the power, direct or indirect, to cause the - direction or management of such entity, whether by contract or - otherwise, or (ii) ownership of fifty percent (50%) or more of the - outstanding shares, or (iii) beneficial ownership of such entity. - - "You" (or "Your") shall mean an individual or Legal Entity - exercising permissions granted by this License. - - "Source" form shall mean the preferred form for making modifications, - including but not limited to software source code, documentation - source, and configuration files. - - "Object" form shall mean any form resulting from mechanical - transformation or translation of a Source form, including but - not limited to compiled object code, generated documentation, - and conversions to other media types. - - "Work" shall mean the work of authorship, whether in Source or - Object form, made available under the License, as indicated by a - copyright notice that is included in or attached to the work - (an example is provided in the Appendix below). - - "Derivative Works" shall mean any work, whether in Source or Object - form, that is based on (or derived from) the Work and for which the - editorial revisions, annotations, elaborations, or other modifications - represent, as a whole, an original work of authorship. For the purposes - of this License, Derivative Works shall not include works that remain - separable from, or merely link (or bind by name) to the interfaces of, - the Work and Derivative Works thereof. - - "Contribution" shall mean any work of authorship, including - the original version of the Work and any modifications or additions - to that Work or Derivative Works thereof, that is intentionally - submitted to Licensor for inclusion in the Work by the copyright owner - or by an individual or Legal Entity authorized to submit on behalf of - the copyright owner. For the purposes of this definition, "submitted" - means any form of electronic, verbal, or written communication sent - to the Licensor or its representatives, including but not limited to - communication on electronic mailing lists, source code control systems, - and issue tracking systems that are managed by, or on behalf of, the - Licensor for the purpose of discussing and improving the Work, but - excluding communication that is conspicuously marked or otherwise - designated in writing by the copyright owner as "Not a Contribution." - - "Contributor" shall mean Licensor and any individual or Legal Entity - on behalf of whom a Contribution has been received by Licensor and - subsequently incorporated within the Work. - - 2. Grant of Copyright License. Subject to the terms and conditions of - this License, each Contributor hereby grants to You a perpetual, - worldwide, non-exclusive, no-charge, royalty-free, irrevocable - copyright license to reproduce, prepare Derivative Works of, - publicly display, publicly perform, sublicense, and distribute the - Work and such Derivative Works in Source or Object form. - - 3. Grant of Patent License. Subject to the terms and conditions of - this License, each Contributor hereby grants to You a perpetual, - worldwide, non-exclusive, no-charge, royalty-free, irrevocable - (except as stated in this section) patent license to make, have made, - use, offer to sell, sell, import, and otherwise transfer the Work, - where such license applies only to those patent claims licensable - by such Contributor that are necessarily infringed by their - Contribution(s) alone or by combination of their Contribution(s) - with the Work to which such Contribution(s) was submitted. If You - institute patent litigation against any entity (including a - cross-claim or counterclaim in a lawsuit) alleging that the Work - or a Contribution incorporated within the Work constitutes direct - or contributory patent infringement, then any patent licenses - granted to You under this License for that Work shall terminate - as of the date such litigation is filed. - - 4. Redistribution. You may reproduce and distribute copies of the - Work or Derivative Works thereof in any medium, with or without - modifications, and in Source or Object form, provided that You - meet the following conditions: - - (a) You must give any other recipients of the Work or - Derivative Works a copy of this License; and - - (b) You must cause any modified files to carry prominent notices - stating that You changed the files; and - - (c) You must retain, in the Source form of any Derivative Works - that You distribute, all copyright, patent, trademark, and - attribution notices from the Source form of the Work, - excluding those notices that do not pertain to any part of - the Derivative Works; and - - (d) If the Work includes a "NOTICE" text file as part of its - distribution, then any Derivative Works that You distribute must - include a readable copy of the attribution notices contained - within such NOTICE file, excluding those notices that do not - pertain to any part of the Derivative Works, in at least one - of the following places: within a NOTICE text file distributed - as part of the Derivative Works; within the Source form or - documentation, if provided along with the Derivative Works; or, - within a display generated by the Derivative Works, if and - wherever such third-party notices normally appear. The contents - of the NOTICE file are for informational purposes only and - do not modify the License. You may add Your own attribution - notices within Derivative Works that You distribute, alongside - or as an addendum to the NOTICE text from the Work, provided - that such additional attribution notices cannot be construed - as modifying the License. - - You may add Your own copyright statement to Your modifications and - may provide additional or different license terms and conditions - for use, reproduction, or distribution of Your modifications, or - for any such Derivative Works as a whole, provided Your use, - reproduction, and distribution of the Work otherwise complies with - the conditions stated in this License. - - 5. Submission of Contributions. Unless You explicitly state otherwise, - any Contribution intentionally submitted for inclusion in the Work - by You to the Licensor shall be under the terms and conditions of - this License, without any additional terms or conditions. - Notwithstanding the above, nothing herein shall supersede or modify - the terms of any separate license agreement you may have executed - with Licensor regarding such Contributions. - - 6. Trademarks. This License does not grant permission to use the trade - names, trademarks, service marks, or product names of the Licensor, - except as required for reasonable and customary use in describing the - origin of the Work and reproducing the content of the NOTICE file. - - 7. Disclaimer of Warranty. Unless required by applicable law or - agreed to in writing, Licensor provides the Work (and each - Contributor provides its Contributions) on an "AS IS" BASIS, - WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or - implied, including, without limitation, any warranties or conditions - of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A - PARTICULAR PURPOSE. You are solely responsible for determining the - appropriateness of using or redistributing the Work and assume any - risks associated with Your exercise of permissions under this License. - - 8. Limitation of Liability. In no event and under no legal theory, - whether in tort (including negligence), contract, or otherwise, - unless required by applicable law (such as deliberate and grossly - negligent acts) or agreed to in writing, shall any Contributor be - liable to You for damages, including any direct, indirect, special, - incidental, or consequential damages of any character arising as a - result of this License or out of the use or inability to use the - Work (including but not limited to damages for loss of goodwill, - work stoppage, computer failure or malfunction, or any and all - other commercial damages or losses), even if such Contributor - has been advised of the possibility of such damages. - - 9. Accepting Warranty or Additional Liability. While redistributing - the Work or Derivative Works thereof, You may choose to offer, - and charge a fee for, acceptance of support, warranty, indemnity, - or other liability obligations and/or rights consistent with this - License. However, in accepting such obligations, You may act only - on Your own behalf and on Your sole responsibility, not on behalf - of any other Contributor, and only if You agree to indemnify, - defend, and hold each Contributor harmless for any liability - incurred by, or claims asserted against, such Contributor by reason - of your accepting any such warranty or additional liability. - - END OF TERMS AND CONDITIONS - - APPENDIX: How to apply the Apache License to your work. - - To apply the Apache License to your work, attach the following - boilerplate notice, with the fields enclosed by brackets "{}" - replaced with your own identifying information. (Don't include - the brackets!) The text should be enclosed in the appropriate - comment syntax for the file format. We also recommend that a - file or class name and description of purpose be included on the - same "printed page" as the copyright notice for easier - identification within third-party archives. - - Licensed 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. - diff --git a/tools/dependencies-report/src/main/resources/notices/rspec-support-3.7.1-NOTICE.txt b/tools/dependencies-report/src/main/resources/notices/rspec-support-3.7.1-NOTICE.txt deleted file mode 100644 index 7a5252109..000000000 --- a/tools/dependencies-report/src/main/resources/notices/rspec-support-3.7.1-NOTICE.txt +++ /dev/null @@ -1,20 +0,0 @@ -* Copyright © 2013 David Chelimsky, Myron Marston, Jon Rowe, Sam Phippen, Xavier Shay, Bradley Schaefer - -Permission is hereby granted, free of charge, to any person obtaining -a copy of this software and associated documentation files (the -"Software"), to deal in the Software without restriction, including -without limitation the rights to use, copy, modify, merge, publish, -distribute, sublicense, and/or sell copies of the Software, and to -permit persons to whom the Software is furnished to do so, subject to -the following conditions: - -The above copyright notice and this permission notice shall be -included in all copies or substantial portions of the Software. - -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, -EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF -MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND -NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE -LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION -OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION -WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. diff --git a/tools/dependencies-report/src/main/resources/notices/rspec-wait-0.0.9-NOTICE.txt b/tools/dependencies-report/src/main/resources/notices/rspec-wait-0.0.9-NOTICE.txt deleted file mode 100644 index d4d42e9b7..000000000 --- a/tools/dependencies-report/src/main/resources/notices/rspec-wait-0.0.9-NOTICE.txt +++ /dev/null @@ -1,22 +0,0 @@ -Copyright (c) 2014 Steve Richert - -MIT License - -Permission is hereby granted, free of charge, to any person obtaining -a copy of this software and associated documentation files (the -"Software"), to deal in the Software without restriction, including -without limitation the rights to use, copy, modify, merge, publish, -distribute, sublicense, and/or sell copies of the Software, and to -permit persons to whom the Software is furnished to do so, subject to -the following conditions: - -The above copyright notice and this permission notice shall be -included in all copies or substantial portions of the Software. - -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, -EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF -MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND -NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE -LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION -OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION -WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. diff --git a/tools/dependencies-report/src/main/resources/notices/ruby-progressbar-1.8.3-NOTICE.txt b/tools/dependencies-report/src/main/resources/notices/ruby-progressbar-NOTICE.txt similarity index 100% rename from tools/dependencies-report/src/main/resources/notices/ruby-progressbar-1.8.3-NOTICE.txt rename to tools/dependencies-report/src/main/resources/notices/ruby-progressbar-NOTICE.txt diff --git a/tools/dependencies-report/src/main/resources/notices/rubyzip-1.2.1-NOTICE.txt b/tools/dependencies-report/src/main/resources/notices/rubyzip-NOTICE.txt similarity index 100% rename from tools/dependencies-report/src/main/resources/notices/rubyzip-1.2.1-NOTICE.txt rename to tools/dependencies-report/src/main/resources/notices/rubyzip-NOTICE.txt diff --git a/tools/dependencies-report/src/main/resources/notices/rufus-scheduler-3.0.9-NOTICE.txt b/tools/dependencies-report/src/main/resources/notices/rufus-scheduler-NOTICE.txt similarity index 100% rename from tools/dependencies-report/src/main/resources/notices/rufus-scheduler-3.0.9-NOTICE.txt rename to tools/dependencies-report/src/main/resources/notices/rufus-scheduler-NOTICE.txt diff --git a/tools/dependencies-report/src/main/resources/notices/safe_yaml-1.0.4-NOTICE.txt b/tools/dependencies-report/src/main/resources/notices/safe_yaml-1.0.4-NOTICE.txt deleted file mode 100644 index 4b276dd15..000000000 --- a/tools/dependencies-report/src/main/resources/notices/safe_yaml-1.0.4-NOTICE.txt +++ /dev/null @@ -1,22 +0,0 @@ -Copyright (c) 2013 Dan Tao - -MIT License - -Permission is hereby granted, free of charge, to any person obtaining -a copy of this software and associated documentation files (the -"Software"), to deal in the Software without restriction, including -without limitation the rights to use, copy, modify, merge, publish, -distribute, sublicense, and/or sell copies of the Software, and to -permit persons to whom the Software is furnished to do so, subject to -the following conditions: - -The above copyright notice and this permission notice shall be -included in all copies or substantial portions of the Software. - -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, -EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF -MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND -NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE -LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION -OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION -WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. diff --git a/tools/dependencies-report/src/main/resources/notices/snakeyaml-1.18-NOTICE.txt b/tools/dependencies-report/src/main/resources/notices/semantic_logger-NOTICE.txt similarity index 90% rename from tools/dependencies-report/src/main/resources/notices/snakeyaml-1.18-NOTICE.txt rename to tools/dependencies-report/src/main/resources/notices/semantic_logger-NOTICE.txt index 8db00b5cb..c6781dac8 100644 --- a/tools/dependencies-report/src/main/resources/notices/snakeyaml-1.18-NOTICE.txt +++ b/tools/dependencies-report/src/main/resources/notices/semantic_logger-NOTICE.txt @@ -1,4 +1,4 @@ -Copyright (c) 2008, http://www.snakeyaml.org +Copyright 2012, 2013, 2014, 2015, 2016 Reid Morrison Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. diff --git a/tools/dependencies-report/src/main/resources/notices/sequel-5.11.0-NOTICE.txt b/tools/dependencies-report/src/main/resources/notices/sequel-NOTICE.txt similarity index 100% rename from tools/dependencies-report/src/main/resources/notices/sequel-5.11.0-NOTICE.txt rename to tools/dependencies-report/src/main/resources/notices/sequel-NOTICE.txt diff --git a/tools/dependencies-report/src/main/resources/notices/simple_oauth-0.3.1-NOTICE.txt b/tools/dependencies-report/src/main/resources/notices/simple_oauth-NOTICE.txt similarity index 100% rename from tools/dependencies-report/src/main/resources/notices/simple_oauth-0.3.1-NOTICE.txt rename to tools/dependencies-report/src/main/resources/notices/simple_oauth-NOTICE.txt diff --git a/tools/dependencies-report/src/main/resources/notices/sinatra-1.4.8-NOTICE.txt b/tools/dependencies-report/src/main/resources/notices/sinatra-NOTICE.txt similarity index 100% rename from tools/dependencies-report/src/main/resources/notices/sinatra-1.4.8-NOTICE.txt rename to tools/dependencies-report/src/main/resources/notices/sinatra-NOTICE.txt diff --git a/tools/dependencies-report/src/main/resources/notices/slop-3.6.0-NOTICE.txt b/tools/dependencies-report/src/main/resources/notices/slop-3.6.0-NOTICE.txt deleted file mode 100644 index ab47fd754..000000000 --- a/tools/dependencies-report/src/main/resources/notices/slop-3.6.0-NOTICE.txt +++ /dev/null @@ -1,20 +0,0 @@ -Copyright (c) 2012 Lee Jarvis - -Permission is hereby granted, free of charge, to any person obtaining -a copy of this software and associated documentation files (the -"Software"), to deal in the Software without restriction, including -without limitation the rights to use, copy, modify, merge, publish, -distribute, sublicense, and/or sell copies of the Software, and to -permit persons to whom the Software is furnished to do so, subject to -the following conditions: - -The above copyright notice and this permission notice shall be -included in all copies or substantial portions of the Software. - -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, -EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF -MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND -NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE -LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION -OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION -WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. diff --git a/tools/dependencies-report/src/main/resources/notices/snappy-0.0.12-NOTICE.txt b/tools/dependencies-report/src/main/resources/notices/snappy-NOTICE.txt similarity index 100% rename from tools/dependencies-report/src/main/resources/notices/snappy-0.0.12-NOTICE.txt rename to tools/dependencies-report/src/main/resources/notices/snappy-NOTICE.txt diff --git a/tools/dependencies-report/src/main/resources/notices/snappy-jars-1.1.0.1.2-NOTICE.txt b/tools/dependencies-report/src/main/resources/notices/snappy-jars-NOTICE.txt similarity index 100% rename from tools/dependencies-report/src/main/resources/notices/snappy-jars-1.1.0.1.2-NOTICE.txt rename to tools/dependencies-report/src/main/resources/notices/snappy-jars-NOTICE.txt diff --git a/tools/dependencies-report/src/main/resources/notices/snmp-1.2.0-NOTICE.txt b/tools/dependencies-report/src/main/resources/notices/snmp-NOTICE.txt similarity index 100% rename from tools/dependencies-report/src/main/resources/notices/snmp-1.2.0-NOTICE.txt rename to tools/dependencies-report/src/main/resources/notices/snmp-NOTICE.txt diff --git a/tools/dependencies-report/src/main/resources/notices/spoon-0.0.6-NOTICE.txt b/tools/dependencies-report/src/main/resources/notices/spoon-NOTICE.txt similarity index 100% rename from tools/dependencies-report/src/main/resources/notices/spoon-0.0.6-NOTICE.txt rename to tools/dependencies-report/src/main/resources/notices/spoon-NOTICE.txt diff --git a/tools/dependencies-report/src/main/resources/notices/stud-0.0.23-NOTICE.txt b/tools/dependencies-report/src/main/resources/notices/stud-NOTICE.txt similarity index 100% rename from tools/dependencies-report/src/main/resources/notices/stud-0.0.23-NOTICE.txt rename to tools/dependencies-report/src/main/resources/notices/stud-NOTICE.txt diff --git a/tools/dependencies-report/src/main/resources/notices/thread_safe-0.3.6-NOTICE.txt b/tools/dependencies-report/src/main/resources/notices/thread_safe-NOTICE.txt similarity index 100% rename from tools/dependencies-report/src/main/resources/notices/thread_safe-0.3.6-NOTICE.txt rename to tools/dependencies-report/src/main/resources/notices/thread_safe-NOTICE.txt diff --git a/tools/dependencies-report/src/main/resources/notices/tilt-2.0.8-NOTICE.txt b/tools/dependencies-report/src/main/resources/notices/tilt-NOTICE.txt similarity index 100% rename from tools/dependencies-report/src/main/resources/notices/tilt-2.0.8-NOTICE.txt rename to tools/dependencies-report/src/main/resources/notices/tilt-NOTICE.txt diff --git a/tools/dependencies-report/src/main/resources/notices/timecop-0.9.1-NOTICE.txt b/tools/dependencies-report/src/main/resources/notices/timecop-0.9.1-NOTICE.txt deleted file mode 100644 index ecd73f93b..000000000 --- a/tools/dependencies-report/src/main/resources/notices/timecop-0.9.1-NOTICE.txt +++ /dev/null @@ -1,22 +0,0 @@ -(The MIT License) - -Copyright (c) 2012 — Travis Jeffery, John Trupiano - -Permission is hereby granted, free of charge, to any person obtaining -a copy of this software and associated documentation files (the -'Software'), to deal in the Software without restriction, including -without limitation the rights to use, copy, modify, merge, publish, -distribute, sublicense, and/or sell copies of the Software, and to -permit persons to whom the Software is furnished to do so, subject to -the following conditions: - -The above copyright notice and this permission notice shall be -included in all copies or substantial portions of the Software. - -THE SOFTWARE IS PROVIDED 'AS IS', WITHOUT WARRANTY OF ANY KIND, -EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF -MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. -IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY -CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, -TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE -SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. diff --git a/tools/dependencies-report/src/main/resources/notices/treetop-1.4.15-NOTICE.txt b/tools/dependencies-report/src/main/resources/notices/treetop-NOTICE.txt similarity index 100% rename from tools/dependencies-report/src/main/resources/notices/treetop-1.4.15-NOTICE.txt rename to tools/dependencies-report/src/main/resources/notices/treetop-NOTICE.txt diff --git a/tools/dependencies-report/src/main/resources/notices/twitter-5.15.0-NOTICE.txt b/tools/dependencies-report/src/main/resources/notices/twitter-NOTICE.txt similarity index 100% rename from tools/dependencies-report/src/main/resources/notices/twitter-5.15.0-NOTICE.txt rename to tools/dependencies-report/src/main/resources/notices/twitter-NOTICE.txt diff --git a/tools/dependencies-report/src/main/resources/notices/tzinfo-1.2.5-NOTICE.txt b/tools/dependencies-report/src/main/resources/notices/tzinfo-NOTICE.txt similarity index 100% rename from tools/dependencies-report/src/main/resources/notices/tzinfo-1.2.5-NOTICE.txt rename to tools/dependencies-report/src/main/resources/notices/tzinfo-NOTICE.txt diff --git a/tools/dependencies-report/src/main/resources/notices/tzinfo-data-1.2018.5-NOTICE.txt b/tools/dependencies-report/src/main/resources/notices/tzinfo-data-NOTICE.txt similarity index 100% rename from tools/dependencies-report/src/main/resources/notices/tzinfo-data-1.2018.5-NOTICE.txt rename to tools/dependencies-report/src/main/resources/notices/tzinfo-data-NOTICE.txt diff --git a/tools/dependencies-report/src/main/resources/notices/unf-0.1.4-NOTICE.txt b/tools/dependencies-report/src/main/resources/notices/unf-NOTICE.txt similarity index 100% rename from tools/dependencies-report/src/main/resources/notices/unf-0.1.4-NOTICE.txt rename to tools/dependencies-report/src/main/resources/notices/unf-NOTICE.txt diff --git a/tools/dependencies-report/src/main/resources/notices/unsafe-fences-1.0-NOTICE.txt b/tools/dependencies-report/src/main/resources/notices/unsafe-fences-1.0-NOTICE.txt deleted file mode 100644 index d64569567..000000000 --- a/tools/dependencies-report/src/main/resources/notices/unsafe-fences-1.0-NOTICE.txt +++ /dev/null @@ -1,202 +0,0 @@ - - Apache License - Version 2.0, January 2004 - http://www.apache.org/licenses/ - - TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION - - 1. Definitions. - - "License" shall mean the terms and conditions for use, reproduction, - and distribution as defined by Sections 1 through 9 of this document. - - "Licensor" shall mean the copyright owner or entity authorized by - the copyright owner that is granting the License. - - "Legal Entity" shall mean the union of the acting entity and all - other entities that control, are controlled by, or are under common - control with that entity. For the purposes of this definition, - "control" means (i) the power, direct or indirect, to cause the - direction or management of such entity, whether by contract or - otherwise, or (ii) ownership of fifty percent (50%) or more of the - outstanding shares, or (iii) beneficial ownership of such entity. - - "You" (or "Your") shall mean an individual or Legal Entity - exercising permissions granted by this License. - - "Source" form shall mean the preferred form for making modifications, - including but not limited to software source code, documentation - source, and configuration files. - - "Object" form shall mean any form resulting from mechanical - transformation or translation of a Source form, including but - not limited to compiled object code, generated documentation, - and conversions to other media types. - - "Work" shall mean the work of authorship, whether in Source or - Object form, made available under the License, as indicated by a - copyright notice that is included in or attached to the work - (an example is provided in the Appendix below). - - "Derivative Works" shall mean any work, whether in Source or Object - form, that is based on (or derived from) the Work and for which the - editorial revisions, annotations, elaborations, or other modifications - represent, as a whole, an original work of authorship. For the purposes - of this License, Derivative Works shall not include works that remain - separable from, or merely link (or bind by name) to the interfaces of, - the Work and Derivative Works thereof. - - "Contribution" shall mean any work of authorship, including - the original version of the Work and any modifications or additions - to that Work or Derivative Works thereof, that is intentionally - submitted to Licensor for inclusion in the Work by the copyright owner - or by an individual or Legal Entity authorized to submit on behalf of - the copyright owner. For the purposes of this definition, "submitted" - means any form of electronic, verbal, or written communication sent - to the Licensor or its representatives, including but not limited to - communication on electronic mailing lists, source code control systems, - and issue tracking systems that are managed by, or on behalf of, the - Licensor for the purpose of discussing and improving the Work, but - excluding communication that is conspicuously marked or otherwise - designated in writing by the copyright owner as "Not a Contribution." - - "Contributor" shall mean Licensor and any individual or Legal Entity - on behalf of whom a Contribution has been received by Licensor and - subsequently incorporated within the Work. - - 2. Grant of Copyright License. Subject to the terms and conditions of - this License, each Contributor hereby grants to You a perpetual, - worldwide, non-exclusive, no-charge, royalty-free, irrevocable - copyright license to reproduce, prepare Derivative Works of, - publicly display, publicly perform, sublicense, and distribute the - Work and such Derivative Works in Source or Object form. - - 3. Grant of Patent License. Subject to the terms and conditions of - this License, each Contributor hereby grants to You a perpetual, - worldwide, non-exclusive, no-charge, royalty-free, irrevocable - (except as stated in this section) patent license to make, have made, - use, offer to sell, sell, import, and otherwise transfer the Work, - where such license applies only to those patent claims licensable - by such Contributor that are necessarily infringed by their - Contribution(s) alone or by combination of their Contribution(s) - with the Work to which such Contribution(s) was submitted. If You - institute patent litigation against any entity (including a - cross-claim or counterclaim in a lawsuit) alleging that the Work - or a Contribution incorporated within the Work constitutes direct - or contributory patent infringement, then any patent licenses - granted to You under this License for that Work shall terminate - as of the date such litigation is filed. - - 4. Redistribution. You may reproduce and distribute copies of the - Work or Derivative Works thereof in any medium, with or without - modifications, and in Source or Object form, provided that You - meet the following conditions: - - (a) You must give any other recipients of the Work or - Derivative Works a copy of this License; and - - (b) You must cause any modified files to carry prominent notices - stating that You changed the files; and - - (c) You must retain, in the Source form of any Derivative Works - that You distribute, all copyright, patent, trademark, and - attribution notices from the Source form of the Work, - excluding those notices that do not pertain to any part of - the Derivative Works; and - - (d) If the Work includes a "NOTICE" text file as part of its - distribution, then any Derivative Works that You distribute must - include a readable copy of the attribution notices contained - within such NOTICE file, excluding those notices that do not - pertain to any part of the Derivative Works, in at least one - of the following places: within a NOTICE text file distributed - as part of the Derivative Works; within the Source form or - documentation, if provided along with the Derivative Works; or, - within a display generated by the Derivative Works, if and - wherever such third-party notices normally appear. The contents - of the NOTICE file are for informational purposes only and - do not modify the License. You may add Your own attribution - notices within Derivative Works that You distribute, alongside - or as an addendum to the NOTICE text from the Work, provided - that such additional attribution notices cannot be construed - as modifying the License. - - You may add Your own copyright statement to Your modifications and - may provide additional or different license terms and conditions - for use, reproduction, or distribution of Your modifications, or - for any such Derivative Works as a whole, provided Your use, - reproduction, and distribution of the Work otherwise complies with - the conditions stated in this License. - - 5. Submission of Contributions. Unless You explicitly state otherwise, - any Contribution intentionally submitted for inclusion in the Work - by You to the Licensor shall be under the terms and conditions of - this License, without any additional terms or conditions. - Notwithstanding the above, nothing herein shall supersede or modify - the terms of any separate license agreement you may have executed - with Licensor regarding such Contributions. - - 6. Trademarks. This License does not grant permission to use the trade - names, trademarks, service marks, or product names of the Licensor, - except as required for reasonable and customary use in describing the - origin of the Work and reproducing the content of the NOTICE file. - - 7. Disclaimer of Warranty. Unless required by applicable law or - agreed to in writing, Licensor provides the Work (and each - Contributor provides its Contributions) on an "AS IS" BASIS, - WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or - implied, including, without limitation, any warranties or conditions - of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A - PARTICULAR PURPOSE. You are solely responsible for determining the - appropriateness of using or redistributing the Work and assume any - risks associated with Your exercise of permissions under this License. - - 8. Limitation of Liability. In no event and under no legal theory, - whether in tort (including negligence), contract, or otherwise, - unless required by applicable law (such as deliberate and grossly - negligent acts) or agreed to in writing, shall any Contributor be - liable to You for damages, including any direct, indirect, special, - incidental, or consequential damages of any character arising as a - result of this License or out of the use or inability to use the - Work (including but not limited to damages for loss of goodwill, - work stoppage, computer failure or malfunction, or any and all - other commercial damages or losses), even if such Contributor - has been advised of the possibility of such damages. - - 9. Accepting Warranty or Additional Liability. While redistributing - the Work or Derivative Works thereof, You may choose to offer, - and charge a fee for, acceptance of support, warranty, indemnity, - or other liability obligations and/or rights consistent with this - License. However, in accepting such obligations, You may act only - on Your own behalf and on Your sole responsibility, not on behalf - of any other Contributor, and only if You agree to indemnify, - defend, and hold each Contributor harmless for any liability - incurred by, or claims asserted against, such Contributor by reason - of your accepting any such warranty or additional liability. - - END OF TERMS AND CONDITIONS - - APPENDIX: How to apply the Apache License to your work. - - To apply the Apache License to your work, attach the following - boilerplate notice, with the fields enclosed by brackets "[]" - replaced with your own identifying information. (Don't include - the brackets!) The text should be enclosed in the appropriate - comment syntax for the file format. We also recommend that a - file or class name and description of purpose be included on the - same "printed page" as the copyright notice for easier - identification within third-party archives. - - Copyright [yyyy] [name of copyright owner] - - Licensed 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. diff --git a/tools/dependencies-report/src/main/resources/notices/webhdfs-0.8.0-NOTICE.txt b/tools/dependencies-report/src/main/resources/notices/webhdfs-NOTICE.txt similarity index 100% rename from tools/dependencies-report/src/main/resources/notices/webhdfs-0.8.0-NOTICE.txt rename to tools/dependencies-report/src/main/resources/notices/webhdfs-NOTICE.txt diff --git a/tools/dependencies-report/src/main/resources/notices/webmock-1.21.0-NOTICE.txt b/tools/dependencies-report/src/main/resources/notices/webmock-1.21.0-NOTICE.txt deleted file mode 100644 index 9a6302d0b..000000000 --- a/tools/dependencies-report/src/main/resources/notices/webmock-1.21.0-NOTICE.txt +++ /dev/null @@ -1,20 +0,0 @@ -Copyright (c) 2009-2010 Bartosz Blimke - -Permission is hereby granted, free of charge, to any person obtaining -a copy of this software and associated documentation files (the -"Software"), to deal in the Software without restriction, including -without limitation the rights to use, copy, modify, merge, publish, -distribute, sublicense, and/or sell copies of the Software, and to -permit persons to whom the Software is furnished to do so, subject to -the following conditions: - -The above copyright notice and this permission notice shall be -included in all copies or substantial portions of the Software. - -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, -EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF -MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND -NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE -LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION -OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION -WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. diff --git a/tools/dependencies-report/src/main/resources/notices/webrick-1.3.1-NOTICE.txt b/tools/dependencies-report/src/main/resources/notices/webrick-1.3.1-NOTICE.txt deleted file mode 100644 index a009caefe..000000000 --- a/tools/dependencies-report/src/main/resources/notices/webrick-1.3.1-NOTICE.txt +++ /dev/null @@ -1,22 +0,0 @@ -Copyright (C) 1993-2013 Yukihiro Matsumoto. All rights reserved. - -Redistribution and use in source and binary forms, with or without -modification, are permitted provided that the following conditions -are met: -1. Redistributions of source code must retain the above copyright -notice, this list of conditions and the following disclaimer. -2. Redistributions in binary form must reproduce the above copyright -notice, this list of conditions and the following disclaimer in the -documentation and/or other materials provided with the distribution. - -THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND -ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE -IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE -ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE -FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL -DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS -OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) -HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT -LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY -OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF -SUCH DAMAGE. diff --git a/tools/dependencies-report/src/main/resources/notices/xml-simple-1.1.5-NOTICE.txt b/tools/dependencies-report/src/main/resources/notices/xml-simple-NOTICE.txt similarity index 100% rename from tools/dependencies-report/src/main/resources/notices/xml-simple-1.1.5-NOTICE.txt rename to tools/dependencies-report/src/main/resources/notices/xml-simple-NOTICE.txt From 98990384ae3fda178c6912285e5b0eb632f764bc Mon Sep 17 00:00:00 2001 From: Joao Duarte Date: Fri, 31 Jan 2020 14:02:38 +0000 Subject: [PATCH 0342/1126] add missing NOTICE.txt --- NOTICE.TXT | 10620 +++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 10620 insertions(+) create mode 100644 NOTICE.TXT diff --git a/NOTICE.TXT b/NOTICE.TXT new file mode 100644 index 000000000..15e9e1138 --- /dev/null +++ b/NOTICE.TXT @@ -0,0 +1,10620 @@ + +========== +Notice for: addressable-2.7.0 +---------- + +Copyright © Bob Aman + + Apache License + Version 2.0, January 2004 + http://www.apache.org/licenses/ + +TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION + +1. Definitions. + + "License" shall mean the terms and conditions for use, reproduction, + and distribution as defined by Sections 1 through 9 of this document. + + "Licensor" shall mean the copyright owner or entity authorized by + the copyright owner that is granting the License. + + "Legal Entity" shall mean the union of the acting entity and all + other entities that control, are controlled by, or are under common + control with that entity. For the purposes of this definition, + "control" means (i) the power, direct or indirect, to cause the + direction or management of such entity, whether by contract or + otherwise, or (ii) ownership of fifty percent (50%) or more of the + outstanding shares, or (iii) beneficial ownership of such entity. + + "You" (or "Your") shall mean an individual or Legal Entity + exercising permissions granted by this License. + + "Source" form shall mean the preferred form for making modifications, + including but not limited to software source code, documentation + source, and configuration files. + + "Object" form shall mean any form resulting from mechanical + transformation or translation of a Source form, including but + not limited to compiled object code, generated documentation, + and conversions to other media types. + + "Work" shall mean the work of authorship, whether in Source or + Object form, made available under the License, as indicated by a + copyright notice that is included in or attached to the work + (an example is provided in the Appendix below). + + "Derivative Works" shall mean any work, whether in Source or Object + form, that is based on (or derived from) the Work and for which the + editorial revisions, annotations, elaborations, or other modifications + represent, as a whole, an original work of authorship. For the purposes + of this License, Derivative Works shall not include works that remain + separable from, or merely link (or bind by name) to the interfaces of, + the Work and Derivative Works thereof. + + "Contribution" shall mean any work of authorship, including + the original version of the Work and any modifications or additions + to that Work or Derivative Works thereof, that is intentionally + submitted to Licensor for inclusion in the Work by the copyright owner + or by an individual or Legal Entity authorized to submit on behalf of + the copyright owner. For the purposes of this definition, "submitted" + means any form of electronic, verbal, or written communication sent + to the Licensor or its representatives, including but not limited to + communication on electronic mailing lists, source code control systems, + and issue tracking systems that are managed by, or on behalf of, the + Licensor for the purpose of discussing and improving the Work, but + excluding communication that is conspicuously marked or otherwise + designated in writing by the copyright owner as "Not a Contribution." + + "Contributor" shall mean Licensor and any individual or Legal Entity + on behalf of whom a Contribution has been received by Licensor and + subsequently incorporated within the Work. + +2. Grant of Copyright License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + copyright license to reproduce, prepare Derivative Works of, + publicly display, publicly perform, sublicense, and distribute the + Work and such Derivative Works in Source or Object form. + +3. Grant of Patent License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + (except as stated in this section) patent license to make, have made, + use, offer to sell, sell, import, and otherwise transfer the Work, + where such license applies only to those patent claims licensable + by such Contributor that are necessarily infringed by their + Contribution(s) alone or by combination of their Contribution(s) + with the Work to which such Contribution(s) was submitted. If You + institute patent litigation against any entity (including a + cross-claim or counterclaim in a lawsuit) alleging that the Work + or a Contribution incorporated within the Work constitutes direct + or contributory patent infringement, then any patent licenses + granted to You under this License for that Work shall terminate + as of the date such litigation is filed. + +4. Redistribution. You may reproduce and distribute copies of the + Work or Derivative Works thereof in any medium, with or without + modifications, and in Source or Object form, provided that You + meet the following conditions: + + (a) You must give any other recipients of the Work or + Derivative Works a copy of this License; and + + (b) You must cause any modified files to carry prominent notices + stating that You changed the files; and + + (c) You must retain, in the Source form of any Derivative Works + that You distribute, all copyright, patent, trademark, and + attribution notices from the Source form of the Work, + excluding those notices that do not pertain to any part of + the Derivative Works; and + + (d) If the Work includes a "NOTICE" text file as part of its + distribution, then any Derivative Works that You distribute must + include a readable copy of the attribution notices contained + within such NOTICE file, excluding those notices that do not + pertain to any part of the Derivative Works, in at least one + of the following places: within a NOTICE text file distributed + as part of the Derivative Works; within the Source form or + documentation, if provided along with the Derivative Works; or, + within a display generated by the Derivative Works, if and + wherever such third-party notices normally appear. The contents + of the NOTICE file are for informational purposes only and + do not modify the License. You may add Your own attribution + notices within Derivative Works that You distribute, alongside + or as an addendum to the NOTICE text from the Work, provided + that such additional attribution notices cannot be construed + as modifying the License. + + You may add Your own copyright statement to Your modifications and + may provide additional or different license terms and conditions + for use, reproduction, or distribution of Your modifications, or + for any such Derivative Works as a whole, provided Your use, + reproduction, and distribution of the Work otherwise complies with + the conditions stated in this License. + +5. Submission of Contributions. Unless You explicitly state otherwise, + any Contribution intentionally submitted for inclusion in the Work + by You to the Licensor shall be under the terms and conditions of + this License, without any additional terms or conditions. + Notwithstanding the above, nothing herein shall supersede or modify + the terms of any separate license agreement you may have executed + with Licensor regarding such Contributions. + +6. Trademarks. This License does not grant permission to use the trade + names, trademarks, service marks, or product names of the Licensor, + except as required for reasonable and customary use in describing the + origin of the Work and reproducing the content of the NOTICE file. + +7. Disclaimer of Warranty. Unless required by applicable law or + agreed to in writing, Licensor provides the Work (and each + Contributor provides its Contributions) on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + implied, including, without limitation, any warranties or conditions + of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A + PARTICULAR PURPOSE. You are solely responsible for determining the + appropriateness of using or redistributing the Work and assume any + risks associated with Your exercise of permissions under this License. + +8. Limitation of Liability. In no event and under no legal theory, + whether in tort (including negligence), contract, or otherwise, + unless required by applicable law (such as deliberate and grossly + negligent acts) or agreed to in writing, shall any Contributor be + liable to You for damages, including any direct, indirect, special, + incidental, or consequential damages of any character arising as a + result of this License or out of the use or inability to use the + Work (including but not limited to damages for loss of goodwill, + work stoppage, computer failure or malfunction, or any and all + other commercial damages or losses), even if such Contributor + has been advised of the possibility of such damages. + +9. Accepting Warranty or Additional Liability. While redistributing + the Work or Derivative Works thereof, You may choose to offer, + and charge a fee for, acceptance of support, warranty, indemnity, + or other liability obligations and/or rights consistent with this + License. However, in accepting such obligations, You may act only + on Your own behalf and on Your sole responsibility, not on behalf + of any other Contributor, and only if You agree to indemnify, + defend, and hold each Contributor harmless for any liability + incurred by, or claims asserted against, such Contributor by reason + of your accepting any such warranty or additional liability. + +END OF TERMS AND CONDITIONS + +APPENDIX: How to apply the Apache License to your work. + + To apply the Apache License to your work, attach the following + boilerplate notice, with the fields enclosed by brackets "[]" + replaced with your own identifying information. (Don't include + the brackets!) The text should be enclosed in the appropriate + comment syntax for the file format. We also recommend that a + file or class name and description of purpose be included on the + same "printed page" as the copyright notice for easier + identification within third-party archives. + +Copyright [yyyy] [name of copyright owner] + +Licensed 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. + +========== +Notice for: atomic-1.1.101 +---------- + +Apache License + +Version 2.0, January 2004 + +http://www.apache.org/licenses/ + +TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION + +1. Definitions. + +"License" shall mean the terms and conditions for use, reproduction, and distribution as +defined by Sections 1 through 9 of this document. + +"Licensor" shall mean the copyright owner or entity authorized by the copyright owner that +is granting the License. + +"Legal Entity" shall mean the union of the acting entity and all other entities that +control, are controlled by, or are under common control with that entity. For the purposes +of this definition, "control" means (i) the power, direct or indirect, to cause the +direction or management of such entity, whether by contract or otherwise, or (ii) ownership +of fifty percent (50%) or more of the outstanding shares, or (iii) beneficial ownership of +such entity. + +"You" (or "Your") shall mean an individual or Legal Entity exercising permissions granted by +this License. + +"Source" form shall mean the preferred form for making modifications, including but not +limited to software source code, documentation source, and configuration files. + +"Object" form shall mean any form resulting from mechanical transformation or translation of +a Source form, including but not limited to compiled object code, generated documentation, +and conversions to other media types. + +"Work" shall mean the work of authorship, whether in Source or Object form, made available +under the License, as indicated by a copyright notice that is included in or attached to the +work (an example is provided in the Appendix below). + +"Derivative Works" shall mean any work, whether in Source or Object form, that is based on +(or derived from) the Work and for which the editorial revisions, annotations, elaborations, +or other modifications represent, as a whole, an original work of authorship. For the +purposes of this License, Derivative Works shall not include works that remain separable +from, or merely link (or bind by name) to the interfaces of, the Work and Derivative Works +thereof. + +"Contribution" shall mean any work of authorship, including the original version of the Work +and any modifications or additions to that Work or Derivative Works thereof, that is +intentionally submitted to Licensor for inclusion in the Work by the copyright owner or by +an individual or Legal Entity authorized to submit on behalf of the copyright owner. For the +purposes of this definition, "submitted" means any form of electronic, verbal, or written +communication sent to the Licensor or its representatives, including but not limited to +communication on electronic mailing lists, source code control systems, and issue tracking +systems that are managed by, or on behalf of, the Licensor for the purpose of discussing and +improving the Work, but excluding communication that is conspicuously marked or otherwise +designated in writing by the copyright owner as "Not a Contribution." + +"Contributor" shall mean Licensor and any individual or Legal Entity on behalf of whom a +Contribution has been received by Licensor and subsequently incorporated within the Work. + +2. Grant of Copyright License. Subject to the terms and conditions of this License, each +Contributor hereby grants to You a perpetual, worldwide, non-exclusive, no-charge, +royalty-free, irrevocable copyright license to reproduce, prepare Derivative Works of, +publicly display, publicly perform, sublicense, and distribute the Work and such Derivative +Works in Source or Object form. + +3. Grant of Patent License. Subject to the terms and conditions of this License, each +Contributor hereby grants to You a perpetual, worldwide, non-exclusive, no-charge, +royalty-free, irrevocable (except as stated in this section) patent license to make, have +made, use, offer to sell, sell, import, and otherwise transfer the Work, where such license +applies only to those patent claims licensable by such Contributor that are necessarily +infringed by their Contribution(s) alone or by combination of their Contribution(s) with the +Work to which such Contribution(s) was submitted. If You institute patent litigation against +any entity (including a cross-claim or counterclaim in a lawsuit) alleging that the Work or +a Contribution incorporated within the Work constitutes direct or contributory patent +infringement, then any patent licenses granted to You under this License for that Work shall +terminate as of the date such litigation is filed. + +4. Redistribution. You may reproduce and distribute copies of the Work or Derivative Works +thereof in any medium, with or without modifications, and in Source or Object form, provided +that You meet the following conditions: + +You must give any other recipients of the Work or Derivative Works a copy of this License; +and + +You must cause any modified files to carry prominent notices stating that You changed the +files; and + +You must retain, in the Source form of any Derivative Works that You distribute, all +copyright, patent, trademark, and attribution notices from the Source form of the Work, +excluding those notices that do not pertain to any part of the Derivative Works; and + +If the Work includes a "NOTICE" text file as part of its distribution, then any Derivative +Works that You distribute must include a readable copy of the attribution notices contained +within such NOTICE file, excluding those notices that do not pertain to any part of the +Derivative Works, in at least one of the following places: within a NOTICE text file +distributed as part of the Derivative Works; within the Source form or documentation, if +provided along with the Derivative Works; or, within a display generated by the Derivative +Works, if and wherever such third-party notices normally appear. The contents of the NOTICE +file are for informational purposes only and do not modify the License. You may add Your own +attribution notices within Derivative Works that You distribute, alongside or as an addendum +to the NOTICE text from the Work, provided that such additional attribution notices cannot +be construed as modifying the License. You may add Your own copyright statement to Your +modifications and may provide additional or different license terms and conditions for use, +reproduction, or distribution of Your modifications, or for any such Derivative Works as a +whole, provided Your use, reproduction, and distribution of the Work otherwise complies with +the conditions stated in this License. + +5. Submission of Contributions. Unless You explicitly state otherwise, any Contribution +intentionally submitted for inclusion in the Work by You to the Licensor shall be under the +terms and conditions of this License, without any additional terms or conditions. +Notwithstanding the above, nothing herein shall supersede or modify the terms of any +separate license agreement you may have executed with Licensor regarding such Contributions. + +6. Trademarks. This License does not grant permission to use the trade names, trademarks, +service marks, or product names of the Licensor, except as required for reasonable and +customary use in describing the origin of the Work and reproducing the content of the NOTICE +file. + +7. Disclaimer of Warranty. Unless required by applicable law or agreed to in writing, +Licensor provides the Work (and each Contributor provides its Contributions) on an "AS IS" +BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied, including, +without limitation, any warranties or conditions of TITLE, NON-INFRINGEMENT, +MERCHANTABILITY, or FITNESS FOR A PARTICULAR PURPOSE. You are solely responsible for +determining the appropriateness of using or redistributing the Work and assume any risks +associated with Your exercise of permissions under this License. + +8. Limitation of Liability. In no event and under no legal theory, whether in tort +(including negligence), contract, or otherwise, unless required by applicable law (such as +deliberate and grossly negligent acts) or agreed to in writing, shall any Contributor be +liable to You for damages, including any direct, indirect, special, incidental, or +consequential damages of any character arising as a result of this License or out of the use +or inability to use the Work (including but not limited to damages for loss of goodwill, +work stoppage, computer failure or malfunction, or any and all other commercial damages or +losses), even if such Contributor has been advised of the possibility of such damages. + +9. Accepting Warranty or Additional Liability. While redistributing the Work or Derivative +Works thereof, You may choose to offer, and charge a fee for, acceptance of support, +warranty, indemnity, or other liability obligations and/or rights consistent with this +License. However, in accepting such obligations, You may act only on Your own behalf and on +Your sole responsibility, not on behalf of any other Contributor, and only if You agree to +indemnify, defend, and hold each Contributor harmless for any liability incurred by, or +claims asserted against, such Contributor by reason of your accepting any such warranty or +additional liability. + +END OF TERMS AND CONDITIONS + +========== +Notice for: avl_tree-1.2.1 +---------- + +Copyright (c) 2012, Hiroshi Nakamura +All rights reserved. + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are +met: + +1. Redistributions of source code must retain the above copyright +notice, this list of conditions and the following disclaimer. + +2. Redistributions in binary form must reproduce the above copyright +notice, this list of conditions and the following disclaimer in the +documentation and/or other materials provided with the distribution. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +========== +Notice for: avro-1.9.1 +---------- + +Apache Avro +Copyright 2010-2015 The Apache Software Foundation + +This product includes software developed at +The Apache Software Foundation (https://www.apache.org/). + + +========== +Notice for: awesome_print-1.7.0 +---------- + +Copyright (c) 2010-2013 Michael Dvorkin +http://www.dvorkin.net +%w(mike dvorkin.net) * "@" || "twitter.com/mid" + +Permission is hereby granted, free of charge, to any person obtaining +a copy of this software and associated documentation files (the +"Software"), to deal in the Software without restriction, including +without limitation the rights to use, copy, modify, merge, publish, +distribute, sublicense, and/or sell copies of the Software, and to +permit persons to whom the Software is furnished to do so, subject to +the following conditions: + +The above copyright notice and this permission notice shall be +included in all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + +========== +Notice for: aws-eventstream-1.0.3 +---------- + +AWS SDK for Ruby +Copyright 2015 Amazon.com, Inc. or its affiliates. All Rights Reserved. + +========== +Notice for: aws-sdk-2.11.436 +---------- + +copyright 2013. amazon web services, inc. all rights reserved. + + Apache License + Version 2.0, January 2004 + http://www.apache.org/licenses/ + + TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION + + 1. Definitions. + + "License" shall mean the terms and conditions for use, reproduction, + and distribution as defined by Sections 1 through 9 of this document. + + "Licensor" shall mean the copyright owner or entity authorized by + the copyright owner that is granting the License. + + "Legal Entity" shall mean the union of the acting entity and all + other entities that control, are controlled by, or are under common + control with that entity. For the purposes of this definition, + "control" means (i) the power, direct or indirect, to cause the + direction or management of such entity, whether by contract or + otherwise, or (ii) ownership of fifty percent (50%) or more of the + outstanding shares, or (iii) beneficial ownership of such entity. + + "You" (or "Your") shall mean an individual or Legal Entity + exercising permissions granted by this License. + + "Source" form shall mean the preferred form for making modifications, + including but not limited to software source code, documentation + source, and configuration files. + + "Object" form shall mean any form resulting from mechanical + transformation or translation of a Source form, including but + not limited to compiled object code, generated documentation, + and conversions to other media types. + + "Work" shall mean the work of authorship, whether in Source or + Object form, made available under the License, as indicated by a + copyright notice that is included in or attached to the work + (an example is provided in the Appendix below). + + "Derivative Works" shall mean any work, whether in Source or Object + form, that is based on (or derived from) the Work and for which the + editorial revisions, annotations, elaborations, or other modifications + represent, as a whole, an original work of authorship. For the purposes + of this License, Derivative Works shall not include works that remain + separable from, or merely link (or bind by name) to the interfaces of, + the Work and Derivative Works thereof. + + "Contribution" shall mean any work of authorship, including + the original version of the Work and any modifications or additions + to that Work or Derivative Works thereof, that is intentionally + submitted to Licensor for inclusion in the Work by the copyright owner + or by an individual or Legal Entity authorized to submit on behalf of + the copyright owner. For the purposes of this definition, "submitted" + means any form of electronic, verbal, or written communication sent + to the Licensor or its representatives, including but not limited to + communication on electronic mailing lists, source code control systems, + and issue tracking systems that are managed by, or on behalf of, the + Licensor for the purpose of discussing and improving the Work, but + excluding communication that is conspicuously marked or otherwise + designated in writing by the copyright owner as "Not a Contribution." + + "Contributor" shall mean Licensor and any individual or Legal Entity + on behalf of whom a Contribution has been received by Licensor and + subsequently incorporated within the Work. + + 2. Grant of Copyright License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + copyright license to reproduce, prepare Derivative Works of, + publicly display, publicly perform, sublicense, and distribute the + Work and such Derivative Works in Source or Object form. + + 3. Grant of Patent License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + (except as stated in this section) patent license to make, have made, + use, offer to sell, sell, import, and otherwise transfer the Work, + where such license applies only to those patent claims licensable + by such Contributor that are necessarily infringed by their + Contribution(s) alone or by combination of their Contribution(s) + with the Work to which such Contribution(s) was submitted. If You + institute patent litigation against any entity (including a + cross-claim or counterclaim in a lawsuit) alleging that the Work + or a Contribution incorporated within the Work constitutes direct + or contributory patent infringement, then any patent licenses + granted to You under this License for that Work shall terminate + as of the date such litigation is filed. + + 4. Redistribution. You may reproduce and distribute copies of the + Work or Derivative Works thereof in any medium, with or without + modifications, and in Source or Object form, provided that You + meet the following conditions: + + (a) You must give any other recipients of the Work or + Derivative Works a copy of this License; and + + (b) You must cause any modified files to carry prominent notices + stating that You changed the files; and + + (c) You must retain, in the Source form of any Derivative Works + that You distribute, all copyright, patent, trademark, and + attribution notices from the Source form of the Work, + excluding those notices that do not pertain to any part of + the Derivative Works; and + + (d) If the Work includes a "NOTICE" text file as part of its + distribution, then any Derivative Works that You distribute must + include a readable copy of the attribution notices contained + within such NOTICE file, excluding those notices that do not + pertain to any part of the Derivative Works, in at least one + of the following places: within a NOTICE text file distributed + as part of the Derivative Works; within the Source form or + documentation, if provided along with the Derivative Works; or, + within a display generated by the Derivative Works, if and + wherever such third-party notices normally appear. The contents + of the NOTICE file are for informational purposes only and + do not modify the License. You may add Your own attribution + notices within Derivative Works that You distribute, alongside + or as an addendum to the NOTICE text from the Work, provided + that such additional attribution notices cannot be construed + as modifying the License. + + You may add Your own copyright statement to Your modifications and + may provide additional or different license terms and conditions + for use, reproduction, or distribution of Your modifications, or + for any such Derivative Works as a whole, provided Your use, + reproduction, and distribution of the Work otherwise complies with + the conditions stated in this License. + + 5. Submission of Contributions. Unless You explicitly state otherwise, + any Contribution intentionally submitted for inclusion in the Work + by You to the Licensor shall be under the terms and conditions of + this License, without any additional terms or conditions. + Notwithstanding the above, nothing herein shall supersede or modify + the terms of any separate license agreement you may have executed + with Licensor regarding such Contributions. + + 6. Trademarks. This License does not grant permission to use the trade + names, trademarks, service marks, or product names of the Licensor, + except as required for reasonable and customary use in describing the + origin of the Work and reproducing the content of the NOTICE file. + + 7. Disclaimer of Warranty. Unless required by applicable law or + agreed to in writing, Licensor provides the Work (and each + Contributor provides its Contributions) on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + implied, including, without limitation, any warranties or conditions + of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A + PARTICULAR PURPOSE. You are solely responsible for determining the + appropriateness of using or redistributing the Work and assume any + risks associated with Your exercise of permissions under this License. + + 8. Limitation of Liability. In no event and under no legal theory, + whether in tort (including negligence), contract, or otherwise, + unless required by applicable law (such as deliberate and grossly + negligent acts) or agreed to in writing, shall any Contributor be + liable to You for damages, including any direct, indirect, special, + incidental, or consequential damages of any character arising as a + result of this License or out of the use or inability to use the + Work (including but not limited to damages for loss of goodwill, + work stoppage, computer failure or malfunction, or any and all + other commercial damages or losses), even if such Contributor + has been advised of the possibility of such damages. + + 9. Accepting Warranty or Additional Liability. While redistributing + the Work or Derivative Works thereof, You may choose to offer, + and charge a fee for, acceptance of support, warranty, indemnity, + or other liability obligations and/or rights consistent with this + License. However, in accepting such obligations, You may act only + on Your own behalf and on Your sole responsibility, not on behalf + of any other Contributor, and only if You agree to indemnify, + defend, and hold each Contributor harmless for any liability + incurred by, or claims asserted against, such Contributor by reason + of your accepting any such warranty or additional liability. + + END OF TERMS AND CONDITIONS + + APPENDIX: How to apply the Apache License to your work. + + To apply the Apache License to your work, attach the following + boilerplate notice, with the fields enclosed by brackets "[]" + replaced with your own identifying information. (Don't include + the brackets!) The text should be enclosed in the appropriate + comment syntax for the file format. We also recommend that a + file or class name and description of purpose be included on the + same "printed page" as the copyright notice for easier + identification within third-party archives. + + Copyright [yyyy] [name of copyright owner] + + Licensed 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. + +========== +Notice for: aws-sdk-core-2.11.436 +---------- + +copyright 2013. amazon web services, inc. all rights reserved. + + Apache License + Version 2.0, January 2004 + http://www.apache.org/licenses/ + + TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION + + 1. Definitions. + + "License" shall mean the terms and conditions for use, reproduction, + and distribution as defined by Sections 1 through 9 of this document. + + "Licensor" shall mean the copyright owner or entity authorized by + the copyright owner that is granting the License. + + "Legal Entity" shall mean the union of the acting entity and all + other entities that control, are controlled by, or are under common + control with that entity. For the purposes of this definition, + "control" means (i) the power, direct or indirect, to cause the + direction or management of such entity, whether by contract or + otherwise, or (ii) ownership of fifty percent (50%) or more of the + outstanding shares, or (iii) beneficial ownership of such entity. + + "You" (or "Your") shall mean an individual or Legal Entity + exercising permissions granted by this License. + + "Source" form shall mean the preferred form for making modifications, + including but not limited to software source code, documentation + source, and configuration files. + + "Object" form shall mean any form resulting from mechanical + transformation or translation of a Source form, including but + not limited to compiled object code, generated documentation, + and conversions to other media types. + + "Work" shall mean the work of authorship, whether in Source or + Object form, made available under the License, as indicated by a + copyright notice that is included in or attached to the work + (an example is provided in the Appendix below). + + "Derivative Works" shall mean any work, whether in Source or Object + form, that is based on (or derived from) the Work and for which the + editorial revisions, annotations, elaborations, or other modifications + represent, as a whole, an original work of authorship. For the purposes + of this License, Derivative Works shall not include works that remain + separable from, or merely link (or bind by name) to the interfaces of, + the Work and Derivative Works thereof. + + "Contribution" shall mean any work of authorship, including + the original version of the Work and any modifications or additions + to that Work or Derivative Works thereof, that is intentionally + submitted to Licensor for inclusion in the Work by the copyright owner + or by an individual or Legal Entity authorized to submit on behalf of + the copyright owner. For the purposes of this definition, "submitted" + means any form of electronic, verbal, or written communication sent + to the Licensor or its representatives, including but not limited to + communication on electronic mailing lists, source code control systems, + and issue tracking systems that are managed by, or on behalf of, the + Licensor for the purpose of discussing and improving the Work, but + excluding communication that is conspicuously marked or otherwise + designated in writing by the copyright owner as "Not a Contribution." + + "Contributor" shall mean Licensor and any individual or Legal Entity + on behalf of whom a Contribution has been received by Licensor and + subsequently incorporated within the Work. + + 2. Grant of Copyright License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + copyright license to reproduce, prepare Derivative Works of, + publicly display, publicly perform, sublicense, and distribute the + Work and such Derivative Works in Source or Object form. + + 3. Grant of Patent License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + (except as stated in this section) patent license to make, have made, + use, offer to sell, sell, import, and otherwise transfer the Work, + where such license applies only to those patent claims licensable + by such Contributor that are necessarily infringed by their + Contribution(s) alone or by combination of their Contribution(s) + with the Work to which such Contribution(s) was submitted. If You + institute patent litigation against any entity (including a + cross-claim or counterclaim in a lawsuit) alleging that the Work + or a Contribution incorporated within the Work constitutes direct + or contributory patent infringement, then any patent licenses + granted to You under this License for that Work shall terminate + as of the date such litigation is filed. + + 4. Redistribution. You may reproduce and distribute copies of the + Work or Derivative Works thereof in any medium, with or without + modifications, and in Source or Object form, provided that You + meet the following conditions: + + (a) You must give any other recipients of the Work or + Derivative Works a copy of this License; and + + (b) You must cause any modified files to carry prominent notices + stating that You changed the files; and + + (c) You must retain, in the Source form of any Derivative Works + that You distribute, all copyright, patent, trademark, and + attribution notices from the Source form of the Work, + excluding those notices that do not pertain to any part of + the Derivative Works; and + + (d) If the Work includes a "NOTICE" text file as part of its + distribution, then any Derivative Works that You distribute must + include a readable copy of the attribution notices contained + within such NOTICE file, excluding those notices that do not + pertain to any part of the Derivative Works, in at least one + of the following places: within a NOTICE text file distributed + as part of the Derivative Works; within the Source form or + documentation, if provided along with the Derivative Works; or, + within a display generated by the Derivative Works, if and + wherever such third-party notices normally appear. The contents + of the NOTICE file are for informational purposes only and + do not modify the License. You may add Your own attribution + notices within Derivative Works that You distribute, alongside + or as an addendum to the NOTICE text from the Work, provided + that such additional attribution notices cannot be construed + as modifying the License. + + You may add Your own copyright statement to Your modifications and + may provide additional or different license terms and conditions + for use, reproduction, or distribution of Your modifications, or + for any such Derivative Works as a whole, provided Your use, + reproduction, and distribution of the Work otherwise complies with + the conditions stated in this License. + + 5. Submission of Contributions. Unless You explicitly state otherwise, + any Contribution intentionally submitted for inclusion in the Work + by You to the Licensor shall be under the terms and conditions of + this License, without any additional terms or conditions. + Notwithstanding the above, nothing herein shall supersede or modify + the terms of any separate license agreement you may have executed + with Licensor regarding such Contributions. + + 6. Trademarks. This License does not grant permission to use the trade + names, trademarks, service marks, or product names of the Licensor, + except as required for reasonable and customary use in describing the + origin of the Work and reproducing the content of the NOTICE file. + + 7. Disclaimer of Warranty. Unless required by applicable law or + agreed to in writing, Licensor provides the Work (and each + Contributor provides its Contributions) on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + implied, including, without limitation, any warranties or conditions + of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A + PARTICULAR PURPOSE. You are solely responsible for determining the + appropriateness of using or redistributing the Work and assume any + risks associated with Your exercise of permissions under this License. + + 8. Limitation of Liability. In no event and under no legal theory, + whether in tort (including negligence), contract, or otherwise, + unless required by applicable law (such as deliberate and grossly + negligent acts) or agreed to in writing, shall any Contributor be + liable to You for damages, including any direct, indirect, special, + incidental, or consequential damages of any character arising as a + result of this License or out of the use or inability to use the + Work (including but not limited to damages for loss of goodwill, + work stoppage, computer failure or malfunction, or any and all + other commercial damages or losses), even if such Contributor + has been advised of the possibility of such damages. + + 9. Accepting Warranty or Additional Liability. While redistributing + the Work or Derivative Works thereof, You may choose to offer, + and charge a fee for, acceptance of support, warranty, indemnity, + or other liability obligations and/or rights consistent with this + License. However, in accepting such obligations, You may act only + on Your own behalf and on Your sole responsibility, not on behalf + of any other Contributor, and only if You agree to indemnify, + defend, and hold each Contributor harmless for any liability + incurred by, or claims asserted against, such Contributor by reason + of your accepting any such warranty or additional liability. + + END OF TERMS AND CONDITIONS + + APPENDIX: How to apply the Apache License to your work. + + To apply the Apache License to your work, attach the following + boilerplate notice, with the fields enclosed by brackets "[]" + replaced with your own identifying information. (Don't include + the brackets!) The text should be enclosed in the appropriate + comment syntax for the file format. We also recommend that a + file or class name and description of purpose be included on the + same "printed page" as the copyright notice for easier + identification within third-party archives. + + Copyright [yyyy] [name of copyright owner] + + Licensed 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. + +========== +Notice for: aws-sdk-resources-2.11.436 +---------- + +copyright 2013. amazon web services, inc. all rights reserved. + + Apache License + Version 2.0, January 2004 + http://www.apache.org/licenses/ + + TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION + + 1. Definitions. + + "License" shall mean the terms and conditions for use, reproduction, + and distribution as defined by Sections 1 through 9 of this document. + + "Licensor" shall mean the copyright owner or entity authorized by + the copyright owner that is granting the License. + + "Legal Entity" shall mean the union of the acting entity and all + other entities that control, are controlled by, or are under common + control with that entity. For the purposes of this definition, + "control" means (i) the power, direct or indirect, to cause the + direction or management of such entity, whether by contract or + otherwise, or (ii) ownership of fifty percent (50%) or more of the + outstanding shares, or (iii) beneficial ownership of such entity. + + "You" (or "Your") shall mean an individual or Legal Entity + exercising permissions granted by this License. + + "Source" form shall mean the preferred form for making modifications, + including but not limited to software source code, documentation + source, and configuration files. + + "Object" form shall mean any form resulting from mechanical + transformation or translation of a Source form, including but + not limited to compiled object code, generated documentation, + and conversions to other media types. + + "Work" shall mean the work of authorship, whether in Source or + Object form, made available under the License, as indicated by a + copyright notice that is included in or attached to the work + (an example is provided in the Appendix below). + + "Derivative Works" shall mean any work, whether in Source or Object + form, that is based on (or derived from) the Work and for which the + editorial revisions, annotations, elaborations, or other modifications + represent, as a whole, an original work of authorship. For the purposes + of this License, Derivative Works shall not include works that remain + separable from, or merely link (or bind by name) to the interfaces of, + the Work and Derivative Works thereof. + + "Contribution" shall mean any work of authorship, including + the original version of the Work and any modifications or additions + to that Work or Derivative Works thereof, that is intentionally + submitted to Licensor for inclusion in the Work by the copyright owner + or by an individual or Legal Entity authorized to submit on behalf of + the copyright owner. For the purposes of this definition, "submitted" + means any form of electronic, verbal, or written communication sent + to the Licensor or its representatives, including but not limited to + communication on electronic mailing lists, source code control systems, + and issue tracking systems that are managed by, or on behalf of, the + Licensor for the purpose of discussing and improving the Work, but + excluding communication that is conspicuously marked or otherwise + designated in writing by the copyright owner as "Not a Contribution." + + "Contributor" shall mean Licensor and any individual or Legal Entity + on behalf of whom a Contribution has been received by Licensor and + subsequently incorporated within the Work. + + 2. Grant of Copyright License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + copyright license to reproduce, prepare Derivative Works of, + publicly display, publicly perform, sublicense, and distribute the + Work and such Derivative Works in Source or Object form. + + 3. Grant of Patent License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + (except as stated in this section) patent license to make, have made, + use, offer to sell, sell, import, and otherwise transfer the Work, + where such license applies only to those patent claims licensable + by such Contributor that are necessarily infringed by their + Contribution(s) alone or by combination of their Contribution(s) + with the Work to which such Contribution(s) was submitted. If You + institute patent litigation against any entity (including a + cross-claim or counterclaim in a lawsuit) alleging that the Work + or a Contribution incorporated within the Work constitutes direct + or contributory patent infringement, then any patent licenses + granted to You under this License for that Work shall terminate + as of the date such litigation is filed. + + 4. Redistribution. You may reproduce and distribute copies of the + Work or Derivative Works thereof in any medium, with or without + modifications, and in Source or Object form, provided that You + meet the following conditions: + + (a) You must give any other recipients of the Work or + Derivative Works a copy of this License; and + + (b) You must cause any modified files to carry prominent notices + stating that You changed the files; and + + (c) You must retain, in the Source form of any Derivative Works + that You distribute, all copyright, patent, trademark, and + attribution notices from the Source form of the Work, + excluding those notices that do not pertain to any part of + the Derivative Works; and + + (d) If the Work includes a "NOTICE" text file as part of its + distribution, then any Derivative Works that You distribute must + include a readable copy of the attribution notices contained + within such NOTICE file, excluding those notices that do not + pertain to any part of the Derivative Works, in at least one + of the following places: within a NOTICE text file distributed + as part of the Derivative Works; within the Source form or + documentation, if provided along with the Derivative Works; or, + within a display generated by the Derivative Works, if and + wherever such third-party notices normally appear. The contents + of the NOTICE file are for informational purposes only and + do not modify the License. You may add Your own attribution + notices within Derivative Works that You distribute, alongside + or as an addendum to the NOTICE text from the Work, provided + that such additional attribution notices cannot be construed + as modifying the License. + + You may add Your own copyright statement to Your modifications and + may provide additional or different license terms and conditions + for use, reproduction, or distribution of Your modifications, or + for any such Derivative Works as a whole, provided Your use, + reproduction, and distribution of the Work otherwise complies with + the conditions stated in this License. + + 5. Submission of Contributions. Unless You explicitly state otherwise, + any Contribution intentionally submitted for inclusion in the Work + by You to the Licensor shall be under the terms and conditions of + this License, without any additional terms or conditions. + Notwithstanding the above, nothing herein shall supersede or modify + the terms of any separate license agreement you may have executed + with Licensor regarding such Contributions. + + 6. Trademarks. This License does not grant permission to use the trade + names, trademarks, service marks, or product names of the Licensor, + except as required for reasonable and customary use in describing the + origin of the Work and reproducing the content of the NOTICE file. + + 7. Disclaimer of Warranty. Unless required by applicable law or + agreed to in writing, Licensor provides the Work (and each + Contributor provides its Contributions) on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + implied, including, without limitation, any warranties or conditions + of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A + PARTICULAR PURPOSE. You are solely responsible for determining the + appropriateness of using or redistributing the Work and assume any + risks associated with Your exercise of permissions under this License. + + 8. Limitation of Liability. In no event and under no legal theory, + whether in tort (including negligence), contract, or otherwise, + unless required by applicable law (such as deliberate and grossly + negligent acts) or agreed to in writing, shall any Contributor be + liable to You for damages, including any direct, indirect, special, + incidental, or consequential damages of any character arising as a + result of this License or out of the use or inability to use the + Work (including but not limited to damages for loss of goodwill, + work stoppage, computer failure or malfunction, or any and all + other commercial damages or losses), even if such Contributor + has been advised of the possibility of such damages. + + 9. Accepting Warranty or Additional Liability. While redistributing + the Work or Derivative Works thereof, You may choose to offer, + and charge a fee for, acceptance of support, warranty, indemnity, + or other liability obligations and/or rights consistent with this + License. However, in accepting such obligations, You may act only + on Your own behalf and on Your sole responsibility, not on behalf + of any other Contributor, and only if You agree to indemnify, + defend, and hold each Contributor harmless for any liability + incurred by, or claims asserted against, such Contributor by reason + of your accepting any such warranty or additional liability. + + END OF TERMS AND CONDITIONS + + APPENDIX: How to apply the Apache License to your work. + + To apply the Apache License to your work, attach the following + boilerplate notice, with the fields enclosed by brackets "[]" + replaced with your own identifying information. (Don't include + the brackets!) The text should be enclosed in the appropriate + comment syntax for the file format. We also recommend that a + file or class name and description of purpose be included on the + same "printed page" as the copyright notice for easier + identification within third-party archives. + + Copyright [yyyy] [name of copyright owner] + + Licensed 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. + +========== +Notice for: aws-sdk-v1-1.67.0 +---------- + +Copyright 2011-2015 Amazon.com, Inc. or its affiliates. All Rights Reserved. + +Licensed under the Apache License, Version 2.0 (the "License"). You +may not use this file except in compliance with the License. A copy of +the License is located at + + http://aws.amazon.com/apache2.0/ + +or in the "license" file accompanying this file. This file 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. +========== +Notice for: aws-sigv4-1.1.0 +---------- + +copyright 2013. amazon web services, inc. all rights reserved. + + Apache License + Version 2.0, January 2004 + http://www.apache.org/licenses/ + + TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION + + 1. Definitions. + + "License" shall mean the terms and conditions for use, reproduction, + and distribution as defined by Sections 1 through 9 of this document. + + "Licensor" shall mean the copyright owner or entity authorized by + the copyright owner that is granting the License. + + "Legal Entity" shall mean the union of the acting entity and all + other entities that control, are controlled by, or are under common + control with that entity. For the purposes of this definition, + "control" means (i) the power, direct or indirect, to cause the + direction or management of such entity, whether by contract or + otherwise, or (ii) ownership of fifty percent (50%) or more of the + outstanding shares, or (iii) beneficial ownership of such entity. + + "You" (or "Your") shall mean an individual or Legal Entity + exercising permissions granted by this License. + + "Source" form shall mean the preferred form for making modifications, + including but not limited to software source code, documentation + source, and configuration files. + + "Object" form shall mean any form resulting from mechanical + transformation or translation of a Source form, including but + not limited to compiled object code, generated documentation, + and conversions to other media types. + + "Work" shall mean the work of authorship, whether in Source or + Object form, made available under the License, as indicated by a + copyright notice that is included in or attached to the work + (an example is provided in the Appendix below). + + "Derivative Works" shall mean any work, whether in Source or Object + form, that is based on (or derived from) the Work and for which the + editorial revisions, annotations, elaborations, or other modifications + represent, as a whole, an original work of authorship. For the purposes + of this License, Derivative Works shall not include works that remain + separable from, or merely link (or bind by name) to the interfaces of, + the Work and Derivative Works thereof. + + "Contribution" shall mean any work of authorship, including + the original version of the Work and any modifications or additions + to that Work or Derivative Works thereof, that is intentionally + submitted to Licensor for inclusion in the Work by the copyright owner + or by an individual or Legal Entity authorized to submit on behalf of + the copyright owner. For the purposes of this definition, "submitted" + means any form of electronic, verbal, or written communication sent + to the Licensor or its representatives, including but not limited to + communication on electronic mailing lists, source code control systems, + and issue tracking systems that are managed by, or on behalf of, the + Licensor for the purpose of discussing and improving the Work, but + excluding communication that is conspicuously marked or otherwise + designated in writing by the copyright owner as "Not a Contribution." + + "Contributor" shall mean Licensor and any individual or Legal Entity + on behalf of whom a Contribution has been received by Licensor and + subsequently incorporated within the Work. + + 2. Grant of Copyright License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + copyright license to reproduce, prepare Derivative Works of, + publicly display, publicly perform, sublicense, and distribute the + Work and such Derivative Works in Source or Object form. + + 3. Grant of Patent License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + (except as stated in this section) patent license to make, have made, + use, offer to sell, sell, import, and otherwise transfer the Work, + where such license applies only to those patent claims licensable + by such Contributor that are necessarily infringed by their + Contribution(s) alone or by combination of their Contribution(s) + with the Work to which such Contribution(s) was submitted. If You + institute patent litigation against any entity (including a + cross-claim or counterclaim in a lawsuit) alleging that the Work + or a Contribution incorporated within the Work constitutes direct + or contributory patent infringement, then any patent licenses + granted to You under this License for that Work shall terminate + as of the date such litigation is filed. + + 4. Redistribution. You may reproduce and distribute copies of the + Work or Derivative Works thereof in any medium, with or without + modifications, and in Source or Object form, provided that You + meet the following conditions: + + (a) You must give any other recipients of the Work or + Derivative Works a copy of this License; and + + (b) You must cause any modified files to carry prominent notices + stating that You changed the files; and + + (c) You must retain, in the Source form of any Derivative Works + that You distribute, all copyright, patent, trademark, and + attribution notices from the Source form of the Work, + excluding those notices that do not pertain to any part of + the Derivative Works; and + + (d) If the Work includes a "NOTICE" text file as part of its + distribution, then any Derivative Works that You distribute must + include a readable copy of the attribution notices contained + within such NOTICE file, excluding those notices that do not + pertain to any part of the Derivative Works, in at least one + of the following places: within a NOTICE text file distributed + as part of the Derivative Works; within the Source form or + documentation, if provided along with the Derivative Works; or, + within a display generated by the Derivative Works, if and + wherever such third-party notices normally appear. The contents + of the NOTICE file are for informational purposes only and + do not modify the License. You may add Your own attribution + notices within Derivative Works that You distribute, alongside + or as an addendum to the NOTICE text from the Work, provided + that such additional attribution notices cannot be construed + as modifying the License. + + You may add Your own copyright statement to Your modifications and + may provide additional or different license terms and conditions + for use, reproduction, or distribution of Your modifications, or + for any such Derivative Works as a whole, provided Your use, + reproduction, and distribution of the Work otherwise complies with + the conditions stated in this License. + + 5. Submission of Contributions. Unless You explicitly state otherwise, + any Contribution intentionally submitted for inclusion in the Work + by You to the Licensor shall be under the terms and conditions of + this License, without any additional terms or conditions. + Notwithstanding the above, nothing herein shall supersede or modify + the terms of any separate license agreement you may have executed + with Licensor regarding such Contributions. + + 6. Trademarks. This License does not grant permission to use the trade + names, trademarks, service marks, or product names of the Licensor, + except as required for reasonable and customary use in describing the + origin of the Work and reproducing the content of the NOTICE file. + + 7. Disclaimer of Warranty. Unless required by applicable law or + agreed to in writing, Licensor provides the Work (and each + Contributor provides its Contributions) on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + implied, including, without limitation, any warranties or conditions + of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A + PARTICULAR PURPOSE. You are solely responsible for determining the + appropriateness of using or redistributing the Work and assume any + risks associated with Your exercise of permissions under this License. + + 8. Limitation of Liability. In no event and under no legal theory, + whether in tort (including negligence), contract, or otherwise, + unless required by applicable law (such as deliberate and grossly + negligent acts) or agreed to in writing, shall any Contributor be + liable to You for damages, including any direct, indirect, special, + incidental, or consequential damages of any character arising as a + result of this License or out of the use or inability to use the + Work (including but not limited to damages for loss of goodwill, + work stoppage, computer failure or malfunction, or any and all + other commercial damages or losses), even if such Contributor + has been advised of the possibility of such damages. + + 9. Accepting Warranty or Additional Liability. While redistributing + the Work or Derivative Works thereof, You may choose to offer, + and charge a fee for, acceptance of support, warranty, indemnity, + or other liability obligations and/or rights consistent with this + License. However, in accepting such obligations, You may act only + on Your own behalf and on Your sole responsibility, not on behalf + of any other Contributor, and only if You agree to indemnify, + defend, and hold each Contributor harmless for any liability + incurred by, or claims asserted against, such Contributor by reason + of your accepting any such warranty or additional liability. + + END OF TERMS AND CONDITIONS + + APPENDIX: How to apply the Apache License to your work. + + To apply the Apache License to your work, attach the following + boilerplate notice, with the fields enclosed by brackets "[]" + replaced with your own identifying information. (Don't include + the brackets!) The text should be enclosed in the appropriate + comment syntax for the file format. We also recommend that a + file or class name and description of purpose be included on the + same "printed page" as the copyright notice for easier + identification within third-party archives. + + Copyright [yyyy] [name of copyright owner] + + Licensed 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. + +========== +Notice for: back_pressure-1.0.0 +---------- + +Copyright [yyyy] [name of copyright owner] + +Licensed 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. + +========== +Notice for: bindata-2.4.4 +---------- + +Copyright (C) 2007-2012 Dion Mendel. All rights reserved. + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions +are met: +1. Redistributions of source code must retain the above copyright +notice, this list of conditions and the following disclaimer. +2. Redistributions in binary form must reproduce the above copyright +notice, this list of conditions and the following disclaimer in the +documentation and/or other materials provided with the distribution. + +THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND +ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE +FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL +DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS +OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) +HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT +LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY +OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF +SUCH DAMAGE. + +========== +Notice for: buftok-0.2.0 +---------- + +Copyright (c) 2006-2013 Tony Arcieri, Martin Emde, Erik Michaels-Ober. Distributed under the [Ruby license][license]. [license]: http://www.ruby-lang.org/en/LICENSE.txt + +Ruby is copyrighted free software by Yukihiro Matsumoto . +You can redistribute it and/or modify it under either the terms of the +2-clause BSDL (see the file BSDL), or the conditions below: + + 1. You may make and give away verbatim copies of the source form of the + software without restriction, provided that you duplicate all of the + original copyright notices and associated disclaimers. + + 2. You may modify your copy of the software in any way, provided that + you do at least ONE of the following: + + a) place your modifications in the Public Domain or otherwise + make them Freely Available, such as by posting said + modifications to Usenet or an equivalent medium, or by allowing + the author to include your modifications in the software. + + b) use the modified software only within your corporation or + organization. + + c) give non-standard binaries non-standard names, with + instructions on where to get the original software distribution. + + d) make other distribution arrangements with the author. + + 3. You may distribute the software in object code or binary form, + provided that you do at least ONE of the following: + + a) distribute the binaries and library files of the software, + together with instructions (in the manual page or equivalent) + on where to get the original distribution. + + b) accompany the distribution with the machine-readable source of + the software. + + c) give non-standard binaries non-standard names, with + instructions on where to get the original software distribution. + + d) make other distribution arrangements with the author. + + 4. You may modify and include the part of the software into any other + software (possibly commercial). But some files in the distribution + are not written by the author, so that they are not under these terms. + + For the list of those files and their copying conditions, see the + file LEGAL. + + 5. The scripts and library files supplied as input to or produced as + output from the software do not automatically fall under the + copyright of the software, but belong to whomever generated them, + and may be sold commercially, and may be aggregated with this + software. + + 6. THIS SOFTWARE IS PROVIDED "AS IS" AND WITHOUT ANY EXPRESS OR + IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED + WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + PURPOSE. + +========== +Notice for: builder-3.2.4 +---------- + +Copyright (c) 2003-2012 Jim Weirich (jim.weirich@gmail.com) + +Permission is hereby granted, free of charge, to any person obtaining +a copy of this software and associated documentation files (the +"Software"), to deal in the Software without restriction, including +without limitation the rights to use, copy, modify, merge, publish, +distribute, sublicense, and/or sell copies of the Software, and to +permit persons to whom the Software is furnished to do so, subject to +the following conditions: + +The above copyright notice and this permission notice shall be +included in all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +========== +Notice for: bundler-1.17.3 +---------- + +Portions copyright (c) 2010 Andre Arko +Portions copyright (c) 2009 Engine Yard + +MIT License + +Permission is hereby granted, free of charge, to any person obtaining +a copy of this software and associated documentation files (the +"Software"), to deal in the Software without restriction, including +without limitation the rights to use, copy, modify, merge, publish, +distribute, sublicense, and/or sell copies of the Software, and to +permit persons to whom the Software is furnished to do so, subject to +the following conditions: + +The above copyright notice and this permission notice shall be +included in all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +========== +Notice for: cabin-0.9.0 +---------- + +Copyright 2011 Jordan Sissel + +Licensed 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. + + +========== +Notice for: chronic_duration-0.10.6 +---------- + +Copyright (c) Henry Poydar + +Permission is hereby granted, free of charge, to any person +obtaining a copy of this software and associated documentation +files (the "Software"), to deal in the Software without +restriction, including without limitation the rights to use, +copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the +Software is furnished to do so, subject to the following +conditions: + +The above copyright notice and this permission notice shall be +included in all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES +OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT +HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, +WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING +FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR +OTHER DEALINGS IN THE SOFTWARE. +========== +Notice for: clamp-0.6.5 +---------- + +Copyright (c) 2010 Mike Williams + +Permission is hereby granted, free of charge, to any person obtaining +a copy of this software and associated documentation files (the +"Software"), to deal in the Software without restriction, including +without limitation the rights to use, copy, modify, merge, publish, +distribute, sublicense, and/or sell copies of the Software, and to +permit persons to whom the Software is furnished to do so, subject to +the following conditions: + +The above copyright notice and this permission notice shall be +included in all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + +========== +Notice for: coderay-1.1.2 +---------- + +Copyright (C) 2005-2012 Kornelius Kalnbach (@murphy_karasu) + +http://coderay.rubychan.de/ + +Permission is hereby granted, free of charge, to any person obtaining +a copy of this software and associated documentation files (the +"Software"), to deal in the Software without restriction, including +without limitation the rights to use, copy, modify, merge, publish, +distribute, sublicense, and/or sell copies of the Software, and to +permit persons to whom the Software is furnished to do so, subject to +the following conditions: + +The above copyright notice and this permission notice shall be +included in all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +========== +Notice for: com.fasterxml.jackson.core:jackson-annotations-2.9.10 +---------- + +This copy of Jackson JSON processor annotations is licensed under the +Apache (Software) License, version 2.0 ("the License"). +See the License for details about distribution rights, and the +specific rights regarding derivate works. + +You may obtain a copy of the License at: + +http://www.apache.org/licenses/LICENSE-2.0 + + + + Apache License + Version 2.0, January 2004 + http://www.apache.org/licenses/ + + TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION + + 1. Definitions. + + "License" shall mean the terms and conditions for use, reproduction, + and distribution as defined by Sections 1 through 9 of this document. + + "Licensor" shall mean the copyright owner or entity authorized by + the copyright owner that is granting the License. + + "Legal Entity" shall mean the union of the acting entity and all + other entities that control, are controlled by, or are under common + control with that entity. For the purposes of this definition, + "control" means (i) the power, direct or indirect, to cause the + direction or management of such entity, whether by contract or + otherwise, or (ii) ownership of fifty percent (50%) or more of the + outstanding shares, or (iii) beneficial ownership of such entity. + + "You" (or "Your") shall mean an individual or Legal Entity + exercising permissions granted by this License. + + "Source" form shall mean the preferred form for making modifications, + including but not limited to software source code, documentation + source, and configuration files. + + "Object" form shall mean any form resulting from mechanical + transformation or translation of a Source form, including but + not limited to compiled object code, generated documentation, + and conversions to other media types. + + "Work" shall mean the work of authorship, whether in Source or + Object form, made available under the License, as indicated by a + copyright notice that is included in or attached to the work + (an example is provided in the Appendix below). + + "Derivative Works" shall mean any work, whether in Source or Object + form, that is based on (or derived from) the Work and for which the + editorial revisions, annotations, elaborations, or other modifications + represent, as a whole, an original work of authorship. For the purposes + of this License, Derivative Works shall not include works that remain + separable from, or merely link (or bind by name) to the interfaces of, + the Work and Derivative Works thereof. + + "Contribution" shall mean any work of authorship, including + the original version of the Work and any modifications or additions + to that Work or Derivative Works thereof, that is intentionally + submitted to Licensor for inclusion in the Work by the copyright owner + or by an individual or Legal Entity authorized to submit on behalf of + the copyright owner. For the purposes of this definition, "submitted" + means any form of electronic, verbal, or written communication sent + to the Licensor or its representatives, including but not limited to + communication on electronic mailing lists, source code control systems, + and issue tracking systems that are managed by, or on behalf of, the + Licensor for the purpose of discussing and improving the Work, but + excluding communication that is conspicuously marked or otherwise + designated in writing by the copyright owner as "Not a Contribution." + + "Contributor" shall mean Licensor and any individual or Legal Entity + on behalf of whom a Contribution has been received by Licensor and + subsequently incorporated within the Work. + + 2. Grant of Copyright License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + copyright license to reproduce, prepare Derivative Works of, + publicly display, publicly perform, sublicense, and distribute the + Work and such Derivative Works in Source or Object form. + + 3. Grant of Patent License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + (except as stated in this section) patent license to make, have made, + use, offer to sell, sell, import, and otherwise transfer the Work, + where such license applies only to those patent claims licensable + by such Contributor that are necessarily infringed by their + Contribution(s) alone or by combination of their Contribution(s) + with the Work to which such Contribution(s) was submitted. If You + institute patent litigation against any entity (including a + cross-claim or counterclaim in a lawsuit) alleging that the Work + or a Contribution incorporated within the Work constitutes direct + or contributory patent infringement, then any patent licenses + granted to You under this License for that Work shall terminate + as of the date such litigation is filed. + + 4. Redistribution. You may reproduce and distribute copies of the + Work or Derivative Works thereof in any medium, with or without + modifications, and in Source or Object form, provided that You + meet the following conditions: + + (a) You must give any other recipients of the Work or + Derivative Works a copy of this License; and + + (b) You must cause any modified files to carry prominent notices + stating that You changed the files; and + + (c) You must retain, in the Source form of any Derivative Works + that You distribute, all copyright, patent, trademark, and + attribution notices from the Source form of the Work, + excluding those notices that do not pertain to any part of + the Derivative Works; and + + (d) If the Work includes a "NOTICE" text file as part of its + distribution, then any Derivative Works that You distribute must + include a readable copy of the attribution notices contained + within such NOTICE file, excluding those notices that do not + pertain to any part of the Derivative Works, in at least one + of the following places: within a NOTICE text file distributed + as part of the Derivative Works; within the Source form or + documentation, if provided along with the Derivative Works; or, + within a display generated by the Derivative Works, if and + wherever such third-party notices normally appear. The contents + of the NOTICE file are for informational purposes only and + do not modify the License. You may add Your own attribution + notices within Derivative Works that You distribute, alongside + or as an addendum to the NOTICE text from the Work, provided + that such additional attribution notices cannot be construed + as modifying the License. + + You may add Your own copyright statement to Your modifications and + may provide additional or different license terms and conditions + for use, reproduction, or distribution of Your modifications, or + for any such Derivative Works as a whole, provided Your use, + reproduction, and distribution of the Work otherwise complies with + the conditions stated in this License. + + 5. Submission of Contributions. Unless You explicitly state otherwise, + any Contribution intentionally submitted for inclusion in the Work + by You to the Licensor shall be under the terms and conditions of + this License, without any additional terms or conditions. + Notwithstanding the above, nothing herein shall supersede or modify + the terms of any separate license agreement you may have executed + with Licensor regarding such Contributions. + + 6. Trademarks. This License does not grant permission to use the trade + names, trademarks, service marks, or product names of the Licensor, + except as required for reasonable and customary use in describing the + origin of the Work and reproducing the content of the NOTICE file. + + 7. Disclaimer of Warranty. Unless required by applicable law or + agreed to in writing, Licensor provides the Work (and each + Contributor provides its Contributions) on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + implied, including, without limitation, any warranties or conditions + of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A + PARTICULAR PURPOSE. You are solely responsible for determining the + appropriateness of using or redistributing the Work and assume any + risks associated with Your exercise of permissions under this License. + + 8. Limitation of Liability. In no event and under no legal theory, + whether in tort (including negligence), contract, or otherwise, + unless required by applicable law (such as deliberate and grossly + negligent acts) or agreed to in writing, shall any Contributor be + liable to You for damages, including any direct, indirect, special, + incidental, or consequential damages of any character arising as a + result of this License or out of the use or inability to use the + Work (including but not limited to damages for loss of goodwill, + work stoppage, computer failure or malfunction, or any and all + other commercial damages or losses), even if such Contributor + has been advised of the possibility of such damages. + + 9. Accepting Warranty or Additional Liability. While redistributing + the Work or Derivative Works thereof, You may choose to offer, + and charge a fee for, acceptance of support, warranty, indemnity, + or other liability obligations and/or rights consistent with this + License. However, in accepting such obligations, You may act only + on Your own behalf and on Your sole responsibility, not on behalf + of any other Contributor, and only if You agree to indemnify, + defend, and hold each Contributor harmless for any liability + incurred by, or claims asserted against, such Contributor by reason + of your accepting any such warranty or additional liability. + + END OF TERMS AND CONDITIONS + + APPENDIX: How to apply the Apache License to your work. + + To apply the Apache License to your work, attach the following + boilerplate notice, with the fields enclosed by brackets "[]" + replaced with your own identifying information. (Don't include + the brackets!) The text should be enclosed in the appropriate + comment syntax for the file format. We also recommend that a + file or class name and description of purpose be included on the + same "printed page" as the copyright notice for easier + identification within third-party archives. + + Copyright [yyyy] [name of copyright owner] + + Licensed 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. + +========== +Notice for: com.fasterxml.jackson.core:jackson-core-2.9.10 +---------- + +# Jackson JSON processor + +Jackson is a high-performance, Free/Open Source JSON processing library. +It was originally written by Tatu Saloranta (tatu.saloranta@iki.fi), and has +been in development since 2007. +It is currently developed by a community of developers, as well as supported +commercially by FasterXML.com. + +## Licensing + +Jackson core and extension components may licensed under different licenses. +To find the details that apply to this artifact see the accompanying LICENSE file. +For more information, including possible other licensing options, contact +FasterXML.com (http://fasterxml.com). + +## Credits + +A list of contributors may be found from CREDITS file, which is included +in some artifacts (usually source distributions); but is always available +from the source code management (SCM) system project uses. + + + Apache License + Version 2.0, January 2004 + http://www.apache.org/licenses/ + + TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION + + 1. Definitions. + + "License" shall mean the terms and conditions for use, reproduction, + and distribution as defined by Sections 1 through 9 of this document. + + "Licensor" shall mean the copyright owner or entity authorized by + the copyright owner that is granting the License. + + "Legal Entity" shall mean the union of the acting entity and all + other entities that control, are controlled by, or are under common + control with that entity. For the purposes of this definition, + "control" means (i) the power, direct or indirect, to cause the + direction or management of such entity, whether by contract or + otherwise, or (ii) ownership of fifty percent (50%) or more of the + outstanding shares, or (iii) beneficial ownership of such entity. + + "You" (or "Your") shall mean an individual or Legal Entity + exercising permissions granted by this License. + + "Source" form shall mean the preferred form for making modifications, + including but not limited to software source code, documentation + source, and configuration files. + + "Object" form shall mean any form resulting from mechanical + transformation or translation of a Source form, including but + not limited to compiled object code, generated documentation, + and conversions to other media types. + + "Work" shall mean the work of authorship, whether in Source or + Object form, made available under the License, as indicated by a + copyright notice that is included in or attached to the work + (an example is provided in the Appendix below). + + "Derivative Works" shall mean any work, whether in Source or Object + form, that is based on (or derived from) the Work and for which the + editorial revisions, annotations, elaborations, or other modifications + represent, as a whole, an original work of authorship. For the purposes + of this License, Derivative Works shall not include works that remain + separable from, or merely link (or bind by name) to the interfaces of, + the Work and Derivative Works thereof. + + "Contribution" shall mean any work of authorship, including + the original version of the Work and any modifications or additions + to that Work or Derivative Works thereof, that is intentionally + submitted to Licensor for inclusion in the Work by the copyright owner + or by an individual or Legal Entity authorized to submit on behalf of + the copyright owner. For the purposes of this definition, "submitted" + means any form of electronic, verbal, or written communication sent + to the Licensor or its representatives, including but not limited to + communication on electronic mailing lists, source code control systems, + and issue tracking systems that are managed by, or on behalf of, the + Licensor for the purpose of discussing and improving the Work, but + excluding communication that is conspicuously marked or otherwise + designated in writing by the copyright owner as "Not a Contribution." + + "Contributor" shall mean Licensor and any individual or Legal Entity + on behalf of whom a Contribution has been received by Licensor and + subsequently incorporated within the Work. + + 2. Grant of Copyright License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + copyright license to reproduce, prepare Derivative Works of, + publicly display, publicly perform, sublicense, and distribute the + Work and such Derivative Works in Source or Object form. + + 3. Grant of Patent License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + (except as stated in this section) patent license to make, have made, + use, offer to sell, sell, import, and otherwise transfer the Work, + where such license applies only to those patent claims licensable + by such Contributor that are necessarily infringed by their + Contribution(s) alone or by combination of their Contribution(s) + with the Work to which such Contribution(s) was submitted. If You + institute patent litigation against any entity (including a + cross-claim or counterclaim in a lawsuit) alleging that the Work + or a Contribution incorporated within the Work constitutes direct + or contributory patent infringement, then any patent licenses + granted to You under this License for that Work shall terminate + as of the date such litigation is filed. + + 4. Redistribution. You may reproduce and distribute copies of the + Work or Derivative Works thereof in any medium, with or without + modifications, and in Source or Object form, provided that You + meet the following conditions: + + (a) You must give any other recipients of the Work or + Derivative Works a copy of this License; and + + (b) You must cause any modified files to carry prominent notices + stating that You changed the files; and + + (c) You must retain, in the Source form of any Derivative Works + that You distribute, all copyright, patent, trademark, and + attribution notices from the Source form of the Work, + excluding those notices that do not pertain to any part of + the Derivative Works; and + + (d) If the Work includes a "NOTICE" text file as part of its + distribution, then any Derivative Works that You distribute must + include a readable copy of the attribution notices contained + within such NOTICE file, excluding those notices that do not + pertain to any part of the Derivative Works, in at least one + of the following places: within a NOTICE text file distributed + as part of the Derivative Works; within the Source form or + documentation, if provided along with the Derivative Works; or, + within a display generated by the Derivative Works, if and + wherever such third-party notices normally appear. The contents + of the NOTICE file are for informational purposes only and + do not modify the License. You may add Your own attribution + notices within Derivative Works that You distribute, alongside + or as an addendum to the NOTICE text from the Work, provided + that such additional attribution notices cannot be construed + as modifying the License. + + You may add Your own copyright statement to Your modifications and + may provide additional or different license terms and conditions + for use, reproduction, or distribution of Your modifications, or + for any such Derivative Works as a whole, provided Your use, + reproduction, and distribution of the Work otherwise complies with + the conditions stated in this License. + + 5. Submission of Contributions. Unless You explicitly state otherwise, + any Contribution intentionally submitted for inclusion in the Work + by You to the Licensor shall be under the terms and conditions of + this License, without any additional terms or conditions. + Notwithstanding the above, nothing herein shall supersede or modify + the terms of any separate license agreement you may have executed + with Licensor regarding such Contributions. + + 6. Trademarks. This License does not grant permission to use the trade + names, trademarks, service marks, or product names of the Licensor, + except as required for reasonable and customary use in describing the + origin of the Work and reproducing the content of the NOTICE file. + + 7. Disclaimer of Warranty. Unless required by applicable law or + agreed to in writing, Licensor provides the Work (and each + Contributor provides its Contributions) on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + implied, including, without limitation, any warranties or conditions + of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A + PARTICULAR PURPOSE. You are solely responsible for determining the + appropriateness of using or redistributing the Work and assume any + risks associated with Your exercise of permissions under this License. + + 8. Limitation of Liability. In no event and under no legal theory, + whether in tort (including negligence), contract, or otherwise, + unless required by applicable law (such as deliberate and grossly + negligent acts) or agreed to in writing, shall any Contributor be + liable to You for damages, including any direct, indirect, special, + incidental, or consequential damages of any character arising as a + result of this License or out of the use or inability to use the + Work (including but not limited to damages for loss of goodwill, + work stoppage, computer failure or malfunction, or any and all + other commercial damages or losses), even if such Contributor + has been advised of the possibility of such damages. + + 9. Accepting Warranty or Additional Liability. While redistributing + the Work or Derivative Works thereof, You may choose to offer, + and charge a fee for, acceptance of support, warranty, indemnity, + or other liability obligations and/or rights consistent with this + License. However, in accepting such obligations, You may act only + on Your own behalf and on Your sole responsibility, not on behalf + of any other Contributor, and only if You agree to indemnify, + defend, and hold each Contributor harmless for any liability + incurred by, or claims asserted against, such Contributor by reason + of your accepting any such warranty or additional liability. + + END OF TERMS AND CONDITIONS + + APPENDIX: How to apply the Apache License to your work. + + To apply the Apache License to your work, attach the following + boilerplate notice, with the fields enclosed by brackets "[]" + replaced with your own identifying information. (Don't include + the brackets!) The text should be enclosed in the appropriate + comment syntax for the file format. We also recommend that a + file or class name and description of purpose be included on the + same "printed page" as the copyright notice for easier + identification within third-party archives. + + Copyright [yyyy] [name of copyright owner] + + Licensed 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. +========== +Notice for: com.fasterxml.jackson.core:jackson-databind-2.9.10.1 +---------- + +# Jackson JSON processor + +Jackson is a high-performance, Free/Open Source JSON processing library. +It was originally written by Tatu Saloranta (tatu.saloranta@iki.fi), and has +been in development since 2007. +It is currently developed by a community of developers, as well as supported +commercially by FasterXML.com. + +## Licensing + +Jackson core and extension components may be licensed under different licenses. +To find the details that apply to this artifact see the accompanying LICENSE file. +For more information, including possible other licensing options, contact +FasterXML.com (http://fasterxml.com). + +## Credits + +A list of contributors may be found from CREDITS file, which is included +in some artifacts (usually source distributions); but is always available +from the source code management (SCM) system project uses. + +This copy of Jackson JSON processor databind module is licensed under the +Apache (Software) License, version 2.0 ("the License"). +See the License for details about distribution rights, and the +specific rights regarding derivate works. + +You may obtain a copy of the License at: + +http://www.apache.org/licenses/LICENSE-2.0 + + + Apache License + Version 2.0, January 2004 + http://www.apache.org/licenses/ + + TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION + + 1. Definitions. + + "License" shall mean the terms and conditions for use, reproduction, + and distribution as defined by Sections 1 through 9 of this document. + + "Licensor" shall mean the copyright owner or entity authorized by + the copyright owner that is granting the License. + + "Legal Entity" shall mean the union of the acting entity and all + other entities that control, are controlled by, or are under common + control with that entity. For the purposes of this definition, + "control" means (i) the power, direct or indirect, to cause the + direction or management of such entity, whether by contract or + otherwise, or (ii) ownership of fifty percent (50%) or more of the + outstanding shares, or (iii) beneficial ownership of such entity. + + "You" (or "Your") shall mean an individual or Legal Entity + exercising permissions granted by this License. + + "Source" form shall mean the preferred form for making modifications, + including but not limited to software source code, documentation + source, and configuration files. + + "Object" form shall mean any form resulting from mechanical + transformation or translation of a Source form, including but + not limited to compiled object code, generated documentation, + and conversions to other media types. + + "Work" shall mean the work of authorship, whether in Source or + Object form, made available under the License, as indicated by a + copyright notice that is included in or attached to the work + (an example is provided in the Appendix below). + + "Derivative Works" shall mean any work, whether in Source or Object + form, that is based on (or derived from) the Work and for which the + editorial revisions, annotations, elaborations, or other modifications + represent, as a whole, an original work of authorship. For the purposes + of this License, Derivative Works shall not include works that remain + separable from, or merely link (or bind by name) to the interfaces of, + the Work and Derivative Works thereof. + + "Contribution" shall mean any work of authorship, including + the original version of the Work and any modifications or additions + to that Work or Derivative Works thereof, that is intentionally + submitted to Licensor for inclusion in the Work by the copyright owner + or by an individual or Legal Entity authorized to submit on behalf of + the copyright owner. For the purposes of this definition, "submitted" + means any form of electronic, verbal, or written communication sent + to the Licensor or its representatives, including but not limited to + communication on electronic mailing lists, source code control systems, + and issue tracking systems that are managed by, or on behalf of, the + Licensor for the purpose of discussing and improving the Work, but + excluding communication that is conspicuously marked or otherwise + designated in writing by the copyright owner as "Not a Contribution." + + "Contributor" shall mean Licensor and any individual or Legal Entity + on behalf of whom a Contribution has been received by Licensor and + subsequently incorporated within the Work. + + 2. Grant of Copyright License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + copyright license to reproduce, prepare Derivative Works of, + publicly display, publicly perform, sublicense, and distribute the + Work and such Derivative Works in Source or Object form. + + 3. Grant of Patent License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + (except as stated in this section) patent license to make, have made, + use, offer to sell, sell, import, and otherwise transfer the Work, + where such license applies only to those patent claims licensable + by such Contributor that are necessarily infringed by their + Contribution(s) alone or by combination of their Contribution(s) + with the Work to which such Contribution(s) was submitted. If You + institute patent litigation against any entity (including a + cross-claim or counterclaim in a lawsuit) alleging that the Work + or a Contribution incorporated within the Work constitutes direct + or contributory patent infringement, then any patent licenses + granted to You under this License for that Work shall terminate + as of the date such litigation is filed. + + 4. Redistribution. You may reproduce and distribute copies of the + Work or Derivative Works thereof in any medium, with or without + modifications, and in Source or Object form, provided that You + meet the following conditions: + + (a) You must give any other recipients of the Work or + Derivative Works a copy of this License; and + + (b) You must cause any modified files to carry prominent notices + stating that You changed the files; and + + (c) You must retain, in the Source form of any Derivative Works + that You distribute, all copyright, patent, trademark, and + attribution notices from the Source form of the Work, + excluding those notices that do not pertain to any part of + the Derivative Works; and + + (d) If the Work includes a "NOTICE" text file as part of its + distribution, then any Derivative Works that You distribute must + include a readable copy of the attribution notices contained + within such NOTICE file, excluding those notices that do not + pertain to any part of the Derivative Works, in at least one + of the following places: within a NOTICE text file distributed + as part of the Derivative Works; within the Source form or + documentation, if provided along with the Derivative Works; or, + within a display generated by the Derivative Works, if and + wherever such third-party notices normally appear. The contents + of the NOTICE file are for informational purposes only and + do not modify the License. You may add Your own attribution + notices within Derivative Works that You distribute, alongside + or as an addendum to the NOTICE text from the Work, provided + that such additional attribution notices cannot be construed + as modifying the License. + + You may add Your own copyright statement to Your modifications and + may provide additional or different license terms and conditions + for use, reproduction, or distribution of Your modifications, or + for any such Derivative Works as a whole, provided Your use, + reproduction, and distribution of the Work otherwise complies with + the conditions stated in this License. + + 5. Submission of Contributions. Unless You explicitly state otherwise, + any Contribution intentionally submitted for inclusion in the Work + by You to the Licensor shall be under the terms and conditions of + this License, without any additional terms or conditions. + Notwithstanding the above, nothing herein shall supersede or modify + the terms of any separate license agreement you may have executed + with Licensor regarding such Contributions. + + 6. Trademarks. This License does not grant permission to use the trade + names, trademarks, service marks, or product names of the Licensor, + except as required for reasonable and customary use in describing the + origin of the Work and reproducing the content of the NOTICE file. + + 7. Disclaimer of Warranty. Unless required by applicable law or + agreed to in writing, Licensor provides the Work (and each + Contributor provides its Contributions) on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + implied, including, without limitation, any warranties or conditions + of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A + PARTICULAR PURPOSE. You are solely responsible for determining the + appropriateness of using or redistributing the Work and assume any + risks associated with Your exercise of permissions under this License. + + 8. Limitation of Liability. In no event and under no legal theory, + whether in tort (including negligence), contract, or otherwise, + unless required by applicable law (such as deliberate and grossly + negligent acts) or agreed to in writing, shall any Contributor be + liable to You for damages, including any direct, indirect, special, + incidental, or consequential damages of any character arising as a + result of this License or out of the use or inability to use the + Work (including but not limited to damages for loss of goodwill, + work stoppage, computer failure or malfunction, or any and all + other commercial damages or losses), even if such Contributor + has been advised of the possibility of such damages. + + 9. Accepting Warranty or Additional Liability. While redistributing + the Work or Derivative Works thereof, You may choose to offer, + and charge a fee for, acceptance of support, warranty, indemnity, + or other liability obligations and/or rights consistent with this + License. However, in accepting such obligations, You may act only + on Your own behalf and on Your sole responsibility, not on behalf + of any other Contributor, and only if You agree to indemnify, + defend, and hold each Contributor harmless for any liability + incurred by, or claims asserted against, such Contributor by reason + of your accepting any such warranty or additional liability. + + END OF TERMS AND CONDITIONS + + APPENDIX: How to apply the Apache License to your work. + + To apply the Apache License to your work, attach the following + boilerplate notice, with the fields enclosed by brackets "[]" + replaced with your own identifying information. (Don't include + the brackets!) The text should be enclosed in the appropriate + comment syntax for the file format. We also recommend that a + file or class name and description of purpose be included on the + same "printed page" as the copyright notice for easier + identification within third-party archives. + + Copyright [yyyy] [name of copyright owner] + + Licensed 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. +========== +Notice for: com.fasterxml.jackson.dataformat:jackson-dataformat-cbor-2.9.10 +---------- + +This copy of Jackson JSON processor databind module is licensed under the +Apache (Software) License, version 2.0 ("the License"). +See the License for details about distribution rights, and the +specific rights regarding derivate works. + +You may obtain a copy of the License at: + +http://www.apache.org/licenses/LICENSE-2.0 + + + Apache License + Version 2.0, January 2004 + http://www.apache.org/licenses/ + + TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION + + 1. Definitions. + + "License" shall mean the terms and conditions for use, reproduction, + and distribution as defined by Sections 1 through 9 of this document. + + "Licensor" shall mean the copyright owner or entity authorized by + the copyright owner that is granting the License. + + "Legal Entity" shall mean the union of the acting entity and all + other entities that control, are controlled by, or are under common + control with that entity. For the purposes of this definition, + "control" means (i) the power, direct or indirect, to cause the + direction or management of such entity, whether by contract or + otherwise, or (ii) ownership of fifty percent (50%) or more of the + outstanding shares, or (iii) beneficial ownership of such entity. + + "You" (or "Your") shall mean an individual or Legal Entity + exercising permissions granted by this License. + + "Source" form shall mean the preferred form for making modifications, + including but not limited to software source code, documentation + source, and configuration files. + + "Object" form shall mean any form resulting from mechanical + transformation or translation of a Source form, including but + not limited to compiled object code, generated documentation, + and conversions to other media types. + + "Work" shall mean the work of authorship, whether in Source or + Object form, made available under the License, as indicated by a + copyright notice that is included in or attached to the work + (an example is provided in the Appendix below). + + "Derivative Works" shall mean any work, whether in Source or Object + form, that is based on (or derived from) the Work and for which the + editorial revisions, annotations, elaborations, or other modifications + represent, as a whole, an original work of authorship. For the purposes + of this License, Derivative Works shall not include works that remain + separable from, or merely link (or bind by name) to the interfaces of, + the Work and Derivative Works thereof. + + "Contribution" shall mean any work of authorship, including + the original version of the Work and any modifications or additions + to that Work or Derivative Works thereof, that is intentionally + submitted to Licensor for inclusion in the Work by the copyright owner + or by an individual or Legal Entity authorized to submit on behalf of + the copyright owner. For the purposes of this definition, "submitted" + means any form of electronic, verbal, or written communication sent + to the Licensor or its representatives, including but not limited to + communication on electronic mailing lists, source code control systems, + and issue tracking systems that are managed by, or on behalf of, the + Licensor for the purpose of discussing and improving the Work, but + excluding communication that is conspicuously marked or otherwise + designated in writing by the copyright owner as "Not a Contribution." + + "Contributor" shall mean Licensor and any individual or Legal Entity + on behalf of whom a Contribution has been received by Licensor and + subsequently incorporated within the Work. + + 2. Grant of Copyright License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + copyright license to reproduce, prepare Derivative Works of, + publicly display, publicly perform, sublicense, and distribute the + Work and such Derivative Works in Source or Object form. + + 3. Grant of Patent License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + (except as stated in this section) patent license to make, have made, + use, offer to sell, sell, import, and otherwise transfer the Work, + where such license applies only to those patent claims licensable + by such Contributor that are necessarily infringed by their + Contribution(s) alone or by combination of their Contribution(s) + with the Work to which such Contribution(s) was submitted. If You + institute patent litigation against any entity (including a + cross-claim or counterclaim in a lawsuit) alleging that the Work + or a Contribution incorporated within the Work constitutes direct + or contributory patent infringement, then any patent licenses + granted to You under this License for that Work shall terminate + as of the date such litigation is filed. + + 4. Redistribution. You may reproduce and distribute copies of the + Work or Derivative Works thereof in any medium, with or without + modifications, and in Source or Object form, provided that You + meet the following conditions: + + (a) You must give any other recipients of the Work or + Derivative Works a copy of this License; and + + (b) You must cause any modified files to carry prominent notices + stating that You changed the files; and + + (c) You must retain, in the Source form of any Derivative Works + that You distribute, all copyright, patent, trademark, and + attribution notices from the Source form of the Work, + excluding those notices that do not pertain to any part of + the Derivative Works; and + + (d) If the Work includes a "NOTICE" text file as part of its + distribution, then any Derivative Works that You distribute must + include a readable copy of the attribution notices contained + within such NOTICE file, excluding those notices that do not + pertain to any part of the Derivative Works, in at least one + of the following places: within a NOTICE text file distributed + as part of the Derivative Works; within the Source form or + documentation, if provided along with the Derivative Works; or, + within a display generated by the Derivative Works, if and + wherever such third-party notices normally appear. The contents + of the NOTICE file are for informational purposes only and + do not modify the License. You may add Your own attribution + notices within Derivative Works that You distribute, alongside + or as an addendum to the NOTICE text from the Work, provided + that such additional attribution notices cannot be construed + as modifying the License. + + You may add Your own copyright statement to Your modifications and + may provide additional or different license terms and conditions + for use, reproduction, or distribution of Your modifications, or + for any such Derivative Works as a whole, provided Your use, + reproduction, and distribution of the Work otherwise complies with + the conditions stated in this License. + + 5. Submission of Contributions. Unless You explicitly state otherwise, + any Contribution intentionally submitted for inclusion in the Work + by You to the Licensor shall be under the terms and conditions of + this License, without any additional terms or conditions. + Notwithstanding the above, nothing herein shall supersede or modify + the terms of any separate license agreement you may have executed + with Licensor regarding such Contributions. + + 6. Trademarks. This License does not grant permission to use the trade + names, trademarks, service marks, or product names of the Licensor, + except as required for reasonable and customary use in describing the + origin of the Work and reproducing the content of the NOTICE file. + + 7. Disclaimer of Warranty. Unless required by applicable law or + agreed to in writing, Licensor provides the Work (and each + Contributor provides its Contributions) on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + implied, including, without limitation, any warranties or conditions + of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A + PARTICULAR PURPOSE. You are solely responsible for determining the + appropriateness of using or redistributing the Work and assume any + risks associated with Your exercise of permissions under this License. + + 8. Limitation of Liability. In no event and under no legal theory, + whether in tort (including negligence), contract, or otherwise, + unless required by applicable law (such as deliberate and grossly + negligent acts) or agreed to in writing, shall any Contributor be + liable to You for damages, including any direct, indirect, special, + incidental, or consequential damages of any character arising as a + result of this License or out of the use or inability to use the + Work (including but not limited to damages for loss of goodwill, + work stoppage, computer failure or malfunction, or any and all + other commercial damages or losses), even if such Contributor + has been advised of the possibility of such damages. + + 9. Accepting Warranty or Additional Liability. While redistributing + the Work or Derivative Works thereof, You may choose to offer, + and charge a fee for, acceptance of support, warranty, indemnity, + or other liability obligations and/or rights consistent with this + License. However, in accepting such obligations, You may act only + on Your own behalf and on Your sole responsibility, not on behalf + of any other Contributor, and only if You agree to indemnify, + defend, and hold each Contributor harmless for any liability + incurred by, or claims asserted against, such Contributor by reason + of your accepting any such warranty or additional liability. + + END OF TERMS AND CONDITIONS + + APPENDIX: How to apply the Apache License to your work. + + To apply the Apache License to your work, attach the following + boilerplate notice, with the fields enclosed by brackets "[]" + replaced with your own identifying information. (Don't include + the brackets!) The text should be enclosed in the appropriate + comment syntax for the file format. We also recommend that a + file or class name and description of purpose be included on the + same "printed page" as the copyright notice for easier + identification within third-party archives. + + Copyright [yyyy] [name of copyright owner] + + Licensed 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. +========== +Notice for: com.fasterxml.jackson.module:jackson-module-afterburner-2.9.10 +---------- + +This copy of Jackson JSON processor databind module is licensed under the +Apache (Software) License, version 2.0 ("the License"). +See the License for details about distribution rights, and the +specific rights regarding derivate works. + +You may obtain a copy of the License at: + +http://www.apache.org/licenses/LICENSE-2.0 + + + Apache License + Version 2.0, January 2004 + http://www.apache.org/licenses/ + + TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION + + 1. Definitions. + + "License" shall mean the terms and conditions for use, reproduction, + and distribution as defined by Sections 1 through 9 of this document. + + "Licensor" shall mean the copyright owner or entity authorized by + the copyright owner that is granting the License. + + "Legal Entity" shall mean the union of the acting entity and all + other entities that control, are controlled by, or are under common + control with that entity. For the purposes of this definition, + "control" means (i) the power, direct or indirect, to cause the + direction or management of such entity, whether by contract or + otherwise, or (ii) ownership of fifty percent (50%) or more of the + outstanding shares, or (iii) beneficial ownership of such entity. + + "You" (or "Your") shall mean an individual or Legal Entity + exercising permissions granted by this License. + + "Source" form shall mean the preferred form for making modifications, + including but not limited to software source code, documentation + source, and configuration files. + + "Object" form shall mean any form resulting from mechanical + transformation or translation of a Source form, including but + not limited to compiled object code, generated documentation, + and conversions to other media types. + + "Work" shall mean the work of authorship, whether in Source or + Object form, made available under the License, as indicated by a + copyright notice that is included in or attached to the work + (an example is provided in the Appendix below). + + "Derivative Works" shall mean any work, whether in Source or Object + form, that is based on (or derived from) the Work and for which the + editorial revisions, annotations, elaborations, or other modifications + represent, as a whole, an original work of authorship. For the purposes + of this License, Derivative Works shall not include works that remain + separable from, or merely link (or bind by name) to the interfaces of, + the Work and Derivative Works thereof. + + "Contribution" shall mean any work of authorship, including + the original version of the Work and any modifications or additions + to that Work or Derivative Works thereof, that is intentionally + submitted to Licensor for inclusion in the Work by the copyright owner + or by an individual or Legal Entity authorized to submit on behalf of + the copyright owner. For the purposes of this definition, "submitted" + means any form of electronic, verbal, or written communication sent + to the Licensor or its representatives, including but not limited to + communication on electronic mailing lists, source code control systems, + and issue tracking systems that are managed by, or on behalf of, the + Licensor for the purpose of discussing and improving the Work, but + excluding communication that is conspicuously marked or otherwise + designated in writing by the copyright owner as "Not a Contribution." + + "Contributor" shall mean Licensor and any individual or Legal Entity + on behalf of whom a Contribution has been received by Licensor and + subsequently incorporated within the Work. + + 2. Grant of Copyright License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + copyright license to reproduce, prepare Derivative Works of, + publicly display, publicly perform, sublicense, and distribute the + Work and such Derivative Works in Source or Object form. + + 3. Grant of Patent License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + (except as stated in this section) patent license to make, have made, + use, offer to sell, sell, import, and otherwise transfer the Work, + where such license applies only to those patent claims licensable + by such Contributor that are necessarily infringed by their + Contribution(s) alone or by combination of their Contribution(s) + with the Work to which such Contribution(s) was submitted. If You + institute patent litigation against any entity (including a + cross-claim or counterclaim in a lawsuit) alleging that the Work + or a Contribution incorporated within the Work constitutes direct + or contributory patent infringement, then any patent licenses + granted to You under this License for that Work shall terminate + as of the date such litigation is filed. + + 4. Redistribution. You may reproduce and distribute copies of the + Work or Derivative Works thereof in any medium, with or without + modifications, and in Source or Object form, provided that You + meet the following conditions: + + (a) You must give any other recipients of the Work or + Derivative Works a copy of this License; and + + (b) You must cause any modified files to carry prominent notices + stating that You changed the files; and + + (c) You must retain, in the Source form of any Derivative Works + that You distribute, all copyright, patent, trademark, and + attribution notices from the Source form of the Work, + excluding those notices that do not pertain to any part of + the Derivative Works; and + + (d) If the Work includes a "NOTICE" text file as part of its + distribution, then any Derivative Works that You distribute must + include a readable copy of the attribution notices contained + within such NOTICE file, excluding those notices that do not + pertain to any part of the Derivative Works, in at least one + of the following places: within a NOTICE text file distributed + as part of the Derivative Works; within the Source form or + documentation, if provided along with the Derivative Works; or, + within a display generated by the Derivative Works, if and + wherever such third-party notices normally appear. The contents + of the NOTICE file are for informational purposes only and + do not modify the License. You may add Your own attribution + notices within Derivative Works that You distribute, alongside + or as an addendum to the NOTICE text from the Work, provided + that such additional attribution notices cannot be construed + as modifying the License. + + You may add Your own copyright statement to Your modifications and + may provide additional or different license terms and conditions + for use, reproduction, or distribution of Your modifications, or + for any such Derivative Works as a whole, provided Your use, + reproduction, and distribution of the Work otherwise complies with + the conditions stated in this License. + + 5. Submission of Contributions. Unless You explicitly state otherwise, + any Contribution intentionally submitted for inclusion in the Work + by You to the Licensor shall be under the terms and conditions of + this License, without any additional terms or conditions. + Notwithstanding the above, nothing herein shall supersede or modify + the terms of any separate license agreement you may have executed + with Licensor regarding such Contributions. + + 6. Trademarks. This License does not grant permission to use the trade + names, trademarks, service marks, or product names of the Licensor, + except as required for reasonable and customary use in describing the + origin of the Work and reproducing the content of the NOTICE file. + + 7. Disclaimer of Warranty. Unless required by applicable law or + agreed to in writing, Licensor provides the Work (and each + Contributor provides its Contributions) on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + implied, including, without limitation, any warranties or conditions + of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A + PARTICULAR PURPOSE. You are solely responsible for determining the + appropriateness of using or redistributing the Work and assume any + risks associated with Your exercise of permissions under this License. + + 8. Limitation of Liability. In no event and under no legal theory, + whether in tort (including negligence), contract, or otherwise, + unless required by applicable law (such as deliberate and grossly + negligent acts) or agreed to in writing, shall any Contributor be + liable to You for damages, including any direct, indirect, special, + incidental, or consequential damages of any character arising as a + result of this License or out of the use or inability to use the + Work (including but not limited to damages for loss of goodwill, + work stoppage, computer failure or malfunction, or any and all + other commercial damages or losses), even if such Contributor + has been advised of the possibility of such damages. + + 9. Accepting Warranty or Additional Liability. While redistributing + the Work or Derivative Works thereof, You may choose to offer, + and charge a fee for, acceptance of support, warranty, indemnity, + or other liability obligations and/or rights consistent with this + License. However, in accepting such obligations, You may act only + on Your own behalf and on Your sole responsibility, not on behalf + of any other Contributor, and only if You agree to indemnify, + defend, and hold each Contributor harmless for any liability + incurred by, or claims asserted against, such Contributor by reason + of your accepting any such warranty or additional liability. + + END OF TERMS AND CONDITIONS + + APPENDIX: How to apply the Apache License to your work. + + To apply the Apache License to your work, attach the following + boilerplate notice, with the fields enclosed by brackets "[]" + replaced with your own identifying information. (Don't include + the brackets!) The text should be enclosed in the appropriate + comment syntax for the file format. We also recommend that a + file or class name and description of purpose be included on the + same "printed page" as the copyright notice for easier + identification within third-party archives. + + Copyright [yyyy] [name of copyright owner] + + Licensed 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. +========== +Notice for: com.google.code.findbugs:jsr305-1.3.9 +---------- + +Cannot find NOTICE.txt for the relatively old jsr305:1.3.9. Per https://search.maven.org/artifact/com.google.code.findbugs/jsr305/1.3.9/jar, the original source repo is at http://findbugs.googlecode.com/svn/trunk and is now defunct. + +========== +Notice for: com.google.errorprone:error_prone_annotations-2.0.18 +---------- + +Apache License + Version 2.0, January 2004 + http://www.apache.org/licenses/ + + TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION + + 1. Definitions. + + "License" shall mean the terms and conditions for use, reproduction, + and distribution as defined by Sections 1 through 9 of this document. + + "Licensor" shall mean the copyright owner or entity authorized by + the copyright owner that is granting the License. + + "Legal Entity" shall mean the union of the acting entity and all + other entities that control, are controlled by, or are under common + control with that entity. For the purposes of this definition, + "control" means (i) the power, direct or indirect, to cause the + direction or management of such entity, whether by contract or + otherwise, or (ii) ownership of fifty percent (50%) or more of the + outstanding shares, or (iii) beneficial ownership of such entity. + + "You" (or "Your") shall mean an individual or Legal Entity + exercising permissions granted by this License. + + "Source" form shall mean the preferred form for making modifications, + including but not limited to software source code, documentation + source, and configuration files. + + "Object" form shall mean any form resulting from mechanical + transformation or translation of a Source form, including but + not limited to compiled object code, generated documentation, + and conversions to other media types. + + "Work" shall mean the work of authorship, whether in Source or + Object form, made available under the License, as indicated by a + copyright notice that is included in or attached to the work + (an example is provided in the Appendix below). + + "Derivative Works" shall mean any work, whether in Source or Object + form, that is based on (or derived from) the Work and for which the + editorial revisions, annotations, elaborations, or other modifications + represent, as a whole, an original work of authorship. For the purposes + of this License, Derivative Works shall not include works that remain + separable from, or merely link (or bind by name) to the interfaces of, + the Work and Derivative Works thereof. + + "Contribution" shall mean any work of authorship, including + the original version of the Work and any modifications or additions + to that Work or Derivative Works thereof, that is intentionally + submitted to Licensor for inclusion in the Work by the copyright owner + or by an individual or Legal Entity authorized to submit on behalf of + the copyright owner. For the purposes of this definition, "submitted" + means any form of electronic, verbal, or written communication sent + to the Licensor or its representatives, including but not limited to + communication on electronic mailing lists, source code control systems, + and issue tracking systems that are managed by, or on behalf of, the + Licensor for the purpose of discussing and improving the Work, but + excluding communication that is conspicuously marked or otherwise + designated in writing by the copyright owner as "Not a Contribution." + + "Contributor" shall mean Licensor and any individual or Legal Entity + on behalf of whom a Contribution has been received by Licensor and + subsequently incorporated within the Work. + + 2. Grant of Copyright License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + copyright license to reproduce, prepare Derivative Works of, + publicly display, publicly perform, sublicense, and distribute the + Work and such Derivative Works in Source or Object form. + + 3. Grant of Patent License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + (except as stated in this section) patent license to make, have made, + use, offer to sell, sell, import, and otherwise transfer the Work, + where such license applies only to those patent claims licensable + by such Contributor that are necessarily infringed by their + Contribution(s) alone or by combination of their Contribution(s) + with the Work to which such Contribution(s) was submitted. If You + institute patent litigation against any entity (including a + cross-claim or counterclaim in a lawsuit) alleging that the Work + or a Contribution incorporated within the Work constitutes direct + or contributory patent infringement, then any patent licenses + granted to You under this License for that Work shall terminate + as of the date such litigation is filed. + + 4. Redistribution. You may reproduce and distribute copies of the + Work or Derivative Works thereof in any medium, with or without + modifications, and in Source or Object form, provided that You + meet the following conditions: + + (a) You must give any other recipients of the Work or + Derivative Works a copy of this License; and + + (b) You must cause any modified files to carry prominent notices + stating that You changed the files; and + + (c) You must retain, in the Source form of any Derivative Works + that You distribute, all copyright, patent, trademark, and + attribution notices from the Source form of the Work, + excluding those notices that do not pertain to any part of + the Derivative Works; and + + (d) If the Work includes a "NOTICE" text file as part of its + distribution, then any Derivative Works that You distribute must + include a readable copy of the attribution notices contained + within such NOTICE file, excluding those notices that do not + pertain to any part of the Derivative Works, in at least one + of the following places: within a NOTICE text file distributed + as part of the Derivative Works; within the Source form or + documentation, if provided along with the Derivative Works; or, + within a display generated by the Derivative Works, if and + wherever such third-party notices normally appear. The contents + of the NOTICE file are for informational purposes only and + do not modify the License. You may add Your own attribution + notices within Derivative Works that You distribute, alongside + or as an addendum to the NOTICE text from the Work, provided + that such additional attribution notices cannot be construed + as modifying the License. + + You may add Your own copyright statement to Your modifications and + may provide additional or different license terms and conditions + for use, reproduction, or distribution of Your modifications, or + for any such Derivative Works as a whole, provided Your use, + reproduction, and distribution of the Work otherwise complies with + the conditions stated in this License. + + 5. Submission of Contributions. Unless You explicitly state otherwise, + any Contribution intentionally submitted for inclusion in the Work + by You to the Licensor shall be under the terms and conditions of + this License, without any additional terms or conditions. + Notwithstanding the above, nothing herein shall supersede or modify + the terms of any separate license agreement you may have executed + with Licensor regarding such Contributions. + + 6. Trademarks. This License does not grant permission to use the trade + names, trademarks, service marks, or product names of the Licensor, + except as required for reasonable and customary use in describing the + origin of the Work and reproducing the content of the NOTICE file. + + 7. Disclaimer of Warranty. Unless required by applicable law or + agreed to in writing, Licensor provides the Work (and each + Contributor provides its Contributions) on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + implied, including, without limitation, any warranties or conditions + of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A + PARTICULAR PURPOSE. You are solely responsible for determining the + appropriateness of using or redistributing the Work and assume any + risks associated with Your exercise of permissions under this License. + + 8. Limitation of Liability. In no event and under no legal theory, + whether in tort (including negligence), contract, or otherwise, + unless required by applicable law (such as deliberate and grossly + negligent acts) or agreed to in writing, shall any Contributor be + liable to You for damages, including any direct, indirect, special, + incidental, or consequential damages of any character arising as a + result of this License or out of the use or inability to use the + Work (including but not limited to damages for loss of goodwill, + work stoppage, computer failure or malfunction, or any and all + other commercial damages or losses), even if such Contributor + has been advised of the possibility of such damages. + + 9. Accepting Warranty or Additional Liability. While redistributing + the Work or Derivative Works thereof, You may choose to offer, + and charge a fee for, acceptance of support, warranty, indemnity, + or other liability obligations and/or rights consistent with this + License. However, in accepting such obligations, You may act only + on Your own behalf and on Your sole responsibility, not on behalf + of any other Contributor, and only if You agree to indemnify, + defend, and hold each Contributor harmless for any liability + incurred by, or claims asserted against, such Contributor by reason + of your accepting any such warranty or additional liability. + + END OF TERMS AND CONDITIONS + + APPENDIX: How to apply the Apache License to your work. + + To apply the Apache License to your work, attach the following + boilerplate notice, with the fields enclosed by brackets "[]" + replaced with your own identifying information. (Don't include + the brackets!) The text should be enclosed in the appropriate + comment syntax for the file format. We also recommend that a + file or class name and description of purpose be included on the + same "printed page" as the copyright notice for easier + identification within third-party archives. + + Copyright [yyyy] [name of copyright owner] + + Licensed 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. + + +========== +Notice for: com.google.googlejavaformat:google-java-format-1.1 +---------- + +Copyright 2015 Google Inc. + + Apache License + Version 2.0, January 2004 + http://www.apache.org/licenses/ + + TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION + + 1. Definitions. + + "License" shall mean the terms and conditions for use, reproduction, + and distribution as defined by Sections 1 through 9 of this document. + + "Licensor" shall mean the copyright owner or entity authorized by + the copyright owner that is granting the License. + + "Legal Entity" shall mean the union of the acting entity and all + other entities that control, are controlled by, or are under common + control with that entity. For the purposes of this definition, + "control" means (i) the power, direct or indirect, to cause the + direction or management of such entity, whether by contract or + otherwise, or (ii) ownership of fifty percent (50%) or more of the + outstanding shares, or (iii) beneficial ownership of such entity. + + "You" (or "Your") shall mean an individual or Legal Entity + exercising permissions granted by this License. + + "Source" form shall mean the preferred form for making modifications, + including but not limited to software source code, documentation + source, and configuration files. + + "Object" form shall mean any form resulting from mechanical + transformation or translation of a Source form, including but + not limited to compiled object code, generated documentation, + and conversions to other media types. + + "Work" shall mean the work of authorship, whether in Source or + Object form, made available under the License, as indicated by a + copyright notice that is included in or attached to the work + (an example is provided in the Appendix below). + + "Derivative Works" shall mean any work, whether in Source or Object + form, that is based on (or derived from) the Work and for which the + editorial revisions, annotations, elaborations, or other modifications + represent, as a whole, an original work of authorship. For the purposes + of this License, Derivative Works shall not include works that remain + separable from, or merely link (or bind by name) to the interfaces of, + the Work and Derivative Works thereof. + + "Contribution" shall mean any work of authorship, including + the original version of the Work and any modifications or additions + to that Work or Derivative Works thereof, that is intentionally + submitted to Licensor for inclusion in the Work by the copyright owner + or by an individual or Legal Entity authorized to submit on behalf of + the copyright owner. For the purposes of this definition, "submitted" + means any form of electronic, verbal, or written communication sent + to the Licensor or its representatives, including but not limited to + communication on electronic mailing lists, source code control systems, + and issue tracking systems that are managed by, or on behalf of, the + Licensor for the purpose of discussing and improving the Work, but + excluding communication that is conspicuously marked or otherwise + designated in writing by the copyright owner as "Not a Contribution." + + "Contributor" shall mean Licensor and any individual or Legal Entity + on behalf of whom a Contribution has been received by Licensor and + subsequently incorporated within the Work. + + 2. Grant of Copyright License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + copyright license to reproduce, prepare Derivative Works of, + publicly display, publicly perform, sublicense, and distribute the + Work and such Derivative Works in Source or Object form. + + 3. Grant of Patent License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + (except as stated in this section) patent license to make, have made, + use, offer to sell, sell, import, and otherwise transfer the Work, + where such license applies only to those patent claims licensable + by such Contributor that are necessarily infringed by their + Contribution(s) alone or by combination of their Contribution(s) + with the Work to which such Contribution(s) was submitted. If You + institute patent litigation against any entity (including a + cross-claim or counterclaim in a lawsuit) alleging that the Work + or a Contribution incorporated within the Work constitutes direct + or contributory patent infringement, then any patent licenses + granted to You under this License for that Work shall terminate + as of the date such litigation is filed. + + 4. Redistribution. You may reproduce and distribute copies of the + Work or Derivative Works thereof in any medium, with or without + modifications, and in Source or Object form, provided that You + meet the following conditions: + + (a) You must give any other recipients of the Work or + Derivative Works a copy of this License; and + + (b) You must cause any modified files to carry prominent notices + stating that You changed the files; and + + (c) You must retain, in the Source form of any Derivative Works + that You distribute, all copyright, patent, trademark, and + attribution notices from the Source form of the Work, + excluding those notices that do not pertain to any part of + the Derivative Works; and + + (d) If the Work includes a "NOTICE" text file as part of its + distribution, then any Derivative Works that You distribute must + include a readable copy of the attribution notices contained + within such NOTICE file, excluding those notices that do not + pertain to any part of the Derivative Works, in at least one + of the following places: within a NOTICE text file distributed + as part of the Derivative Works; within the Source form or + documentation, if provided along with the Derivative Works; or, + within a display generated by the Derivative Works, if and + wherever such third-party notices normally appear. The contents + of the NOTICE file are for informational purposes only and + do not modify the License. You may add Your own attribution + notices within Derivative Works that You distribute, alongside + or as an addendum to the NOTICE text from the Work, provided + that such additional attribution notices cannot be construed + as modifying the License. + + You may add Your own copyright statement to Your modifications and + may provide additional or different license terms and conditions + for use, reproduction, or distribution of Your modifications, or + for any such Derivative Works as a whole, provided Your use, + reproduction, and distribution of the Work otherwise complies with + the conditions stated in this License. + + 5. Submission of Contributions. Unless You explicitly state otherwise, + any Contribution intentionally submitted for inclusion in the Work + by You to the Licensor shall be under the terms and conditions of + this License, without any additional terms or conditions. + Notwithstanding the above, nothing herein shall supersede or modify + the terms of any separate license agreement you may have executed + with Licensor regarding such Contributions. + + 6. Trademarks. This License does not grant permission to use the trade + names, trademarks, service marks, or product names of the Licensor, + except as required for reasonable and customary use in describing the + origin of the Work and reproducing the content of the NOTICE file. + + 7. Disclaimer of Warranty. Unless required by applicable law or + agreed to in writing, Licensor provides the Work (and each + Contributor provides its Contributions) on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + implied, including, without limitation, any warranties or conditions + of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A + PARTICULAR PURPOSE. You are solely responsible for determining the + appropriateness of using or redistributing the Work and assume any + risks associated with Your exercise of permissions under this License. + + 8. Limitation of Liability. In no event and under no legal theory, + whether in tort (including negligence), contract, or otherwise, + unless required by applicable law (such as deliberate and grossly + negligent acts) or agreed to in writing, shall any Contributor be + liable to You for damages, including any direct, indirect, special, + incidental, or consequential damages of any character arising as a + result of this License or out of the use or inability to use the + Work (including but not limited to damages for loss of goodwill, + work stoppage, computer failure or malfunction, or any and all + other commercial damages or losses), even if such Contributor + has been advised of the possibility of such damages. + + 9. Accepting Warranty or Additional Liability. While redistributing + the Work or Derivative Works thereof, You may choose to offer, + and charge a fee for, acceptance of support, warranty, indemnity, + or other liability obligations and/or rights consistent with this + License. However, in accepting such obligations, You may act only + on Your own behalf and on Your sole responsibility, not on behalf + of any other Contributor, and only if You agree to indemnify, + defend, and hold each Contributor harmless for any liability + incurred by, or claims asserted against, such Contributor by reason + of your accepting any such warranty or additional liability. + + END OF TERMS AND CONDITIONS + + APPENDIX: How to apply the Apache License to your work. + + To apply the Apache License to your work, attach the following + boilerplate notice, with the fields enclosed by brackets "[]" + replaced with your own identifying information. (Don't include + the brackets!) The text should be enclosed in the appropriate + comment syntax for the file format. We also recommend that a + file or class name and description of purpose be included on the + same "printed page" as the copyright notice for easier + identification within third-party archives. + + Copyright [yyyy] [name of copyright owner] + + Licensed 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. + +------------------------------------------------------------------------------ + +The following NCSA license applies only to google-java-format-diff.py. + +============================================================================== +LLVM Release License +============================================================================== +University of Illinois/NCSA +Open Source License + +Copyright (c) 2007-2015 University of Illinois at Urbana-Champaign. +All rights reserved. + +Developed by: + + LLVM Team + + University of Illinois at Urbana-Champaign + + http://llvm.org + +Permission is hereby granted, free of charge, to any person obtaining a copy of +this software and associated documentation files (the "Software"), to deal with +the Software without restriction, including without limitation the rights to +use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies +of the Software, and to permit persons to whom the Software is furnished to do +so, subject to the following conditions: + + * Redistributions of source code must retain the above copyright notice, + this list of conditions and the following disclaimers. + + * Redistributions in binary form must reproduce the above copyright notice, + this list of conditions and the following disclaimers in the + documentation and/or other materials provided with the distribution. + + * Neither the names of the LLVM Team, University of Illinois at + Urbana-Champaign, nor the names of its contributors may be used to + endorse or promote products derived from this Software without specific + prior written permission. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS +FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +CONTRIBUTORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS WITH THE +SOFTWARE. + +============================================================================== +The LLVM software contains code written by third parties. Such software will +have its own individual LICENSE.TXT file in the directory in which it appears. +This file will describe the copyrights, license, and restrictions which apply +to that code. + +The disclaimer of warranty in the University of Illinois Open Source License +applies to all code in the LLVM Distribution, and nothing in any of the +other licenses gives permission to use the names of the LLVM Team or the +University of Illinois to endorse or promote products derived from this +Software. + +The following pieces of software have additional or alternate copyrights, +licenses, and/or restrictions: + +Program Directory +------- --------- + + + +========== +Notice for: com.google.guava:guava-22.0 +---------- + + + Apache License + Version 2.0, January 2004 + http://www.apache.org/licenses/ + + TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION + + 1. Definitions. + + "License" shall mean the terms and conditions for use, reproduction, + and distribution as defined by Sections 1 through 9 of this document. + + "Licensor" shall mean the copyright owner or entity authorized by + the copyright owner that is granting the License. + + "Legal Entity" shall mean the union of the acting entity and all + other entities that control, are controlled by, or are under common + control with that entity. For the purposes of this definition, + "control" means (i) the power, direct or indirect, to cause the + direction or management of such entity, whether by contract or + otherwise, or (ii) ownership of fifty percent (50%) or more of the + outstanding shares, or (iii) beneficial ownership of such entity. + + "You" (or "Your") shall mean an individual or Legal Entity + exercising permissions granted by this License. + + "Source" form shall mean the preferred form for making modifications, + including but not limited to software source code, documentation + source, and configuration files. + + "Object" form shall mean any form resulting from mechanical + transformation or translation of a Source form, including but + not limited to compiled object code, generated documentation, + and conversions to other media types. + + "Work" shall mean the work of authorship, whether in Source or + Object form, made available under the License, as indicated by a + copyright notice that is included in or attached to the work + (an example is provided in the Appendix below). + + "Derivative Works" shall mean any work, whether in Source or Object + form, that is based on (or derived from) the Work and for which the + editorial revisions, annotations, elaborations, or other modifications + represent, as a whole, an original work of authorship. For the purposes + of this License, Derivative Works shall not include works that remain + separable from, or merely link (or bind by name) to the interfaces of, + the Work and Derivative Works thereof. + + "Contribution" shall mean any work of authorship, including + the original version of the Work and any modifications or additions + to that Work or Derivative Works thereof, that is intentionally + submitted to Licensor for inclusion in the Work by the copyright owner + or by an individual or Legal Entity authorized to submit on behalf of + the copyright owner. For the purposes of this definition, "submitted" + means any form of electronic, verbal, or written communication sent + to the Licensor or its representatives, including but not limited to + communication on electronic mailing lists, source code control systems, + and issue tracking systems that are managed by, or on behalf of, the + Licensor for the purpose of discussing and improving the Work, but + excluding communication that is conspicuously marked or otherwise + designated in writing by the copyright owner as "Not a Contribution." + + "Contributor" shall mean Licensor and any individual or Legal Entity + on behalf of whom a Contribution has been received by Licensor and + subsequently incorporated within the Work. + + 2. Grant of Copyright License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + copyright license to reproduce, prepare Derivative Works of, + publicly display, publicly perform, sublicense, and distribute the + Work and such Derivative Works in Source or Object form. + + 3. Grant of Patent License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + (except as stated in this section) patent license to make, have made, + use, offer to sell, sell, import, and otherwise transfer the Work, + where such license applies only to those patent claims licensable + by such Contributor that are necessarily infringed by their + Contribution(s) alone or by combination of their Contribution(s) + with the Work to which such Contribution(s) was submitted. If You + institute patent litigation against any entity (including a + cross-claim or counterclaim in a lawsuit) alleging that the Work + or a Contribution incorporated within the Work constitutes direct + or contributory patent infringement, then any patent licenses + granted to You under this License for that Work shall terminate + as of the date such litigation is filed. + + 4. Redistribution. You may reproduce and distribute copies of the + Work or Derivative Works thereof in any medium, with or without + modifications, and in Source or Object form, provided that You + meet the following conditions: + + (a) You must give any other recipients of the Work or + Derivative Works a copy of this License; and + + (b) You must cause any modified files to carry prominent notices + stating that You changed the files; and + + (c) You must retain, in the Source form of any Derivative Works + that You distribute, all copyright, patent, trademark, and + attribution notices from the Source form of the Work, + excluding those notices that do not pertain to any part of + the Derivative Works; and + + (d) If the Work includes a "NOTICE" text file as part of its + distribution, then any Derivative Works that You distribute must + include a readable copy of the attribution notices contained + within such NOTICE file, excluding those notices that do not + pertain to any part of the Derivative Works, in at least one + of the following places: within a NOTICE text file distributed + as part of the Derivative Works; within the Source form or + documentation, if provided along with the Derivative Works; or, + within a display generated by the Derivative Works, if and + wherever such third-party notices normally appear. The contents + of the NOTICE file are for informational purposes only and + do not modify the License. You may add Your own attribution + notices within Derivative Works that You distribute, alongside + or as an addendum to the NOTICE text from the Work, provided + that such additional attribution notices cannot be construed + as modifying the License. + + You may add Your own copyright statement to Your modifications and + may provide additional or different license terms and conditions + for use, reproduction, or distribution of Your modifications, or + for any such Derivative Works as a whole, provided Your use, + reproduction, and distribution of the Work otherwise complies with + the conditions stated in this License. + + 5. Submission of Contributions. Unless You explicitly state otherwise, + any Contribution intentionally submitted for inclusion in the Work + by You to the Licensor shall be under the terms and conditions of + this License, without any additional terms or conditions. + Notwithstanding the above, nothing herein shall supersede or modify + the terms of any separate license agreement you may have executed + with Licensor regarding such Contributions. + + 6. Trademarks. This License does not grant permission to use the trade + names, trademarks, service marks, or product names of the Licensor, + except as required for reasonable and customary use in describing the + origin of the Work and reproducing the content of the NOTICE file. + + 7. Disclaimer of Warranty. Unless required by applicable law or + agreed to in writing, Licensor provides the Work (and each + Contributor provides its Contributions) on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + implied, including, without limitation, any warranties or conditions + of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A + PARTICULAR PURPOSE. You are solely responsible for determining the + appropriateness of using or redistributing the Work and assume any + risks associated with Your exercise of permissions under this License. + + 8. Limitation of Liability. In no event and under no legal theory, + whether in tort (including negligence), contract, or otherwise, + unless required by applicable law (such as deliberate and grossly + negligent acts) or agreed to in writing, shall any Contributor be + liable to You for damages, including any direct, indirect, special, + incidental, or consequential damages of any character arising as a + result of this License or out of the use or inability to use the + Work (including but not limited to damages for loss of goodwill, + work stoppage, computer failure or malfunction, or any and all + other commercial damages or losses), even if such Contributor + has been advised of the possibility of such damages. + + 9. Accepting Warranty or Additional Liability. While redistributing + the Work or Derivative Works thereof, You may choose to offer, + and charge a fee for, acceptance of support, warranty, indemnity, + or other liability obligations and/or rights consistent with this + License. However, in accepting such obligations, You may act only + on Your own behalf and on Your sole responsibility, not on behalf + of any other Contributor, and only if You agree to indemnify, + defend, and hold each Contributor harmless for any liability + incurred by, or claims asserted against, such Contributor by reason + of your accepting any such warranty or additional liability. + + END OF TERMS AND CONDITIONS + + APPENDIX: How to apply the Apache License to your work. + + To apply the Apache License to your work, attach the following + boilerplate notice, with the fields enclosed by brackets "[]" + replaced with your own identifying information. (Don't include + the brackets!) The text should be enclosed in the appropriate + comment syntax for the file format. We also recommend that a + file or class name and description of purpose be included on the + same "printed page" as the copyright notice for easier + identification within third-party archives. + + Copyright [yyyy] [name of copyright owner] + + Licensed 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. +========== +Notice for: com.google.j2objc:j2objc-annotations-1.1 +---------- + + + Apache License + Version 2.0, January 2004 + http://www.apache.org/licenses/ + + TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION + + 1. Definitions. + + "License" shall mean the terms and conditions for use, reproduction, + and distribution as defined by Sections 1 through 9 of this document. + + "Licensor" shall mean the copyright owner or entity authorized by + the copyright owner that is granting the License. + + "Legal Entity" shall mean the union of the acting entity and all + other entities that control, are controlled by, or are under common + control with that entity. For the purposes of this definition, + "control" means (i) the power, direct or indirect, to cause the + direction or management of such entity, whether by contract or + otherwise, or (ii) ownership of fifty percent (50%) or more of the + outstanding shares, or (iii) beneficial ownership of such entity. + + "You" (or "Your") shall mean an individual or Legal Entity + exercising permissions granted by this License. + + "Source" form shall mean the preferred form for making modifications, + including but not limited to software source code, documentation + source, and configuration files. + + "Object" form shall mean any form resulting from mechanical + transformation or translation of a Source form, including but + not limited to compiled object code, generated documentation, + and conversions to other media types. + + "Work" shall mean the work of authorship, whether in Source or + Object form, made available under the License, as indicated by a + copyright notice that is included in or attached to the work + (an example is provided in the Appendix below). + + "Derivative Works" shall mean any work, whether in Source or Object + form, that is based on (or derived from) the Work and for which the + editorial revisions, annotations, elaborations, or other modifications + represent, as a whole, an original work of authorship. For the purposes + of this License, Derivative Works shall not include works that remain + separable from, or merely link (or bind by name) to the interfaces of, + the Work and Derivative Works thereof. + + "Contribution" shall mean any work of authorship, including + the original version of the Work and any modifications or additions + to that Work or Derivative Works thereof, that is intentionally + submitted to Licensor for inclusion in the Work by the copyright owner + or by an individual or Legal Entity authorized to submit on behalf of + the copyright owner. For the purposes of this definition, "submitted" + means any form of electronic, verbal, or written communication sent + to the Licensor or its representatives, including but not limited to + communication on electronic mailing lists, source code control systems, + and issue tracking systems that are managed by, or on behalf of, the + Licensor for the purpose of discussing and improving the Work, but + excluding communication that is conspicuously marked or otherwise + designated in writing by the copyright owner as "Not a Contribution." + + "Contributor" shall mean Licensor and any individual or Legal Entity + on behalf of whom a Contribution has been received by Licensor and + subsequently incorporated within the Work. + + 2. Grant of Copyright License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + copyright license to reproduce, prepare Derivative Works of, + publicly display, publicly perform, sublicense, and distribute the + Work and such Derivative Works in Source or Object form. + + 3. Grant of Patent License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + (except as stated in this section) patent license to make, have made, + use, offer to sell, sell, import, and otherwise transfer the Work, + where such license applies only to those patent claims licensable + by such Contributor that are necessarily infringed by their + Contribution(s) alone or by combination of their Contribution(s) + with the Work to which such Contribution(s) was submitted. If You + institute patent litigation against any entity (including a + cross-claim or counterclaim in a lawsuit) alleging that the Work + or a Contribution incorporated within the Work constitutes direct + or contributory patent infringement, then any patent licenses + granted to You under this License for that Work shall terminate + as of the date such litigation is filed. + + 4. Redistribution. You may reproduce and distribute copies of the + Work or Derivative Works thereof in any medium, with or without + modifications, and in Source or Object form, provided that You + meet the following conditions: + + (a) You must give any other recipients of the Work or + Derivative Works a copy of this License; and + + (b) You must cause any modified files to carry prominent notices + stating that You changed the files; and + + (c) You must retain, in the Source form of any Derivative Works + that You distribute, all copyright, patent, trademark, and + attribution notices from the Source form of the Work, + excluding those notices that do not pertain to any part of + the Derivative Works; and + + (d) If the Work includes a "NOTICE" text file as part of its + distribution, then any Derivative Works that You distribute must + include a readable copy of the attribution notices contained + within such NOTICE file, excluding those notices that do not + pertain to any part of the Derivative Works, in at least one + of the following places: within a NOTICE text file distributed + as part of the Derivative Works; within the Source form or + documentation, if provided along with the Derivative Works; or, + within a display generated by the Derivative Works, if and + wherever such third-party notices normally appear. The contents + of the NOTICE file are for informational purposes only and + do not modify the License. You may add Your own attribution + notices within Derivative Works that You distribute, alongside + or as an addendum to the NOTICE text from the Work, provided + that such additional attribution notices cannot be construed + as modifying the License. + + You may add Your own copyright statement to Your modifications and + may provide additional or different license terms and conditions + for use, reproduction, or distribution of Your modifications, or + for any such Derivative Works as a whole, provided Your use, + reproduction, and distribution of the Work otherwise complies with + the conditions stated in this License. + + 5. Submission of Contributions. Unless You explicitly state otherwise, + any Contribution intentionally submitted for inclusion in the Work + by You to the Licensor shall be under the terms and conditions of + this License, without any additional terms or conditions. + Notwithstanding the above, nothing herein shall supersede or modify + the terms of any separate license agreement you may have executed + with Licensor regarding such Contributions. + + 6. Trademarks. This License does not grant permission to use the trade + names, trademarks, service marks, or product names of the Licensor, + except as required for reasonable and customary use in describing the + origin of the Work and reproducing the content of the NOTICE file. + + 7. Disclaimer of Warranty. Unless required by applicable law or + agreed to in writing, Licensor provides the Work (and each + Contributor provides its Contributions) on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + implied, including, without limitation, any warranties or conditions + of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A + PARTICULAR PURPOSE. You are solely responsible for determining the + appropriateness of using or redistributing the Work and assume any + risks associated with Your exercise of permissions under this License. + + 8. Limitation of Liability. In no event and under no legal theory, + whether in tort (including negligence), contract, or otherwise, + unless required by applicable law (such as deliberate and grossly + negligent acts) or agreed to in writing, shall any Contributor be + liable to You for damages, including any direct, indirect, special, + incidental, or consequential damages of any character arising as a + result of this License or out of the use or inability to use the + Work (including but not limited to damages for loss of goodwill, + work stoppage, computer failure or malfunction, or any and all + other commercial damages or losses), even if such Contributor + has been advised of the possibility of such damages. + + 9. Accepting Warranty or Additional Liability. While redistributing + the Work or Derivative Works thereof, You may choose to offer, + and charge a fee for, acceptance of support, warranty, indemnity, + or other liability obligations and/or rights consistent with this + License. However, in accepting such obligations, You may act only + on Your own behalf and on Your sole responsibility, not on behalf + of any other Contributor, and only if You agree to indemnify, + defend, and hold each Contributor harmless for any liability + incurred by, or claims asserted against, such Contributor by reason + of your accepting any such warranty or additional liability. + + END OF TERMS AND CONDITIONS + + APPENDIX: How to apply the Apache License to your work. + + To apply the Apache License to your work, attach the following + boilerplate notice, with the fields enclosed by brackets "[]" + replaced with your own identifying information. (Don't include + the brackets!) The text should be enclosed in the appropriate + comment syntax for the file format. We also recommend that a + file or class name and description of purpose be included on the + same "printed page" as the copyright notice for easier + identification within third-party archives. + + Copyright [yyyy] [name of copyright owner] + + Licensed 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. + + +========== +Notice for: commons-codec:commons-codec-1.10.0 +---------- + +Apache Commons Codec +Copyright 2002-2017 The Apache Software Foundation + +This product includes software developed at +The Apache Software Foundation (http://www.apache.org/). + +src/test/org/apache/commons/codec/language/DoubleMetaphoneTest.java +contains test data from http://aspell.net/test/orig/batch0.tab. +Copyright (C) 2002 Kevin Atkinson (kevina@gnu.org) + +=============================================================================== + +The content of package org.apache.commons.codec.language.bm has been translated +from the original php source code available at http://stevemorse.org/phoneticinfo.htm +with permission from the original authors. +Original source copyright: +Copyright (c) 2008 Alexander Beider & Stephen P. Morse. + + + Apache License + Version 2.0, January 2004 + http://www.apache.org/licenses/ + + TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION + + 1. Definitions. + + "License" shall mean the terms and conditions for use, reproduction, + and distribution as defined by Sections 1 through 9 of this document. + + "Licensor" shall mean the copyright owner or entity authorized by + the copyright owner that is granting the License. + + "Legal Entity" shall mean the union of the acting entity and all + other entities that control, are controlled by, or are under common + control with that entity. For the purposes of this definition, + "control" means (i) the power, direct or indirect, to cause the + direction or management of such entity, whether by contract or + otherwise, or (ii) ownership of fifty percent (50%) or more of the + outstanding shares, or (iii) beneficial ownership of such entity. + + "You" (or "Your") shall mean an individual or Legal Entity + exercising permissions granted by this License. + + "Source" form shall mean the preferred form for making modifications, + including but not limited to software source code, documentation + source, and configuration files. + + "Object" form shall mean any form resulting from mechanical + transformation or translation of a Source form, including but + not limited to compiled object code, generated documentation, + and conversions to other media types. + + "Work" shall mean the work of authorship, whether in Source or + Object form, made available under the License, as indicated by a + copyright notice that is included in or attached to the work + (an example is provided in the Appendix below). + + "Derivative Works" shall mean any work, whether in Source or Object + form, that is based on (or derived from) the Work and for which the + editorial revisions, annotations, elaborations, or other modifications + represent, as a whole, an original work of authorship. For the purposes + of this License, Derivative Works shall not include works that remain + separable from, or merely link (or bind by name) to the interfaces of, + the Work and Derivative Works thereof. + + "Contribution" shall mean any work of authorship, including + the original version of the Work and any modifications or additions + to that Work or Derivative Works thereof, that is intentionally + submitted to Licensor for inclusion in the Work by the copyright owner + or by an individual or Legal Entity authorized to submit on behalf of + the copyright owner. For the purposes of this definition, "submitted" + means any form of electronic, verbal, or written communication sent + to the Licensor or its representatives, including but not limited to + communication on electronic mailing lists, source code control systems, + and issue tracking systems that are managed by, or on behalf of, the + Licensor for the purpose of discussing and improving the Work, but + excluding communication that is conspicuously marked or otherwise + designated in writing by the copyright owner as "Not a Contribution." + + "Contributor" shall mean Licensor and any individual or Legal Entity + on behalf of whom a Contribution has been received by Licensor and + subsequently incorporated within the Work. + + 2. Grant of Copyright License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + copyright license to reproduce, prepare Derivative Works of, + publicly display, publicly perform, sublicense, and distribute the + Work and such Derivative Works in Source or Object form. + + 3. Grant of Patent License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + (except as stated in this section) patent license to make, have made, + use, offer to sell, sell, import, and otherwise transfer the Work, + where such license applies only to those patent claims licensable + by such Contributor that are necessarily infringed by their + Contribution(s) alone or by combination of their Contribution(s) + with the Work to which such Contribution(s) was submitted. If You + institute patent litigation against any entity (including a + cross-claim or counterclaim in a lawsuit) alleging that the Work + or a Contribution incorporated within the Work constitutes direct + or contributory patent infringement, then any patent licenses + granted to You under this License for that Work shall terminate + as of the date such litigation is filed. + + 4. Redistribution. You may reproduce and distribute copies of the + Work or Derivative Works thereof in any medium, with or without + modifications, and in Source or Object form, provided that You + meet the following conditions: + + (a) You must give any other recipients of the Work or + Derivative Works a copy of this License; and + + (b) You must cause any modified files to carry prominent notices + stating that You changed the files; and + + (c) You must retain, in the Source form of any Derivative Works + that You distribute, all copyright, patent, trademark, and + attribution notices from the Source form of the Work, + excluding those notices that do not pertain to any part of + the Derivative Works; and + + (d) If the Work includes a "NOTICE" text file as part of its + distribution, then any Derivative Works that You distribute must + include a readable copy of the attribution notices contained + within such NOTICE file, excluding those notices that do not + pertain to any part of the Derivative Works, in at least one + of the following places: within a NOTICE text file distributed + as part of the Derivative Works; within the Source form or + documentation, if provided along with the Derivative Works; or, + within a display generated by the Derivative Works, if and + wherever such third-party notices normally appear. The contents + of the NOTICE file are for informational purposes only and + do not modify the License. You may add Your own attribution + notices within Derivative Works that You distribute, alongside + or as an addendum to the NOTICE text from the Work, provided + that such additional attribution notices cannot be construed + as modifying the License. + + You may add Your own copyright statement to Your modifications and + may provide additional or different license terms and conditions + for use, reproduction, or distribution of Your modifications, or + for any such Derivative Works as a whole, provided Your use, + reproduction, and distribution of the Work otherwise complies with + the conditions stated in this License. + + 5. Submission of Contributions. Unless You explicitly state otherwise, + any Contribution intentionally submitted for inclusion in the Work + by You to the Licensor shall be under the terms and conditions of + this License, without any additional terms or conditions. + Notwithstanding the above, nothing herein shall supersede or modify + the terms of any separate license agreement you may have executed + with Licensor regarding such Contributions. + + 6. Trademarks. This License does not grant permission to use the trade + names, trademarks, service marks, or product names of the Licensor, + except as required for reasonable and customary use in describing the + origin of the Work and reproducing the content of the NOTICE file. + + 7. Disclaimer of Warranty. Unless required by applicable law or + agreed to in writing, Licensor provides the Work (and each + Contributor provides its Contributions) on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + implied, including, without limitation, any warranties or conditions + of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A + PARTICULAR PURPOSE. You are solely responsible for determining the + appropriateness of using or redistributing the Work and assume any + risks associated with Your exercise of permissions under this License. + + 8. Limitation of Liability. In no event and under no legal theory, + whether in tort (including negligence), contract, or otherwise, + unless required by applicable law (such as deliberate and grossly + negligent acts) or agreed to in writing, shall any Contributor be + liable to You for damages, including any direct, indirect, special, + incidental, or consequential damages of any character arising as a + result of this License or out of the use or inability to use the + Work (including but not limited to damages for loss of goodwill, + work stoppage, computer failure or malfunction, or any and all + other commercial damages or losses), even if such Contributor + has been advised of the possibility of such damages. + + 9. Accepting Warranty or Additional Liability. While redistributing + the Work or Derivative Works thereof, You may choose to offer, + and charge a fee for, acceptance of support, warranty, indemnity, + or other liability obligations and/or rights consistent with this + License. However, in accepting such obligations, You may act only + on Your own behalf and on Your sole responsibility, not on behalf + of any other Contributor, and only if You agree to indemnify, + defend, and hold each Contributor harmless for any liability + incurred by, or claims asserted against, such Contributor by reason + of your accepting any such warranty or additional liability. + + END OF TERMS AND CONDITIONS + + APPENDIX: How to apply the Apache License to your work. + + To apply the Apache License to your work, attach the following + boilerplate notice, with the fields enclosed by brackets "[]" + replaced with your own identifying information. (Don't include + the brackets!) The text should be enclosed in the appropriate + comment syntax for the file format. We also recommend that a + file or class name and description of purpose be included on the + same "printed page" as the copyright notice for easier + identification within third-party archives. + + Copyright [yyyy] [name of copyright owner] + + Licensed 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. +========== +Notice for: commons-logging:commons-logging-1.2.0 +---------- + +Apache Commons Logging +Copyright 2003-2016 The Apache Software Foundation + +This product includes software developed at +The Apache Software Foundation (http://www.apache.org/). + + + Apache License + Version 2.0, January 2004 + http://www.apache.org/licenses/ + + TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION + + 1. Definitions. + + "License" shall mean the terms and conditions for use, reproduction, + and distribution as defined by Sections 1 through 9 of this document. + + "Licensor" shall mean the copyright owner or entity authorized by + the copyright owner that is granting the License. + + "Legal Entity" shall mean the union of the acting entity and all + other entities that control, are controlled by, or are under common + control with that entity. For the purposes of this definition, + "control" means (i) the power, direct or indirect, to cause the + direction or management of such entity, whether by contract or + otherwise, or (ii) ownership of fifty percent (50%) or more of the + outstanding shares, or (iii) beneficial ownership of such entity. + + "You" (or "Your") shall mean an individual or Legal Entity + exercising permissions granted by this License. + + "Source" form shall mean the preferred form for making modifications, + including but not limited to software source code, documentation + source, and configuration files. + + "Object" form shall mean any form resulting from mechanical + transformation or translation of a Source form, including but + not limited to compiled object code, generated documentation, + and conversions to other media types. + + "Work" shall mean the work of authorship, whether in Source or + Object form, made available under the License, as indicated by a + copyright notice that is included in or attached to the work + (an example is provided in the Appendix below). + + "Derivative Works" shall mean any work, whether in Source or Object + form, that is based on (or derived from) the Work and for which the + editorial revisions, annotations, elaborations, or other modifications + represent, as a whole, an original work of authorship. For the purposes + of this License, Derivative Works shall not include works that remain + separable from, or merely link (or bind by name) to the interfaces of, + the Work and Derivative Works thereof. + + "Contribution" shall mean any work of authorship, including + the original version of the Work and any modifications or additions + to that Work or Derivative Works thereof, that is intentionally + submitted to Licensor for inclusion in the Work by the copyright owner + or by an individual or Legal Entity authorized to submit on behalf of + the copyright owner. For the purposes of this definition, "submitted" + means any form of electronic, verbal, or written communication sent + to the Licensor or its representatives, including but not limited to + communication on electronic mailing lists, source code control systems, + and issue tracking systems that are managed by, or on behalf of, the + Licensor for the purpose of discussing and improving the Work, but + excluding communication that is conspicuously marked or otherwise + designated in writing by the copyright owner as "Not a Contribution." + + "Contributor" shall mean Licensor and any individual or Legal Entity + on behalf of whom a Contribution has been received by Licensor and + subsequently incorporated within the Work. + + 2. Grant of Copyright License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + copyright license to reproduce, prepare Derivative Works of, + publicly display, publicly perform, sublicense, and distribute the + Work and such Derivative Works in Source or Object form. + + 3. Grant of Patent License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + (except as stated in this section) patent license to make, have made, + use, offer to sell, sell, import, and otherwise transfer the Work, + where such license applies only to those patent claims licensable + by such Contributor that are necessarily infringed by their + Contribution(s) alone or by combination of their Contribution(s) + with the Work to which such Contribution(s) was submitted. If You + institute patent litigation against any entity (including a + cross-claim or counterclaim in a lawsuit) alleging that the Work + or a Contribution incorporated within the Work constitutes direct + or contributory patent infringement, then any patent licenses + granted to You under this License for that Work shall terminate + as of the date such litigation is filed. + + 4. Redistribution. You may reproduce and distribute copies of the + Work or Derivative Works thereof in any medium, with or without + modifications, and in Source or Object form, provided that You + meet the following conditions: + + (a) You must give any other recipients of the Work or + Derivative Works a copy of this License; and + + (b) You must cause any modified files to carry prominent notices + stating that You changed the files; and + + (c) You must retain, in the Source form of any Derivative Works + that You distribute, all copyright, patent, trademark, and + attribution notices from the Source form of the Work, + excluding those notices that do not pertain to any part of + the Derivative Works; and + + (d) If the Work includes a "NOTICE" text file as part of its + distribution, then any Derivative Works that You distribute must + include a readable copy of the attribution notices contained + within such NOTICE file, excluding those notices that do not + pertain to any part of the Derivative Works, in at least one + of the following places: within a NOTICE text file distributed + as part of the Derivative Works; within the Source form or + documentation, if provided along with the Derivative Works; or, + within a display generated by the Derivative Works, if and + wherever such third-party notices normally appear. The contents + of the NOTICE file are for informational purposes only and + do not modify the License. You may add Your own attribution + notices within Derivative Works that You distribute, alongside + or as an addendum to the NOTICE text from the Work, provided + that such additional attribution notices cannot be construed + as modifying the License. + + You may add Your own copyright statement to Your modifications and + may provide additional or different license terms and conditions + for use, reproduction, or distribution of Your modifications, or + for any such Derivative Works as a whole, provided Your use, + reproduction, and distribution of the Work otherwise complies with + the conditions stated in this License. + + 5. Submission of Contributions. Unless You explicitly state otherwise, + any Contribution intentionally submitted for inclusion in the Work + by You to the Licensor shall be under the terms and conditions of + this License, without any additional terms or conditions. + Notwithstanding the above, nothing herein shall supersede or modify + the terms of any separate license agreement you may have executed + with Licensor regarding such Contributions. + + 6. Trademarks. This License does not grant permission to use the trade + names, trademarks, service marks, or product names of the Licensor, + except as required for reasonable and customary use in describing the + origin of the Work and reproducing the content of the NOTICE file. + + 7. Disclaimer of Warranty. Unless required by applicable law or + agreed to in writing, Licensor provides the Work (and each + Contributor provides its Contributions) on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + implied, including, without limitation, any warranties or conditions + of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A + PARTICULAR PURPOSE. You are solely responsible for determining the + appropriateness of using or redistributing the Work and assume any + risks associated with Your exercise of permissions under this License. + + 8. Limitation of Liability. In no event and under no legal theory, + whether in tort (including negligence), contract, or otherwise, + unless required by applicable law (such as deliberate and grossly + negligent acts) or agreed to in writing, shall any Contributor be + liable to You for damages, including any direct, indirect, special, + incidental, or consequential damages of any character arising as a + result of this License or out of the use or inability to use the + Work (including but not limited to damages for loss of goodwill, + work stoppage, computer failure or malfunction, or any and all + other commercial damages or losses), even if such Contributor + has been advised of the possibility of such damages. + + 9. Accepting Warranty or Additional Liability. While redistributing + the Work or Derivative Works thereof, You may choose to offer, + and charge a fee for, acceptance of support, warranty, indemnity, + or other liability obligations and/or rights consistent with this + License. However, in accepting such obligations, You may act only + on Your own behalf and on Your sole responsibility, not on behalf + of any other Contributor, and only if You agree to indemnify, + defend, and hold each Contributor harmless for any liability + incurred by, or claims asserted against, such Contributor by reason + of your accepting any such warranty or additional liability. + + END OF TERMS AND CONDITIONS + + APPENDIX: How to apply the Apache License to your work. + + To apply the Apache License to your work, attach the following + boilerplate notice, with the fields enclosed by brackets "[]" + replaced with your own identifying information. (Don't include + the brackets!) The text should be enclosed in the appropriate + comment syntax for the file format. We also recommend that a + file or class name and description of purpose be included on the + same "printed page" as the copyright notice for easier + identification within third-party archives. + + Copyright [yyyy] [name of copyright owner] + + Licensed 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. +========== +Notice for: concurrent-ruby-1.1.5 +---------- + +Copyright (c) Jerry D'Antonio -- released under the MIT license. + +http://www.opensource.org/licenses/mit-license.php + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE. + +========== +Notice for: dalli-2.7.10 +---------- + +Copyright (c) Peter M. Goldstein, Mike Perham + +Permission is hereby granted, free of charge, to any person obtaining +a copy of this software and associated documentation files (the +"Software"), to deal in the Software without restriction, including +without limitation the rights to use, copy, modify, merge, publish, +distribute, sublicense, and/or sell copies of the Software, and to +permit persons to whom the Software is furnished to do so, subject to +the following conditions: + +The above copyright notice and this permission notice shall be +included in all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + +========== +Notice for: domain_name-0.5.20190701 +---------- + +Copyright (c) 2011-2017 Akinori MUSHA + +All rights reserved. + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions +are met: +1. Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. +2. Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in the + documentation and/or other materials provided with the distribution. + +THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND +ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE +FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL +DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS +OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) +HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT +LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY +OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF +SUCH DAMAGE. + +* lib/domain_name/punycode.rb + +This file is derived from the implementation of punycode available at +here: + +https://www.verisign.com/en_US/channel-resources/domain-registry-products/idn-sdks/index.xhtml + +Copyright (C) 2000-2002 Verisign Inc., All rights reserved. + +Redistribution and use in source and binary forms, with or +without modification, are permitted provided that the following +conditions are met: + + 1) Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + + 2) Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in + the documentation and/or other materials provided with the + distribution. + + 3) Neither the name of the VeriSign Inc. nor the names of its + contributors may be used to endorse or promote products derived + from this software without specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS +FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE +COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, +INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, +BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS +OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED +AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT +LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN +ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE +POSSIBILITY OF SUCH DAMAGE. + +This software is licensed under the BSD open source license. For more +information visit www.opensource.org. + +Authors: + John Colosi (VeriSign) + Srikanth Veeramachaneni (VeriSign) + Nagesh Chigurupati (Verisign) + Praveen Srinivasan(Verisign) + +* lib/domain_name/etld_data.rb + +This file is generated from the Public Suffix List +(https://publicsuffix.org/), which is licensed under MPL 2.0: + +https://mozilla.org/MPL/2.0/ + +========== +Notice for: dotenv-2.7.5 +---------- + +Copyright (c) 2012 Brandon Keepers + +MIT License + +Permission is hereby granted, free of charge, to any person obtaining +a copy of this software and associated documentation files (the +"Software"), to deal in the Software without restriction, including +without limitation the rights to use, copy, modify, merge, publish, +distribute, sublicense, and/or sell copies of the Software, and to +permit persons to whom the Software is furnished to do so, subject to +the following conditions: + +The above copyright notice and this permission notice shall be +included in all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + +========== +Notice for: edn-1.1.1 +---------- + +Copyright (c) 2012 Relevance Inc & Clinton N. Dreisbach + +MIT License + +Permission is hereby granted, free of charge, to any person obtaining +a copy of this software and associated documentation files (the +"Software"), to deal in the Software without restriction, including +without limitation the rights to use, copy, modify, merge, publish, +distribute, sublicense, and/or sell copies of the Software, and to +permit persons to whom the Software is furnished to do so, subject to +the following conditions: + +The above copyright notice and this permission notice shall be +included in all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + +========== +Notice for: elasticsearch-5.0.5 +---------- + +source: https://github.com/elastic/elasticsearch-ruby/blob/v5.0.4/elasticsearch-api/LICENSE.txt + +Copyright 2013 Elasticsearch + +Licensed 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. + +========== +Notice for: elasticsearch-api-5.0.5 +---------- + +source: https://github.com/elastic/elasticsearch-ruby/blob/v5.0.4/elasticsearch-transport/LICENSE.txt + +Copyright (c) 2013 Elasticsearch + +Licensed 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. + +========== +Notice for: elasticsearch-transport-5.0.5 +---------- + +source: https://github.com/elastic/elasticsearch-ruby/blob/v5.0.4/elasticsearch/LICENSE.txt + +Copyright (c) 2013 Elasticsearch + +Licensed 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. + +========== +Notice for: equalizer-0.0.11 +---------- + +source: https://github.com/dkubb/equalizer/blob/v0.0.10/LICENSE + +Copyright (c) 2009-2013 Dan Kubb +Copyright (c) 2012 Markus Schirp (packaging) + +Permission is hereby granted, free of charge, to any person obtaining +a copy of this software and associated documentation files (the +"Software"), to deal in the Software without restriction, including +without limitation the rights to use, copy, modify, merge, publish, +distribute, sublicense, and/or sell copies of the Software, and to +permit persons to whom the Software is furnished to do so, subject to +the following conditions: + +The above copyright notice and this permission notice shall be +included in all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + +========== +Notice for: faraday-0.15.4 +---------- + +source: https://github.com/lostisland/faraday/blob/v0.9.2/LICENSE.md + +Copyright (c) 2009-2015 Rick Olson, Zack Hobson + +Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + +========== +Notice for: ffi-1.12.1 +---------- + +source: https://github.com/ffi/ffi/blob/1.9.23/LICENSE + +Copyright (c) 2008-2016, Ruby FFI project contributors +All rights reserved. + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are met: + * Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + * Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in the + documentation and/or other materials provided with the distribution. + * Neither the name of the Ruby FFI project nor the + names of its contributors may be used to endorse or promote products + derived from this software without specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND +ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED +WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +DISCLAIMED. IN NO EVENT SHALL BE LIABLE FOR ANY +DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES +(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; +LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND +ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS +SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +========== +Notice for: filesize-0.2.0 +---------- + +https://github.com/dominikh/filesize/blob/v0.0.4/LICENSE + +Copyright (c) 2009 Dominik Honnef + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE. + +========== +Notice for: gelfd2-0.4.1 +---------- + +Copyright 2011-2013 John E. Vincent and contributors. + +Licensed 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. + +========== +Notice for: gems-1.2.0 +---------- + +source: https://github.com/rubygems/gems/blob/v0.8.3/LICENSE.md + +Copyright (c) 2011-2013 Erik Michaels-Ober + +Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + +========== +Notice for: gene_pool-1.5.0 +---------- + +Copyright (c) 2010-2011 Brad Pardee + +Permission is hereby granted, free of charge, to any person obtaining +a copy of this software and associated documentation files (the +"Software"), to deal in the Software without restriction, including +without limitation the rights to use, copy, modify, merge, publish, +distribute, sublicense, and/or sell copies of the Software, and to +permit persons to whom the Software is furnished to do so, subject to +the following conditions: + +The above copyright notice and this permission notice shall be +included in all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + +========== +Notice for: gradle.plugin.com.github.jk1:gradle-license-report-0.7.1 +---------- + +source: https://github.com/jk1/Gradle-License-Report/blob/master/LICENSE + + Apache License + Version 2.0, January 2004 + http://www.apache.org/licenses/ + + TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION + + 1. Definitions. + + "License" shall mean the terms and conditions for use, reproduction, + and distribution as defined by Sections 1 through 9 of this document. + + "Licensor" shall mean the copyright owner or entity authorized by + the copyright owner that is granting the License. + + "Legal Entity" shall mean the union of the acting entity and all + other entities that control, are controlled by, or are under common + control with that entity. For the purposes of this definition, + "control" means (i) the power, direct or indirect, to cause the + direction or management of such entity, whether by contract or + otherwise, or (ii) ownership of fifty percent (50%) or more of the + outstanding shares, or (iii) beneficial ownership of such entity. + + "You" (or "Your") shall mean an individual or Legal Entity + exercising permissions granted by this License. + + "Source" form shall mean the preferred form for making modifications, + including but not limited to software source code, documentation + source, and configuration files. + + "Object" form shall mean any form resulting from mechanical + transformation or translation of a Source form, including but + not limited to compiled object code, generated documentation, + and conversions to other media types. + + "Work" shall mean the work of authorship, whether in Source or + Object form, made available under the License, as indicated by a + copyright notice that is included in or attached to the work + (an example is provided in the Appendix below). + + "Derivative Works" shall mean any work, whether in Source or Object + form, that is based on (or derived from) the Work and for which the + editorial revisions, annotations, elaborations, or other modifications + represent, as a whole, an original work of authorship. For the purposes + of this License, Derivative Works shall not include works that remain + separable from, or merely link (or bind by name) to the interfaces of, + the Work and Derivative Works thereof. + + "Contribution" shall mean any work of authorship, including + the original version of the Work and any modifications or additions + to that Work or Derivative Works thereof, that is intentionally + submitted to Licensor for inclusion in the Work by the copyright owner + or by an individual or Legal Entity authorized to submit on behalf of + the copyright owner. For the purposes of this definition, "submitted" + means any form of electronic, verbal, or written communication sent + to the Licensor or its representatives, including but not limited to + communication on electronic mailing lists, source code control systems, + and issue tracking systems that are managed by, or on behalf of, the + Licensor for the purpose of discussing and improving the Work, but + excluding communication that is conspicuously marked or otherwise + designated in writing by the copyright owner as "Not a Contribution." + + "Contributor" shall mean Licensor and any individual or Legal Entity + on behalf of whom a Contribution has been received by Licensor and + subsequently incorporated within the Work. + + 2. Grant of Copyright License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + copyright license to reproduce, prepare Derivative Works of, + publicly display, publicly perform, sublicense, and distribute the + Work and such Derivative Works in Source or Object form. + + 3. Grant of Patent License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + (except as stated in this section) patent license to make, have made, + use, offer to sell, sell, import, and otherwise transfer the Work, + where such license applies only to those patent claims licensable + by such Contributor that are necessarily infringed by their + Contribution(s) alone or by combination of their Contribution(s) + with the Work to which such Contribution(s) was submitted. If You + institute patent litigation against any entity (including a + cross-claim or counterclaim in a lawsuit) alleging that the Work + or a Contribution incorporated within the Work constitutes direct + or contributory patent infringement, then any patent licenses + granted to You under this License for that Work shall terminate + as of the date such litigation is filed. + + 4. Redistribution. You may reproduce and distribute copies of the + Work or Derivative Works thereof in any medium, with or without + modifications, and in Source or Object form, provided that You + meet the following conditions: + + (a) You must give any other recipients of the Work or + Derivative Works a copy of this License; and + + (b) You must cause any modified files to carry prominent notices + stating that You changed the files; and + + (c) You must retain, in the Source form of any Derivative Works + that You distribute, all copyright, patent, trademark, and + attribution notices from the Source form of the Work, + excluding those notices that do not pertain to any part of + the Derivative Works; and + + (d) If the Work includes a "NOTICE" text file as part of its + distribution, then any Derivative Works that You distribute must + include a readable copy of the attribution notices contained + within such NOTICE file, excluding those notices that do not + pertain to any part of the Derivative Works, in at least one + of the following places: within a NOTICE text file distributed + as part of the Derivative Works; within the Source form or + documentation, if provided along with the Derivative Works; or, + within a display generated by the Derivative Works, if and + wherever such third-party notices normally appear. The contents + of the NOTICE file are for informational purposes only and + do not modify the License. You may add Your own attribution + notices within Derivative Works that You distribute, alongside + or as an addendum to the NOTICE text from the Work, provided + that such additional attribution notices cannot be construed + as modifying the License. + + You may add Your own copyright statement to Your modifications and + may provide additional or different license terms and conditions + for use, reproduction, or distribution of Your modifications, or + for any such Derivative Works as a whole, provided Your use, + reproduction, and distribution of the Work otherwise complies with + the conditions stated in this License. + + 5. Submission of Contributions. Unless You explicitly state otherwise, + any Contribution intentionally submitted for inclusion in the Work + by You to the Licensor shall be under the terms and conditions of + this License, without any additional terms or conditions. + Notwithstanding the above, nothing herein shall supersede or modify + the terms of any separate license agreement you may have executed + with Licensor regarding such Contributions. + + 6. Trademarks. This License does not grant permission to use the trade + names, trademarks, service marks, or product names of the Licensor, + except as required for reasonable and customary use in describing the + origin of the Work and reproducing the content of the NOTICE file. + + 7. Disclaimer of Warranty. Unless required by applicable law or + agreed to in writing, Licensor provides the Work (and each + Contributor provides its Contributions) on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + implied, including, without limitation, any warranties or conditions + of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A + PARTICULAR PURPOSE. You are solely responsible for determining the + appropriateness of using or redistributing the Work and assume any + risks associated with Your exercise of permissions under this License. + + 8. Limitation of Liability. In no event and under no legal theory, + whether in tort (including negligence), contract, or otherwise, + unless required by applicable law (such as deliberate and grossly + negligent acts) or agreed to in writing, shall any Contributor be + liable to You for damages, including any direct, indirect, special, + incidental, or consequential damages of any character arising as a + result of this License or out of the use or inability to use the + Work (including but not limited to damages for loss of goodwill, + work stoppage, computer failure or malfunction, or any and all + other commercial damages or losses), even if such Contributor + has been advised of the possibility of such damages. + + 9. Accepting Warranty or Additional Liability. While redistributing + the Work or Derivative Works thereof, You may choose to offer, + and charge a fee for, acceptance of support, warranty, indemnity, + or other liability obligations and/or rights consistent with this + License. However, in accepting such obligations, You may act only + on Your own behalf and on Your sole responsibility, not on behalf + of any other Contributor, and only if You agree to indemnify, + defend, and hold each Contributor harmless for any liability + incurred by, or claims asserted against, such Contributor by reason + of your accepting any such warranty or additional liability. + + END OF TERMS AND CONDITIONS + + APPENDIX: How to apply the Apache License to your work. + + To apply the Apache License to your work, attach the following + boilerplate notice, with the fields enclosed by brackets "{}" + replaced with your own identifying information. (Don't include + the brackets!) The text should be enclosed in the appropriate + comment syntax for the file format. We also recommend that a + file or class name and description of purpose be included on the + same "printed page" as the copyright notice for easier + identification within third-party archives. + + Copyright {yyyy} {name of copyright owner} + + Licensed 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. + +========== +Notice for: hitimes-1.3.1 +---------- + +source: https://github.com/copiousfreetime/hitimes/blob/v1.2.6/LICENSE + +ISC LICENSE - http://opensource.org/licenses/isc-license.txt + +Copyright (c) 2008-2015 Jeremy Hinegardner + +Permission to use, copy, modify, and/or distribute this software for any +purpose with or without fee is hereby granted, provided that the above +copyright notice and this permission notice appear in all copies. + +THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES +WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF +MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR +ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES +WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN +ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF +OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + +========== +Notice for: http-3.3.0 +---------- + +source: https://github.com/httprb/http/blob/v0.9.9/LICENSE.txt + +Copyright (c) 2011-2015 Tony Arcieri, Erik Michaels-Ober, Alexey V. Zapparov, Zachary Anker + +Permission is hereby granted, free of charge, to any person obtaining +a copy of this software and associated documentation files (the +"Software"), to deal in the Software without restriction, including +without limitation the rights to use, copy, modify, merge, publish, +distribute, sublicense, and/or sell copies of the Software, and to +permit persons to whom the Software is furnished to do so, subject to +the following conditions: + +The above copyright notice and this permission notice shall be +included in all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + + +========== +Notice for: http-cookie-1.0.3 +---------- + +source: https://github.com/sparklemotion/http-cookie/blob/v1.0.3/LICENSE.txt + +Copyright (c) 2013 Akinori MUSHA +Copyright (c) 2011-2012 Akinori MUSHA, Eric Hodel +Copyright (c) 2006-2011 Aaron Patterson, Mike Dalessio + +MIT License + +Permission is hereby granted, free of charge, to any person obtaining +a copy of this software and associated documentation files (the +"Software"), to deal in the Software without restriction, including +without limitation the rights to use, copy, modify, merge, publish, +distribute, sublicense, and/or sell copies of the Software, and to +permit persons to whom the Software is furnished to do so, subject to +the following conditions: + +The above copyright notice and this permission notice shall be +included in all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + +========== +Notice for: http-form_data-2.2.0 +---------- + +source: https://github.com/httprb/form_data/blob/v1.0.1/LICENSE.txt + +Copyright (c) 2015 Aleksey V Zapparov + +MIT License + +Permission is hereby granted, free of charge, to any person obtaining +a copy of this software and associated documentation files (the +"Software"), to deal in the Software without restriction, including +without limitation the rights to use, copy, modify, merge, publish, +distribute, sublicense, and/or sell copies of the Software, and to +permit persons to whom the Software is furnished to do so, subject to +the following conditions: + +The above copyright notice and this permission notice shall be +included in all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + + +========== +Notice for: http_parser.rb-0.6.0 +---------- + +source: https://github.com/tmm1/http_parser.rb/blob/v0.6.0/LICENSE-MIT + +Copyright 2009,2010 Marc-André Cournoyer +Copyright 2010,2011 Aman Gupta + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to +deal in the Software without restriction, including without limitation the +rights to use, copy, modify, merge, publish, distribute, sublicense, and/or +sell copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING +FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS +IN THE SOFTWARE. + +========== +Notice for: i18n-1.8.2 +---------- + +source: https://github.com/svenfuchs/i18n/blob/v0.6.9/MIT-LICENSE + +Copyright (c) 2008 The Ruby I18n team + +Permission is hereby granted, free of charge, to any person obtaining +a copy of this software and associated documentation files (the +"Software"), to deal in the Software without restriction, including +without limitation the rights to use, copy, modify, merge, publish, +distribute, sublicense, and/or sell copies of the Software, and to +permit persons to whom the Software is furnished to do so, subject to +the following conditions: + +The above copyright notice and this permission notice shall be +included in all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + +========== +Notice for: insist-1.0.0 +---------- + +source: https://github.com/jordansissel/ruby-insist/blob/master/LICENSE + +Copyright 2012-2013 Jordan Sissel and contributors. + +Licensed 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. + +========== +Notice for: jar-dependencies-0.4.0 +---------- + +source: https://github.com/mkristian/jar-dependencies/blob/0.3.12/MIT-LICENSE + +Copyright (c) 2014 Christian Meier + +Permission is hereby granted, free of charge, to any person obtaining +a copy of this software and associated documentation files (the +"Software"), to deal in the Software without restriction, including +without limitation the rights to use, copy, modify, merge, publish, +distribute, sublicense, and/or sell copies of the Software, and to +permit persons to whom the Software is furnished to do so, subject to +the following conditions: + +The above copyright notice and this permission notice shall be +included in all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + + +========== +Notice for: jls-grok-0.11.5 +---------- + +source: https://github.com/jordansissel/ruby-grok/blob/master/LICENSE + + Apache License + Version 2.0, January 2004 + http://www.apache.org/licenses/ + + TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION + + 1. Definitions. + + "License" shall mean the terms and conditions for use, reproduction, + and distribution as defined by Sections 1 through 9 of this document. + + "Licensor" shall mean the copyright owner or entity authorized by + the copyright owner that is granting the License. + + "Legal Entity" shall mean the union of the acting entity and all + other entities that control, are controlled by, or are under common + control with that entity. For the purposes of this definition, + "control" means (i) the power, direct or indirect, to cause the + direction or management of such entity, whether by contract or + otherwise, or (ii) ownership of fifty percent (50%) or more of the + outstanding shares, or (iii) beneficial ownership of such entity. + + "You" (or "Your") shall mean an individual or Legal Entity + exercising permissions granted by this License. + + "Source" form shall mean the preferred form for making modifications, + including but not limited to software source code, documentation + source, and configuration files. + + "Object" form shall mean any form resulting from mechanical + transformation or translation of a Source form, including but + not limited to compiled object code, generated documentation, + and conversions to other media types. + + "Work" shall mean the work of authorship, whether in Source or + Object form, made available under the License, as indicated by a + copyright notice that is included in or attached to the work + (an example is provided in the Appendix below). + + "Derivative Works" shall mean any work, whether in Source or Object + form, that is based on (or derived from) the Work and for which the + editorial revisions, annotations, elaborations, or other modifications + represent, as a whole, an original work of authorship. For the purposes + of this License, Derivative Works shall not include works that remain + separable from, or merely link (or bind by name) to the interfaces of, + the Work and Derivative Works thereof. + + "Contribution" shall mean any work of authorship, including + the original version of the Work and any modifications or additions + to that Work or Derivative Works thereof, that is intentionally + submitted to Licensor for inclusion in the Work by the copyright owner + or by an individual or Legal Entity authorized to submit on behalf of + the copyright owner. For the purposes of this definition, "submitted" + means any form of electronic, verbal, or written communication sent + to the Licensor or its representatives, including but not limited to + communication on electronic mailing lists, source code control systems, + and issue tracking systems that are managed by, or on behalf of, the + Licensor for the purpose of discussing and improving the Work, but + excluding communication that is conspicuously marked or otherwise + designated in writing by the copyright owner as "Not a Contribution." + + "Contributor" shall mean Licensor and any individual or Legal Entity + on behalf of whom a Contribution has been received by Licensor and + subsequently incorporated within the Work. + + 2. Grant of Copyright License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + copyright license to reproduce, prepare Derivative Works of, + publicly display, publicly perform, sublicense, and distribute the + Work and such Derivative Works in Source or Object form. + + 3. Grant of Patent License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + (except as stated in this section) patent license to make, have made, + use, offer to sell, sell, import, and otherwise transfer the Work, + where such license applies only to those patent claims licensable + by such Contributor that are necessarily infringed by their + Contribution(s) alone or by combination of their Contribution(s) + with the Work to which such Contribution(s) was submitted. If You + institute patent litigation against any entity (including a + cross-claim or counterclaim in a lawsuit) alleging that the Work + or a Contribution incorporated within the Work constitutes direct + or contributory patent infringement, then any patent licenses + granted to You under this License for that Work shall terminate + as of the date such litigation is filed. + + 4. Redistribution. You may reproduce and distribute copies of the + Work or Derivative Works thereof in any medium, with or without + modifications, and in Source or Object form, provided that You + meet the following conditions: + + (a) You must give any other recipients of the Work or + Derivative Works a copy of this License; and + + (b) You must cause any modified files to carry prominent notices + stating that You changed the files; and + + (c) You must retain, in the Source form of any Derivative Works + that You distribute, all copyright, patent, trademark, and + attribution notices from the Source form of the Work, + excluding those notices that do not pertain to any part of + the Derivative Works; and + + (d) If the Work includes a "NOTICE" text file as part of its + distribution, then any Derivative Works that You distribute must + include a readable copy of the attribution notices contained + within such NOTICE file, excluding those notices that do not + pertain to any part of the Derivative Works, in at least one + of the following places: within a NOTICE text file distributed + as part of the Derivative Works; within the Source form or + documentation, if provided along with the Derivative Works; or, + within a display generated by the Derivative Works, if and + wherever such third-party notices normally appear. The contents + of the NOTICE file are for informational purposes only and + do not modify the License. You may add Your own attribution + notices within Derivative Works that You distribute, alongside + or as an addendum to the NOTICE text from the Work, provided + that such additional attribution notices cannot be construed + as modifying the License. + + You may add Your own copyright statement to Your modifications and + may provide additional or different license terms and conditions + for use, reproduction, or distribution of Your modifications, or + for any such Derivative Works as a whole, provided Your use, + reproduction, and distribution of the Work otherwise complies with + the conditions stated in this License. + + 5. Submission of Contributions. Unless You explicitly state otherwise, + any Contribution intentionally submitted for inclusion in the Work + by You to the Licensor shall be under the terms and conditions of + this License, without any additional terms or conditions. + Notwithstanding the above, nothing herein shall supersede or modify + the terms of any separate license agreement you may have executed + with Licensor regarding such Contributions. + + 6. Trademarks. This License does not grant permission to use the trade + names, trademarks, service marks, or product names of the Licensor, + except as required for reasonable and customary use in describing the + origin of the Work and reproducing the content of the NOTICE file. + + 7. Disclaimer of Warranty. Unless required by applicable law or + agreed to in writing, Licensor provides the Work (and each + Contributor provides its Contributions) on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + implied, including, without limitation, any warranties or conditions + of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A + PARTICULAR PURPOSE. You are solely responsible for determining the + appropriateness of using or redistributing the Work and assume any + risks associated with Your exercise of permissions under this License. + + 8. Limitation of Liability. In no event and under no legal theory, + whether in tort (including negligence), contract, or otherwise, + unless required by applicable law (such as deliberate and grossly + negligent acts) or agreed to in writing, shall any Contributor be + liable to You for damages, including any direct, indirect, special, + incidental, or consequential damages of any character arising as a + result of this License or out of the use or inability to use the + Work (including but not limited to damages for loss of goodwill, + work stoppage, computer failure or malfunction, or any and all + other commercial damages or losses), even if such Contributor + has been advised of the possibility of such damages. + + 9. Accepting Warranty or Additional Liability. While redistributing + the Work or Derivative Works thereof, You may choose to offer, + and charge a fee for, acceptance of support, warranty, indemnity, + or other liability obligations and/or rights consistent with this + License. However, in accepting such obligations, You may act only + on Your own behalf and on Your sole responsibility, not on behalf + of any other Contributor, and only if You agree to indemnify, + defend, and hold each Contributor harmless for any liability + incurred by, or claims asserted against, such Contributor by reason + of your accepting any such warranty or additional liability. + + END OF TERMS AND CONDITIONS + + APPENDIX: How to apply the Apache License to your work. + + To apply the Apache License to your work, attach the following + boilerplate notice, with the fields enclosed by brackets "[]" + replaced with your own identifying information. (Don't include + the brackets!) The text should be enclosed in the appropriate + comment syntax for the file format. We also recommend that a + file or class name and description of purpose be included on the + same "printed page" as the copyright notice for easier + identification within third-party archives. + + Copyright [yyyy] [name of copyright owner] + + Licensed 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. + +========== +Notice for: jls-lumberjack-0.0.26 +---------- + +source: https://github.com/elastic/ruby-lumberjack/blob/master/LICENSE + + +Copyright 2012–2015 Jordan Sissel and contributors. + +Licensed 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. + +========== +Notice for: jmespath-1.4.0 +---------- + +source: https://github.com/jmespath/jmespath.rb/blob/v1.4.0/LICENSE.txt + + Apache License + Version 2.0, January 2004 + http://www.apache.org/licenses/ + +TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION + +1. Definitions. + + "License" shall mean the terms and conditions for use, reproduction, + and distribution as defined by Sections 1 through 9 of this document. + + "Licensor" shall mean the copyright owner or entity authorized by + the copyright owner that is granting the License. + + "Legal Entity" shall mean the union of the acting entity and all + other entities that control, are controlled by, or are under common + control with that entity. For the purposes of this definition, + "control" means (i) the power, direct or indirect, to cause the + direction or management of such entity, whether by contract or + otherwise, or (ii) ownership of fifty percent (50%) or more of the + outstanding shares, or (iii) beneficial ownership of such entity. + + "You" (or "Your") shall mean an individual or Legal Entity + exercising permissions granted by this License. + + "Source" form shall mean the preferred form for making modifications, + including but not limited to software source code, documentation + source, and configuration files. + + "Object" form shall mean any form resulting from mechanical + transformation or translation of a Source form, including but + not limited to compiled object code, generated documentation, + and conversions to other media types. + + "Work" shall mean the work of authorship, whether in Source or + Object form, made available under the License, as indicated by a + copyright notice that is included in or attached to the work + (an example is provided in the Appendix below). + + "Derivative Works" shall mean any work, whether in Source or Object + form, that is based on (or derived from) the Work and for which the + editorial revisions, annotations, elaborations, or other modifications + represent, as a whole, an original work of authorship. For the purposes + of this License, Derivative Works shall not include works that remain + separable from, or merely link (or bind by name) to the interfaces of, + the Work and Derivative Works thereof. + + "Contribution" shall mean any work of authorship, including + the original version of the Work and any modifications or additions + to that Work or Derivative Works thereof, that is intentionally + submitted to Licensor for inclusion in the Work by the copyright owner + or by an individual or Legal Entity authorized to submit on behalf of + the copyright owner. For the purposes of this definition, "submitted" + means any form of electronic, verbal, or written communication sent + to the Licensor or its representatives, including but not limited to + communication on electronic mailing lists, source code control systems, + and issue tracking systems that are managed by, or on behalf of, the + Licensor for the purpose of discussing and improving the Work, but + excluding communication that is conspicuously marked or otherwise + designated in writing by the copyright owner as "Not a Contribution." + + "Contributor" shall mean Licensor and any individual or Legal Entity + on behalf of whom a Contribution has been received by Licensor and + subsequently incorporated within the Work. + +2. Grant of Copyright License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + copyright license to reproduce, prepare Derivative Works of, + publicly display, publicly perform, sublicense, and distribute the + Work and such Derivative Works in Source or Object form. + +3. Grant of Patent License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + (except as stated in this section) patent license to make, have made, + use, offer to sell, sell, import, and otherwise transfer the Work, + where such license applies only to those patent claims licensable + by such Contributor that are necessarily infringed by their + Contribution(s) alone or by combination of their Contribution(s) + with the Work to which such Contribution(s) was submitted. If You + institute patent litigation against any entity (including a + cross-claim or counterclaim in a lawsuit) alleging that the Work + or a Contribution incorporated within the Work constitutes direct + or contributory patent infringement, then any patent licenses + granted to You under this License for that Work shall terminate + as of the date such litigation is filed. + +4. Redistribution. You may reproduce and distribute copies of the + Work or Derivative Works thereof in any medium, with or without + modifications, and in Source or Object form, provided that You + meet the following conditions: + + (a) You must give any other recipients of the Work or + Derivative Works a copy of this License; and + + (b) You must cause any modified files to carry prominent notices + stating that You changed the files; and + + (c) You must retain, in the Source form of any Derivative Works + that You distribute, all copyright, patent, trademark, and + attribution notices from the Source form of the Work, + excluding those notices that do not pertain to any part of + the Derivative Works; and + + (d) If the Work includes a "NOTICE" text file as part of its + distribution, then any Derivative Works that You distribute must + include a readable copy of the attribution notices contained + within such NOTICE file, excluding those notices that do not + pertain to any part of the Derivative Works, in at least one + of the following places: within a NOTICE text file distributed + as part of the Derivative Works; within the Source form or + documentation, if provided along with the Derivative Works; or, + within a display generated by the Derivative Works, if and + wherever such third-party notices normally appear. The contents + of the NOTICE file are for informational purposes only and + do not modify the License. You may add Your own attribution + notices within Derivative Works that You distribute, alongside + or as an addendum to the NOTICE text from the Work, provided + that such additional attribution notices cannot be construed + as modifying the License. + + You may add Your own copyright statement to Your modifications and + may provide additional or different license terms and conditions + for use, reproduction, or distribution of Your modifications, or + for any such Derivative Works as a whole, provided Your use, + reproduction, and distribution of the Work otherwise complies with + the conditions stated in this License. + +5. Submission of Contributions. Unless You explicitly state otherwise, + any Contribution intentionally submitted for inclusion in the Work + by You to the Licensor shall be under the terms and conditions of + this License, without any additional terms or conditions. + Notwithstanding the above, nothing herein shall supersede or modify + the terms of any separate license agreement you may have executed + with Licensor regarding such Contributions. + +6. Trademarks. This License does not grant permission to use the trade + names, trademarks, service marks, or product names of the Licensor, + except as required for reasonable and customary use in describing the + origin of the Work and reproducing the content of the NOTICE file. + +7. Disclaimer of Warranty. Unless required by applicable law or + agreed to in writing, Licensor provides the Work (and each + Contributor provides its Contributions) on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + implied, including, without limitation, any warranties or conditions + of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A + PARTICULAR PURPOSE. You are solely responsible for determining the + appropriateness of using or redistributing the Work and assume any + risks associated with Your exercise of permissions under this License. + +8. Limitation of Liability. In no event and under no legal theory, + whether in tort (including negligence), contract, or otherwise, + unless required by applicable law (such as deliberate and grossly + negligent acts) or agreed to in writing, shall any Contributor be + liable to You for damages, including any direct, indirect, special, + incidental, or consequential damages of any character arising as a + result of this License or out of the use or inability to use the + Work (including but not limited to damages for loss of goodwill, + work stoppage, computer failure or malfunction, or any and all + other commercial damages or losses), even if such Contributor + has been advised of the possibility of such damages. + +9. Accepting Warranty or Additional Liability. While redistributing + the Work or Derivative Works thereof, You may choose to offer, + and charge a fee for, acceptance of support, warranty, indemnity, + or other liability obligations and/or rights consistent with this + License. However, in accepting such obligations, You may act only + on Your own behalf and on Your sole responsibility, not on behalf + of any other Contributor, and only if You agree to indemnify, + defend, and hold each Contributor harmless for any liability + incurred by, or claims asserted against, such Contributor by reason + of your accepting any such warranty or additional liability. + +========== +Notice for: jrjackson-0.4.11 +---------- + +https://github.com/guyboertje/jrjackson/blob/v0.4.6/README.md + +LICENSE applicable to this library: + +Apache License 2.0 see http://www.apache.org/licenses/LICENSE-2.0 + +========== +Notice for: jruby- +---------- + +JRuby is Copyright (c) 2007-2018 The JRuby project, and is released +under a tri EPL/GPL/LGPL license. You can use it, redistribute it +and/or modify it under the terms of the: + + Eclipse Public License version 2.0 + OR + GNU General Public License version 2 + OR + GNU Lesser General Public License version 2.1 + +bytelist (http://github.com/jruby/bytelist), +jnr-posix (https://github.com/jnr/jnr-posix), +jruby-openssl (https://github.com/jruby/jruby-openssl), +jruby-readline (https://github.com/jruby/jruby-readline), +psych (https://github.com/ruby/psych), +yydebug (https://github.com/jruby/jay-yydebug/) +are released under the same copyright/license. + +Some additional libraries distributed with JRuby are not covered by +JRuby's licence. Most of these libraries and their licenses are listed +below. Also see LICENSE.RUBY for most files found in lib/ruby/stdlib. + + asm (http://asm.objectweb.org) is distributed under the BSD license and is + + Copyright (c) 2000-2011 INRIA, France Telecom + All rights reserved. + + jline2 (https://github.com/jline/jline2) is distributed under the BSD license: + + Copyright (c) 2002-2012, the original author or authors. + All rights reserved. + + jzlib (http://www.jcraft.com/jzlib/) is distributed under the BSD license: + + Copyright (c) 2000-2011 ymnk, JCraft,Inc. All rights reserved. + + The "rake" library (https://github.com/ruby/rake) is distributed under + the MIT license, and has the following copyright: + + Copyright (c) 2003, 2004 Jim Weirich + + jcodings (http://github.com/jruby/jcodings) and + joni (http://github.com/jruby/joni) are distributed + under the MIT license without copyright. + + Bouncycastle is released under the MIT license: + + Copyright (c) 2000 - 2006 The Legion Of The Bouncy Castle. + + jnr-x86asm (https://github.com/jnr/jnr-x86asm) is distributed under the MIT + license with the following copyright: + + Copyright (C) 2010 Wayne Meissner + Copyright (c) 2008-2009, Petr Kobalicek + + The following libraries are redistributed under the Apache Software + License v2.0, available below. + invokebinder (https://github.com/headius/invokebinder) + jffi (https://github.com/jnr/jffi) + jitescript (https://github.com/qmx/jitescript) + jnr-constants (http://github.com/jnr/jnr-constants) + jnr-enxio (https://github.com/jnr/jnr-enxio) + jnr-ffi (https://github.com/jnr/jnr-jffi) + jnr-netdb (http://github.com/jnr/jnr-netdb) + jnr-unixsocket (https://github.com/jnr/jnr-unixsocket) + joda-time (http://joda-time.sourceforge.net) + maven (http://maven.apache.org/) + nailgun (http://martiansoftware.com/nailgun) + options (https://github.com/headius/options) + snakeyaml (https://github.com/asomov/snakeyaml) + unsafe-fences (https://github.com/headius/unsafe-fences) + + racc (runtime only, https://github.com/tenderlove/racc) is + distributed under the same license terms as the Ruby standard + library. This includes all files under lib/ruby/stdlib/racc. + See LICENSE.RUBY. + + json-generator and json-parser (https://github.com/flori/json) native + extenstions under the same license terms as the Ruby standard library. + See LICENSE.RUBY + +The complete text of the Eclipse Public License is as follows: + + Eclipse Public License - v 2.0 + + THE ACCOMPANYING PROGRAM IS PROVIDED UNDER THE TERMS OF THIS ECLIPSE + PUBLIC LICENSE ("AGREEMENT"). ANY USE, REPRODUCTION OR DISTRIBUTION + OF THE PROGRAM CONSTITUTES RECIPIENT'S ACCEPTANCE OF THIS AGREEMENT. + + 1. DEFINITIONS + + "Contribution" means: + + a) in the case of the initial Contributor, the initial content + Distributed under this Agreement, and + + b) in the case of each subsequent Contributor: + i) changes to the Program, and + ii) additions to the Program; + where such changes and/or additions to the Program originate from + and are Distributed by that particular Contributor. A Contribution + "originates" from a Contributor if it was added to the Program by + such Contributor itself or anyone acting on such Contributor's behalf. + Contributions do not include changes or additions to the Program that + are not Modified Works. + + "Contributor" means any person or entity that Distributes the Program. + + "Licensed Patents" mean patent claims licensable by a Contributor which + are necessarily infringed by the use or sale of its Contribution alone + or when combined with the Program. + + "Program" means the Contributions Distributed in accordance with this + Agreement. + + "Recipient" means anyone who receives the Program under this Agreement + or any Secondary License (as applicable), including Contributors. + + "Derivative Works" shall mean any work, whether in Source Code or other + form, that is based on (or derived from) the Program and for which the + editorial revisions, annotations, elaborations, or other modifications + represent, as a whole, an original work of authorship. + + "Modified Works" shall mean any work in Source Code or other form that + results from an addition to, deletion from, or modification of the + contents of the Program, including, for purposes of clarity any new file + in Source Code form that contains any contents of the Program. Modified + Works shall not include works that contain only declarations, + interfaces, types, classes, structures, or files of the Program solely + in each case in order to link to, bind by name, or subclass the Program + or Modified Works thereof. + + "Distribute" means the acts of a) distributing or b) making available + in any manner that enables the transfer of a copy. + + "Source Code" means the form of a Program preferred for making + modifications, including but not limited to software source code, + documentation source, and configuration files. + + "Secondary License" means either the GNU General Public License, + Version 2.0, or any later versions of that license, including any + exceptions or additional permissions as identified by the initial + Contributor. + + 2. GRANT OF RIGHTS + + a) Subject to the terms of this Agreement, each Contributor hereby + grants Recipient a non-exclusive, worldwide, royalty-free copyright + license to reproduce, prepare Derivative Works of, publicly display, + publicly perform, Distribute and sublicense the Contribution of such + Contributor, if any, and such Derivative Works. + + b) Subject to the terms of this Agreement, each Contributor hereby + grants Recipient a non-exclusive, worldwide, royalty-free patent + license under Licensed Patents to make, use, sell, offer to sell, + import and otherwise transfer the Contribution of such Contributor, + if any, in Source Code or other form. This patent license shall + apply to the combination of the Contribution and the Program if, at + the time the Contribution is added by the Contributor, such addition + of the Contribution causes such combination to be covered by the + Licensed Patents. The patent license shall not apply to any other + combinations which include the Contribution. No hardware per se is + licensed hereunder. + + c) Recipient understands that although each Contributor grants the + licenses to its Contributions set forth herein, no assurances are + provided by any Contributor that the Program does not infringe the + patent or other intellectual property rights of any other entity. + Each Contributor disclaims any liability to Recipient for claims + brought by any other entity based on infringement of intellectual + property rights or otherwise. As a condition to exercising the + rights and licenses granted hereunder, each Recipient hereby + assumes sole responsibility to secure any other intellectual + property rights needed, if any. For example, if a third party + patent license is required to allow Recipient to Distribute the + Program, it is Recipient's responsibility to acquire that license + before distributing the Program. + + d) Each Contributor represents that to its knowledge it has + sufficient copyright rights in its Contribution, if any, to grant + the copyright license set forth in this Agreement. + + e) Notwithstanding the terms of any Secondary License, no + Contributor makes additional grants to any Recipient (other than + those set forth in this Agreement) as a result of such Recipient's + receipt of the Program under the terms of a Secondary License + (if permitted under the terms of Section 3). + + 3. REQUIREMENTS + + 3.1 If a Contributor Distributes the Program in any form, then: + + a) the Program must also be made available as Source Code, in + accordance with section 3.2, and the Contributor must accompany + the Program with a statement that the Source Code for the Program + is available under this Agreement, and informs Recipients how to + obtain it in a reasonable manner on or through a medium customarily + used for software exchange; and + + b) the Contributor may Distribute the Program under a license + different than this Agreement, provided that such license: + i) effectively disclaims on behalf of all other Contributors all + warranties and conditions, express and implied, including + warranties or conditions of title and non-infringement, and + implied warranties or conditions of merchantability and fitness + for a particular purpose; + + ii) effectively excludes on behalf of all other Contributors all + liability for damages, including direct, indirect, special, + incidental and consequential damages, such as lost profits; + + iii) does not attempt to limit or alter the recipients' rights + in the Source Code under section 3.2; and + + iv) requires any subsequent distribution of the Program by any + party to be under a license that satisfies the requirements + of this section 3. + + 3.2 When the Program is Distributed as Source Code: + + a) it must be made available under this Agreement, or if the + Program (i) is combined with other material in a separate file or + files made available under a Secondary License, and (ii) the initial + Contributor attached to the Source Code the notice described in + Exhibit A of this Agreement, then the Program may be made available + under the terms of such Secondary Licenses, and + + b) a copy of this Agreement must be included with each copy of + the Program. + + 3.3 Contributors may not remove or alter any copyright, patent, + trademark, attribution notices, disclaimers of warranty, or limitations + of liability ("notices") contained within the Program from any copy of + the Program which they Distribute, provided that Contributors may add + their own appropriate notices. + + 4. COMMERCIAL DISTRIBUTION + + Commercial distributors of software may accept certain responsibilities + with respect to end users, business partners and the like. While this + license is intended to facilitate the commercial use of the Program, + the Contributor who includes the Program in a commercial product + offering should do so in a manner which does not create potential + liability for other Contributors. Therefore, if a Contributor includes + the Program in a commercial product offering, such Contributor + ("Commercial Contributor") hereby agrees to defend and indemnify every + other Contributor ("Indemnified Contributor") against any losses, + damages and costs (collectively "Losses") arising from claims, lawsuits + and other legal actions brought by a third party against the Indemnified + Contributor to the extent caused by the acts or omissions of such + Commercial Contributor in connection with its distribution of the Program + in a commercial product offering. The obligations in this section do not + apply to any claims or Losses relating to any actual or alleged + intellectual property infringement. In order to qualify, an Indemnified + Contributor must: a) promptly notify the Commercial Contributor in + writing of such claim, and b) allow the Commercial Contributor to control, + and cooperate with the Commercial Contributor in, the defense and any + related settlement negotiations. The Indemnified Contributor may + participate in any such claim at its own expense. + + For example, a Contributor might include the Program in a commercial + product offering, Product X. That Contributor is then a Commercial + Contributor. If that Commercial Contributor then makes performance + claims, or offers warranties related to Product X, those performance + claims and warranties are such Commercial Contributor's responsibility + alone. Under this section, the Commercial Contributor would have to + defend claims against the other Contributors related to those performance + claims and warranties, and if a court requires any other Contributor to + pay any damages as a result, the Commercial Contributor must pay + those damages. + + 5. NO WARRANTY + + EXCEPT AS EXPRESSLY SET FORTH IN THIS AGREEMENT, AND TO THE EXTENT + PERMITTED BY APPLICABLE LAW, THE PROGRAM IS PROVIDED ON AN "AS IS" + BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, EITHER EXPRESS OR + IMPLIED INCLUDING, WITHOUT LIMITATION, ANY WARRANTIES OR CONDITIONS OF + TITLE, NON-INFRINGEMENT, MERCHANTABILITY OR FITNESS FOR A PARTICULAR + PURPOSE. Each Recipient is solely responsible for determining the + appropriateness of using and distributing the Program and assumes all + risks associated with its exercise of rights under this Agreement, + including but not limited to the risks and costs of program errors, + compliance with applicable laws, damage to or loss of data, programs + or equipment, and unavailability or interruption of operations. + + 6. DISCLAIMER OF LIABILITY + + EXCEPT AS EXPRESSLY SET FORTH IN THIS AGREEMENT, AND TO THE EXTENT + PERMITTED BY APPLICABLE LAW, NEITHER RECIPIENT NOR ANY CONTRIBUTORS + SHALL HAVE ANY LIABILITY FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING WITHOUT LIMITATION LOST + PROFITS), HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + ARISING IN ANY WAY OUT OF THE USE OR DISTRIBUTION OF THE PROGRAM OR THE + EXERCISE OF ANY RIGHTS GRANTED HEREUNDER, EVEN IF ADVISED OF THE + POSSIBILITY OF SUCH DAMAGES. + + 7. GENERAL + + If any provision of this Agreement is invalid or unenforceable under + applicable law, it shall not affect the validity or enforceability of + the remainder of the terms of this Agreement, and without further + action by the parties hereto, such provision shall be reformed to the + minimum extent necessary to make such provision valid and enforceable. + + If Recipient institutes patent litigation against any entity + (including a cross-claim or counterclaim in a lawsuit) alleging that the + Program itself (excluding combinations of the Program with other software + or hardware) infringes such Recipient's patent(s), then such Recipient's + rights granted under Section 2(b) shall terminate as of the date such + litigation is filed. + + All Recipient's rights under this Agreement shall terminate if it + fails to comply with any of the material terms or conditions of this + Agreement and does not cure such failure in a reasonable period of + time after becoming aware of such noncompliance. If all Recipient's + rights under this Agreement terminate, Recipient agrees to cease use + and distribution of the Program as soon as reasonably practicable. + However, Recipient's obligations under this Agreement and any licenses + granted by Recipient relating to the Program shall continue and survive. + + Everyone is permitted to copy and distribute copies of this Agreement, + but in order to avoid inconsistency the Agreement is copyrighted and + may only be modified in the following manner. The Agreement Steward + reserves the right to publish new versions (including revisions) of + this Agreement from time to time. No one other than the Agreement + Steward has the right to modify this Agreement. The Eclipse Foundation + is the initial Agreement Steward. The Eclipse Foundation may assign the + responsibility to serve as the Agreement Steward to a suitable separate + entity. Each new version of the Agreement will be given a distinguishing + version number. The Program (including Contributions) may always be + Distributed subject to the version of the Agreement under which it was + received. In addition, after a new version of the Agreement is published, + Contributor may elect to Distribute the Program (including its + Contributions) under the new version. + + Except as expressly stated in Sections 2(a) and 2(b) above, Recipient + receives no rights or licenses to the intellectual property of any + Contributor under this Agreement, whether expressly, by implication, + estoppel or otherwise. All rights in the Program not expressly granted + under this Agreement are reserved. Nothing in this Agreement is intended + to be enforceable by any entity that is not a Contributor or Recipient. + No third-party beneficiary rights are created under this Agreement. + + Exhibit A - Form of Secondary Licenses Notice + + "This Source Code may also be made available under the following + Secondary Licenses when the conditions for such availability set forth + in the Eclipse Public License, v. 2.0 are satisfied: {name license(s), + version(s), and exceptions or additional permissions here}." + + Simply including a copy of this Agreement, including this Exhibit A + is not sufficient to license the Source Code under Secondary Licenses. + + If it is not possible or desirable to put the notice in a particular + file, then You may include the notice in a location (such as a LICENSE + file in a relevant directory) where a recipient would be likely to + look for such a notice. + + You may add additional accurate notices of copyright ownership. + +The complete text of the GNU General Public License v2 is as follows: + + GNU GENERAL PUBLIC LICENSE + Version 2, June 1991 + + Copyright (C) 1989, 1991 Free Software Foundation, Inc. + 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + Everyone is permitted to copy and distribute verbatim copies + of this license document, but changing it is not allowed. + + Preamble + + The licenses for most software are designed to take away your + freedom to share and change it. By contrast, the GNU General Public + License is intended to guarantee your freedom to share and change free + software--to make sure the software is free for all its users. This + General Public License applies to most of the Free Software + Foundation's software and to any other program whose authors commit to + using it. (Some other Free Software Foundation software is covered by + the GNU Library General Public License instead.) You can apply it to + your programs, too. + + When we speak of free software, we are referring to freedom, not + price. Our General Public Licenses are designed to make sure that you + have the freedom to distribute copies of free software (and charge for + this service if you wish), that you receive source code or can get it + if you want it, that you can change the software or use pieces of it + in new free programs; and that you know you can do these things. + + To protect your rights, we need to make restrictions that forbid + anyone to deny you these rights or to ask you to surrender the rights. + These restrictions translate to certain responsibilities for you if you + distribute copies of the software, or if you modify it. + + For example, if you distribute copies of such a program, whether + gratis or for a fee, you must give the recipients all the rights that + you have. You must make sure that they, too, receive or can get the + source code. And you must show them these terms so they know their + rights. + + We protect your rights with two steps: (1) copyright the software, and + (2) offer you this license which gives you legal permission to copy, + distribute and/or modify the software. + + Also, for each author's protection and ours, we want to make certain + that everyone understands that there is no warranty for this free + software. If the software is modified by someone else and passed on, we + want its recipients to know that what they have is not the original, so + that any problems introduced by others will not reflect on the original + authors' reputations. + + Finally, any free program is threatened constantly by software + patents. We wish to avoid the danger that redistributors of a free + program will individually obtain patent licenses, in effect making the + program proprietary. To prevent this, we have made it clear that any + patent must be licensed for everyone's free use or not licensed at all. + + The precise terms and conditions for copying, distribution and + modification follow. + + GNU GENERAL PUBLIC LICENSE + TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION + + 0. This License applies to any program or other work which contains + a notice placed by the copyright holder saying it may be distributed + under the terms of this General Public License. The "Program", below, + refers to any such program or work, and a "work based on the Program" + means either the Program or any derivative work under copyright law: + that is to say, a work containing the Program or a portion of it, + either verbatim or with modifications and/or translated into another + language. (Hereinafter, translation is included without limitation in + the term "modification".) Each licensee is addressed as "you". + + Activities other than copying, distribution and modification are not + covered by this License; they are outside its scope. The act of + running the Program is not restricted, and the output from the Program + is covered only if its contents constitute a work based on the + Program (independent of having been made by running the Program). + Whether that is true depends on what the Program does. + + 1. You may copy and distribute verbatim copies of the Program's + source code as you receive it, in any medium, provided that you + conspicuously and appropriately publish on each copy an appropriate + copyright notice and disclaimer of warranty; keep intact all the + notices that refer to this License and to the absence of any warranty; + and give any other recipients of the Program a copy of this License + along with the Program. + + You may charge a fee for the physical act of transferring a copy, and + you may at your option offer warranty protection in exchange for a fee. + + 2. You may modify your copy or copies of the Program or any portion + of it, thus forming a work based on the Program, and copy and + distribute such modifications or work under the terms of Section 1 + above, provided that you also meet all of these conditions: + + a) You must cause the modified files to carry prominent notices + stating that you changed the files and the date of any change. + + b) You must cause any work that you distribute or publish, that in + whole or in part contains or is derived from the Program or any + part thereof, to be licensed as a whole at no charge to all third + parties under the terms of this License. + + c) If the modified program normally reads commands interactively + when run, you must cause it, when started running for such + interactive use in the most ordinary way, to print or display an + announcement including an appropriate copyright notice and a + notice that there is no warranty (or else, saying that you provide + a warranty) and that users may redistribute the program under + these conditions, and telling the user how to view a copy of this + License. (Exception: if the Program itself is interactive but + does not normally print such an announcement, your work based on + the Program is not required to print an announcement.) + + These requirements apply to the modified work as a whole. If + identifiable sections of that work are not derived from the Program, + and can be reasonably considered independent and separate works in + themselves, then this License, and its terms, do not apply to those + sections when you distribute them as separate works. But when you + distribute the same sections as part of a whole which is a work based + on the Program, the distribution of the whole must be on the terms of + this License, whose permissions for other licensees extend to the + entire whole, and thus to each and every part regardless of who wrote it. + + Thus, it is not the intent of this section to claim rights or contest + your rights to work written entirely by you; rather, the intent is to + exercise the right to control the distribution of derivative or + collective works based on the Program. + + In addition, mere aggregation of another work not based on the Program + with the Program (or with a work based on the Program) on a volume of + a storage or distribution medium does not bring the other work under + the scope of this License. + + 3. You may copy and distribute the Program (or a work based on it, + under Section 2) in object code or executable form under the terms of + Sections 1 and 2 above provided that you also do one of the following: + + a) Accompany it with the complete corresponding machine-readable + source code, which must be distributed under the terms of Sections + 1 and 2 above on a medium customarily used for software interchange; or, + + b) Accompany it with a written offer, valid for at least three + years, to give any third party, for a charge no more than your + cost of physically performing source distribution, a complete + machine-readable copy of the corresponding source code, to be + distributed under the terms of Sections 1 and 2 above on a medium + customarily used for software interchange; or, + + c) Accompany it with the information you received as to the offer + to distribute corresponding source code. (This alternative is + allowed only for noncommercial distribution and only if you + received the program in object code or executable form with such + an offer, in accord with Subsection b above.) + + The source code for a work means the preferred form of the work for + making modifications to it. For an executable work, complete source + code means all the source code for all modules it contains, plus any + associated interface definition files, plus the scripts used to + control compilation and installation of the executable. However, as a + special exception, the source code distributed need not include + anything that is normally distributed (in either source or binary + form) with the major components (compiler, kernel, and so on) of the + operating system on which the executable runs, unless that component + itself accompanies the executable. + + If distribution of executable or object code is made by offering + access to copy from a designated place, then offering equivalent + access to copy the source code from the same place counts as + distribution of the source code, even though third parties are not + compelled to copy the source along with the object code. + + 4. You may not copy, modify, sublicense, or distribute the Program + except as expressly provided under this License. Any attempt + otherwise to copy, modify, sublicense or distribute the Program is + void, and will automatically terminate your rights under this License. + However, parties who have received copies, or rights, from you under + this License will not have their licenses terminated so long as such + parties remain in full compliance. + + 5. You are not required to accept this License, since you have not + signed it. However, nothing else grants you permission to modify or + distribute the Program or its derivative works. These actions are + prohibited by law if you do not accept this License. Therefore, by + modifying or distributing the Program (or any work based on the + Program), you indicate your acceptance of this License to do so, and + all its terms and conditions for copying, distributing or modifying + the Program or works based on it. + + 6. Each time you redistribute the Program (or any work based on the + Program), the recipient automatically receives a license from the + original licensor to copy, distribute or modify the Program subject to + these terms and conditions. You may not impose any further + restrictions on the recipients' exercise of the rights granted herein. + You are not responsible for enforcing compliance by third parties to + this License. + + 7. If, as a consequence of a court judgment or allegation of patent + infringement or for any other reason (not limited to patent issues), + conditions are imposed on you (whether by court order, agreement or + otherwise) that contradict the conditions of this License, they do not + excuse you from the conditions of this License. If you cannot + distribute so as to satisfy simultaneously your obligations under this + License and any other pertinent obligations, then as a consequence you + may not distribute the Program at all. For example, if a patent + license would not permit royalty-free redistribution of the Program by + all those who receive copies directly or indirectly through you, then + the only way you could satisfy both it and this License would be to + refrain entirely from distribution of the Program. + + If any portion of this section is held invalid or unenforceable under + any particular circumstance, the balance of the section is intended to + apply and the section as a whole is intended to apply in other + circumstances. + + It is not the purpose of this section to induce you to infringe any + patents or other property right claims or to contest validity of any + such claims; this section has the sole purpose of protecting the + integrity of the free software distribution system, which is + implemented by public license practices. Many people have made + generous contributions to the wide range of software distributed + through that system in reliance on consistent application of that + system; it is up to the author/donor to decide if he or she is willing + to distribute software through any other system and a licensee cannot + impose that choice. + + This section is intended to make thoroughly clear what is believed to + be a consequence of the rest of this License. + + 8. If the distribution and/or use of the Program is restricted in + certain countries either by patents or by copyrighted interfaces, the + original copyright holder who places the Program under this License + may add an explicit geographical distribution limitation excluding + those countries, so that distribution is permitted only in or among + countries not thus excluded. In such case, this License incorporates + the limitation as if written in the body of this License. + + 9. The Free Software Foundation may publish revised and/or new versions + of the General Public License from time to time. Such new versions will + be similar in spirit to the present version, but may differ in detail to + address new problems or concerns. + + Each version is given a distinguishing version number. If the Program + specifies a version number of this License which applies to it and "any + later version", you have the option of following the terms and conditions + either of that version or of any later version published by the Free + Software Foundation. If the Program does not specify a version number of + this License, you may choose any version ever published by the Free Software + Foundation. + + 10. If you wish to incorporate parts of the Program into other free + programs whose distribution conditions are different, write to the author + to ask for permission. For software which is copyrighted by the Free + Software Foundation, write to the Free Software Foundation; we sometimes + make exceptions for this. Our decision will be guided by the two goals + of preserving the free status of all derivatives of our free software and + of promoting the sharing and reuse of software generally. + + NO WARRANTY + + 11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY + FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN + OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES + PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED + OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS + TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE + PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING, + REPAIR OR CORRECTION. + + 12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING + WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR + REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, + INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING + OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED + TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY + YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER + PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE + POSSIBILITY OF SUCH DAMAGES. + + END OF TERMS AND CONDITIONS + +The complete text of the GNU Lesser General Public License 2.1 is as follows: + + GNU LESSER GENERAL PUBLIC LICENSE + Version 2.1, February 1999 + + Copyright (C) 1991, 1999 Free Software Foundation, Inc. + 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + Everyone is permitted to copy and distribute verbatim copies + of this license document, but changing it is not allowed. + + [This is the first released version of the Lesser GPL. It also counts + as the successor of the GNU Library Public License, version 2, hence + the version number 2.1.] + + Preamble + + The licenses for most software are designed to take away your + freedom to share and change it. By contrast, the GNU General Public + Licenses are intended to guarantee your freedom to share and change + free software--to make sure the software is free for all its users. + + This license, the Lesser General Public License, applies to some + specially designated software packages--typically libraries--of the + Free Software Foundation and other authors who decide to use it. You + can use it too, but we suggest you first think carefully about whether + this license or the ordinary General Public License is the better + strategy to use in any particular case, based on the explanations below. + + When we speak of free software, we are referring to freedom of use, + not price. Our General Public Licenses are designed to make sure that + you have the freedom to distribute copies of free software (and charge + for this service if you wish); that you receive source code or can get + it if you want it; that you can change the software and use pieces of + it in new free programs; and that you are informed that you can do + these things. + + To protect your rights, we need to make restrictions that forbid + distributors to deny you these rights or to ask you to surrender these + rights. These restrictions translate to certain responsibilities for + you if you distribute copies of the library or if you modify it. + + For example, if you distribute copies of the library, whether gratis + or for a fee, you must give the recipients all the rights that we gave + you. You must make sure that they, too, receive or can get the source + code. If you link other code with the library, you must provide + complete object files to the recipients, so that they can relink them + with the library after making changes to the library and recompiling + it. And you must show them these terms so they know their rights. + + We protect your rights with a two-step method: (1) we copyright the + library, and (2) we offer you this license, which gives you legal + permission to copy, distribute and/or modify the library. + + To protect each distributor, we want to make it very clear that + there is no warranty for the free library. Also, if the library is + modified by someone else and passed on, the recipients should know + that what they have is not the original version, so that the original + author's reputation will not be affected by problems that might be + introduced by others. + + Finally, software patents pose a constant threat to the existence of + any free program. We wish to make sure that a company cannot + effectively restrict the users of a free program by obtaining a + restrictive license from a patent holder. Therefore, we insist that + any patent license obtained for a version of the library must be + consistent with the full freedom of use specified in this license. + + Most GNU software, including some libraries, is covered by the + ordinary GNU General Public License. This license, the GNU Lesser + General Public License, applies to certain designated libraries, and + is quite different from the ordinary General Public License. We use + this license for certain libraries in order to permit linking those + libraries into non-free programs. + + When a program is linked with a library, whether statically or using + a shared library, the combination of the two is legally speaking a + combined work, a derivative of the original library. The ordinary + General Public License therefore permits such linking only if the + entire combination fits its criteria of freedom. The Lesser General + Public License permits more lax criteria for linking other code with + the library. + + We call this license the "Lesser" General Public License because it + does Less to protect the user's freedom than the ordinary General + Public License. It also provides other free software developers Less + of an advantage over competing non-free programs. These disadvantages + are the reason we use the ordinary General Public License for many + libraries. However, the Lesser license provides advantages in certain + special circumstances. + + For example, on rare occasions, there may be a special need to + encourage the widest possible use of a certain library, so that it becomes + a de-facto standard. To achieve this, non-free programs must be + allowed to use the library. A more frequent case is that a free + library does the same job as widely used non-free libraries. In this + case, there is little to gain by limiting the free library to free + software only, so we use the Lesser General Public License. + + In other cases, permission to use a particular library in non-free + programs enables a greater number of people to use a large body of + free software. For example, permission to use the GNU C Library in + non-free programs enables many more people to use the whole GNU + operating system, as well as its variant, the GNU/Linux operating + system. + + Although the Lesser General Public License is Less protective of the + users' freedom, it does ensure that the user of a program that is + linked with the Library has the freedom and the wherewithal to run + that program using a modified version of the Library. + + The precise terms and conditions for copying, distribution and + modification follow. Pay close attention to the difference between a + "work based on the library" and a "work that uses the library". The + former contains code derived from the library, whereas the latter must + be combined with the library in order to run. + + GNU LESSER GENERAL PUBLIC LICENSE + TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION + + 0. This License Agreement applies to any software library or other + program which contains a notice placed by the copyright holder or + other authorized party saying it may be distributed under the terms of + this Lesser General Public License (also called "this License"). + Each licensee is addressed as "you". + + A "library" means a collection of software functions and/or data + prepared so as to be conveniently linked with application programs + (which use some of those functions and data) to form executables. + + The "Library", below, refers to any such software library or work + which has been distributed under these terms. A "work based on the + Library" means either the Library or any derivative work under + copyright law: that is to say, a work containing the Library or a + portion of it, either verbatim or with modifications and/or translated + straightforwardly into another language. (Hereinafter, translation is + included without limitation in the term "modification".) + + "Source code" for a work means the preferred form of the work for + making modifications to it. For a library, complete source code means + all the source code for all modules it contains, plus any associated + interface definition files, plus the scripts used to control compilation + and installation of the library. + + Activities other than copying, distribution and modification are not + covered by this License; they are outside its scope. The act of + running a program using the Library is not restricted, and output from + such a program is covered only if its contents constitute a work based + on the Library (independent of the use of the Library in a tool for + writing it). Whether that is true depends on what the Library does + and what the program that uses the Library does. + + 1. You may copy and distribute verbatim copies of the Library's + complete source code as you receive it, in any medium, provided that + you conspicuously and appropriately publish on each copy an + appropriate copyright notice and disclaimer of warranty; keep intact + all the notices that refer to this License and to the absence of any + warranty; and distribute a copy of this License along with the + Library. + + You may charge a fee for the physical act of transferring a copy, + and you may at your option offer warranty protection in exchange for a + fee. + + 2. You may modify your copy or copies of the Library or any portion + of it, thus forming a work based on the Library, and copy and + distribute such modifications or work under the terms of Section 1 + above, provided that you also meet all of these conditions: + + a) The modified work must itself be a software library. + + b) You must cause the files modified to carry prominent notices + stating that you changed the files and the date of any change. + + c) You must cause the whole of the work to be licensed at no + charge to all third parties under the terms of this License. + + d) If a facility in the modified Library refers to a function or a + table of data to be supplied by an application program that uses + the facility, other than as an argument passed when the facility + is invoked, then you must make a good faith effort to ensure that, + in the event an application does not supply such function or + table, the facility still operates, and performs whatever part of + its purpose remains meaningful. + + (For example, a function in a library to compute square roots has + a purpose that is entirely well-defined independent of the + application. Therefore, Subsection 2d requires that any + application-supplied function or table used by this function must + be optional: if the application does not supply it, the square + root function must still compute square roots.) + + These requirements apply to the modified work as a whole. If + identifiable sections of that work are not derived from the Library, + and can be reasonably considered independent and separate works in + themselves, then this License, and its terms, do not apply to those + sections when you distribute them as separate works. But when you + distribute the same sections as part of a whole which is a work based + on the Library, the distribution of the whole must be on the terms of + this License, whose permissions for other licensees extend to the + entire whole, and thus to each and every part regardless of who wrote + it. + + Thus, it is not the intent of this section to claim rights or contest + your rights to work written entirely by you; rather, the intent is to + exercise the right to control the distribution of derivative or + collective works based on the Library. + + In addition, mere aggregation of another work not based on the Library + with the Library (or with a work based on the Library) on a volume of + a storage or distribution medium does not bring the other work under + the scope of this License. + + 3. You may opt to apply the terms of the ordinary GNU General Public + License instead of this License to a given copy of the Library. To do + this, you must alter all the notices that refer to this License, so + that they refer to the ordinary GNU General Public License, version 2, + instead of to this License. (If a newer version than version 2 of the + ordinary GNU General Public License has appeared, then you can specify + that version instead if you wish.) Do not make any other change in + these notices. + + Once this change is made in a given copy, it is irreversible for + that copy, so the ordinary GNU General Public License applies to all + subsequent copies and derivative works made from that copy. + + This option is useful when you wish to copy part of the code of + the Library into a program that is not a library. + + 4. You may copy and distribute the Library (or a portion or + derivative of it, under Section 2) in object code or executable form + under the terms of Sections 1 and 2 above provided that you accompany + it with the complete corresponding machine-readable source code, which + must be distributed under the terms of Sections 1 and 2 above on a + medium customarily used for software interchange. + + If distribution of object code is made by offering access to copy + from a designated place, then offering equivalent access to copy the + source code from the same place satisfies the requirement to + distribute the source code, even though third parties are not + compelled to copy the source along with the object code. + + 5. A program that contains no derivative of any portion of the + Library, but is designed to work with the Library by being compiled or + linked with it, is called a "work that uses the Library". Such a + work, in isolation, is not a derivative work of the Library, and + therefore falls outside the scope of this License. + + However, linking a "work that uses the Library" with the Library + creates an executable that is a derivative of the Library (because it + contains portions of the Library), rather than a "work that uses the + library". The executable is therefore covered by this License. + Section 6 states terms for distribution of such executables. + + When a "work that uses the Library" uses material from a header file + that is part of the Library, the object code for the work may be a + derivative work of the Library even though the source code is not. + Whether this is true is especially significant if the work can be + linked without the Library, or if the work is itself a library. The + threshold for this to be true is not precisely defined by law. + + If such an object file uses only numerical parameters, data + structure layouts and accessors, and small macros and small inline + functions (ten lines or less in length), then the use of the object + file is unrestricted, regardless of whether it is legally a derivative + work. (Executables containing this object code plus portions of the + Library will still fall under Section 6.) + + Otherwise, if the work is a derivative of the Library, you may + distribute the object code for the work under the terms of Section 6. + Any executables containing that work also fall under Section 6, + whether or not they are linked directly with the Library itself. + + 6. As an exception to the Sections above, you may also combine or + link a "work that uses the Library" with the Library to produce a + work containing portions of the Library, and distribute that work + under terms of your choice, provided that the terms permit + modification of the work for the customer's own use and reverse + engineering for debugging such modifications. + + You must give prominent notice with each copy of the work that the + Library is used in it and that the Library and its use are covered by + this License. You must supply a copy of this License. If the work + during execution displays copyright notices, you must include the + copyright notice for the Library among them, as well as a reference + directing the user to the copy of this License. Also, you must do one + of these things: + + a) Accompany the work with the complete corresponding + machine-readable source code for the Library including whatever + changes were used in the work (which must be distributed under + Sections 1 and 2 above); and, if the work is an executable linked + with the Library, with the complete machine-readable "work that + uses the Library", as object code and/or source code, so that the + user can modify the Library and then relink to produce a modified + executable containing the modified Library. (It is understood + that the user who changes the contents of definitions files in the + Library will not necessarily be able to recompile the application + to use the modified definitions.) + + b) Use a suitable shared library mechanism for linking with the + Library. A suitable mechanism is one that (1) uses at run time a + copy of the library already present on the user's computer system, + rather than copying library functions into the executable, and (2) + will operate properly with a modified version of the library, if + the user installs one, as long as the modified version is + interface-compatible with the version that the work was made with. + + c) Accompany the work with a written offer, valid for at + least three years, to give the same user the materials + specified in Subsection 6a, above, for a charge no more + than the cost of performing this distribution. + + d) If distribution of the work is made by offering access to copy + from a designated place, offer equivalent access to copy the above + specified materials from the same place. + + e) Verify that the user has already received a copy of these + materials or that you have already sent this user a copy. + + For an executable, the required form of the "work that uses the + Library" must include any data and utility programs needed for + reproducing the executable from it. However, as a special exception, + the materials to be distributed need not include anything that is + normally distributed (in either source or binary form) with the major + components (compiler, kernel, and so on) of the operating system on + which the executable runs, unless that component itself accompanies + the executable. + + It may happen that this requirement contradicts the license + restrictions of other proprietary libraries that do not normally + accompany the operating system. Such a contradiction means you cannot + use both them and the Library together in an executable that you + distribute. + + 7. You may place library facilities that are a work based on the + Library side-by-side in a single library together with other library + facilities not covered by this License, and distribute such a combined + library, provided that the separate distribution of the work based on + the Library and of the other library facilities is otherwise + permitted, and provided that you do these two things: + + a) Accompany the combined library with a copy of the same work + based on the Library, uncombined with any other library + facilities. This must be distributed under the terms of the + Sections above. + + b) Give prominent notice with the combined library of the fact + that part of it is a work based on the Library, and explaining + where to find the accompanying uncombined form of the same work. + + 8. You may not copy, modify, sublicense, link with, or distribute + the Library except as expressly provided under this License. Any + attempt otherwise to copy, modify, sublicense, link with, or + distribute the Library is void, and will automatically terminate your + rights under this License. However, parties who have received copies, + or rights, from you under this License will not have their licenses + terminated so long as such parties remain in full compliance. + + 9. You are not required to accept this License, since you have not + signed it. However, nothing else grants you permission to modify or + distribute the Library or its derivative works. These actions are + prohibited by law if you do not accept this License. Therefore, by + modifying or distributing the Library (or any work based on the + Library), you indicate your acceptance of this License to do so, and + all its terms and conditions for copying, distributing or modifying + the Library or works based on it. + + 10. Each time you redistribute the Library (or any work based on the + Library), the recipient automatically receives a license from the + original licensor to copy, distribute, link with or modify the Library + subject to these terms and conditions. You may not impose any further + restrictions on the recipients' exercise of the rights granted herein. + You are not responsible for enforcing compliance by third parties with + this License. + + 11. If, as a consequence of a court judgment or allegation of patent + infringement or for any other reason (not limited to patent issues), + conditions are imposed on you (whether by court order, agreement or + otherwise) that contradict the conditions of this License, they do not + excuse you from the conditions of this License. If you cannot + distribute so as to satisfy simultaneously your obligations under this + License and any other pertinent obligations, then as a consequence you + may not distribute the Library at all. For example, if a patent + license would not permit royalty-free redistribution of the Library by + all those who receive copies directly or indirectly through you, then + the only way you could satisfy both it and this License would be to + refrain entirely from distribution of the Library. + + If any portion of this section is held invalid or unenforceable under any + particular circumstance, the balance of the section is intended to apply, + and the section as a whole is intended to apply in other circumstances. + + It is not the purpose of this section to induce you to infringe any + patents or other property right claims or to contest validity of any + such claims; this section has the sole purpose of protecting the + integrity of the free software distribution system which is + implemented by public license practices. Many people have made + generous contributions to the wide range of software distributed + through that system in reliance on consistent application of that + system; it is up to the author/donor to decide if he or she is willing + to distribute software through any other system and a licensee cannot + impose that choice. + + This section is intended to make thoroughly clear what is believed to + be a consequence of the rest of this License. + + 12. If the distribution and/or use of the Library is restricted in + certain countries either by patents or by copyrighted interfaces, the + original copyright holder who places the Library under this License may add + an explicit geographical distribution limitation excluding those countries, + so that distribution is permitted only in or among countries not thus + excluded. In such case, this License incorporates the limitation as if + written in the body of this License. + + 13. The Free Software Foundation may publish revised and/or new + versions of the Lesser General Public License from time to time. + Such new versions will be similar in spirit to the present version, + but may differ in detail to address new problems or concerns. + + Each version is given a distinguishing version number. If the Library + specifies a version number of this License which applies to it and + "any later version", you have the option of following the terms and + conditions either of that version or of any later version published by + the Free Software Foundation. If the Library does not specify a + license version number, you may choose any version ever published by + the Free Software Foundation. + + 14. If you wish to incorporate parts of the Library into other free + programs whose distribution conditions are incompatible with these, + write to the author to ask for permission. For software which is + copyrighted by the Free Software Foundation, write to the Free + Software Foundation; we sometimes make exceptions for this. Our + decision will be guided by the two goals of preserving the free status + of all derivatives of our free software and of promoting the sharing + and reuse of software generally. + + NO WARRANTY + + 15. BECAUSE THE LIBRARY IS LICENSED FREE OF CHARGE, THERE IS NO + WARRANTY FOR THE LIBRARY, TO THE EXTENT PERMITTED BY APPLICABLE LAW. + EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR + OTHER PARTIES PROVIDE THE LIBRARY "AS IS" WITHOUT WARRANTY OF ANY + KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE + IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE + LIBRARY IS WITH YOU. SHOULD THE LIBRARY PROVE DEFECTIVE, YOU ASSUME + THE COST OF ALL NECESSARY SERVICING, REPAIR OR CORRECTION. + + 16. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN + WRITING WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY + AND/OR REDISTRIBUTE THE LIBRARY AS PERMITTED ABOVE, BE LIABLE TO YOU + FOR DAMAGES, INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR + CONSEQUENTIAL DAMAGES ARISING OUT OF THE USE OR INABILITY TO USE THE + LIBRARY (INCLUDING BUT NOT LIMITED TO LOSS OF DATA OR DATA BEING + RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD PARTIES OR A + FAILURE OF THE LIBRARY TO OPERATE WITH ANY OTHER SOFTWARE), EVEN IF + SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH + DAMAGES. + + END OF TERMS AND CONDITIONS + + How to Apply These Terms to Your New Libraries + + If you develop a new library, and you want it to be of the greatest + possible use to the public, we recommend making it free software that + everyone can redistribute and change. You can do so by permitting + redistribution under these terms (or, alternatively, under the terms of the + ordinary General Public License). + + To apply these terms, attach the following notices to the library. It is + safest to attach them to the start of each source file to most effectively + convey the exclusion of warranty; and each file should have at least the + "copyright" line and a pointer to where the full notice is found. + + + Copyright (C) + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with this library; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + + Also add information on how to contact you by electronic and paper mail. + + You should also get your employer (if you work as a programmer) or your + school, if any, to sign a "copyright disclaimer" for the library, if + necessary. Here is a sample; alter the names: + + Yoyodyne, Inc., hereby disclaims all copyright interest in the + library `Frob' (a library for tweaking knobs) written by James Random Hacker. + + , 1 April 1990 + Ty Coon, President of Vice + + That's all there is to it! + +The following licenses cover code other than JRuby which is included with JRuby. + +Licenses listed below include: + +* GNU General Public License version 3 +* Apache 2.0 License +* BSD License +* MIT License + +The complete text of the GNU General Public License version 3 is as follows: + + GNU GENERAL PUBLIC LICENSE + Version 3, 29 June 2007 + + Copyright (C) 2007 Free Software Foundation, Inc. + Everyone is permitted to copy and distribute verbatim copies + of this license document, but changing it is not allowed. + + Preamble + + The GNU General Public License is a free, copyleft license for + software and other kinds of works. + + The licenses for most software and other practical works are designed + to take away your freedom to share and change the works. By contrast, + the GNU General Public License is intended to guarantee your freedom to + share and change all versions of a program--to make sure it remains free + software for all its users. We, the Free Software Foundation, use the + GNU General Public License for most of our software; it applies also to + any other work released this way by its authors. You can apply it to + your programs, too. + + When we speak of free software, we are referring to freedom, not + price. Our General Public Licenses are designed to make sure that you + have the freedom to distribute copies of free software (and charge for + them if you wish), that you receive source code or can get it if you + want it, that you can change the software or use pieces of it in new + free programs, and that you know you can do these things. + + To protect your rights, we need to prevent others from denying you + these rights or asking you to surrender the rights. Therefore, you have + certain responsibilities if you distribute copies of the software, or if + you modify it: responsibilities to respect the freedom of others. + + For example, if you distribute copies of such a program, whether + gratis or for a fee, you must pass on to the recipients the same + freedoms that you received. You must make sure that they, too, receive + or can get the source code. And you must show them these terms so they + know their rights. + + Developers that use the GNU GPL protect your rights with two steps: + (1) assert copyright on the software, and (2) offer you this License + giving you legal permission to copy, distribute and/or modify it. + + For the developers' and authors' protection, the GPL clearly explains + that there is no warranty for this free software. For both users' and + authors' sake, the GPL requires that modified versions be marked as + changed, so that their problems will not be attributed erroneously to + authors of previous versions. + + Some devices are designed to deny users access to install or run + modified versions of the software inside them, although the manufacturer + can do so. This is fundamentally incompatible with the aim of + protecting users' freedom to change the software. The systematic + pattern of such abuse occurs in the area of products for individuals to + use, which is precisely where it is most unacceptable. Therefore, we + have designed this version of the GPL to prohibit the practice for those + products. If such problems arise substantially in other domains, we + stand ready to extend this provision to those domains in future versions + of the GPL, as needed to protect the freedom of users. + + Finally, every program is threatened constantly by software patents. + States should not allow patents to restrict development and use of + software on general-purpose computers, but in those that do, we wish to + avoid the special danger that patents applied to a free program could + make it effectively proprietary. To prevent this, the GPL assures that + patents cannot be used to render the program non-free. + + The precise terms and conditions for copying, distribution and + modification follow. + + TERMS AND CONDITIONS + + 0. Definitions. + + "This License" refers to version 3 of the GNU General Public License. + + "Copyright" also means copyright-like laws that apply to other kinds of + works, such as semiconductor masks. + + "The Program" refers to any copyrightable work licensed under this + License. Each licensee is addressed as "you". "Licensees" and + "recipients" may be individuals or organizations. + + To "modify" a work means to copy from or adapt all or part of the work + in a fashion requiring copyright permission, other than the making of an + exact copy. The resulting work is called a "modified version" of the + earlier work or a work "based on" the earlier work. + + A "covered work" means either the unmodified Program or a work based + on the Program. + + To "propagate" a work means to do anything with it that, without + permission, would make you directly or secondarily liable for + infringement under applicable copyright law, except executing it on a + computer or modifying a private copy. Propagation includes copying, + distribution (with or without modification), making available to the + public, and in some countries other activities as well. + + To "convey" a work means any kind of propagation that enables other + parties to make or receive copies. Mere interaction with a user through + a computer network, with no transfer of a copy, is not conveying. + + An interactive user interface displays "Appropriate Legal Notices" + to the extent that it includes a convenient and prominently visible + feature that (1) displays an appropriate copyright notice, and (2) + tells the user that there is no warranty for the work (except to the + extent that warranties are provided), that licensees may convey the + work under this License, and how to view a copy of this License. If + the interface presents a list of user commands or options, such as a + menu, a prominent item in the list meets this criterion. + + 1. Source Code. + + The "source code" for a work means the preferred form of the work + for making modifications to it. "Object code" means any non-source + form of a work. + + A "Standard Interface" means an interface that either is an official + standard defined by a recognized standards body, or, in the case of + interfaces specified for a particular programming language, one that + is widely used among developers working in that language. + + The "System Libraries" of an executable work include anything, other + than the work as a whole, that (a) is included in the normal form of + packaging a Major Component, but which is not part of that Major + Component, and (b) serves only to enable use of the work with that + Major Component, or to implement a Standard Interface for which an + implementation is available to the public in source code form. A + "Major Component", in this context, means a major essential component + (kernel, window system, and so on) of the specific operating system + (if any) on which the executable work runs, or a compiler used to + produce the work, or an object code interpreter used to run it. + + The "Corresponding Source" for a work in object code form means all + the source code needed to generate, install, and (for an executable + work) run the object code and to modify the work, including scripts to + control those activities. However, it does not include the work's + System Libraries, or general-purpose tools or generally available free + programs which are used unmodified in performing those activities but + which are not part of the work. For example, Corresponding Source + includes interface definition files associated with source files for + the work, and the source code for shared libraries and dynamically + linked subprograms that the work is specifically designed to require, + such as by intimate data communication or control flow between those + subprograms and other parts of the work. + + The Corresponding Source need not include anything that users + can regenerate automatically from other parts of the Corresponding + Source. + + The Corresponding Source for a work in source code form is that + same work. + + 2. Basic Permissions. + + All rights granted under this License are granted for the term of + copyright on the Program, and are irrevocable provided the stated + conditions are met. This License explicitly affirms your unlimited + permission to run the unmodified Program. The output from running a + covered work is covered by this License only if the output, given its + content, constitutes a covered work. This License acknowledges your + rights of fair use or other equivalent, as provided by copyright law. + + You may make, run and propagate covered works that you do not + convey, without conditions so long as your license otherwise remains + in force. You may convey covered works to others for the sole purpose + of having them make modifications exclusively for you, or provide you + with facilities for running those works, provided that you comply with + the terms of this License in conveying all material for which you do + not control copyright. Those thus making or running the covered works + for you must do so exclusively on your behalf, under your direction + and control, on terms that prohibit them from making any copies of + your copyrighted material outside their relationship with you. + + Conveying under any other circumstances is permitted solely under + the conditions stated below. Sublicensing is not allowed; section 10 + makes it unnecessary. + + 3. Protecting Users' Legal Rights From Anti-Circumvention Law. + + No covered work shall be deemed part of an effective technological + measure under any applicable law fulfilling obligations under article + 11 of the WIPO copyright treaty adopted on 20 December 1996, or + similar laws prohibiting or restricting circumvention of such + measures. + + When you convey a covered work, you waive any legal power to forbid + circumvention of technological measures to the extent such circumvention + is effected by exercising rights under this License with respect to + the covered work, and you disclaim any intention to limit operation or + modification of the work as a means of enforcing, against the work's + users, your or third parties' legal rights to forbid circumvention of + technological measures. + + 4. Conveying Verbatim Copies. + + You may convey verbatim copies of the Program's source code as you + receive it, in any medium, provided that you conspicuously and + appropriately publish on each copy an appropriate copyright notice; + keep intact all notices stating that this License and any + non-permissive terms added in accord with section 7 apply to the code; + keep intact all notices of the absence of any warranty; and give all + recipients a copy of this License along with the Program. + + You may charge any price or no price for each copy that you convey, + and you may offer support or warranty protection for a fee. + + 5. Conveying Modified Source Versions. + + You may convey a work based on the Program, or the modifications to + produce it from the Program, in the form of source code under the + terms of section 4, provided that you also meet all of these conditions: + + a) The work must carry prominent notices stating that you modified + it, and giving a relevant date. + + b) The work must carry prominent notices stating that it is + released under this License and any conditions added under section + 7. This requirement modifies the requirement in section 4 to + "keep intact all notices". + + c) You must license the entire work, as a whole, under this + License to anyone who comes into possession of a copy. This + License will therefore apply, along with any applicable section 7 + additional terms, to the whole of the work, and all its parts, + regardless of how they are packaged. This License gives no + permission to license the work in any other way, but it does not + invalidate such permission if you have separately received it. + + d) If the work has interactive user interfaces, each must display + Appropriate Legal Notices; however, if the Program has interactive + interfaces that do not display Appropriate Legal Notices, your + work need not make them do so. + + A compilation of a covered work with other separate and independent + works, which are not by their nature extensions of the covered work, + and which are not combined with it such as to form a larger program, + in or on a volume of a storage or distribution medium, is called an + "aggregate" if the compilation and its resulting copyright are not + used to limit the access or legal rights of the compilation's users + beyond what the individual works permit. Inclusion of a covered work + in an aggregate does not cause this License to apply to the other + parts of the aggregate. + + 6. Conveying Non-Source Forms. + + You may convey a covered work in object code form under the terms + of sections 4 and 5, provided that you also convey the + machine-readable Corresponding Source under the terms of this License, + in one of these ways: + + a) Convey the object code in, or embodied in, a physical product + (including a physical distribution medium), accompanied by the + Corresponding Source fixed on a durable physical medium + customarily used for software interchange. + + b) Convey the object code in, or embodied in, a physical product + (including a physical distribution medium), accompanied by a + written offer, valid for at least three years and valid for as + long as you offer spare parts or customer support for that product + model, to give anyone who possesses the object code either (1) a + copy of the Corresponding Source for all the software in the + product that is covered by this License, on a durable physical + medium customarily used for software interchange, for a price no + more than your reasonable cost of physically performing this + conveying of source, or (2) access to copy the + Corresponding Source from a network server at no charge. + + c) Convey individual copies of the object code with a copy of the + written offer to provide the Corresponding Source. This + alternative is allowed only occasionally and noncommercially, and + only if you received the object code with such an offer, in accord + with subsection 6b. + + d) Convey the object code by offering access from a designated + place (gratis or for a charge), and offer equivalent access to the + Corresponding Source in the same way through the same place at no + further charge. You need not require recipients to copy the + Corresponding Source along with the object code. If the place to + copy the object code is a network server, the Corresponding Source + may be on a different server (operated by you or a third party) + that supports equivalent copying facilities, provided you maintain + clear directions next to the object code saying where to find the + Corresponding Source. Regardless of what server hosts the + Corresponding Source, you remain obligated to ensure that it is + available for as long as needed to satisfy these requirements. + + e) Convey the object code using peer-to-peer transmission, provided + you inform other peers where the object code and Corresponding + Source of the work are being offered to the general public at no + charge under subsection 6d. + + A separable portion of the object code, whose source code is excluded + from the Corresponding Source as a System Library, need not be + included in conveying the object code work. + + A "User Product" is either (1) a "consumer product", which means any + tangible personal property which is normally used for personal, family, + or household purposes, or (2) anything designed or sold for incorporation + into a dwelling. In determining whether a product is a consumer product, + doubtful cases shall be resolved in favor of coverage. For a particular + product received by a particular user, "normally used" refers to a + typical or common use of that class of product, regardless of the status + of the particular user or of the way in which the particular user + actually uses, or expects or is expected to use, the product. A product + is a consumer product regardless of whether the product has substantial + commercial, industrial or non-consumer uses, unless such uses represent + the only significant mode of use of the product. + + "Installation Information" for a User Product means any methods, + procedures, authorization keys, or other information required to install + and execute modified versions of a covered work in that User Product from + a modified version of its Corresponding Source. The information must + suffice to ensure that the continued functioning of the modified object + code is in no case prevented or interfered with solely because + modification has been made. + + If you convey an object code work under this section in, or with, or + specifically for use in, a User Product, and the conveying occurs as + part of a transaction in which the right of possession and use of the + User Product is transferred to the recipient in perpetuity or for a + fixed term (regardless of how the transaction is characterized), the + Corresponding Source conveyed under this section must be accompanied + by the Installation Information. But this requirement does not apply + if neither you nor any third party retains the ability to install + modified object code on the User Product (for example, the work has + been installed in ROM). + + The requirement to provide Installation Information does not include a + requirement to continue to provide support service, warranty, or updates + for a work that has been modified or installed by the recipient, or for + the User Product in which it has been modified or installed. Access to a + network may be denied when the modification itself materially and + adversely affects the operation of the network or violates the rules and + protocols for communication across the network. + + Corresponding Source conveyed, and Installation Information provided, + in accord with this section must be in a format that is publicly + documented (and with an implementation available to the public in + source code form), and must require no special password or key for + unpacking, reading or copying. + + 7. Additional Terms. + + "Additional permissions" are terms that supplement the terms of this + License by making exceptions from one or more of its conditions. + Additional permissions that are applicable to the entire Program shall + be treated as though they were included in this License, to the extent + that they are valid under applicable law. If additional permissions + apply only to part of the Program, that part may be used separately + under those permissions, but the entire Program remains governed by + this License without regard to the additional permissions. + + When you convey a copy of a covered work, you may at your option + remove any additional permissions from that copy, or from any part of + it. (Additional permissions may be written to require their own + removal in certain cases when you modify the work.) You may place + additional permissions on material, added by you to a covered work, + for which you have or can give appropriate copyright permission. + + Notwithstanding any other provision of this License, for material you + add to a covered work, you may (if authorized by the copyright holders of + that material) supplement the terms of this License with terms: + + a) Disclaiming warranty or limiting liability differently from the + terms of sections 15 and 16 of this License; or + + b) Requiring preservation of specified reasonable legal notices or + author attributions in that material or in the Appropriate Legal + Notices displayed by works containing it; or + + c) Prohibiting misrepresentation of the origin of that material, or + requiring that modified versions of such material be marked in + reasonable ways as different from the original version; or + + d) Limiting the use for publicity purposes of names of licensors or + authors of the material; or + + e) Declining to grant rights under trademark law for use of some + trade names, trademarks, or service marks; or + + f) Requiring indemnification of licensors and authors of that + material by anyone who conveys the material (or modified versions of + it) with contractual assumptions of liability to the recipient, for + any liability that these contractual assumptions directly impose on + those licensors and authors. + + All other non-permissive additional terms are considered "further + restrictions" within the meaning of section 10. If the Program as you + received it, or any part of it, contains a notice stating that it is + governed by this License along with a term that is a further + restriction, you may remove that term. If a license document contains + a further restriction but permits relicensing or conveying under this + License, you may add to a covered work material governed by the terms + of that license document, provided that the further restriction does + not survive such relicensing or conveying. + + If you add terms to a covered work in accord with this section, you + must place, in the relevant source files, a statement of the + additional terms that apply to those files, or a notice indicating + where to find the applicable terms. + + Additional terms, permissive or non-permissive, may be stated in the + form of a separately written license, or stated as exceptions; + the above requirements apply either way. + + 8. Termination. + + You may not propagate or modify a covered work except as expressly + provided under this License. Any attempt otherwise to propagate or + modify it is void, and will automatically terminate your rights under + this License (including any patent licenses granted under the third + paragraph of section 11). + + However, if you cease all violation of this License, then your + license from a particular copyright holder is reinstated (a) + provisionally, unless and until the copyright holder explicitly and + finally terminates your license, and (b) permanently, if the copyright + holder fails to notify you of the violation by some reasonable means + prior to 60 days after the cessation. + + Moreover, your license from a particular copyright holder is + reinstated permanently if the copyright holder notifies you of the + violation by some reasonable means, this is the first time you have + received notice of violation of this License (for any work) from that + copyright holder, and you cure the violation prior to 30 days after + your receipt of the notice. + + Termination of your rights under this section does not terminate the + licenses of parties who have received copies or rights from you under + this License. If your rights have been terminated and not permanently + reinstated, you do not qualify to receive new licenses for the same + material under section 10. + + 9. Acceptance Not Required for Having Copies. + + You are not required to accept this License in order to receive or + run a copy of the Program. Ancillary propagation of a covered work + occurring solely as a consequence of using peer-to-peer transmission + to receive a copy likewise does not require acceptance. However, + nothing other than this License grants you permission to propagate or + modify any covered work. These actions infringe copyright if you do + not accept this License. Therefore, by modifying or propagating a + covered work, you indicate your acceptance of this License to do so. + + 10. Automatic Licensing of Downstream Recipients. + + Each time you convey a covered work, the recipient automatically + receives a license from the original licensors, to run, modify and + propagate that work, subject to this License. You are not responsible + for enforcing compliance by third parties with this License. + + An "entity transaction" is a transaction transferring control of an + organization, or substantially all assets of one, or subdividing an + organization, or merging organizations. If propagation of a covered + work results from an entity transaction, each party to that + transaction who receives a copy of the work also receives whatever + licenses to the work the party's predecessor in interest had or could + give under the previous paragraph, plus a right to possession of the + Corresponding Source of the work from the predecessor in interest, if + the predecessor has it or can get it with reasonable efforts. + + You may not impose any further restrictions on the exercise of the + rights granted or affirmed under this License. For example, you may + not impose a license fee, royalty, or other charge for exercise of + rights granted under this License, and you may not initiate litigation + (including a cross-claim or counterclaim in a lawsuit) alleging that + any patent claim is infringed by making, using, selling, offering for + sale, or importing the Program or any portion of it. + + 11. Patents. + + A "contributor" is a copyright holder who authorizes use under this + License of the Program or a work on which the Program is based. The + work thus licensed is called the contributor's "contributor version". + + A contributor's "essential patent claims" are all patent claims + owned or controlled by the contributor, whether already acquired or + hereafter acquired, that would be infringed by some manner, permitted + by this License, of making, using, or selling its contributor version, + but do not include claims that would be infringed only as a + consequence of further modification of the contributor version. For + purposes of this definition, "control" includes the right to grant + patent sublicenses in a manner consistent with the requirements of + this License. + + Each contributor grants you a non-exclusive, worldwide, royalty-free + patent license under the contributor's essential patent claims, to + make, use, sell, offer for sale, import and otherwise run, modify and + propagate the contents of its contributor version. + + In the following three paragraphs, a "patent license" is any express + agreement or commitment, however denominated, not to enforce a patent + (such as an express permission to practice a patent or covenant not to + sue for patent infringement). To "grant" such a patent license to a + party means to make such an agreement or commitment not to enforce a + patent against the party. + + If you convey a covered work, knowingly relying on a patent license, + and the Corresponding Source of the work is not available for anyone + to copy, free of charge and under the terms of this License, through a + publicly available network server or other readily accessible means, + then you must either (1) cause the Corresponding Source to be so + available, or (2) arrange to deprive yourself of the benefit of the + patent license for this particular work, or (3) arrange, in a manner + consistent with the requirements of this License, to extend the patent + license to downstream recipients. "Knowingly relying" means you have + actual knowledge that, but for the patent license, your conveying the + covered work in a country, or your recipient's use of the covered work + in a country, would infringe one or more identifiable patents in that + country that you have reason to believe are valid. + + If, pursuant to or in connection with a single transaction or + arrangement, you convey, or propagate by procuring conveyance of, a + covered work, and grant a patent license to some of the parties + receiving the covered work authorizing them to use, propagate, modify + or convey a specific copy of the covered work, then the patent license + you grant is automatically extended to all recipients of the covered + work and works based on it. + + A patent license is "discriminatory" if it does not include within + the scope of its coverage, prohibits the exercise of, or is + conditioned on the non-exercise of one or more of the rights that are + specifically granted under this License. You may not convey a covered + work if you are a party to an arrangement with a third party that is + in the business of distributing software, under which you make payment + to the third party based on the extent of your activity of conveying + the work, and under which the third party grants, to any of the + parties who would receive the covered work from you, a discriminatory + patent license (a) in connection with copies of the covered work + conveyed by you (or copies made from those copies), or (b) primarily + for and in connection with specific products or compilations that + contain the covered work, unless you entered into that arrangement, + or that patent license was granted, prior to 28 March 2007. + + Nothing in this License shall be construed as excluding or limiting + any implied license or other defenses to infringement that may + otherwise be available to you under applicable patent law. + + 12. No Surrender of Others' Freedom. + + If conditions are imposed on you (whether by court order, agreement or + otherwise) that contradict the conditions of this License, they do not + excuse you from the conditions of this License. If you cannot convey a + covered work so as to satisfy simultaneously your obligations under this + License and any other pertinent obligations, then as a consequence you may + not convey it at all. For example, if you agree to terms that obligate you + to collect a royalty for further conveying from those to whom you convey + the Program, the only way you could satisfy both those terms and this + License would be to refrain entirely from conveying the Program. + + 13. Use with the GNU Affero General Public License. + + Notwithstanding any other provision of this License, you have + permission to link or combine any covered work with a work licensed + under version 3 of the GNU Affero General Public License into a single + combined work, and to convey the resulting work. The terms of this + License will continue to apply to the part which is the covered work, + but the special requirements of the GNU Affero General Public License, + section 13, concerning interaction through a network will apply to the + combination as such. + + 14. Revised Versions of this License. + + The Free Software Foundation may publish revised and/or new versions of + the GNU General Public License from time to time. Such new versions will + be similar in spirit to the present version, but may differ in detail to + address new problems or concerns. + + Each version is given a distinguishing version number. If the + Program specifies that a certain numbered version of the GNU General + Public License "or any later version" applies to it, you have the + option of following the terms and conditions either of that numbered + version or of any later version published by the Free Software + Foundation. If the Program does not specify a version number of the + GNU General Public License, you may choose any version ever published + by the Free Software Foundation. + + If the Program specifies that a proxy can decide which future + versions of the GNU General Public License can be used, that proxy's + public statement of acceptance of a version permanently authorizes you + to choose that version for the Program. + + Later license versions may give you additional or different + permissions. However, no additional obligations are imposed on any + author or copyright holder as a result of your choosing to follow a + later version. + + 15. Disclaimer of Warranty. + + THERE IS NO WARRANTY FOR THE PROGRAM, TO THE EXTENT PERMITTED BY + APPLICABLE LAW. EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT + HOLDERS AND/OR OTHER PARTIES PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY + OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, + THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE PROGRAM + IS WITH YOU. SHOULD THE PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF + ALL NECESSARY SERVICING, REPAIR OR CORRECTION. + + 16. Limitation of Liability. + + IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING + WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MODIFIES AND/OR CONVEYS + THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY + GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE + USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED TO LOSS OF + DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD + PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER PROGRAMS), + EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF + SUCH DAMAGES. + + 17. Interpretation of Sections 15 and 16. + + If the disclaimer of warranty and limitation of liability provided + above cannot be given local legal effect according to their terms, + reviewing courts shall apply local law that most closely approximates + an absolute waiver of all civil liability in connection with the + Program, unless a warranty or assumption of liability accompanies a + copy of the Program in return for a fee. + + END OF TERMS AND CONDITIONS + + How to Apply These Terms to Your New Programs + + If you develop a new program, and you want it to be of the greatest + possible use to the public, the best way to achieve this is to make it + free software which everyone can redistribute and change under these terms. + + To do so, attach the following notices to the program. It is safest + to attach them to the start of each source file to most effectively + state the exclusion of warranty; and each file should have at least + the "copyright" line and a pointer to where the full notice is found. + + + Copyright (C) + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see . + + Also add information on how to contact you by electronic and paper mail. + + If the program does terminal interaction, make it output a short + notice like this when it starts in an interactive mode: + + Copyright (C) + This program comes with ABSOLUTELY NO WARRANTY; for details type `show w'. + This is free software, and you are welcome to redistribute it + under certain conditions; type `show c' for details. + + The hypothetical commands `show w' and `show c' should show the appropriate + parts of the General Public License. Of course, your program's commands + might be different; for a GUI interface, you would use an "about box". + + You should also get your employer (if you work as a programmer) or school, + if any, to sign a "copyright disclaimer" for the program, if necessary. + For more information on this, and how to apply and follow the GNU GPL, see + . + + The GNU General Public License does not permit incorporating your program + into proprietary programs. If your program is a subroutine library, you + may consider it more useful to permit linking proprietary applications with + the library. If this is what you want to do, use the GNU Lesser General + Public License instead of this License. But first, please read + . + +The complete text of the Apache 2.0 License is as follows: + + Apache License + Version 2.0, January 2004 + http://www.apache.org/licenses/ + + TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION + + 1. Definitions. + + "License" shall mean the terms and conditions for use, reproduction, + and distribution as defined by Sections 1 through 9 of this document. + + "Licensor" shall mean the copyright owner or entity authorized by + the copyright owner that is granting the License. + + "Legal Entity" shall mean the union of the acting entity and all + other entities that control, are controlled by, or are under common + control with that entity. For the purposes of this definition, + "control" means (i) the power, direct or indirect, to cause the + direction or management of such entity, whether by contract or + otherwise, or (ii) ownership of fifty percent (50%) or more of the + outstanding shares, or (iii) beneficial ownership of such entity. + + "You" (or "Your") shall mean an individual or Legal Entity + exercising permissions granted by this License. + + "Source" form shall mean the preferred form for making modifications, + including but not limited to software source code, documentation + source, and configuration files. + + "Object" form shall mean any form resulting from mechanical + transformation or translation of a Source form, including but + not limited to compiled object code, generated documentation, + and conversions to other media types. + + "Work" shall mean the work of authorship, whether in Source or + Object form, made available under the License, as indicated by a + copyright notice that is included in or attached to the work + (an example is provided in the Appendix below). + + "Derivative Works" shall mean any work, whether in Source or Object + form, that is based on (or derived from) the Work and for which the + editorial revisions, annotations, elaborations, or other modifications + represent, as a whole, an original work of authorship. For the purposes + of this License, Derivative Works shall not include works that remain + separable from, or merely link (or bind by name) to the interfaces of, + the Work and Derivative Works thereof. + + "Contribution" shall mean any work of authorship, including + the original version of the Work and any modifications or additions + to that Work or Derivative Works thereof, that is intentionally + submitted to Licensor for inclusion in the Work by the copyright owner + or by an individual or Legal Entity authorized to submit on behalf of + the copyright owner. For the purposes of this definition, "submitted" + means any form of electronic, verbal, or written communication sent + to the Licensor or its representatives, including but not limited to + communication on electronic mailing lists, source code control systems, + and issue tracking systems that are managed by, or on behalf of, the + Licensor for the purpose of discussing and improving the Work, but + excluding communication that is conspicuously marked or otherwise + designated in writing by the copyright owner as "Not a Contribution." + + "Contributor" shall mean Licensor and any individual or Legal Entity + on behalf of whom a Contribution has been received by Licensor and + subsequently incorporated within the Work. + + 2. Grant of Copyright License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + copyright license to reproduce, prepare Derivative Works of, + publicly display, publicly perform, sublicense, and distribute the + Work and such Derivative Works in Source or Object form. + + 3. Grant of Patent License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + (except as stated in this section) patent license to make, have made, + use, offer to sell, sell, import, and otherwise transfer the Work, + where such license applies only to those patent claims licensable + by such Contributor that are necessarily infringed by their + Contribution(s) alone or by combination of their Contribution(s) + with the Work to which such Contribution(s) was submitted. If You + institute patent litigation against any entity (including a + cross-claim or counterclaim in a lawsuit) alleging that the Work + or a Contribution incorporated within the Work constitutes direct + or contributory patent infringement, then any patent licenses + granted to You under this License for that Work shall terminate + as of the date such litigation is filed. + + 4. Redistribution. You may reproduce and distribute copies of the + Work or Derivative Works thereof in any medium, with or without + modifications, and in Source or Object form, provided that You + meet the following conditions: + + (a) You must give any other recipients of the Work or + Derivative Works a copy of this License; and + + (b) You must cause any modified files to carry prominent notices + stating that You changed the files; and + + (c) You must retain, in the Source form of any Derivative Works + that You distribute, all copyright, patent, trademark, and + attribution notices from the Source form of the Work, + excluding those notices that do not pertain to any part of + the Derivative Works; and + + (d) If the Work includes a "NOTICE" text file as part of its + distribution, then any Derivative Works that You distribute must + include a readable copy of the attribution notices contained + within such NOTICE file, excluding those notices that do not + pertain to any part of the Derivative Works, in at least one + of the following places: within a NOTICE text file distributed + as part of the Derivative Works; within the Source form or + documentation, if provided along with the Derivative Works; or, + within a display generated by the Derivative Works, if and + wherever such third-party notices normally appear. The contents + of the NOTICE file are for informational purposes only and + do not modify the License. You may add Your own attribution + notices within Derivative Works that You distribute, alongside + or as an addendum to the NOTICE text from the Work, provided + that such additional attribution notices cannot be construed + as modifying the License. + + You may add Your own copyright statement to Your modifications and + may provide additional or different license terms and conditions + for use, reproduction, or distribution of Your modifications, or + for any such Derivative Works as a whole, provided Your use, + reproduction, and distribution of the Work otherwise complies with + the conditions stated in this License. + + 5. Submission of Contributions. Unless You explicitly state otherwise, + any Contribution intentionally submitted for inclusion in the Work + by You to the Licensor shall be under the terms and conditions of + this License, without any additional terms or conditions. + Notwithstanding the above, nothing herein shall supersede or modify + the terms of any separate license agreement you may have executed + with Licensor regarding such Contributions. + + 6. Trademarks. This License does not grant permission to use the trade + names, trademarks, service marks, or product names of the Licensor, + except as required for reasonable and customary use in describing the + origin of the Work and reproducing the content of the NOTICE file. + + 7. Disclaimer of Warranty. Unless required by applicable law or + agreed to in writing, Licensor provides the Work (and each + Contributor provides its Contributions) on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + implied, including, without limitation, any warranties or conditions + of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A + PARTICULAR PURPOSE. You are solely responsible for determining the + appropriateness of using or redistributing the Work and assume any + risks associated with Your exercise of permissions under this License. + + 8. Limitation of Liability. In no event and under no legal theory, + whether in tort (including negligence), contract, or otherwise, + unless required by applicable law (such as deliberate and grossly + negligent acts) or agreed to in writing, shall any Contributor be + liable to You for damages, including any direct, indirect, special, + incidental, or consequential damages of any character arising as a + result of this License or out of the use or inability to use the + Work (including but not limited to damages for loss of goodwill, + work stoppage, computer failure or malfunction, or any and all + other commercial damages or losses), even if such Contributor + has been advised of the possibility of such damages. + + 9. Accepting Warranty or Additional Liability. While redistributing + the Work or Derivative Works thereof, You may choose to offer, + and charge a fee for, acceptance of support, warranty, indemnity, + or other liability obligations and/or rights consistent with this + License. However, in accepting such obligations, You may act only + on Your own behalf and on Your sole responsibility, not on behalf + of any other Contributor, and only if You agree to indemnify, + defend, and hold each Contributor harmless for any liability + incurred by, or claims asserted against, such Contributor by reason + of your accepting any such warranty or additional liability. + + END OF TERMS AND CONDITIONS + + APPENDIX: How to apply the Apache License to your work. + + To apply the Apache License to your work, attach the following + boilerplate notice, with the fields enclosed by brackets "[]" + replaced with your own identifying information. (Don't include + the brackets!) The text should be enclosed in the appropriate + comment syntax for the file format. We also recommend that a + file or class name and description of purpose be included on the + same "printed page" as the copyright notice for easier + identification within third-party archives. + + Copyright [yyyy] [name of copyright owner] + + Licensed 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. + +The complete text of the BSD license can be is as follows: + + Redistribution and use in source and binary forms, with or without + modification, are permitted provided that the following conditions + are met: + 1. Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + 2. Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in the + documentation and/or other materials provided with the distribution. + 3. Neither the name of the University nor the names of its contributors + may be used to endorse or promote products derived from this software + without specific prior written permission. + + THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE + LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF + THE POSSIBILITY OF SUCH DAMAGE. + +The complete text of the MIT license is as follows: + + Permission is hereby granted, free of charge, to any person + obtaining a copy of this software and associated documentation + files (the “Software”), to deal in the Software without + restriction, including without limitation the rights to use, + copy, modify, merge, publish, distribute, sublicense, and/or sell + copies of the Software, and to permit persons to whom the + Software is furnished to do so, subject to the following + conditions: + + The above copyright notice and this permission notice shall be + included in all copies or substantial portions of the Software. + + THE SOFTWARE IS PROVIDED “AS IS”, WITHOUT WARRANTY OF ANY KIND, + EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES + OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT + HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, + WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR + OTHER DEALINGS IN THE SOFTWARE. + +The complete text of the GPL v2, and classpath exception: + +The GNU General Public License (GPL) + +Version 2, June 1991 + +Copyright (C) 1989, 1991 Free Software Foundation, Inc. +59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + +Everyone is permitted to copy and distribute verbatim copies of this license +document, but changing it is not allowed. + +Preamble + +The licenses for most software are designed to take away your freedom to share +and change it. By contrast, the GNU General Public License is intended to +guarantee your freedom to share and change free software--to make sure the +software is free for all its users. This General Public License applies to +most of the Free Software Foundation's software and to any other program whose +authors commit to using it. (Some other Free Software Foundation software is +covered by the GNU Library General Public License instead.) You can apply it to +your programs, too. + +When we speak of free software, we are referring to freedom, not price. Our +General Public Licenses are designed to make sure that you have the freedom to +distribute copies of free software (and charge for this service if you wish), +that you receive source code or can get it if you want it, that you can change +the software or use pieces of it in new free programs; and that you know you +can do these things. + +To protect your rights, we need to make restrictions that forbid anyone to deny +you these rights or to ask you to surrender the rights. These restrictions +translate to certain responsibilities for you if you distribute copies of the +software, or if you modify it. + +For example, if you distribute copies of such a program, whether gratis or for +a fee, you must give the recipients all the rights that you have. You must +make sure that they, too, receive or can get the source code. And you must +show them these terms so they know their rights. + +We protect your rights with two steps: (1) copyright the software, and (2) +offer you this license which gives you legal permission to copy, distribute +and/or modify the software. + +Also, for each author's protection and ours, we want to make certain that +everyone understands that there is no warranty for this free software. If the +software is modified by someone else and passed on, we want its recipients to +know that what they have is not the original, so that any problems introduced +by others will not reflect on the original authors' reputations. + +Finally, any free program is threatened constantly by software patents. We +wish to avoid the danger that redistributors of a free program will +individually obtain patent licenses, in effect making the program proprietary. +To prevent this, we have made it clear that any patent must be licensed for +everyone's free use or not licensed at all. + +The precise terms and conditions for copying, distribution and modification +follow. + +TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION + +0. This License applies to any program or other work which contains a notice +placed by the copyright holder saying it may be distributed under the terms of +this General Public License. The "Program", below, refers to any such program +or work, and a "work based on the Program" means either the Program or any +derivative work under copyright law: that is to say, a work containing the +Program or a portion of it, either verbatim or with modifications and/or +translated into another language. (Hereinafter, translation is included +without limitation in the term "modification".) Each licensee is addressed as +"you". + +Activities other than copying, distribution and modification are not covered by +this License; they are outside its scope. The act of running the Program is +not restricted, and the output from the Program is covered only if its contents +constitute a work based on the Program (independent of having been made by +running the Program). Whether that is true depends on what the Program does. + +1. You may copy and distribute verbatim copies of the Program's source code as +you receive it, in any medium, provided that you conspicuously and +appropriately publish on each copy an appropriate copyright notice and +disclaimer of warranty; keep intact all the notices that refer to this License +and to the absence of any warranty; and give any other recipients of the +Program a copy of this License along with the Program. + +You may charge a fee for the physical act of transferring a copy, and you may +at your option offer warranty protection in exchange for a fee. + +2. You may modify your copy or copies of the Program or any portion of it, thus +forming a work based on the Program, and copy and distribute such modifications +or work under the terms of Section 1 above, provided that you also meet all of +these conditions: + + a) You must cause the modified files to carry prominent notices stating + that you changed the files and the date of any change. + + b) You must cause any work that you distribute or publish, that in whole or + in part contains or is derived from the Program or any part thereof, to be + licensed as a whole at no charge to all third parties under the terms of + this License. + + c) If the modified program normally reads commands interactively when run, + you must cause it, when started running for such interactive use in the + most ordinary way, to print or display an announcement including an + appropriate copyright notice and a notice that there is no warranty (or + else, saying that you provide a warranty) and that users may redistribute + the program under these conditions, and telling the user how to view a copy + of this License. (Exception: if the Program itself is interactive but does + not normally print such an announcement, your work based on the Program is + not required to print an announcement.) + +These requirements apply to the modified work as a whole. If identifiable +sections of that work are not derived from the Program, and can be reasonably +considered independent and separate works in themselves, then this License, and +its terms, do not apply to those sections when you distribute them as separate +works. But when you distribute the same sections as part of a whole which is a +work based on the Program, the distribution of the whole must be on the terms +of this License, whose permissions for other licensees extend to the entire +whole, and thus to each and every part regardless of who wrote it. + +Thus, it is not the intent of this section to claim rights or contest your +rights to work written entirely by you; rather, the intent is to exercise the +right to control the distribution of derivative or collective works based on +the Program. + +In addition, mere aggregation of another work not based on the Program with the +Program (or with a work based on the Program) on a volume of a storage or +distribution medium does not bring the other work under the scope of this +License. + +3. You may copy and distribute the Program (or a work based on it, under +Section 2) in object code or executable form under the terms of Sections 1 and +2 above provided that you also do one of the following: + + a) Accompany it with the complete corresponding machine-readable source + code, which must be distributed under the terms of Sections 1 and 2 above + on a medium customarily used for software interchange; or, + + b) Accompany it with a written offer, valid for at least three years, to + give any third party, for a charge no more than your cost of physically + performing source distribution, a complete machine-readable copy of the + corresponding source code, to be distributed under the terms of Sections 1 + and 2 above on a medium customarily used for software interchange; or, + + c) Accompany it with the information you received as to the offer to + distribute corresponding source code. (This alternative is allowed only + for noncommercial distribution and only if you received the program in + object code or executable form with such an offer, in accord with + Subsection b above.) + +The source code for a work means the preferred form of the work for making +modifications to it. For an executable work, complete source code means all +the source code for all modules it contains, plus any associated interface +definition files, plus the scripts used to control compilation and installation +of the executable. However, as a special exception, the source code +distributed need not include anything that is normally distributed (in either +source or binary form) with the major components (compiler, kernel, and so on) +of the operating system on which the executable runs, unless that component +itself accompanies the executable. + +If distribution of executable or object code is made by offering access to copy +from a designated place, then offering equivalent access to copy the source +code from the same place counts as distribution of the source code, even though +third parties are not compelled to copy the source along with the object code. + +4. You may not copy, modify, sublicense, or distribute the Program except as +expressly provided under this License. Any attempt otherwise to copy, modify, +sublicense or distribute the Program is void, and will automatically terminate +your rights under this License. However, parties who have received copies, or +rights, from you under this License will not have their licenses terminated so +long as such parties remain in full compliance. + +5. You are not required to accept this License, since you have not signed it. +However, nothing else grants you permission to modify or distribute the Program +or its derivative works. These actions are prohibited by law if you do not +accept this License. Therefore, by modifying or distributing the Program (or +any work based on the Program), you indicate your acceptance of this License to +do so, and all its terms and conditions for copying, distributing or modifying +the Program or works based on it. + +6. Each time you redistribute the Program (or any work based on the Program), +the recipient automatically receives a license from the original licensor to +copy, distribute or modify the Program subject to these terms and conditions. +You may not impose any further restrictions on the recipients' exercise of the +rights granted herein. You are not responsible for enforcing compliance by +third parties to this License. + +7. If, as a consequence of a court judgment or allegation of patent +infringement or for any other reason (not limited to patent issues), conditions +are imposed on you (whether by court order, agreement or otherwise) that +contradict the conditions of this License, they do not excuse you from the +conditions of this License. If you cannot distribute so as to satisfy +simultaneously your obligations under this License and any other pertinent +obligations, then as a consequence you may not distribute the Program at all. +For example, if a patent license would not permit royalty-free redistribution +of the Program by all those who receive copies directly or indirectly through +you, then the only way you could satisfy both it and this License would be to +refrain entirely from distribution of the Program. + +If any portion of this section is held invalid or unenforceable under any +particular circumstance, the balance of the section is intended to apply and +the section as a whole is intended to apply in other circumstances. + +It is not the purpose of this section to induce you to infringe any patents or +other property right claims or to contest validity of any such claims; this +section has the sole purpose of protecting the integrity of the free software +distribution system, which is implemented by public license practices. Many +people have made generous contributions to the wide range of software +distributed through that system in reliance on consistent application of that +system; it is up to the author/donor to decide if he or she is willing to +distribute software through any other system and a licensee cannot impose that +choice. + +This section is intended to make thoroughly clear what is believed to be a +consequence of the rest of this License. + +8. If the distribution and/or use of the Program is restricted in certain +countries either by patents or by copyrighted interfaces, the original +copyright holder who places the Program under this License may add an explicit +geographical distribution limitation excluding those countries, so that +distribution is permitted only in or among countries not thus excluded. In +such case, this License incorporates the limitation as if written in the body +of this License. + +9. The Free Software Foundation may publish revised and/or new versions of the +General Public License from time to time. Such new versions will be similar in +spirit to the present version, but may differ in detail to address new problems +or concerns. + +Each version is given a distinguishing version number. If the Program +specifies a version number of this License which applies to it and "any later +version", you have the option of following the terms and conditions either of +that version or of any later version published by the Free Software Foundation. +If the Program does not specify a version number of this License, you may +choose any version ever published by the Free Software Foundation. + +10. If you wish to incorporate parts of the Program into other free programs +whose distribution conditions are different, write to the author to ask for +permission. For software which is copyrighted by the Free Software Foundation, +write to the Free Software Foundation; we sometimes make exceptions for this. +Our decision will be guided by the two goals of preserving the free status of +all derivatives of our free software and of promoting the sharing and reuse of +software generally. + +NO WARRANTY + +11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY FOR +THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN OTHERWISE +STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES PROVIDE THE +PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED OR IMPLIED, +INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND +FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND +PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE PROGRAM PROVE DEFECTIVE, +YOU ASSUME THE COST OF ALL NECESSARY SERVICING, REPAIR OR CORRECTION. + +12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING WILL +ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR REDISTRIBUTE THE +PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY +GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE USE OR +INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED TO LOSS OF DATA OR DATA +BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD PARTIES OR A +FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER PROGRAMS), EVEN IF SUCH HOLDER +OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGES. + +END OF TERMS AND CONDITIONS + +How to Apply These Terms to Your New Programs + +If you develop a new program, and you want it to be of the greatest possible +use to the public, the best way to achieve this is to make it free software +which everyone can redistribute and change under these terms. + +To do so, attach the following notices to the program. It is safest to attach +them to the start of each source file to most effectively convey the exclusion +of warranty; and each file should have at least the "copyright" line and a +pointer to where the full notice is found. + + One line to give the program's name and a brief idea of what it does. + + Copyright (C) + + This program is free software; you can redistribute it and/or modify it + under the terms of the GNU General Public License as published by the Free + Software Foundation; either version 2 of the License, or (at your option) + any later version. + + This program is distributed in the hope that it will be useful, but WITHOUT + ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + more details. + + You should have received a copy of the GNU General Public License along + with this program; if not, write to the Free Software Foundation, Inc., 59 + Temple Place, Suite 330, Boston, MA 02111-1307 USA + +Also add information on how to contact you by electronic and paper mail. + +If the program is interactive, make it output a short notice like this when it +starts in an interactive mode: + + Gnomovision version 69, Copyright (C) year name of author Gnomovision comes + with ABSOLUTELY NO WARRANTY; for details type 'show w'. This is free + software, and you are welcome to redistribute it under certain conditions; + type 'show c' for details. + +The hypothetical commands 'show w' and 'show c' should show the appropriate +parts of the General Public License. Of course, the commands you use may be +called something other than 'show w' and 'show c'; they could even be +mouse-clicks or menu items--whatever suits your program. + +You should also get your employer (if you work as a programmer) or your school, +if any, to sign a "copyright disclaimer" for the program, if necessary. Here +is a sample; alter the names: + + Yoyodyne, Inc., hereby disclaims all copyright interest in the program + 'Gnomovision' (which makes passes at compilers) written by James Hacker. + + signature of Ty Coon, 1 April 1989 + + Ty Coon, President of Vice + +This General Public License does not permit incorporating your program into +proprietary programs. If your program is a subroutine library, you may +consider it more useful to permit linking proprietary applications with the +library. If this is what you want to do, use the GNU Library General Public +License instead of this License. + +"CLASSPATH" EXCEPTION TO THE GPL + +Certain source files distributed by Oracle America and/or its affiliates are +subject to the following clarification and special exception to the GPL, but +only where Oracle has expressly included in the particular source file's header +the words "Oracle designates this particular file as subject to the "Classpath" +exception as provided by Oracle in the LICENSE file that accompanied this code." + + Linking this library statically or dynamically with other modules is making + a combined work based on this library. Thus, the terms and conditions of + the GNU General Public License cover the whole combination. + + As a special exception, the copyright holders of this library give you + permission to link this library with independent modules to produce an + executable, regardless of the license terms of these independent modules, + and to copy and distribute the resulting executable under terms of your + choice, provided that you also meet, for each linked independent module, + the terms and conditions of the license of that module. An independent + module is a module which is not derived from or based on this library. If + you modify this library, you may extend this exception to your version of + the library, but you are not obligated to do so. If you do not wish to do + so, delete this exception statement from your version. + +The full text of the zlib licence: + +Copyright (C) 1995-2013 Jean-loup Gailly and Mark Adler + +This software is provided 'as-is', without any express or implied +warranty. In no event will the authors be held liable for any damages +arising from the use of this software. + +Permission is granted to anyone to use this software for any purpose, +including commercial applications, and to alter it and redistribute it +freely, subject to the following restrictions: + +1. The origin of this software must not be misrepresented; you must not + claim that you wrote the original software. If you use this software + in a product, an acknowledgment in the product documentation would be + appreciated but is not required. +2. Altered source versions must be plainly marked as such, and must not be + misrepresented as being the original software. +3. This notice may not be removed or altered from any source distribution. + +Jean-loup Gailly Mark Adler +jloup@gzip.org madler@alumni.caltech.edu + +========== +Notice for: jruby-jms-1.3.0 +---------- + +Copyright 2008, 2009, 2010, 2011 J. Reid Morrison, Inc. + +Licensed 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. + +========== +Notice for: jruby-openssl-0.10.2 +---------- + +source: https://github.com/jruby/jruby-openssl/blob/v0.9.21/LICENSE.txt + +JRuby-OpenSSL is distributed under the same license as JRuby a tri EPL/GPL/LGPL +license. You can use it, redistribute it and/or modify it under the terms of the: + + Eclipse Public License version 1.0 + GNU General Public License version 2.0 + GNU Lesser General Public License version 2.1 + +The contents of this file are subject to the Common Public License Version 1.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.eclipse.org/legal/cpl-v10.html + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS +FOR APARTICULAR PURPOSE AND NONINFRINGEMENT. +IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, +DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, +ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER +DEALINGS IN THE SOFTWARE. + + Copyright (C) 2007-2009 Ola Bini + Copyright (C) 2009-2017 The JRuby Team + +Alternatively, the contents of this file may be used under the terms of +either of the GNU General Public License Version 2 or later (the "GPL"), +or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), +in which case the provisions of the GPL or the LGPL are applicable instead +of those above. If you wish to allow use of your version of this file only +under the terms of either the GPL or the LGPL, and not to allow others to +use your version of this file under the terms of the EPL, indicate your +decision by deleting the provisions above and replace them with the notice +and other provisions required by the GPL or the LGPL. If you do not delete +the provisions above, a recipient may use your version of this file under +the terms of any one of the EPL, the GPL or the LGPL. + + +JRuby-OpenSSL includes software by The Legion of the Bouncy Castle Inc. +Please, visit (http://bouncycastle.org/license.html) for licensing details. +========== +Notice for: jruby-stdin-channel-0.2.0 +---------- + +source: https://github.com/colinsurprenant/jruby-stdin-channel/blob/v0.2.0/LICENSE.md + +Licensed 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. +========== +Notice for: json-1.8.6 +---------- + +source: https://github.com/tmattia/json-generator/blob/v0.1.0/LICENSE.txt + +Copyright (c) 2013 ThoughtWorks Brasil & Abril Midia + +MIT License + +Permission is hereby granted, free of charge, to any person obtaining +a copy of this software and associated documentation files (the +"Software"), to deal in the Software without restriction, including +without limitation the rights to use, copy, modify, merge, publish, +distribute, sublicense, and/or sell copies of the Software, and to +permit persons to whom the Software is furnished to do so, subject to +the following conditions: + +The above copyright notice and this permission notice shall be +included in all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +========== +Notice for: lru_redux-1.1.0 +---------- + +source: https://github.com/SamSaffron/lru_redux/blob/v1.1.0/LICENSE.txt + +Copyright (c) 2013 Sam Saffron + +MIT License + +Permission is hereby granted, free of charge, to any person obtaining +a copy of this software and associated documentation files (the +"Software"), to deal in the Software without restriction, including +without limitation the rights to use, copy, modify, merge, publish, +distribute, sublicense, and/or sell copies of the Software, and to +permit persons to whom the Software is furnished to do so, subject to +the following conditions: + +The above copyright notice and this permission notice shall be +included in all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +========== +Notice for: mail-2.6.6 +---------- + +source: https://github.com/mikel/mail/blob/2.6.6/MIT-LICENSE + +Copyright (c) 2009-2017 Mikel Lindsaar + +Permission is hereby granted, free of charge, to any person obtaining +a copy of this software and associated documentation files (the +'Software'), to deal in the Software without restriction, including +without limitation the rights to use, copy, modify, merge, publish, +distribute, sublicense, and/or sell copies of the Software, and to +permit persons to whom the Software is furnished to do so, subject to +the following conditions: + +The above copyright notice and this permission notice shall be +included in all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED 'AS IS', WITHOUT WARRANTY OF ANY KIND, +EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. +IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY +CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, +TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE +SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + +========== +Notice for: manticore-0.6.4 +---------- + +source: https://github.com/cheald/manticore/blob/v0.6.1/LICENSE.txt + +Copyright (c) 2015 Chris Heald + +Permission is hereby granted, free of charge, to any person obtaining +a copy of this software and associated documentation files (the +"Software"), to deal in the Software without restriction, including +without limitation the rights to use, copy, modify, merge, publish, +distribute, sublicense, and/or sell copies of the Software, and to +permit persons to whom the Software is furnished to do so, subject to +the following conditions: + +The above copyright notice and this permission notice shall be +included in all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + +========== +Notice for: march_hare-4.1.1 +---------- + +source: https://github.com/ruby-amqp/march_hare/blob/v3.1.1/LICENSE + +Copyright (c) 2011-2013 Theo Hultberg +Copyright (c) 2013-2017 Michael S. Klishin and contributors + +Permission is hereby granted, free of charge, to any person obtaining +a copy of this software and associated documentation files (the +"Software"), to deal in the Software without restriction, including +without limitation the rights to use, copy, modify, merge, publish, +distribute, sublicense, and/or sell copies of the Software, and to +permit persons to whom the Software is furnished to do so, subject to +the following conditions: + +The above copyright notice and this permission notice shall be +included in all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + +========== +Notice for: memoizable-0.4.2 +---------- + +source: https://github.com/dkubb/memoizable/blob/v0.4.2/LICENSE.md + +Copyright (c) 2013 Dan Kubb, Erik Michaels-Ober + +Permission is hereby granted, free of charge, to any person obtaining +a copy of this software and associated documentation files (the +"Software"), to deal in the Software without restriction, including +without limitation the rights to use, copy, modify, merge, publish, +distribute, sublicense, and/or sell copies of the Software, and to +permit persons to whom the Software is furnished to do so, subject to +the following conditions: + +The above copyright notice and this permission notice shall be +included in all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +========== +Notice for: method_source-0.9.2 +---------- + +source: https://github.com/banister/method_source/blob/v0.9.0/README.markdown#license + +Copyright (c) 2011 John Mair (banisterfiend) + +Permission is hereby granted, free of charge, to any person obtaining +a copy of this software and associated documentation files (the +'Software'), to deal in the Software without restriction, including +without limitation the rights to use, copy, modify, merge, publish, +distribute, sublicense, and/or sell copies of the Software, and to +permit persons to whom the Software is furnished to do so, subject to +the following conditions: + +The above copyright notice and this permission notice shall be +included in all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED 'AS IS', WITHOUT WARRANTY OF ANY KIND, +EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. +IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY +CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, +TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE +SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + +========== +Notice for: metriks-0.9.9.8 +---------- + +source: https://github.com/eric/metriks/blob/v0.9.9.8/LICENSE + +Copyright (c) 2012 Eric Lindvall + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE. +========== +Notice for: mime-types-2.6.2 +---------- + +source: https://github.com/mime-types/ruby-mime-types/blob/v2.6.2/Licence.rdoc + +* Copyright 2003–2015 Austin Ziegler. +* Adapted from MIME::Types (Perl) by Mark Overmeer. + +=== MIT License + +Permission is hereby granted, free of charge, to any person obtaining a copy of +this software and associated documentation files (the "Software"), to deal in +the Software without restriction, including without limitation the rights to +use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies +of the Software, and to permit persons to whom the Software is furnished to do +so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. + +========== +Notice for: minitar-0.9 +---------- + +source: https://github.com/halostatue/minitar/blob/v0.6.1/Licence.md + +minitar is free software that may be redistributed and/or modified under the +terms of Ruby’s licence or the Simplified BSD licence. + +* Copyright 2004–2017 Austin Ziegler. +* Portions copyright 2004 Mauricio Julio Fernández Pradier. + +========== +Notice for: msgpack-1.3.1 +---------- + +source: https://github.com/msgpack/msgpack-ruby/blob/v1.2.4/ext/msgpack/ + + Copyright (C) 2008-2013 Sadayuki Furuhashi + + Licensed 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. +========== +Notice for: multi_json-1.14.1 +---------- + +source: https://github.com/intridea/multi_json/blob/v1.13.1/LICENSE.md + +Copyright (c) 2010-2013 Michael Bleigh, Josh Kalderimis, Erik Michaels-Ober, Pavel Pravosud + +Permission is hereby granted, free of charge, to any person obtaining +a copy of this software and associated documentation files (the +"Software"), to deal in the Software without restriction, including +without limitation the rights to use, copy, modify, merge, publish, +distribute, sublicense, and/or sell copies of the Software, and to +permit persons to whom the Software is furnished to do so, subject to +the following conditions: + +The above copyright notice and this permission notice shall be +included in all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +========== +Notice for: multipart-post-2.1.1 +---------- + +source: https://github.com/nicksieger/multipart-post/blob/v2.0.0/README.md#license + +Copyright (c) 2007-2013 Nick Sieger + +Permission is hereby granted, free of charge, to any person obtaining +a copy of this software and associated documentation files (the +'Software'), to deal in the Software without restriction, including +without limitation the rights to use, copy, modify, merge, publish, +distribute, sublicense, and/or sell copies of the Software, and to +permit persons to whom the Software is furnished to do so, subject to +the following conditions: + +The above copyright notice and this permission notice shall be +included in all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED 'AS IS', WITHOUT WARRANTY OF ANY KIND, +EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. +IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY +CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, +TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE +SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + +========== +Notice for: murmurhash3-0.1.6 +---------- + +source: https://github.com/funny-falcon/murmurhash3-ruby/blob/v0.1.5/LICENSE + +Copyright (c) 2012 Sokolov Yura 'funny-falcon' + +MIT License + +Permission is hereby granted, free of charge, to any person obtaining +a copy of this software and associated documentation files (the +"Software"), to deal in the Software without restriction, including +without limitation the rights to use, copy, modify, merge, publish, +distribute, sublicense, and/or sell copies of the Software, and to +permit persons to whom the Software is furnished to do so, subject to +the following conditions: + +The above copyright notice and this permission notice shall be +included in all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + +========== +Notice for: mustache-0.99.8 +---------- + +source: https://github.com/mustache/mustache/blob/v0.99.8/LICENSE + +Copyright (c) 2009 Chris Wanstrath + +Permission is hereby granted, free of charge, to any person obtaining +a copy of this software and associated documentation files (the +"Software"), to deal in the Software without restriction, including +without limitation the rights to use, copy, modify, merge, publish, +distribute, sublicense, and/or sell copies of the Software, and to +permit persons to whom the Software is furnished to do so, subject to +the following conditions: + +The above copyright notice and this permission notice shall be +included in all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + +========== +Notice for: mustermann-1.0.3 +---------- + +Copyright (c) 2013-2017 Konstantin Haase +Copyright (c) 2016-2017 Zachary Scott + +Permission is hereby granted, free of charge, to any person +obtaining a copy of this software and associated documentation +files (the "Software"), to deal in the Software without +restriction, including without limitation the rights to use, +copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the +Software is furnished to do so, subject to the following +conditions: + +The above copyright notice and this permission notice shall be +included in all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES +OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT +HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, +WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING +FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR +OTHER DEALINGS IN THE SOFTWARE. + +========== +Notice for: naught-1.1.0 +---------- + +source: https://github.com/avdi/naught/blob/v1.1.0/LICENSE.txt + +Copyright (c) 2013 Avdi Grimm + +MIT License + +Permission is hereby granted, free of charge, to any person obtaining +a copy of this software and associated documentation files (the +"Software"), to deal in the Software without restriction, including +without limitation the rights to use, copy, modify, merge, publish, +distribute, sublicense, and/or sell copies of the Software, and to +permit persons to whom the Software is furnished to do so, subject to +the following conditions: + +The above copyright notice and this permission notice shall be +included in all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + +========== +Notice for: nio4r-2.5.2 +---------- + +Released under the MIT license. + +Copyright, 2019, by Tony Arcieri. +Copyright, 2019, by Samuel G. D. Williams. + +Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + +========== +Notice for: nokogiri-1.10.7 +---------- + +source: https://github.com/sparklemotion/nokogiri/blob/v1.8.2/LICENSE.md + +Copyright (c) 2008 - 2017: + +* [Aaron Patterson](http://tenderlovemaking.com) +* [Mike Dalessio](http://mike.daless.io) +* [Charles Nutter](http://blog.headius.com) +* [Sergio Arbeo](http://www.serabe.com) +* [Patrick Mahoney](http://polycrystal.org) +* [Yoko Harada](http://yokolet.blogspot.com) +* [Akinori MUSHA](https://akinori.org) +* [John Shahid](https://github.com/jvshahid) + +Permission is hereby granted, free of charge, to any person obtaining +a copy of this software and associated documentation files (the +'Software'), to deal in the Software without restriction, including +without limitation the rights to use, copy, modify, merge, publish, +distribute, sublicense, and/or sell copies of the Software, and to +permit persons to whom the Software is furnished to do so, subject to +the following conditions: + +The above copyright notice and this permission notice shall be +included in all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED 'AS IS', WITHOUT WARRANTY OF ANY KIND, +EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. +IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY +CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, +TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE +SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + +========== +Notice for: numerizer-0.1.1 +---------- + +FAKER + +========== +Notice for: openssl_pkcs8_pure-0.0.0.2 +---------- + +- Copyright (c) 2017, T. Yamada + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are met: + +1. Redistributions of source code must retain the above copyright notice, this + list of conditions and the following disclaimer. +2. Redistributions in binary form must reproduce the above copyright notice, + this list of conditions and the following disclaimer in the documentation + and/or other materials provided with the distribution. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND +ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED +WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR +ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES +(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; +LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND +ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS +SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + + +========== +Notice for: org.apache.logging.log4j:log4j-api-2.12.1 +---------- + +source: https://git-wip-us.apache.org/repos/asf?p=logging-log4j2.git;a=blob;f=NOTICE.txt;h=bd95322f254fc6f691b47e77df8c21229f47b8d4;hb=HEAD + +Apache Log4j +Copyright 1999-2017 Apache Software Foundation + +This product includes software developed at +The Apache Software Foundation (http://www.apache.org/). + +ResolverUtil.java +Copyright 2005-2006 Tim Fennell + +Dumbster SMTP test server +Copyright 2004 Jason Paul Kitchen + +TypeUtil.java +Copyright 2002-2012 Ramnivas Laddad, Juergen Hoeller, Chris Beams + +picocli (http://picocli.info) +Copyright 2017 Remko Popma +========== +Notice for: org.apache.logging.log4j:log4j-core-2.12.1 +---------- + +source: https://git-wip-us.apache.org/repos/asf?p=logging-log4j2.git;a=blob;f=NOTICE.txt;h=bd95322f254fc6f691b47e77df8c21229f47b8d4;hb=HEAD + +Apache Log4j +Copyright 1999-2017 Apache Software Foundation + +This product includes software developed at +The Apache Software Foundation (http://www.apache.org/). + +ResolverUtil.java +Copyright 2005-2006 Tim Fennell + +Dumbster SMTP test server +Copyright 2004 Jason Paul Kitchen + +TypeUtil.java +Copyright 2002-2012 Ramnivas Laddad, Juergen Hoeller, Chris Beams + +picocli (http://picocli.info) +Copyright 2017 Remko Popma +========== +Notice for: org.apache.logging.log4j:log4j-slf4j-impl-2.12.1 +---------- + +source: https://git-wip-us.apache.org/repos/asf?p=logging-log4j2.git;a=blob;f=NOTICE.txt;h=bd95322f254fc6f691b47e77df8c21229f47b8d4;hb=HEAD + +Apache Log4j +Copyright 1999-2017 Apache Software Foundation + +This product includes software developed at +The Apache Software Foundation (http://www.apache.org/). + +ResolverUtil.java +Copyright 2005-2006 Tim Fennell + +Dumbster SMTP test server +Copyright 2004 Jason Paul Kitchen + +TypeUtil.java +Copyright 2002-2012 Ramnivas Laddad, Juergen Hoeller, Chris Beams + +picocli (http://picocli.info) +Copyright 2017 Remko Popma +========== +Notice for: org.codehaus.janino:commons-compiler-3.1.0 +---------- + +Janino - An embedded Java[TM] compiler + +Copyright (c) 2001-2016, Arno Unkrig +Copyright (c) 2015-2016 TIBCO Software Inc. +All rights reserved. + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions +are met: + + 1. Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + 2. Redistributions in binary form must reproduce the above + copyright notice, this list of conditions and the following + disclaimer in the documentation and/or other materials + provided with the distribution. + 3. Neither the name of JANINO nor the names of its contributors + may be used to endorse or promote products derived from this + software without specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" +AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDERS OR CONTRIBUTORS BE +LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR +CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF +SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS +INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER +IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR +OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN +IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +========== +Notice for: org.codehaus.janino:janino-3.1.0 +---------- + +Janino - An embedded Java[TM] compiler + +Copyright (c) 2001-2016, Arno Unkrig +Copyright (c) 2015-2016 TIBCO Software Inc. +All rights reserved. + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions +are met: + + 1. Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + 2. Redistributions in binary form must reproduce the above + copyright notice, this list of conditions and the following + disclaimer in the documentation and/or other materials + provided with the distribution. + 3. Neither the name of JANINO nor the names of its contributors + may be used to endorse or promote products derived from this + software without specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" +AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDERS OR CONTRIBUTORS BE +LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR +CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF +SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS +INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER +IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR +OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN +IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +========== +Notice for: org.codehaus.mojo:animal-sniffer-annotations-1.14 +---------- + + The MIT License + + Copyright (c) 2009 codehaus.org. + + Permission is hereby granted, free of charge, to any person obtaining a copy + of this software and associated documentation files (the "Software"), to deal + in the Software without restriction, including without limitation the rights + to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + copies of the Software, and to permit persons to whom the Software is + furnished to do so, subject to the following conditions: + + The above copyright notice and this permission notice shall be included in + all copies or substantial portions of the Software. + + THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + THE SOFTWARE. + + +========== +Notice for: org.eclipse.core:org.eclipse.core.commands-3.6.0 +---------- + +Copyright © Eclipse Foundation, Inc. All Rights Reserved. + +Eclipse Public License - v 1.0 +THE ACCOMPANYING PROGRAM IS PROVIDED UNDER THE TERMS OF THIS ECLIPSE PUBLIC LICENSE ("AGREEMENT"). ANY USE, REPRODUCTION OR DISTRIBUTION OF THE PROGRAM CONSTITUTES RECIPIENT'S ACCEPTANCE OF THIS AGREEMENT. + +1. DEFINITIONS + +"Contribution" means: + +a) in the case of the initial Contributor, the initial code and documentation distributed under this Agreement, and + +b) in the case of each subsequent Contributor: + +i) changes to the Program, and + +ii) additions to the Program; + +where such changes and/or additions to the Program originate from and are distributed by that particular Contributor. A Contribution 'originates' from a Contributor if it was added to the Program by such Contributor itself or anyone acting on such Contributor's behalf. Contributions do not include additions to the Program which: (i) are separate modules of software distributed in conjunction with the Program under their own license agreement, and (ii) are not derivative works of the Program. + +"Contributor" means any person or entity that distributes the Program. + +"Licensed Patents" mean patent claims licensable by a Contributor which are necessarily infringed by the use or sale of its Contribution alone or when combined with the Program. + +"Program" means the Contributions distributed in accordance with this Agreement. + +"Recipient" means anyone who receives the Program under this Agreement, including all Contributors. + +2. GRANT OF RIGHTS + +a) Subject to the terms of this Agreement, each Contributor hereby grants Recipient a non-exclusive, worldwide, royalty-free copyright license to reproduce, prepare derivative works of, publicly display, publicly perform, distribute and sublicense the Contribution of such Contributor, if any, and such derivative works, in source code and object code form. + +b) Subject to the terms of this Agreement, each Contributor hereby grants Recipient a non-exclusive, worldwide, royalty-free patent license under Licensed Patents to make, use, sell, offer to sell, import and otherwise transfer the Contribution of such Contributor, if any, in source code and object code form. This patent license shall apply to the combination of the Contribution and the Program if, at the time the Contribution is added by the Contributor, such addition of the Contribution causes such combination to be covered by the Licensed Patents. The patent license shall not apply to any other combinations which include the Contribution. No hardware per se is licensed hereunder. + +c) Recipient understands that although each Contributor grants the licenses to its Contributions set forth herein, no assurances are provided by any Contributor that the Program does not infringe the patent or other intellectual property rights of any other entity. Each Contributor disclaims any liability to Recipient for claims brought by any other entity based on infringement of intellectual property rights or otherwise. As a condition to exercising the rights and licenses granted hereunder, each Recipient hereby assumes sole responsibility to secure any other intellectual property rights needed, if any. For example, if a third party patent license is required to allow Recipient to distribute the Program, it is Recipient's responsibility to acquire that license before distributing the Program. + +d) Each Contributor represents that to its knowledge it has sufficient copyright rights in its Contribution, if any, to grant the copyright license set forth in this Agreement. + +3. REQUIREMENTS + +A Contributor may choose to distribute the Program in object code form under its own license agreement, provided that: + +a) it complies with the terms and conditions of this Agreement; and + +b) its license agreement: + +i) effectively disclaims on behalf of all Contributors all warranties and conditions, express and implied, including warranties or conditions of title and non-infringement, and implied warranties or conditions of merchantability and fitness for a particular purpose; + +ii) effectively excludes on behalf of all Contributors all liability for damages, including direct, indirect, special, incidental and consequential damages, such as lost profits; + +iii) states that any provisions which differ from this Agreement are offered by that Contributor alone and not by any other party; and + +iv) states that source code for the Program is available from such Contributor, and informs licensees how to obtain it in a reasonable manner on or through a medium customarily used for software exchange. + +When the Program is made available in source code form: + +a) it must be made available under this Agreement; and + +b) a copy of this Agreement must be included with each copy of the Program. + +Contributors may not remove or alter any copyright notices contained within the Program. + +Each Contributor must identify itself as the originator of its Contribution, if any, in a manner that reasonably allows subsequent Recipients to identify the originator of the Contribution. + +4. COMMERCIAL DISTRIBUTION + +Commercial distributors of software may accept certain responsibilities with respect to end users, business partners and the like. While this license is intended to facilitate the commercial use of the Program, the Contributor who includes the Program in a commercial product offering should do so in a manner which does not create potential liability for other Contributors. Therefore, if a Contributor includes the Program in a commercial product offering, such Contributor ("Commercial Contributor") hereby agrees to defend and indemnify every other Contributor ("Indemnified Contributor") against any losses, damages and costs (collectively "Losses") arising from claims, lawsuits and other legal actions brought by a third party against the Indemnified Contributor to the extent caused by the acts or omissions of such Commercial Contributor in connection with its distribution of the Program in a commercial product offering. The obligations in this section do not apply to any claims or Losses relating to any actual or alleged intellectual property infringement. In order to qualify, an Indemnified Contributor must: a) promptly notify the Commercial Contributor in writing of such claim, and b) allow the Commercial Contributor to control, and cooperate with the Commercial Contributor in, the defense and any related settlement negotiations. The Indemnified Contributor may participate in any such claim at its own expense. + +For example, a Contributor might include the Program in a commercial product offering, Product X. That Contributor is then a Commercial Contributor. If that Commercial Contributor then makes performance claims, or offers warranties related to Product X, those performance claims and warranties are such Commercial Contributor's responsibility alone. Under this section, the Commercial Contributor would have to defend claims against the other Contributors related to those performance claims and warranties, and if a court requires any other Contributor to pay any damages as a result, the Commercial Contributor must pay those damages. + +5. NO WARRANTY + +EXCEPT AS EXPRESSLY SET FORTH IN THIS AGREEMENT, THE PROGRAM IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED INCLUDING, WITHOUT LIMITATION, ANY WARRANTIES OR CONDITIONS OF TITLE, NON-INFRINGEMENT, MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE. Each Recipient is solely responsible for determining the appropriateness of using and distributing the Program and assumes all risks associated with its exercise of rights under this Agreement , including but not limited to the risks and costs of program errors, compliance with applicable laws, damage to or loss of data, programs or equipment, and unavailability or interruption of operations. + +6. DISCLAIMER OF LIABILITY + +EXCEPT AS EXPRESSLY SET FORTH IN THIS AGREEMENT, NEITHER RECIPIENT NOR ANY CONTRIBUTORS SHALL HAVE ANY LIABILITY FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING WITHOUT LIMITATION LOST PROFITS), HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OR DISTRIBUTION OF THE PROGRAM OR THE EXERCISE OF ANY RIGHTS GRANTED HEREUNDER, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGES. + +7. GENERAL + +If any provision of this Agreement is invalid or unenforceable under applicable law, it shall not affect the validity or enforceability of the remainder of the terms of this Agreement, and without further action by the parties hereto, such provision shall be reformed to the minimum extent necessary to make such provision valid and enforceable. + +If Recipient institutes patent litigation against any entity (including a cross-claim or counterclaim in a lawsuit) alleging that the Program itself (excluding combinations of the Program with other software or hardware) infringes such Recipient's patent(s), then such Recipient's rights granted under Section 2(b) shall terminate as of the date such litigation is filed. + +All Recipient's rights under this Agreement shall terminate if it fails to comply with any of the material terms or conditions of this Agreement and does not cure such failure in a reasonable period of time after becoming aware of such noncompliance. If all Recipient's rights under this Agreement terminate, Recipient agrees to cease use and distribution of the Program as soon as reasonably practicable. However, Recipient's obligations under this Agreement and any licenses granted by Recipient relating to the Program shall continue and survive. + +Everyone is permitted to copy and distribute copies of this Agreement, but in order to avoid inconsistency the Agreement is copyrighted and may only be modified in the following manner. The Agreement Steward reserves the right to publish new versions (including revisions) of this Agreement from time to time. No one other than the Agreement Steward has the right to modify this Agreement. The Eclipse Foundation is the initial Agreement Steward. The Eclipse Foundation may assign the responsibility to serve as the Agreement Steward to a suitable separate entity. Each new version of the Agreement will be given a distinguishing version number. The Program (including Contributions) may always be distributed subject to the version of the Agreement under which it was received. In addition, after a new version of the Agreement is published, Contributor may elect to distribute the Program (including its Contributions) under the new version. Except as expressly stated in Sections 2(a) and 2(b) above, Recipient receives no rights or licenses to the intellectual property of any Contributor under this Agreement, whether expressly, by implication, estoppel or otherwise. All rights in the Program not expressly granted under this Agreement are reserved. + +This Agreement is governed by the laws of the State of New York and the intellectual property laws of the United States of America. No party to this Agreement will bring a legal action under this Agreement more than one year after the cause of action arose. Each party waives its rights to a jury trial in any resulting litigation. +========== +Notice for: org.eclipse.core:org.eclipse.core.contenttype-3.4.100 +---------- + +Copyright © Eclipse Foundation, Inc. All Rights Reserved. + +Eclipse Public License - v 1.0 +THE ACCOMPANYING PROGRAM IS PROVIDED UNDER THE TERMS OF THIS ECLIPSE PUBLIC LICENSE ("AGREEMENT"). ANY USE, REPRODUCTION OR DISTRIBUTION OF THE PROGRAM CONSTITUTES RECIPIENT'S ACCEPTANCE OF THIS AGREEMENT. + +1. DEFINITIONS + +"Contribution" means: + +a) in the case of the initial Contributor, the initial code and documentation distributed under this Agreement, and + +b) in the case of each subsequent Contributor: + +i) changes to the Program, and + +ii) additions to the Program; + +where such changes and/or additions to the Program originate from and are distributed by that particular Contributor. A Contribution 'originates' from a Contributor if it was added to the Program by such Contributor itself or anyone acting on such Contributor's behalf. Contributions do not include additions to the Program which: (i) are separate modules of software distributed in conjunction with the Program under their own license agreement, and (ii) are not derivative works of the Program. + +"Contributor" means any person or entity that distributes the Program. + +"Licensed Patents" mean patent claims licensable by a Contributor which are necessarily infringed by the use or sale of its Contribution alone or when combined with the Program. + +"Program" means the Contributions distributed in accordance with this Agreement. + +"Recipient" means anyone who receives the Program under this Agreement, including all Contributors. + +2. GRANT OF RIGHTS + +a) Subject to the terms of this Agreement, each Contributor hereby grants Recipient a non-exclusive, worldwide, royalty-free copyright license to reproduce, prepare derivative works of, publicly display, publicly perform, distribute and sublicense the Contribution of such Contributor, if any, and such derivative works, in source code and object code form. + +b) Subject to the terms of this Agreement, each Contributor hereby grants Recipient a non-exclusive, worldwide, royalty-free patent license under Licensed Patents to make, use, sell, offer to sell, import and otherwise transfer the Contribution of such Contributor, if any, in source code and object code form. This patent license shall apply to the combination of the Contribution and the Program if, at the time the Contribution is added by the Contributor, such addition of the Contribution causes such combination to be covered by the Licensed Patents. The patent license shall not apply to any other combinations which include the Contribution. No hardware per se is licensed hereunder. + +c) Recipient understands that although each Contributor grants the licenses to its Contributions set forth herein, no assurances are provided by any Contributor that the Program does not infringe the patent or other intellectual property rights of any other entity. Each Contributor disclaims any liability to Recipient for claims brought by any other entity based on infringement of intellectual property rights or otherwise. As a condition to exercising the rights and licenses granted hereunder, each Recipient hereby assumes sole responsibility to secure any other intellectual property rights needed, if any. For example, if a third party patent license is required to allow Recipient to distribute the Program, it is Recipient's responsibility to acquire that license before distributing the Program. + +d) Each Contributor represents that to its knowledge it has sufficient copyright rights in its Contribution, if any, to grant the copyright license set forth in this Agreement. + +3. REQUIREMENTS + +A Contributor may choose to distribute the Program in object code form under its own license agreement, provided that: + +a) it complies with the terms and conditions of this Agreement; and + +b) its license agreement: + +i) effectively disclaims on behalf of all Contributors all warranties and conditions, express and implied, including warranties or conditions of title and non-infringement, and implied warranties or conditions of merchantability and fitness for a particular purpose; + +ii) effectively excludes on behalf of all Contributors all liability for damages, including direct, indirect, special, incidental and consequential damages, such as lost profits; + +iii) states that any provisions which differ from this Agreement are offered by that Contributor alone and not by any other party; and + +iv) states that source code for the Program is available from such Contributor, and informs licensees how to obtain it in a reasonable manner on or through a medium customarily used for software exchange. + +When the Program is made available in source code form: + +a) it must be made available under this Agreement; and + +b) a copy of this Agreement must be included with each copy of the Program. + +Contributors may not remove or alter any copyright notices contained within the Program. + +Each Contributor must identify itself as the originator of its Contribution, if any, in a manner that reasonably allows subsequent Recipients to identify the originator of the Contribution. + +4. COMMERCIAL DISTRIBUTION + +Commercial distributors of software may accept certain responsibilities with respect to end users, business partners and the like. While this license is intended to facilitate the commercial use of the Program, the Contributor who includes the Program in a commercial product offering should do so in a manner which does not create potential liability for other Contributors. Therefore, if a Contributor includes the Program in a commercial product offering, such Contributor ("Commercial Contributor") hereby agrees to defend and indemnify every other Contributor ("Indemnified Contributor") against any losses, damages and costs (collectively "Losses") arising from claims, lawsuits and other legal actions brought by a third party against the Indemnified Contributor to the extent caused by the acts or omissions of such Commercial Contributor in connection with its distribution of the Program in a commercial product offering. The obligations in this section do not apply to any claims or Losses relating to any actual or alleged intellectual property infringement. In order to qualify, an Indemnified Contributor must: a) promptly notify the Commercial Contributor in writing of such claim, and b) allow the Commercial Contributor to control, and cooperate with the Commercial Contributor in, the defense and any related settlement negotiations. The Indemnified Contributor may participate in any such claim at its own expense. + +For example, a Contributor might include the Program in a commercial product offering, Product X. That Contributor is then a Commercial Contributor. If that Commercial Contributor then makes performance claims, or offers warranties related to Product X, those performance claims and warranties are such Commercial Contributor's responsibility alone. Under this section, the Commercial Contributor would have to defend claims against the other Contributors related to those performance claims and warranties, and if a court requires any other Contributor to pay any damages as a result, the Commercial Contributor must pay those damages. + +5. NO WARRANTY + +EXCEPT AS EXPRESSLY SET FORTH IN THIS AGREEMENT, THE PROGRAM IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED INCLUDING, WITHOUT LIMITATION, ANY WARRANTIES OR CONDITIONS OF TITLE, NON-INFRINGEMENT, MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE. Each Recipient is solely responsible for determining the appropriateness of using and distributing the Program and assumes all risks associated with its exercise of rights under this Agreement , including but not limited to the risks and costs of program errors, compliance with applicable laws, damage to or loss of data, programs or equipment, and unavailability or interruption of operations. + +6. DISCLAIMER OF LIABILITY + +EXCEPT AS EXPRESSLY SET FORTH IN THIS AGREEMENT, NEITHER RECIPIENT NOR ANY CONTRIBUTORS SHALL HAVE ANY LIABILITY FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING WITHOUT LIMITATION LOST PROFITS), HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OR DISTRIBUTION OF THE PROGRAM OR THE EXERCISE OF ANY RIGHTS GRANTED HEREUNDER, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGES. + +7. GENERAL + +If any provision of this Agreement is invalid or unenforceable under applicable law, it shall not affect the validity or enforceability of the remainder of the terms of this Agreement, and without further action by the parties hereto, such provision shall be reformed to the minimum extent necessary to make such provision valid and enforceable. + +If Recipient institutes patent litigation against any entity (including a cross-claim or counterclaim in a lawsuit) alleging that the Program itself (excluding combinations of the Program with other software or hardware) infringes such Recipient's patent(s), then such Recipient's rights granted under Section 2(b) shall terminate as of the date such litigation is filed. + +All Recipient's rights under this Agreement shall terminate if it fails to comply with any of the material terms or conditions of this Agreement and does not cure such failure in a reasonable period of time after becoming aware of such noncompliance. If all Recipient's rights under this Agreement terminate, Recipient agrees to cease use and distribution of the Program as soon as reasonably practicable. However, Recipient's obligations under this Agreement and any licenses granted by Recipient relating to the Program shall continue and survive. + +Everyone is permitted to copy and distribute copies of this Agreement, but in order to avoid inconsistency the Agreement is copyrighted and may only be modified in the following manner. The Agreement Steward reserves the right to publish new versions (including revisions) of this Agreement from time to time. No one other than the Agreement Steward has the right to modify this Agreement. The Eclipse Foundation is the initial Agreement Steward. The Eclipse Foundation may assign the responsibility to serve as the Agreement Steward to a suitable separate entity. Each new version of the Agreement will be given a distinguishing version number. The Program (including Contributions) may always be distributed subject to the version of the Agreement under which it was received. In addition, after a new version of the Agreement is published, Contributor may elect to distribute the Program (including its Contributions) under the new version. Except as expressly stated in Sections 2(a) and 2(b) above, Recipient receives no rights or licenses to the intellectual property of any Contributor under this Agreement, whether expressly, by implication, estoppel or otherwise. All rights in the Program not expressly granted under this Agreement are reserved. + +This Agreement is governed by the laws of the State of New York and the intellectual property laws of the United States of America. No party to this Agreement will bring a legal action under this Agreement more than one year after the cause of action arose. Each party waives its rights to a jury trial in any resulting litigation. +========== +Notice for: org.eclipse.core:org.eclipse.core.expressions-3.4.300 +---------- + +Copyright © Eclipse Foundation, Inc. All Rights Reserved. + +Eclipse Public License - v 1.0 +THE ACCOMPANYING PROGRAM IS PROVIDED UNDER THE TERMS OF THIS ECLIPSE PUBLIC LICENSE ("AGREEMENT"). ANY USE, REPRODUCTION OR DISTRIBUTION OF THE PROGRAM CONSTITUTES RECIPIENT'S ACCEPTANCE OF THIS AGREEMENT. + +1. DEFINITIONS + +"Contribution" means: + +a) in the case of the initial Contributor, the initial code and documentation distributed under this Agreement, and + +b) in the case of each subsequent Contributor: + +i) changes to the Program, and + +ii) additions to the Program; + +where such changes and/or additions to the Program originate from and are distributed by that particular Contributor. A Contribution 'originates' from a Contributor if it was added to the Program by such Contributor itself or anyone acting on such Contributor's behalf. Contributions do not include additions to the Program which: (i) are separate modules of software distributed in conjunction with the Program under their own license agreement, and (ii) are not derivative works of the Program. + +"Contributor" means any person or entity that distributes the Program. + +"Licensed Patents" mean patent claims licensable by a Contributor which are necessarily infringed by the use or sale of its Contribution alone or when combined with the Program. + +"Program" means the Contributions distributed in accordance with this Agreement. + +"Recipient" means anyone who receives the Program under this Agreement, including all Contributors. + +2. GRANT OF RIGHTS + +a) Subject to the terms of this Agreement, each Contributor hereby grants Recipient a non-exclusive, worldwide, royalty-free copyright license to reproduce, prepare derivative works of, publicly display, publicly perform, distribute and sublicense the Contribution of such Contributor, if any, and such derivative works, in source code and object code form. + +b) Subject to the terms of this Agreement, each Contributor hereby grants Recipient a non-exclusive, worldwide, royalty-free patent license under Licensed Patents to make, use, sell, offer to sell, import and otherwise transfer the Contribution of such Contributor, if any, in source code and object code form. This patent license shall apply to the combination of the Contribution and the Program if, at the time the Contribution is added by the Contributor, such addition of the Contribution causes such combination to be covered by the Licensed Patents. The patent license shall not apply to any other combinations which include the Contribution. No hardware per se is licensed hereunder. + +c) Recipient understands that although each Contributor grants the licenses to its Contributions set forth herein, no assurances are provided by any Contributor that the Program does not infringe the patent or other intellectual property rights of any other entity. Each Contributor disclaims any liability to Recipient for claims brought by any other entity based on infringement of intellectual property rights or otherwise. As a condition to exercising the rights and licenses granted hereunder, each Recipient hereby assumes sole responsibility to secure any other intellectual property rights needed, if any. For example, if a third party patent license is required to allow Recipient to distribute the Program, it is Recipient's responsibility to acquire that license before distributing the Program. + +d) Each Contributor represents that to its knowledge it has sufficient copyright rights in its Contribution, if any, to grant the copyright license set forth in this Agreement. + +3. REQUIREMENTS + +A Contributor may choose to distribute the Program in object code form under its own license agreement, provided that: + +a) it complies with the terms and conditions of this Agreement; and + +b) its license agreement: + +i) effectively disclaims on behalf of all Contributors all warranties and conditions, express and implied, including warranties or conditions of title and non-infringement, and implied warranties or conditions of merchantability and fitness for a particular purpose; + +ii) effectively excludes on behalf of all Contributors all liability for damages, including direct, indirect, special, incidental and consequential damages, such as lost profits; + +iii) states that any provisions which differ from this Agreement are offered by that Contributor alone and not by any other party; and + +iv) states that source code for the Program is available from such Contributor, and informs licensees how to obtain it in a reasonable manner on or through a medium customarily used for software exchange. + +When the Program is made available in source code form: + +a) it must be made available under this Agreement; and + +b) a copy of this Agreement must be included with each copy of the Program. + +Contributors may not remove or alter any copyright notices contained within the Program. + +Each Contributor must identify itself as the originator of its Contribution, if any, in a manner that reasonably allows subsequent Recipients to identify the originator of the Contribution. + +4. COMMERCIAL DISTRIBUTION + +Commercial distributors of software may accept certain responsibilities with respect to end users, business partners and the like. While this license is intended to facilitate the commercial use of the Program, the Contributor who includes the Program in a commercial product offering should do so in a manner which does not create potential liability for other Contributors. Therefore, if a Contributor includes the Program in a commercial product offering, such Contributor ("Commercial Contributor") hereby agrees to defend and indemnify every other Contributor ("Indemnified Contributor") against any losses, damages and costs (collectively "Losses") arising from claims, lawsuits and other legal actions brought by a third party against the Indemnified Contributor to the extent caused by the acts or omissions of such Commercial Contributor in connection with its distribution of the Program in a commercial product offering. The obligations in this section do not apply to any claims or Losses relating to any actual or alleged intellectual property infringement. In order to qualify, an Indemnified Contributor must: a) promptly notify the Commercial Contributor in writing of such claim, and b) allow the Commercial Contributor to control, and cooperate with the Commercial Contributor in, the defense and any related settlement negotiations. The Indemnified Contributor may participate in any such claim at its own expense. + +For example, a Contributor might include the Program in a commercial product offering, Product X. That Contributor is then a Commercial Contributor. If that Commercial Contributor then makes performance claims, or offers warranties related to Product X, those performance claims and warranties are such Commercial Contributor's responsibility alone. Under this section, the Commercial Contributor would have to defend claims against the other Contributors related to those performance claims and warranties, and if a court requires any other Contributor to pay any damages as a result, the Commercial Contributor must pay those damages. + +5. NO WARRANTY + +EXCEPT AS EXPRESSLY SET FORTH IN THIS AGREEMENT, THE PROGRAM IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED INCLUDING, WITHOUT LIMITATION, ANY WARRANTIES OR CONDITIONS OF TITLE, NON-INFRINGEMENT, MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE. Each Recipient is solely responsible for determining the appropriateness of using and distributing the Program and assumes all risks associated with its exercise of rights under this Agreement , including but not limited to the risks and costs of program errors, compliance with applicable laws, damage to or loss of data, programs or equipment, and unavailability or interruption of operations. + +6. DISCLAIMER OF LIABILITY + +EXCEPT AS EXPRESSLY SET FORTH IN THIS AGREEMENT, NEITHER RECIPIENT NOR ANY CONTRIBUTORS SHALL HAVE ANY LIABILITY FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING WITHOUT LIMITATION LOST PROFITS), HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OR DISTRIBUTION OF THE PROGRAM OR THE EXERCISE OF ANY RIGHTS GRANTED HEREUNDER, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGES. + +7. GENERAL + +If any provision of this Agreement is invalid or unenforceable under applicable law, it shall not affect the validity or enforceability of the remainder of the terms of this Agreement, and without further action by the parties hereto, such provision shall be reformed to the minimum extent necessary to make such provision valid and enforceable. + +If Recipient institutes patent litigation against any entity (including a cross-claim or counterclaim in a lawsuit) alleging that the Program itself (excluding combinations of the Program with other software or hardware) infringes such Recipient's patent(s), then such Recipient's rights granted under Section 2(b) shall terminate as of the date such litigation is filed. + +All Recipient's rights under this Agreement shall terminate if it fails to comply with any of the material terms or conditions of this Agreement and does not cure such failure in a reasonable period of time after becoming aware of such noncompliance. If all Recipient's rights under this Agreement terminate, Recipient agrees to cease use and distribution of the Program as soon as reasonably practicable. However, Recipient's obligations under this Agreement and any licenses granted by Recipient relating to the Program shall continue and survive. + +Everyone is permitted to copy and distribute copies of this Agreement, but in order to avoid inconsistency the Agreement is copyrighted and may only be modified in the following manner. The Agreement Steward reserves the right to publish new versions (including revisions) of this Agreement from time to time. No one other than the Agreement Steward has the right to modify this Agreement. The Eclipse Foundation is the initial Agreement Steward. The Eclipse Foundation may assign the responsibility to serve as the Agreement Steward to a suitable separate entity. Each new version of the Agreement will be given a distinguishing version number. The Program (including Contributions) may always be distributed subject to the version of the Agreement under which it was received. In addition, after a new version of the Agreement is published, Contributor may elect to distribute the Program (including its Contributions) under the new version. Except as expressly stated in Sections 2(a) and 2(b) above, Recipient receives no rights or licenses to the intellectual property of any Contributor under this Agreement, whether expressly, by implication, estoppel or otherwise. All rights in the Program not expressly granted under this Agreement are reserved. + +This Agreement is governed by the laws of the State of New York and the intellectual property laws of the United States of America. No party to this Agreement will bring a legal action under this Agreement more than one year after the cause of action arose. Each party waives its rights to a jury trial in any resulting litigation. +========== +Notice for: org.eclipse.core:org.eclipse.core.filesystem-1.3.100 +---------- + +Copyright © Eclipse Foundation, Inc. All Rights Reserved. + +Eclipse Public License - v 1.0 +THE ACCOMPANYING PROGRAM IS PROVIDED UNDER THE TERMS OF THIS ECLIPSE PUBLIC LICENSE ("AGREEMENT"). ANY USE, REPRODUCTION OR DISTRIBUTION OF THE PROGRAM CONSTITUTES RECIPIENT'S ACCEPTANCE OF THIS AGREEMENT. + +1. DEFINITIONS + +"Contribution" means: + +a) in the case of the initial Contributor, the initial code and documentation distributed under this Agreement, and + +b) in the case of each subsequent Contributor: + +i) changes to the Program, and + +ii) additions to the Program; + +where such changes and/or additions to the Program originate from and are distributed by that particular Contributor. A Contribution 'originates' from a Contributor if it was added to the Program by such Contributor itself or anyone acting on such Contributor's behalf. Contributions do not include additions to the Program which: (i) are separate modules of software distributed in conjunction with the Program under their own license agreement, and (ii) are not derivative works of the Program. + +"Contributor" means any person or entity that distributes the Program. + +"Licensed Patents" mean patent claims licensable by a Contributor which are necessarily infringed by the use or sale of its Contribution alone or when combined with the Program. + +"Program" means the Contributions distributed in accordance with this Agreement. + +"Recipient" means anyone who receives the Program under this Agreement, including all Contributors. + +2. GRANT OF RIGHTS + +a) Subject to the terms of this Agreement, each Contributor hereby grants Recipient a non-exclusive, worldwide, royalty-free copyright license to reproduce, prepare derivative works of, publicly display, publicly perform, distribute and sublicense the Contribution of such Contributor, if any, and such derivative works, in source code and object code form. + +b) Subject to the terms of this Agreement, each Contributor hereby grants Recipient a non-exclusive, worldwide, royalty-free patent license under Licensed Patents to make, use, sell, offer to sell, import and otherwise transfer the Contribution of such Contributor, if any, in source code and object code form. This patent license shall apply to the combination of the Contribution and the Program if, at the time the Contribution is added by the Contributor, such addition of the Contribution causes such combination to be covered by the Licensed Patents. The patent license shall not apply to any other combinations which include the Contribution. No hardware per se is licensed hereunder. + +c) Recipient understands that although each Contributor grants the licenses to its Contributions set forth herein, no assurances are provided by any Contributor that the Program does not infringe the patent or other intellectual property rights of any other entity. Each Contributor disclaims any liability to Recipient for claims brought by any other entity based on infringement of intellectual property rights or otherwise. As a condition to exercising the rights and licenses granted hereunder, each Recipient hereby assumes sole responsibility to secure any other intellectual property rights needed, if any. For example, if a third party patent license is required to allow Recipient to distribute the Program, it is Recipient's responsibility to acquire that license before distributing the Program. + +d) Each Contributor represents that to its knowledge it has sufficient copyright rights in its Contribution, if any, to grant the copyright license set forth in this Agreement. + +3. REQUIREMENTS + +A Contributor may choose to distribute the Program in object code form under its own license agreement, provided that: + +a) it complies with the terms and conditions of this Agreement; and + +b) its license agreement: + +i) effectively disclaims on behalf of all Contributors all warranties and conditions, express and implied, including warranties or conditions of title and non-infringement, and implied warranties or conditions of merchantability and fitness for a particular purpose; + +ii) effectively excludes on behalf of all Contributors all liability for damages, including direct, indirect, special, incidental and consequential damages, such as lost profits; + +iii) states that any provisions which differ from this Agreement are offered by that Contributor alone and not by any other party; and + +iv) states that source code for the Program is available from such Contributor, and informs licensees how to obtain it in a reasonable manner on or through a medium customarily used for software exchange. + +When the Program is made available in source code form: + +a) it must be made available under this Agreement; and + +b) a copy of this Agreement must be included with each copy of the Program. + +Contributors may not remove or alter any copyright notices contained within the Program. + +Each Contributor must identify itself as the originator of its Contribution, if any, in a manner that reasonably allows subsequent Recipients to identify the originator of the Contribution. + +4. COMMERCIAL DISTRIBUTION + +Commercial distributors of software may accept certain responsibilities with respect to end users, business partners and the like. While this license is intended to facilitate the commercial use of the Program, the Contributor who includes the Program in a commercial product offering should do so in a manner which does not create potential liability for other Contributors. Therefore, if a Contributor includes the Program in a commercial product offering, such Contributor ("Commercial Contributor") hereby agrees to defend and indemnify every other Contributor ("Indemnified Contributor") against any losses, damages and costs (collectively "Losses") arising from claims, lawsuits and other legal actions brought by a third party against the Indemnified Contributor to the extent caused by the acts or omissions of such Commercial Contributor in connection with its distribution of the Program in a commercial product offering. The obligations in this section do not apply to any claims or Losses relating to any actual or alleged intellectual property infringement. In order to qualify, an Indemnified Contributor must: a) promptly notify the Commercial Contributor in writing of such claim, and b) allow the Commercial Contributor to control, and cooperate with the Commercial Contributor in, the defense and any related settlement negotiations. The Indemnified Contributor may participate in any such claim at its own expense. + +For example, a Contributor might include the Program in a commercial product offering, Product X. That Contributor is then a Commercial Contributor. If that Commercial Contributor then makes performance claims, or offers warranties related to Product X, those performance claims and warranties are such Commercial Contributor's responsibility alone. Under this section, the Commercial Contributor would have to defend claims against the other Contributors related to those performance claims and warranties, and if a court requires any other Contributor to pay any damages as a result, the Commercial Contributor must pay those damages. + +5. NO WARRANTY + +EXCEPT AS EXPRESSLY SET FORTH IN THIS AGREEMENT, THE PROGRAM IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED INCLUDING, WITHOUT LIMITATION, ANY WARRANTIES OR CONDITIONS OF TITLE, NON-INFRINGEMENT, MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE. Each Recipient is solely responsible for determining the appropriateness of using and distributing the Program and assumes all risks associated with its exercise of rights under this Agreement , including but not limited to the risks and costs of program errors, compliance with applicable laws, damage to or loss of data, programs or equipment, and unavailability or interruption of operations. + +6. DISCLAIMER OF LIABILITY + +EXCEPT AS EXPRESSLY SET FORTH IN THIS AGREEMENT, NEITHER RECIPIENT NOR ANY CONTRIBUTORS SHALL HAVE ANY LIABILITY FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING WITHOUT LIMITATION LOST PROFITS), HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OR DISTRIBUTION OF THE PROGRAM OR THE EXERCISE OF ANY RIGHTS GRANTED HEREUNDER, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGES. + +7. GENERAL + +If any provision of this Agreement is invalid or unenforceable under applicable law, it shall not affect the validity or enforceability of the remainder of the terms of this Agreement, and without further action by the parties hereto, such provision shall be reformed to the minimum extent necessary to make such provision valid and enforceable. + +If Recipient institutes patent litigation against any entity (including a cross-claim or counterclaim in a lawsuit) alleging that the Program itself (excluding combinations of the Program with other software or hardware) infringes such Recipient's patent(s), then such Recipient's rights granted under Section 2(b) shall terminate as of the date such litigation is filed. + +All Recipient's rights under this Agreement shall terminate if it fails to comply with any of the material terms or conditions of this Agreement and does not cure such failure in a reasonable period of time after becoming aware of such noncompliance. If all Recipient's rights under this Agreement terminate, Recipient agrees to cease use and distribution of the Program as soon as reasonably practicable. However, Recipient's obligations under this Agreement and any licenses granted by Recipient relating to the Program shall continue and survive. + +Everyone is permitted to copy and distribute copies of this Agreement, but in order to avoid inconsistency the Agreement is copyrighted and may only be modified in the following manner. The Agreement Steward reserves the right to publish new versions (including revisions) of this Agreement from time to time. No one other than the Agreement Steward has the right to modify this Agreement. The Eclipse Foundation is the initial Agreement Steward. The Eclipse Foundation may assign the responsibility to serve as the Agreement Steward to a suitable separate entity. Each new version of the Agreement will be given a distinguishing version number. The Program (including Contributions) may always be distributed subject to the version of the Agreement under which it was received. In addition, after a new version of the Agreement is published, Contributor may elect to distribute the Program (including its Contributions) under the new version. Except as expressly stated in Sections 2(a) and 2(b) above, Recipient receives no rights or licenses to the intellectual property of any Contributor under this Agreement, whether expressly, by implication, estoppel or otherwise. All rights in the Program not expressly granted under this Agreement are reserved. + +This Agreement is governed by the laws of the State of New York and the intellectual property laws of the United States of America. No party to this Agreement will bring a legal action under this Agreement more than one year after the cause of action arose. Each party waives its rights to a jury trial in any resulting litigation. +========== +Notice for: org.eclipse.core:org.eclipse.core.jobs-3.5.100 +---------- + +Copyright © Eclipse Foundation, Inc. All Rights Reserved. + +Eclipse Public License - v 1.0 +THE ACCOMPANYING PROGRAM IS PROVIDED UNDER THE TERMS OF THIS ECLIPSE PUBLIC LICENSE ("AGREEMENT"). ANY USE, REPRODUCTION OR DISTRIBUTION OF THE PROGRAM CONSTITUTES RECIPIENT'S ACCEPTANCE OF THIS AGREEMENT. + +1. DEFINITIONS + +"Contribution" means: + +a) in the case of the initial Contributor, the initial code and documentation distributed under this Agreement, and + +b) in the case of each subsequent Contributor: + +i) changes to the Program, and + +ii) additions to the Program; + +where such changes and/or additions to the Program originate from and are distributed by that particular Contributor. A Contribution 'originates' from a Contributor if it was added to the Program by such Contributor itself or anyone acting on such Contributor's behalf. Contributions do not include additions to the Program which: (i) are separate modules of software distributed in conjunction with the Program under their own license agreement, and (ii) are not derivative works of the Program. + +"Contributor" means any person or entity that distributes the Program. + +"Licensed Patents" mean patent claims licensable by a Contributor which are necessarily infringed by the use or sale of its Contribution alone or when combined with the Program. + +"Program" means the Contributions distributed in accordance with this Agreement. + +"Recipient" means anyone who receives the Program under this Agreement, including all Contributors. + +2. GRANT OF RIGHTS + +a) Subject to the terms of this Agreement, each Contributor hereby grants Recipient a non-exclusive, worldwide, royalty-free copyright license to reproduce, prepare derivative works of, publicly display, publicly perform, distribute and sublicense the Contribution of such Contributor, if any, and such derivative works, in source code and object code form. + +b) Subject to the terms of this Agreement, each Contributor hereby grants Recipient a non-exclusive, worldwide, royalty-free patent license under Licensed Patents to make, use, sell, offer to sell, import and otherwise transfer the Contribution of such Contributor, if any, in source code and object code form. This patent license shall apply to the combination of the Contribution and the Program if, at the time the Contribution is added by the Contributor, such addition of the Contribution causes such combination to be covered by the Licensed Patents. The patent license shall not apply to any other combinations which include the Contribution. No hardware per se is licensed hereunder. + +c) Recipient understands that although each Contributor grants the licenses to its Contributions set forth herein, no assurances are provided by any Contributor that the Program does not infringe the patent or other intellectual property rights of any other entity. Each Contributor disclaims any liability to Recipient for claims brought by any other entity based on infringement of intellectual property rights or otherwise. As a condition to exercising the rights and licenses granted hereunder, each Recipient hereby assumes sole responsibility to secure any other intellectual property rights needed, if any. For example, if a third party patent license is required to allow Recipient to distribute the Program, it is Recipient's responsibility to acquire that license before distributing the Program. + +d) Each Contributor represents that to its knowledge it has sufficient copyright rights in its Contribution, if any, to grant the copyright license set forth in this Agreement. + +3. REQUIREMENTS + +A Contributor may choose to distribute the Program in object code form under its own license agreement, provided that: + +a) it complies with the terms and conditions of this Agreement; and + +b) its license agreement: + +i) effectively disclaims on behalf of all Contributors all warranties and conditions, express and implied, including warranties or conditions of title and non-infringement, and implied warranties or conditions of merchantability and fitness for a particular purpose; + +ii) effectively excludes on behalf of all Contributors all liability for damages, including direct, indirect, special, incidental and consequential damages, such as lost profits; + +iii) states that any provisions which differ from this Agreement are offered by that Contributor alone and not by any other party; and + +iv) states that source code for the Program is available from such Contributor, and informs licensees how to obtain it in a reasonable manner on or through a medium customarily used for software exchange. + +When the Program is made available in source code form: + +a) it must be made available under this Agreement; and + +b) a copy of this Agreement must be included with each copy of the Program. + +Contributors may not remove or alter any copyright notices contained within the Program. + +Each Contributor must identify itself as the originator of its Contribution, if any, in a manner that reasonably allows subsequent Recipients to identify the originator of the Contribution. + +4. COMMERCIAL DISTRIBUTION + +Commercial distributors of software may accept certain responsibilities with respect to end users, business partners and the like. While this license is intended to facilitate the commercial use of the Program, the Contributor who includes the Program in a commercial product offering should do so in a manner which does not create potential liability for other Contributors. Therefore, if a Contributor includes the Program in a commercial product offering, such Contributor ("Commercial Contributor") hereby agrees to defend and indemnify every other Contributor ("Indemnified Contributor") against any losses, damages and costs (collectively "Losses") arising from claims, lawsuits and other legal actions brought by a third party against the Indemnified Contributor to the extent caused by the acts or omissions of such Commercial Contributor in connection with its distribution of the Program in a commercial product offering. The obligations in this section do not apply to any claims or Losses relating to any actual or alleged intellectual property infringement. In order to qualify, an Indemnified Contributor must: a) promptly notify the Commercial Contributor in writing of such claim, and b) allow the Commercial Contributor to control, and cooperate with the Commercial Contributor in, the defense and any related settlement negotiations. The Indemnified Contributor may participate in any such claim at its own expense. + +For example, a Contributor might include the Program in a commercial product offering, Product X. That Contributor is then a Commercial Contributor. If that Commercial Contributor then makes performance claims, or offers warranties related to Product X, those performance claims and warranties are such Commercial Contributor's responsibility alone. Under this section, the Commercial Contributor would have to defend claims against the other Contributors related to those performance claims and warranties, and if a court requires any other Contributor to pay any damages as a result, the Commercial Contributor must pay those damages. + +5. NO WARRANTY + +EXCEPT AS EXPRESSLY SET FORTH IN THIS AGREEMENT, THE PROGRAM IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED INCLUDING, WITHOUT LIMITATION, ANY WARRANTIES OR CONDITIONS OF TITLE, NON-INFRINGEMENT, MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE. Each Recipient is solely responsible for determining the appropriateness of using and distributing the Program and assumes all risks associated with its exercise of rights under this Agreement , including but not limited to the risks and costs of program errors, compliance with applicable laws, damage to or loss of data, programs or equipment, and unavailability or interruption of operations. + +6. DISCLAIMER OF LIABILITY + +EXCEPT AS EXPRESSLY SET FORTH IN THIS AGREEMENT, NEITHER RECIPIENT NOR ANY CONTRIBUTORS SHALL HAVE ANY LIABILITY FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING WITHOUT LIMITATION LOST PROFITS), HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OR DISTRIBUTION OF THE PROGRAM OR THE EXERCISE OF ANY RIGHTS GRANTED HEREUNDER, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGES. + +7. GENERAL + +If any provision of this Agreement is invalid or unenforceable under applicable law, it shall not affect the validity or enforceability of the remainder of the terms of this Agreement, and without further action by the parties hereto, such provision shall be reformed to the minimum extent necessary to make such provision valid and enforceable. + +If Recipient institutes patent litigation against any entity (including a cross-claim or counterclaim in a lawsuit) alleging that the Program itself (excluding combinations of the Program with other software or hardware) infringes such Recipient's patent(s), then such Recipient's rights granted under Section 2(b) shall terminate as of the date such litigation is filed. + +All Recipient's rights under this Agreement shall terminate if it fails to comply with any of the material terms or conditions of this Agreement and does not cure such failure in a reasonable period of time after becoming aware of such noncompliance. If all Recipient's rights under this Agreement terminate, Recipient agrees to cease use and distribution of the Program as soon as reasonably practicable. However, Recipient's obligations under this Agreement and any licenses granted by Recipient relating to the Program shall continue and survive. + +Everyone is permitted to copy and distribute copies of this Agreement, but in order to avoid inconsistency the Agreement is copyrighted and may only be modified in the following manner. The Agreement Steward reserves the right to publish new versions (including revisions) of this Agreement from time to time. No one other than the Agreement Steward has the right to modify this Agreement. The Eclipse Foundation is the initial Agreement Steward. The Eclipse Foundation may assign the responsibility to serve as the Agreement Steward to a suitable separate entity. Each new version of the Agreement will be given a distinguishing version number. The Program (including Contributions) may always be distributed subject to the version of the Agreement under which it was received. In addition, after a new version of the Agreement is published, Contributor may elect to distribute the Program (including its Contributions) under the new version. Except as expressly stated in Sections 2(a) and 2(b) above, Recipient receives no rights or licenses to the intellectual property of any Contributor under this Agreement, whether expressly, by implication, estoppel or otherwise. All rights in the Program not expressly granted under this Agreement are reserved. + +This Agreement is governed by the laws of the State of New York and the intellectual property laws of the United States of America. No party to this Agreement will bring a legal action under this Agreement more than one year after the cause of action arose. Each party waives its rights to a jury trial in any resulting litigation. +========== +Notice for: org.eclipse.core:org.eclipse.core.resources-3.7.100 +---------- + +Copyright © Eclipse Foundation, Inc. All Rights Reserved. + +Eclipse Public License - v 1.0 +THE ACCOMPANYING PROGRAM IS PROVIDED UNDER THE TERMS OF THIS ECLIPSE PUBLIC LICENSE ("AGREEMENT"). ANY USE, REPRODUCTION OR DISTRIBUTION OF THE PROGRAM CONSTITUTES RECIPIENT'S ACCEPTANCE OF THIS AGREEMENT. + +1. DEFINITIONS + +"Contribution" means: + +a) in the case of the initial Contributor, the initial code and documentation distributed under this Agreement, and + +b) in the case of each subsequent Contributor: + +i) changes to the Program, and + +ii) additions to the Program; + +where such changes and/or additions to the Program originate from and are distributed by that particular Contributor. A Contribution 'originates' from a Contributor if it was added to the Program by such Contributor itself or anyone acting on such Contributor's behalf. Contributions do not include additions to the Program which: (i) are separate modules of software distributed in conjunction with the Program under their own license agreement, and (ii) are not derivative works of the Program. + +"Contributor" means any person or entity that distributes the Program. + +"Licensed Patents" mean patent claims licensable by a Contributor which are necessarily infringed by the use or sale of its Contribution alone or when combined with the Program. + +"Program" means the Contributions distributed in accordance with this Agreement. + +"Recipient" means anyone who receives the Program under this Agreement, including all Contributors. + +2. GRANT OF RIGHTS + +a) Subject to the terms of this Agreement, each Contributor hereby grants Recipient a non-exclusive, worldwide, royalty-free copyright license to reproduce, prepare derivative works of, publicly display, publicly perform, distribute and sublicense the Contribution of such Contributor, if any, and such derivative works, in source code and object code form. + +b) Subject to the terms of this Agreement, each Contributor hereby grants Recipient a non-exclusive, worldwide, royalty-free patent license under Licensed Patents to make, use, sell, offer to sell, import and otherwise transfer the Contribution of such Contributor, if any, in source code and object code form. This patent license shall apply to the combination of the Contribution and the Program if, at the time the Contribution is added by the Contributor, such addition of the Contribution causes such combination to be covered by the Licensed Patents. The patent license shall not apply to any other combinations which include the Contribution. No hardware per se is licensed hereunder. + +c) Recipient understands that although each Contributor grants the licenses to its Contributions set forth herein, no assurances are provided by any Contributor that the Program does not infringe the patent or other intellectual property rights of any other entity. Each Contributor disclaims any liability to Recipient for claims brought by any other entity based on infringement of intellectual property rights or otherwise. As a condition to exercising the rights and licenses granted hereunder, each Recipient hereby assumes sole responsibility to secure any other intellectual property rights needed, if any. For example, if a third party patent license is required to allow Recipient to distribute the Program, it is Recipient's responsibility to acquire that license before distributing the Program. + +d) Each Contributor represents that to its knowledge it has sufficient copyright rights in its Contribution, if any, to grant the copyright license set forth in this Agreement. + +3. REQUIREMENTS + +A Contributor may choose to distribute the Program in object code form under its own license agreement, provided that: + +a) it complies with the terms and conditions of this Agreement; and + +b) its license agreement: + +i) effectively disclaims on behalf of all Contributors all warranties and conditions, express and implied, including warranties or conditions of title and non-infringement, and implied warranties or conditions of merchantability and fitness for a particular purpose; + +ii) effectively excludes on behalf of all Contributors all liability for damages, including direct, indirect, special, incidental and consequential damages, such as lost profits; + +iii) states that any provisions which differ from this Agreement are offered by that Contributor alone and not by any other party; and + +iv) states that source code for the Program is available from such Contributor, and informs licensees how to obtain it in a reasonable manner on or through a medium customarily used for software exchange. + +When the Program is made available in source code form: + +a) it must be made available under this Agreement; and + +b) a copy of this Agreement must be included with each copy of the Program. + +Contributors may not remove or alter any copyright notices contained within the Program. + +Each Contributor must identify itself as the originator of its Contribution, if any, in a manner that reasonably allows subsequent Recipients to identify the originator of the Contribution. + +4. COMMERCIAL DISTRIBUTION + +Commercial distributors of software may accept certain responsibilities with respect to end users, business partners and the like. While this license is intended to facilitate the commercial use of the Program, the Contributor who includes the Program in a commercial product offering should do so in a manner which does not create potential liability for other Contributors. Therefore, if a Contributor includes the Program in a commercial product offering, such Contributor ("Commercial Contributor") hereby agrees to defend and indemnify every other Contributor ("Indemnified Contributor") against any losses, damages and costs (collectively "Losses") arising from claims, lawsuits and other legal actions brought by a third party against the Indemnified Contributor to the extent caused by the acts or omissions of such Commercial Contributor in connection with its distribution of the Program in a commercial product offering. The obligations in this section do not apply to any claims or Losses relating to any actual or alleged intellectual property infringement. In order to qualify, an Indemnified Contributor must: a) promptly notify the Commercial Contributor in writing of such claim, and b) allow the Commercial Contributor to control, and cooperate with the Commercial Contributor in, the defense and any related settlement negotiations. The Indemnified Contributor may participate in any such claim at its own expense. + +For example, a Contributor might include the Program in a commercial product offering, Product X. That Contributor is then a Commercial Contributor. If that Commercial Contributor then makes performance claims, or offers warranties related to Product X, those performance claims and warranties are such Commercial Contributor's responsibility alone. Under this section, the Commercial Contributor would have to defend claims against the other Contributors related to those performance claims and warranties, and if a court requires any other Contributor to pay any damages as a result, the Commercial Contributor must pay those damages. + +5. NO WARRANTY + +EXCEPT AS EXPRESSLY SET FORTH IN THIS AGREEMENT, THE PROGRAM IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED INCLUDING, WITHOUT LIMITATION, ANY WARRANTIES OR CONDITIONS OF TITLE, NON-INFRINGEMENT, MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE. Each Recipient is solely responsible for determining the appropriateness of using and distributing the Program and assumes all risks associated with its exercise of rights under this Agreement , including but not limited to the risks and costs of program errors, compliance with applicable laws, damage to or loss of data, programs or equipment, and unavailability or interruption of operations. + +6. DISCLAIMER OF LIABILITY + +EXCEPT AS EXPRESSLY SET FORTH IN THIS AGREEMENT, NEITHER RECIPIENT NOR ANY CONTRIBUTORS SHALL HAVE ANY LIABILITY FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING WITHOUT LIMITATION LOST PROFITS), HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OR DISTRIBUTION OF THE PROGRAM OR THE EXERCISE OF ANY RIGHTS GRANTED HEREUNDER, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGES. + +7. GENERAL + +If any provision of this Agreement is invalid or unenforceable under applicable law, it shall not affect the validity or enforceability of the remainder of the terms of this Agreement, and without further action by the parties hereto, such provision shall be reformed to the minimum extent necessary to make such provision valid and enforceable. + +If Recipient institutes patent litigation against any entity (including a cross-claim or counterclaim in a lawsuit) alleging that the Program itself (excluding combinations of the Program with other software or hardware) infringes such Recipient's patent(s), then such Recipient's rights granted under Section 2(b) shall terminate as of the date such litigation is filed. + +All Recipient's rights under this Agreement shall terminate if it fails to comply with any of the material terms or conditions of this Agreement and does not cure such failure in a reasonable period of time after becoming aware of such noncompliance. If all Recipient's rights under this Agreement terminate, Recipient agrees to cease use and distribution of the Program as soon as reasonably practicable. However, Recipient's obligations under this Agreement and any licenses granted by Recipient relating to the Program shall continue and survive. + +Everyone is permitted to copy and distribute copies of this Agreement, but in order to avoid inconsistency the Agreement is copyrighted and may only be modified in the following manner. The Agreement Steward reserves the right to publish new versions (including revisions) of this Agreement from time to time. No one other than the Agreement Steward has the right to modify this Agreement. The Eclipse Foundation is the initial Agreement Steward. The Eclipse Foundation may assign the responsibility to serve as the Agreement Steward to a suitable separate entity. Each new version of the Agreement will be given a distinguishing version number. The Program (including Contributions) may always be distributed subject to the version of the Agreement under which it was received. In addition, after a new version of the Agreement is published, Contributor may elect to distribute the Program (including its Contributions) under the new version. Except as expressly stated in Sections 2(a) and 2(b) above, Recipient receives no rights or licenses to the intellectual property of any Contributor under this Agreement, whether expressly, by implication, estoppel or otherwise. All rights in the Program not expressly granted under this Agreement are reserved. + +This Agreement is governed by the laws of the State of New York and the intellectual property laws of the United States of America. No party to this Agreement will bring a legal action under this Agreement more than one year after the cause of action arose. Each party waives its rights to a jury trial in any resulting litigation. +========== +Notice for: org.eclipse.core:org.eclipse.core.runtime-3.7.0 +---------- + +Copyright © Eclipse Foundation, Inc. All Rights Reserved. + +Eclipse Public License - v 1.0 +THE ACCOMPANYING PROGRAM IS PROVIDED UNDER THE TERMS OF THIS ECLIPSE PUBLIC LICENSE ("AGREEMENT"). ANY USE, REPRODUCTION OR DISTRIBUTION OF THE PROGRAM CONSTITUTES RECIPIENT'S ACCEPTANCE OF THIS AGREEMENT. + +1. DEFINITIONS + +"Contribution" means: + +a) in the case of the initial Contributor, the initial code and documentation distributed under this Agreement, and + +b) in the case of each subsequent Contributor: + +i) changes to the Program, and + +ii) additions to the Program; + +where such changes and/or additions to the Program originate from and are distributed by that particular Contributor. A Contribution 'originates' from a Contributor if it was added to the Program by such Contributor itself or anyone acting on such Contributor's behalf. Contributions do not include additions to the Program which: (i) are separate modules of software distributed in conjunction with the Program under their own license agreement, and (ii) are not derivative works of the Program. + +"Contributor" means any person or entity that distributes the Program. + +"Licensed Patents" mean patent claims licensable by a Contributor which are necessarily infringed by the use or sale of its Contribution alone or when combined with the Program. + +"Program" means the Contributions distributed in accordance with this Agreement. + +"Recipient" means anyone who receives the Program under this Agreement, including all Contributors. + +2. GRANT OF RIGHTS + +a) Subject to the terms of this Agreement, each Contributor hereby grants Recipient a non-exclusive, worldwide, royalty-free copyright license to reproduce, prepare derivative works of, publicly display, publicly perform, distribute and sublicense the Contribution of such Contributor, if any, and such derivative works, in source code and object code form. + +b) Subject to the terms of this Agreement, each Contributor hereby grants Recipient a non-exclusive, worldwide, royalty-free patent license under Licensed Patents to make, use, sell, offer to sell, import and otherwise transfer the Contribution of such Contributor, if any, in source code and object code form. This patent license shall apply to the combination of the Contribution and the Program if, at the time the Contribution is added by the Contributor, such addition of the Contribution causes such combination to be covered by the Licensed Patents. The patent license shall not apply to any other combinations which include the Contribution. No hardware per se is licensed hereunder. + +c) Recipient understands that although each Contributor grants the licenses to its Contributions set forth herein, no assurances are provided by any Contributor that the Program does not infringe the patent or other intellectual property rights of any other entity. Each Contributor disclaims any liability to Recipient for claims brought by any other entity based on infringement of intellectual property rights or otherwise. As a condition to exercising the rights and licenses granted hereunder, each Recipient hereby assumes sole responsibility to secure any other intellectual property rights needed, if any. For example, if a third party patent license is required to allow Recipient to distribute the Program, it is Recipient's responsibility to acquire that license before distributing the Program. + +d) Each Contributor represents that to its knowledge it has sufficient copyright rights in its Contribution, if any, to grant the copyright license set forth in this Agreement. + +3. REQUIREMENTS + +A Contributor may choose to distribute the Program in object code form under its own license agreement, provided that: + +a) it complies with the terms and conditions of this Agreement; and + +b) its license agreement: + +i) effectively disclaims on behalf of all Contributors all warranties and conditions, express and implied, including warranties or conditions of title and non-infringement, and implied warranties or conditions of merchantability and fitness for a particular purpose; + +ii) effectively excludes on behalf of all Contributors all liability for damages, including direct, indirect, special, incidental and consequential damages, such as lost profits; + +iii) states that any provisions which differ from this Agreement are offered by that Contributor alone and not by any other party; and + +iv) states that source code for the Program is available from such Contributor, and informs licensees how to obtain it in a reasonable manner on or through a medium customarily used for software exchange. + +When the Program is made available in source code form: + +a) it must be made available under this Agreement; and + +b) a copy of this Agreement must be included with each copy of the Program. + +Contributors may not remove or alter any copyright notices contained within the Program. + +Each Contributor must identify itself as the originator of its Contribution, if any, in a manner that reasonably allows subsequent Recipients to identify the originator of the Contribution. + +4. COMMERCIAL DISTRIBUTION + +Commercial distributors of software may accept certain responsibilities with respect to end users, business partners and the like. While this license is intended to facilitate the commercial use of the Program, the Contributor who includes the Program in a commercial product offering should do so in a manner which does not create potential liability for other Contributors. Therefore, if a Contributor includes the Program in a commercial product offering, such Contributor ("Commercial Contributor") hereby agrees to defend and indemnify every other Contributor ("Indemnified Contributor") against any losses, damages and costs (collectively "Losses") arising from claims, lawsuits and other legal actions brought by a third party against the Indemnified Contributor to the extent caused by the acts or omissions of such Commercial Contributor in connection with its distribution of the Program in a commercial product offering. The obligations in this section do not apply to any claims or Losses relating to any actual or alleged intellectual property infringement. In order to qualify, an Indemnified Contributor must: a) promptly notify the Commercial Contributor in writing of such claim, and b) allow the Commercial Contributor to control, and cooperate with the Commercial Contributor in, the defense and any related settlement negotiations. The Indemnified Contributor may participate in any such claim at its own expense. + +For example, a Contributor might include the Program in a commercial product offering, Product X. That Contributor is then a Commercial Contributor. If that Commercial Contributor then makes performance claims, or offers warranties related to Product X, those performance claims and warranties are such Commercial Contributor's responsibility alone. Under this section, the Commercial Contributor would have to defend claims against the other Contributors related to those performance claims and warranties, and if a court requires any other Contributor to pay any damages as a result, the Commercial Contributor must pay those damages. + +5. NO WARRANTY + +EXCEPT AS EXPRESSLY SET FORTH IN THIS AGREEMENT, THE PROGRAM IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED INCLUDING, WITHOUT LIMITATION, ANY WARRANTIES OR CONDITIONS OF TITLE, NON-INFRINGEMENT, MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE. Each Recipient is solely responsible for determining the appropriateness of using and distributing the Program and assumes all risks associated with its exercise of rights under this Agreement , including but not limited to the risks and costs of program errors, compliance with applicable laws, damage to or loss of data, programs or equipment, and unavailability or interruption of operations. + +6. DISCLAIMER OF LIABILITY + +EXCEPT AS EXPRESSLY SET FORTH IN THIS AGREEMENT, NEITHER RECIPIENT NOR ANY CONTRIBUTORS SHALL HAVE ANY LIABILITY FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING WITHOUT LIMITATION LOST PROFITS), HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OR DISTRIBUTION OF THE PROGRAM OR THE EXERCISE OF ANY RIGHTS GRANTED HEREUNDER, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGES. + +7. GENERAL + +If any provision of this Agreement is invalid or unenforceable under applicable law, it shall not affect the validity or enforceability of the remainder of the terms of this Agreement, and without further action by the parties hereto, such provision shall be reformed to the minimum extent necessary to make such provision valid and enforceable. + +If Recipient institutes patent litigation against any entity (including a cross-claim or counterclaim in a lawsuit) alleging that the Program itself (excluding combinations of the Program with other software or hardware) infringes such Recipient's patent(s), then such Recipient's rights granted under Section 2(b) shall terminate as of the date such litigation is filed. + +All Recipient's rights under this Agreement shall terminate if it fails to comply with any of the material terms or conditions of this Agreement and does not cure such failure in a reasonable period of time after becoming aware of such noncompliance. If all Recipient's rights under this Agreement terminate, Recipient agrees to cease use and distribution of the Program as soon as reasonably practicable. However, Recipient's obligations under this Agreement and any licenses granted by Recipient relating to the Program shall continue and survive. + +Everyone is permitted to copy and distribute copies of this Agreement, but in order to avoid inconsistency the Agreement is copyrighted and may only be modified in the following manner. The Agreement Steward reserves the right to publish new versions (including revisions) of this Agreement from time to time. No one other than the Agreement Steward has the right to modify this Agreement. The Eclipse Foundation is the initial Agreement Steward. The Eclipse Foundation may assign the responsibility to serve as the Agreement Steward to a suitable separate entity. Each new version of the Agreement will be given a distinguishing version number. The Program (including Contributions) may always be distributed subject to the version of the Agreement under which it was received. In addition, after a new version of the Agreement is published, Contributor may elect to distribute the Program (including its Contributions) under the new version. Except as expressly stated in Sections 2(a) and 2(b) above, Recipient receives no rights or licenses to the intellectual property of any Contributor under this Agreement, whether expressly, by implication, estoppel or otherwise. All rights in the Program not expressly granted under this Agreement are reserved. + +This Agreement is governed by the laws of the State of New York and the intellectual property laws of the United States of America. No party to this Agreement will bring a legal action under this Agreement more than one year after the cause of action arose. Each party waives its rights to a jury trial in any resulting litigation. +========== +Notice for: org.eclipse.equinox:org.eclipse.equinox.app-1.3.100 +---------- + + Copyright (c) 2012 Eclipse Foundation. + All rights reserved. This program and the accompanying materials + are made available under the terms of the Eclipse Distribution License v1.0 + which accompanies this distribution, and is available at + http://www.eclipse.org/org/documents/edl-v10.php +========== +Notice for: org.eclipse.equinox:org.eclipse.equinox.common-3.6.0 +---------- + + Copyright (c) 2012 Eclipse Foundation. + All rights reserved. This program and the accompanying materials + are made available under the terms of the Eclipse Distribution License v1.0 + which accompanies this distribution, and is available at + http://www.eclipse.org/org/documents/edl-v10.php +========== +Notice for: org.eclipse.equinox:org.eclipse.equinox.preferences-3.4.1 +---------- + + Copyright (c) 2012 Eclipse Foundation. + All rights reserved. This program and the accompanying materials + are made available under the terms of the Eclipse Distribution License v1.0 + which accompanies this distribution, and is available at + http://www.eclipse.org/org/documents/edl-v10.php +========== +Notice for: org.eclipse.equinox:org.eclipse.equinox.registry-3.5.101 +---------- + + Copyright (c) 2012 Eclipse Foundation. + All rights reserved. This program and the accompanying materials + are made available under the terms of the Eclipse Distribution License v1.0 + which accompanies this distribution, and is available at + http://www.eclipse.org/org/documents/edl-v10.php +========== +Notice for: org.eclipse.jdt:org.eclipse.jdt.core-3.10.0 +---------- + + Copyright (c) 2012, 2016 Eclipse Foundation and others. + All rights reserved. This program and the accompanying materials + are made available under the terms of the Eclipse Distribution License v1.0 + which accompanies this distribution, and is available at + http://www.eclipse.org/org/documents/edl-v10.php +========== +Notice for: org.eclipse.osgi:org.eclipse.osgi-3.7.1 +---------- + + Copyright (c) 2012, 2017 Eclipse Foundation. + All rights reserved. This program and the accompanying materials + are made available under the terms of the Eclipse Distribution License v1.0 + which accompanies this distribution, and is available at + http://www.eclipse.org/org/documents/edl-v10.php +========== +Notice for: org.eclipse.text:org.eclipse.text-3.5.101 +---------- + +Copyright © Eclipse Foundation, Inc. All Rights Reserved. + +Eclipse Public License - v 1.0 +THE ACCOMPANYING PROGRAM IS PROVIDED UNDER THE TERMS OF THIS ECLIPSE PUBLIC LICENSE ("AGREEMENT"). ANY USE, REPRODUCTION OR DISTRIBUTION OF THE PROGRAM CONSTITUTES RECIPIENT'S ACCEPTANCE OF THIS AGREEMENT. + +1. DEFINITIONS + +"Contribution" means: + +a) in the case of the initial Contributor, the initial code and documentation distributed under this Agreement, and + +b) in the case of each subsequent Contributor: + +i) changes to the Program, and + +ii) additions to the Program; + +where such changes and/or additions to the Program originate from and are distributed by that particular Contributor. A Contribution 'originates' from a Contributor if it was added to the Program by such Contributor itself or anyone acting on such Contributor's behalf. Contributions do not include additions to the Program which: (i) are separate modules of software distributed in conjunction with the Program under their own license agreement, and (ii) are not derivative works of the Program. + +"Contributor" means any person or entity that distributes the Program. + +"Licensed Patents" mean patent claims licensable by a Contributor which are necessarily infringed by the use or sale of its Contribution alone or when combined with the Program. + +"Program" means the Contributions distributed in accordance with this Agreement. + +"Recipient" means anyone who receives the Program under this Agreement, including all Contributors. + +2. GRANT OF RIGHTS + +a) Subject to the terms of this Agreement, each Contributor hereby grants Recipient a non-exclusive, worldwide, royalty-free copyright license to reproduce, prepare derivative works of, publicly display, publicly perform, distribute and sublicense the Contribution of such Contributor, if any, and such derivative works, in source code and object code form. + +b) Subject to the terms of this Agreement, each Contributor hereby grants Recipient a non-exclusive, worldwide, royalty-free patent license under Licensed Patents to make, use, sell, offer to sell, import and otherwise transfer the Contribution of such Contributor, if any, in source code and object code form. This patent license shall apply to the combination of the Contribution and the Program if, at the time the Contribution is added by the Contributor, such addition of the Contribution causes such combination to be covered by the Licensed Patents. The patent license shall not apply to any other combinations which include the Contribution. No hardware per se is licensed hereunder. + +c) Recipient understands that although each Contributor grants the licenses to its Contributions set forth herein, no assurances are provided by any Contributor that the Program does not infringe the patent or other intellectual property rights of any other entity. Each Contributor disclaims any liability to Recipient for claims brought by any other entity based on infringement of intellectual property rights or otherwise. As a condition to exercising the rights and licenses granted hereunder, each Recipient hereby assumes sole responsibility to secure any other intellectual property rights needed, if any. For example, if a third party patent license is required to allow Recipient to distribute the Program, it is Recipient's responsibility to acquire that license before distributing the Program. + +d) Each Contributor represents that to its knowledge it has sufficient copyright rights in its Contribution, if any, to grant the copyright license set forth in this Agreement. + +3. REQUIREMENTS + +A Contributor may choose to distribute the Program in object code form under its own license agreement, provided that: + +a) it complies with the terms and conditions of this Agreement; and + +b) its license agreement: + +i) effectively disclaims on behalf of all Contributors all warranties and conditions, express and implied, including warranties or conditions of title and non-infringement, and implied warranties or conditions of merchantability and fitness for a particular purpose; + +ii) effectively excludes on behalf of all Contributors all liability for damages, including direct, indirect, special, incidental and consequential damages, such as lost profits; + +iii) states that any provisions which differ from this Agreement are offered by that Contributor alone and not by any other party; and + +iv) states that source code for the Program is available from such Contributor, and informs licensees how to obtain it in a reasonable manner on or through a medium customarily used for software exchange. + +When the Program is made available in source code form: + +a) it must be made available under this Agreement; and + +b) a copy of this Agreement must be included with each copy of the Program. + +Contributors may not remove or alter any copyright notices contained within the Program. + +Each Contributor must identify itself as the originator of its Contribution, if any, in a manner that reasonably allows subsequent Recipients to identify the originator of the Contribution. + +4. COMMERCIAL DISTRIBUTION + +Commercial distributors of software may accept certain responsibilities with respect to end users, business partners and the like. While this license is intended to facilitate the commercial use of the Program, the Contributor who includes the Program in a commercial product offering should do so in a manner which does not create potential liability for other Contributors. Therefore, if a Contributor includes the Program in a commercial product offering, such Contributor ("Commercial Contributor") hereby agrees to defend and indemnify every other Contributor ("Indemnified Contributor") against any losses, damages and costs (collectively "Losses") arising from claims, lawsuits and other legal actions brought by a third party against the Indemnified Contributor to the extent caused by the acts or omissions of such Commercial Contributor in connection with its distribution of the Program in a commercial product offering. The obligations in this section do not apply to any claims or Losses relating to any actual or alleged intellectual property infringement. In order to qualify, an Indemnified Contributor must: a) promptly notify the Commercial Contributor in writing of such claim, and b) allow the Commercial Contributor to control, and cooperate with the Commercial Contributor in, the defense and any related settlement negotiations. The Indemnified Contributor may participate in any such claim at its own expense. + +For example, a Contributor might include the Program in a commercial product offering, Product X. That Contributor is then a Commercial Contributor. If that Commercial Contributor then makes performance claims, or offers warranties related to Product X, those performance claims and warranties are such Commercial Contributor's responsibility alone. Under this section, the Commercial Contributor would have to defend claims against the other Contributors related to those performance claims and warranties, and if a court requires any other Contributor to pay any damages as a result, the Commercial Contributor must pay those damages. + +5. NO WARRANTY + +EXCEPT AS EXPRESSLY SET FORTH IN THIS AGREEMENT, THE PROGRAM IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED INCLUDING, WITHOUT LIMITATION, ANY WARRANTIES OR CONDITIONS OF TITLE, NON-INFRINGEMENT, MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE. Each Recipient is solely responsible for determining the appropriateness of using and distributing the Program and assumes all risks associated with its exercise of rights under this Agreement , including but not limited to the risks and costs of program errors, compliance with applicable laws, damage to or loss of data, programs or equipment, and unavailability or interruption of operations. + +6. DISCLAIMER OF LIABILITY + +EXCEPT AS EXPRESSLY SET FORTH IN THIS AGREEMENT, NEITHER RECIPIENT NOR ANY CONTRIBUTORS SHALL HAVE ANY LIABILITY FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING WITHOUT LIMITATION LOST PROFITS), HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OR DISTRIBUTION OF THE PROGRAM OR THE EXERCISE OF ANY RIGHTS GRANTED HEREUNDER, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGES. + +7. GENERAL + +If any provision of this Agreement is invalid or unenforceable under applicable law, it shall not affect the validity or enforceability of the remainder of the terms of this Agreement, and without further action by the parties hereto, such provision shall be reformed to the minimum extent necessary to make such provision valid and enforceable. + +If Recipient institutes patent litigation against any entity (including a cross-claim or counterclaim in a lawsuit) alleging that the Program itself (excluding combinations of the Program with other software or hardware) infringes such Recipient's patent(s), then such Recipient's rights granted under Section 2(b) shall terminate as of the date such litigation is filed. + +All Recipient's rights under this Agreement shall terminate if it fails to comply with any of the material terms or conditions of this Agreement and does not cure such failure in a reasonable period of time after becoming aware of such noncompliance. If all Recipient's rights under this Agreement terminate, Recipient agrees to cease use and distribution of the Program as soon as reasonably practicable. However, Recipient's obligations under this Agreement and any licenses granted by Recipient relating to the Program shall continue and survive. + +Everyone is permitted to copy and distribute copies of this Agreement, but in order to avoid inconsistency the Agreement is copyrighted and may only be modified in the following manner. The Agreement Steward reserves the right to publish new versions (including revisions) of this Agreement from time to time. No one other than the Agreement Steward has the right to modify this Agreement. The Eclipse Foundation is the initial Agreement Steward. The Eclipse Foundation may assign the responsibility to serve as the Agreement Steward to a suitable separate entity. Each new version of the Agreement will be given a distinguishing version number. The Program (including Contributions) may always be distributed subject to the version of the Agreement under which it was received. In addition, after a new version of the Agreement is published, Contributor may elect to distribute the Program (including its Contributions) under the new version. Except as expressly stated in Sections 2(a) and 2(b) above, Recipient receives no rights or licenses to the intellectual property of any Contributor under this Agreement, whether expressly, by implication, estoppel or otherwise. All rights in the Program not expressly granted under this Agreement are reserved. + +This Agreement is governed by the laws of the State of New York and the intellectual property laws of the United States of America. No party to this Agreement will bring a legal action under this Agreement more than one year after the cause of action arose. Each party waives its rights to a jury trial in any resulting litigation. +========== +Notice for: org.javassist:javassist-3.26.0-GA +---------- + +Copyright (C) 1999-2019 by Shigeru Chiba, All rights reserved. + +This software is distributed under the Mozilla Public License Version 1.1, the GNU Lesser General Public License Version 2.1 or later, or the Apache License Version 2.0. + +========== +Notice for: org.jruby:jruby-complete-9.2.9.0 +---------- + +JRuby is Copyright (c) 2007-2018 The JRuby project + +Eclipse Public License - v 2.0 + + THE ACCOMPANYING PROGRAM IS PROVIDED UNDER THE TERMS OF THIS ECLIPSE + PUBLIC LICENSE ("AGREEMENT"). ANY USE, REPRODUCTION OR DISTRIBUTION + OF THE PROGRAM CONSTITUTES RECIPIENT'S ACCEPTANCE OF THIS AGREEMENT. + + 1. DEFINITIONS + + "Contribution" means: + + a) in the case of the initial Contributor, the initial content + Distributed under this Agreement, and + + b) in the case of each subsequent Contributor: + i) changes to the Program, and + ii) additions to the Program; + where such changes and/or additions to the Program originate from + and are Distributed by that particular Contributor. A Contribution + "originates" from a Contributor if it was added to the Program by + such Contributor itself or anyone acting on such Contributor's behalf. + Contributions do not include changes or additions to the Program that + are not Modified Works. + + "Contributor" means any person or entity that Distributes the Program. + + "Licensed Patents" mean patent claims licensable by a Contributor which + are necessarily infringed by the use or sale of its Contribution alone + or when combined with the Program. + + "Program" means the Contributions Distributed in accordance with this + Agreement. + + "Recipient" means anyone who receives the Program under this Agreement + or any Secondary License (as applicable), including Contributors. + + "Derivative Works" shall mean any work, whether in Source Code or other + form, that is based on (or derived from) the Program and for which the + editorial revisions, annotations, elaborations, or other modifications + represent, as a whole, an original work of authorship. + + "Modified Works" shall mean any work in Source Code or other form that + results from an addition to, deletion from, or modification of the + contents of the Program, including, for purposes of clarity any new file + in Source Code form that contains any contents of the Program. Modified + Works shall not include works that contain only declarations, + interfaces, types, classes, structures, or files of the Program solely + in each case in order to link to, bind by name, or subclass the Program + or Modified Works thereof. + + "Distribute" means the acts of a) distributing or b) making available + in any manner that enables the transfer of a copy. + + "Source Code" means the form of a Program preferred for making + modifications, including but not limited to software source code, + documentation source, and configuration files. + + "Secondary License" means either the GNU General Public License, + Version 2.0, or any later versions of that license, including any + exceptions or additional permissions as identified by the initial + Contributor. + + 2. GRANT OF RIGHTS + + a) Subject to the terms of this Agreement, each Contributor hereby + grants Recipient a non-exclusive, worldwide, royalty-free copyright + license to reproduce, prepare Derivative Works of, publicly display, + publicly perform, Distribute and sublicense the Contribution of such + Contributor, if any, and such Derivative Works. + + b) Subject to the terms of this Agreement, each Contributor hereby + grants Recipient a non-exclusive, worldwide, royalty-free patent + license under Licensed Patents to make, use, sell, offer to sell, + import and otherwise transfer the Contribution of such Contributor, + if any, in Source Code or other form. This patent license shall + apply to the combination of the Contribution and the Program if, at + the time the Contribution is added by the Contributor, such addition + of the Contribution causes such combination to be covered by the + Licensed Patents. The patent license shall not apply to any other + combinations which include the Contribution. No hardware per se is + licensed hereunder. + + c) Recipient understands that although each Contributor grants the + licenses to its Contributions set forth herein, no assurances are + provided by any Contributor that the Program does not infringe the + patent or other intellectual property rights of any other entity. + Each Contributor disclaims any liability to Recipient for claims + brought by any other entity based on infringement of intellectual + property rights or otherwise. As a condition to exercising the + rights and licenses granted hereunder, each Recipient hereby + assumes sole responsibility to secure any other intellectual + property rights needed, if any. For example, if a third party + patent license is required to allow Recipient to Distribute the + Program, it is Recipient's responsibility to acquire that license + before distributing the Program. + + d) Each Contributor represents that to its knowledge it has + sufficient copyright rights in its Contribution, if any, to grant + the copyright license set forth in this Agreement. + + e) Notwithstanding the terms of any Secondary License, no + Contributor makes additional grants to any Recipient (other than + those set forth in this Agreement) as a result of such Recipient's + receipt of the Program under the terms of a Secondary License + (if permitted under the terms of Section 3). + + 3. REQUIREMENTS + + 3.1 If a Contributor Distributes the Program in any form, then: + + a) the Program must also be made available as Source Code, in + accordance with section 3.2, and the Contributor must accompany + the Program with a statement that the Source Code for the Program + is available under this Agreement, and informs Recipients how to + obtain it in a reasonable manner on or through a medium customarily + used for software exchange; and + + b) the Contributor may Distribute the Program under a license + different than this Agreement, provided that such license: + i) effectively disclaims on behalf of all other Contributors all + warranties and conditions, express and implied, including + warranties or conditions of title and non-infringement, and + implied warranties or conditions of merchantability and fitness + for a particular purpose; + + ii) effectively excludes on behalf of all other Contributors all + liability for damages, including direct, indirect, special, + incidental and consequential damages, such as lost profits; + + iii) does not attempt to limit or alter the recipients' rights + in the Source Code under section 3.2; and + + iv) requires any subsequent distribution of the Program by any + party to be under a license that satisfies the requirements + of this section 3. + + 3.2 When the Program is Distributed as Source Code: + + a) it must be made available under this Agreement, or if the + Program (i) is combined with other material in a separate file or + files made available under a Secondary License, and (ii) the initial + Contributor attached to the Source Code the notice described in + Exhibit A of this Agreement, then the Program may be made available + under the terms of such Secondary Licenses, and + + b) a copy of this Agreement must be included with each copy of + the Program. + + 3.3 Contributors may not remove or alter any copyright, patent, + trademark, attribution notices, disclaimers of warranty, or limitations + of liability ("notices") contained within the Program from any copy of + the Program which they Distribute, provided that Contributors may add + their own appropriate notices. + + 4. COMMERCIAL DISTRIBUTION + + Commercial distributors of software may accept certain responsibilities + with respect to end users, business partners and the like. While this + license is intended to facilitate the commercial use of the Program, + the Contributor who includes the Program in a commercial product + offering should do so in a manner which does not create potential + liability for other Contributors. Therefore, if a Contributor includes + the Program in a commercial product offering, such Contributor + ("Commercial Contributor") hereby agrees to defend and indemnify every + other Contributor ("Indemnified Contributor") against any losses, + damages and costs (collectively "Losses") arising from claims, lawsuits + and other legal actions brought by a third party against the Indemnified + Contributor to the extent caused by the acts or omissions of such + Commercial Contributor in connection with its distribution of the Program + in a commercial product offering. The obligations in this section do not + apply to any claims or Losses relating to any actual or alleged + intellectual property infringement. In order to qualify, an Indemnified + Contributor must: a) promptly notify the Commercial Contributor in + writing of such claim, and b) allow the Commercial Contributor to control, + and cooperate with the Commercial Contributor in, the defense and any + related settlement negotiations. The Indemnified Contributor may + participate in any such claim at its own expense. + + For example, a Contributor might include the Program in a commercial + product offering, Product X. That Contributor is then a Commercial + Contributor. If that Commercial Contributor then makes performance + claims, or offers warranties related to Product X, those performance + claims and warranties are such Commercial Contributor's responsibility + alone. Under this section, the Commercial Contributor would have to + defend claims against the other Contributors related to those performance + claims and warranties, and if a court requires any other Contributor to + pay any damages as a result, the Commercial Contributor must pay + those damages. + + 5. NO WARRANTY + + EXCEPT AS EXPRESSLY SET FORTH IN THIS AGREEMENT, AND TO THE EXTENT + PERMITTED BY APPLICABLE LAW, THE PROGRAM IS PROVIDED ON AN "AS IS" + BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, EITHER EXPRESS OR + IMPLIED INCLUDING, WITHOUT LIMITATION, ANY WARRANTIES OR CONDITIONS OF + TITLE, NON-INFRINGEMENT, MERCHANTABILITY OR FITNESS FOR A PARTICULAR + PURPOSE. Each Recipient is solely responsible for determining the + appropriateness of using and distributing the Program and assumes all + risks associated with its exercise of rights under this Agreement, + including but not limited to the risks and costs of program errors, + compliance with applicable laws, damage to or loss of data, programs + or equipment, and unavailability or interruption of operations. + + 6. DISCLAIMER OF LIABILITY + + EXCEPT AS EXPRESSLY SET FORTH IN THIS AGREEMENT, AND TO THE EXTENT + PERMITTED BY APPLICABLE LAW, NEITHER RECIPIENT NOR ANY CONTRIBUTORS + SHALL HAVE ANY LIABILITY FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING WITHOUT LIMITATION LOST + PROFITS), HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + ARISING IN ANY WAY OUT OF THE USE OR DISTRIBUTION OF THE PROGRAM OR THE + EXERCISE OF ANY RIGHTS GRANTED HEREUNDER, EVEN IF ADVISED OF THE + POSSIBILITY OF SUCH DAMAGES. + + 7. GENERAL + + If any provision of this Agreement is invalid or unenforceable under + applicable law, it shall not affect the validity or enforceability of + the remainder of the terms of this Agreement, and without further + action by the parties hereto, such provision shall be reformed to the + minimum extent necessary to make such provision valid and enforceable. + + If Recipient institutes patent litigation against any entity + (including a cross-claim or counterclaim in a lawsuit) alleging that the + Program itself (excluding combinations of the Program with other software + or hardware) infringes such Recipient's patent(s), then such Recipient's + rights granted under Section 2(b) shall terminate as of the date such + litigation is filed. + + All Recipient's rights under this Agreement shall terminate if it + fails to comply with any of the material terms or conditions of this + Agreement and does not cure such failure in a reasonable period of + time after becoming aware of such noncompliance. If all Recipient's + rights under this Agreement terminate, Recipient agrees to cease use + and distribution of the Program as soon as reasonably practicable. + However, Recipient's obligations under this Agreement and any licenses + granted by Recipient relating to the Program shall continue and survive. + + Everyone is permitted to copy and distribute copies of this Agreement, + but in order to avoid inconsistency the Agreement is copyrighted and + may only be modified in the following manner. The Agreement Steward + reserves the right to publish new versions (including revisions) of + this Agreement from time to time. No one other than the Agreement + Steward has the right to modify this Agreement. The Eclipse Foundation + is the initial Agreement Steward. The Eclipse Foundation may assign the + responsibility to serve as the Agreement Steward to a suitable separate + entity. Each new version of the Agreement will be given a distinguishing + version number. The Program (including Contributions) may always be + Distributed subject to the version of the Agreement under which it was + received. In addition, after a new version of the Agreement is published, + Contributor may elect to Distribute the Program (including its + Contributions) under the new version. + + Except as expressly stated in Sections 2(a) and 2(b) above, Recipient + receives no rights or licenses to the intellectual property of any + Contributor under this Agreement, whether expressly, by implication, + estoppel or otherwise. All rights in the Program not expressly granted + under this Agreement are reserved. Nothing in this Agreement is intended + to be enforceable by any entity that is not a Contributor or Recipient. + No third-party beneficiary rights are created under this Agreement. + + Exhibit A - Form of Secondary Licenses Notice + + "This Source Code may also be made available under the following + Secondary Licenses when the conditions for such availability set forth + in the Eclipse Public License, v. 2.0 are satisfied: {name license(s), + version(s), and exceptions or additional permissions here}." + + Simply including a copy of this Agreement, including this Exhibit A + is not sufficient to license the Source Code under Secondary Licenses. + + If it is not possible or desirable to put the notice in a particular + file, then You may include the notice in a location (such as a LICENSE + file in a relevant directory) where a recipient would be likely to + look for such a notice. + + You may add additional accurate notices of copyright ownership. +========== +Notice for: org.reflections:reflections-0.9.11 +---------- + + DO WHAT THE FUCK YOU WANT TO PUBLIC LICENSE + Version 2, December 2004 + + Copyright (C) 2004 Sam Hocevar + + Everyone is permitted to copy and distribute verbatim or modified + copies of this license document, and changing it is allowed as long + as the name is changed. + + DO WHAT THE FUCK YOU WANT TO PUBLIC LICENSE + TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION + + 0. You just DO WHAT THE FUCK YOU WANT TO. + +Also licensed under BSD-2-Clause according to https://github.com/ronmamo/reflections/blob/0.9.11/pom.xml#L20-L22 + +========== +Notice for: org.slf4j:slf4j-api-1.7.25 +---------- + +Copyright (c) 2004-2007 QOS.ch +All rights reserved. + +Permission is hereby granted, free of charge, to any person obtaining +a copy of this software and associated documentation files (the +"Software"), to deal in the Software without restriction, including +without limitation the rights to use, copy, modify, merge, publish, +distribute, sublicense, and/or sell copies of the Software, and to +permit persons to whom the Software is furnished to do so, subject to +the following conditions: + +The above copyright notice and this permission notice shall be +included in all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +========== +Notice for: paquet-0.2.1 +---------- + +Copyright (c) 2012–2016 Elasticsearch + +Licensed 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. +========== +Notice for: pleaserun-0.0.30 +---------- + +Copyright 2014 Jordan Sissel contributors. + +Licensed 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. + +========== +Notice for: polyglot-0.3.5 +---------- + +Copyright (c) 2007 Clifford Heath + +Permission is hereby granted, free of charge, to any person obtaining +a copy of this software and associated documentation files (the +"Software"), to deal in the Software without restriction, including +without limitation the rights to use, copy, modify, merge, publish, +distribute, sublicense, and/or sell copies of the Software, and to +permit persons to whom the Software is furnished to do so, subject to +the following conditions: + +The above copyright notice and this permission notice shall be +included in all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +========== +Notice for: pry-0.12.2 +---------- + +Copyright (c) 2016 John Mair (banisterfiend) + +Permission is hereby granted, free of charge, to any person obtaining +a copy of this software and associated documentation files (the +'Software'), to deal in the Software without restriction, including +without limitation the rights to use, copy, modify, merge, publish, +distribute, sublicense, and/or sell copies of the Software, and to +permit persons to whom the Software is furnished to do so, subject to +the following conditions: + +The above copyright notice and this permission notice shall be +included in all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED 'AS IS', WITHOUT WARRANTY OF ANY KIND, +EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. +IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY +CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, +TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE +SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + +========== +Notice for: public_suffix-3.1.1 +---------- + +Copyright (c) 2009-2018 Simone Carletti + +MIT License + +Permission is hereby granted, free of charge, to any person obtaining +a copy of this software and associated documentation files (the +"Software"), to deal in the Software without restriction, including +without limitation the rights to use, copy, modify, merge, publish, +distribute, sublicense, and/or sell copies of the Software, and to +permit persons to whom the Software is furnished to do so, subject to +the following conditions: + +The above copyright notice and this permission notice shall be +included in all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + +========== +Notice for: puma-4.3.1 +---------- + +Some code copyright (c) 2005, Zed Shaw +Copyright (c) 2011, Evan Phoenix +All rights reserved. + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are met: + +* Redistributions of source code must retain the above copyright notice, this + list of conditions and the following disclaimer. +* Redistributions in binary form must reproduce the above copyright notice + this list of conditions and the following disclaimer in the documentation + and/or other materials provided with the distribution. +* Neither the name of the Evan Phoenix nor the names of its contributors + may be used to endorse or promote products derived from this software + without specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" +AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE +FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL +DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR +SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER +CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, +OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +========== +Notice for: rack-2.1.2 +---------- + +The MIT License (MIT) + +Copyright (C) 2007-2018 Christian Neukirchen + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to +deal in the Software without restriction, including without limitation the +rights to use, copy, modify, merge, publish, distribute, sublicense, and/or +sell copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL +THE AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER +IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN +CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +========== +Notice for: rack-protection-2.0.8.1 +---------- + +The MIT License (MIT) + +Copyright (c) 2011-2017 Konstantin Haase +Copyright (c) 2015-2017 Zachary Scott + +Permission is hereby granted, free of charge, to any person obtaining +a copy of this software and associated documentation files (the +'Software'), to deal in the Software without restriction, including +without limitation the rights to use, copy, modify, merge, publish, +distribute, sublicense, and/or sell copies of the Software, and to +permit persons to whom the Software is furnished to do so, subject to +the following conditions: + +The above copyright notice and this permission notice shall be +included in all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED 'AS IS', WITHOUT WARRANTY OF ANY KIND, +EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. +IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY +CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, +TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE +SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +========== +Notice for: rake-12.3.3 +---------- + +Copyright (c) Jim Weirich + +Permission is hereby granted, free of charge, to any person obtaining +a copy of this software and associated documentation files (the +"Software"), to deal in the Software without restriction, including +without limitation the rights to use, copy, modify, merge, publish, +distribute, sublicense, and/or sell copies of the Software, and to +permit persons to whom the Software is furnished to do so, subject to +the following conditions: + +The above copyright notice and this permission notice shall be +included in all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + + +========== +Notice for: redis-4.1.3 +---------- + +Copyright (c) 2009 Ezra Zygmuntowicz + +Permission is hereby granted, free of charge, to any person obtaining +a copy of this software and associated documentation files (the +"Software"), to deal in the Software without restriction, including +without limitation the rights to use, copy, modify, merge, publish, +distribute, sublicense, and/or sell copies of the Software, and to +permit persons to whom the Software is furnished to do so, subject to +the following conditions: + +The above copyright notice and this permission notice shall be +included in all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +========== +Notice for: ruby-progressbar-1.10.1 +---------- + +Copyright (c) 2010-2016 The Kompanee, Ltd + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE. + +========== +Notice for: rubyzip-1.3.0 +---------- + +Authors: + +* Alexander Simonov ( alex at simonov.me) +* Alan Harper ( alan at aussiegeek.net) +* Thomas Sondergaard (thomas at sondergaard.cc) +* Technorama Ltd. (oss-ruby-zip at technorama.net) +* extra-field support contributed by Tatsuki Sugiura (sugi at nemui.org) + +Rubyzip is distributed under the same license as ruby. See http://www.ruby-lang.org/en/LICENSE.txt: + +Ruby is copyrighted free software by Yukihiro Matsumoto . +You can redistribute it and/or modify it under either the terms of the +2-clause BSDL (see the file BSDL), or the conditions below: + + 1. You may make and give away verbatim copies of the source form of the + software without restriction, provided that you duplicate all of the + original copyright notices and associated disclaimers. + + 2. You may modify your copy of the software in any way, provided that + you do at least ONE of the following: + + a) place your modifications in the Public Domain or otherwise + make them Freely Available, such as by posting said + modifications to Usenet or an equivalent medium, or by allowing + the author to include your modifications in the software. + + b) use the modified software only within your corporation or + organization. + + c) give non-standard binaries non-standard names, with + instructions on where to get the original software distribution. + + d) make other distribution arrangements with the author. + + 3. You may distribute the software in object code or binary form, + provided that you do at least ONE of the following: + + a) distribute the binaries and library files of the software, + together with instructions (in the manual page or equivalent) + on where to get the original distribution. + + b) accompany the distribution with the machine-readable source of + the software. + + c) give non-standard binaries non-standard names, with + instructions on where to get the original software distribution. + + d) make other distribution arrangements with the author. + + 4. You may modify and include the part of the software into any other + software (possibly commercial). But some files in the distribution + are not written by the author, so that they are not under these terms. + + For the list of those files and their copying conditions, see the + file LEGAL. + + 5. The scripts and library files supplied as input to or produced as + output from the software do not automatically fall under the + copyright of the software, but belong to whomever generated them, + and may be sold commercially, and may be aggregated with this + software. + + 6. THIS SOFTWARE IS PROVIDED "AS IS" AND WITHOUT ANY EXPRESS OR + IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED + WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + PURPOSE. + +========== +Notice for: rufus-scheduler-3.0.9 +---------- + + +Copyright (c) 2005-2014, John Mettraux, jmettraux@gmail.com + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE. + + +========== +Notice for: semantic_logger-3.4.1 +---------- + +Copyright 2012, 2013, 2014, 2015, 2016 Reid Morrison + +Licensed 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. + +========== +Notice for: sequel-5.28.0 +---------- + +Copyright (c) 2007-2008 Sharon Rosner +Copyright (c) 2008-2018 Jeremy Evans + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to +deal in the Software without restriction, including without limitation the +rights to use, copy, modify, merge, publish, distribute, sublicense, and/or +sell copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL +THE AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER +IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN +CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + +========== +Notice for: simple_oauth-0.3.1 +---------- + +Copyright (c) 2010-2013 Steve Richert, Erik Michaels-Ober + +Permission is hereby granted, free of charge, to any person obtaining +a copy of this software and associated documentation files (the +"Software"), to deal in the Software without restriction, including +without limitation the rights to use, copy, modify, merge, publish, +distribute, sublicense, and/or sell copies of the Software, and to +permit persons to whom the Software is furnished to do so, subject to +the following conditions: + +The above copyright notice and this permission notice shall be +included in all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + +========== +Notice for: sinatra-2.0.8.1 +---------- + +Copyright (c) 2007, 2008, 2009 Blake Mizerany +Copyright (c) 2010, 2011, 2012, 2013, 2014, 2015, 2016 Konstantin Haase + +Permission is hereby granted, free of charge, to any person +obtaining a copy of this software and associated documentation +files (the "Software"), to deal in the Software without +restriction, including without limitation the rights to use, +copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the +Software is furnished to do so, subject to the following +conditions: + +The above copyright notice and this permission notice shall be +included in all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES +OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT +HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, +WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING +FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR +OTHER DEALINGS IN THE SOFTWARE. + +========== +Notice for: snappy-0.0.12 +---------- + +Copyright (c) 2011-2013 miyucy + +MIT License + +Permission is hereby granted, free of charge, to any person obtaining +a copy of this software and associated documentation files (the +"Software"), to deal in the Software without restriction, including +without limitation the rights to use, copy, modify, merge, publish, +distribute, sublicense, and/or sell copies of the Software, and to +permit persons to whom the Software is furnished to do so, subject to +the following conditions: + +The above copyright notice and this permission notice shall be +included in all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + +========== +Notice for: snappy-jars-1.1.0.1.2 +---------- + +Copyright Doug Mayer (https://github.com/doxavore) + +README.md: "Per the real implementation, Apache License v2.0." + +Licensed 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. + +========== +Notice for: snmp-1.3.2 +---------- + +Copyright (c) 2004-2014 David R. Halliday + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE. + +========== +Notice for: spoon-0.0.6 +---------- + +Apache License + +Version 2.0, January 2004 + +http://www.apache.org/licenses/ + +TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION + +1. Definitions. + +"License" shall mean the terms and conditions for use, reproduction, and distribution as +defined by Sections 1 through 9 of this document. + +"Licensor" shall mean the copyright owner or entity authorized by the copyright owner that +is granting the License. + +"Legal Entity" shall mean the union of the acting entity and all other entities that +control, are controlled by, or are under common control with that entity. For the purposes +of this definition, "control" means (i) the power, direct or indirect, to cause the +direction or management of such entity, whether by contract or otherwise, or (ii) ownership +of fifty percent (50%) or more of the outstanding shares, or (iii) beneficial ownership of +such entity. + +"You" (or "Your") shall mean an individual or Legal Entity exercising permissions granted by +this License. + +"Source" form shall mean the preferred form for making modifications, including but not +limited to software source code, documentation source, and configuration files. + +"Object" form shall mean any form resulting from mechanical transformation or translation of +a Source form, including but not limited to compiled object code, generated documentation, +and conversions to other media types. + +"Work" shall mean the work of authorship, whether in Source or Object form, made available +under the License, as indicated by a copyright notice that is included in or attached to the +work (an example is provided in the Appendix below). + +"Derivative Works" shall mean any work, whether in Source or Object form, that is based on +(or derived from) the Work and for which the editorial revisions, annotations, elaborations, +or other modifications represent, as a whole, an original work of authorship. For the +purposes of this License, Derivative Works shall not include works that remain separable +from, or merely link (or bind by name) to the interfaces of, the Work and Derivative Works +thereof. + +"Contribution" shall mean any work of authorship, including the original version of the Work +and any modifications or additions to that Work or Derivative Works thereof, that is +intentionally submitted to Licensor for inclusion in the Work by the copyright owner or by +an individual or Legal Entity authorized to submit on behalf of the copyright owner. For the +purposes of this definition, "submitted" means any form of electronic, verbal, or written +communication sent to the Licensor or its representatives, including but not limited to +communication on electronic mailing lists, source code control systems, and issue tracking +systems that are managed by, or on behalf of, the Licensor for the purpose of discussing and +improving the Work, but excluding communication that is conspicuously marked or otherwise +designated in writing by the copyright owner as "Not a Contribution." + +"Contributor" shall mean Licensor and any individual or Legal Entity on behalf of whom a +Contribution has been received by Licensor and subsequently incorporated within the Work. + +2. Grant of Copyright License. Subject to the terms and conditions of this License, each +Contributor hereby grants to You a perpetual, worldwide, non-exclusive, no-charge, +royalty-free, irrevocable copyright license to reproduce, prepare Derivative Works of, +publicly display, publicly perform, sublicense, and distribute the Work and such Derivative +Works in Source or Object form. + +3. Grant of Patent License. Subject to the terms and conditions of this License, each +Contributor hereby grants to You a perpetual, worldwide, non-exclusive, no-charge, +royalty-free, irrevocable (except as stated in this section) patent license to make, have +made, use, offer to sell, sell, import, and otherwise transfer the Work, where such license +applies only to those patent claims licensable by such Contributor that are necessarily +infringed by their Contribution(s) alone or by combination of their Contribution(s) with the +Work to which such Contribution(s) was submitted. If You institute patent litigation against +any entity (including a cross-claim or counterclaim in a lawsuit) alleging that the Work or +a Contribution incorporated within the Work constitutes direct or contributory patent +infringement, then any patent licenses granted to You under this License for that Work shall +terminate as of the date such litigation is filed. + +4. Redistribution. You may reproduce and distribute copies of the Work or Derivative Works +thereof in any medium, with or without modifications, and in Source or Object form, provided +that You meet the following conditions: + +You must give any other recipients of the Work or Derivative Works a copy of this License; +and + +You must cause any modified files to carry prominent notices stating that You changed the +files; and + +You must retain, in the Source form of any Derivative Works that You distribute, all +copyright, patent, trademark, and attribution notices from the Source form of the Work, +excluding those notices that do not pertain to any part of the Derivative Works; and + +If the Work includes a "NOTICE" text file as part of its distribution, then any Derivative +Works that You distribute must include a readable copy of the attribution notices contained +within such NOTICE file, excluding those notices that do not pertain to any part of the +Derivative Works, in at least one of the following places: within a NOTICE text file +distributed as part of the Derivative Works; within the Source form or documentation, if +provided along with the Derivative Works; or, within a display generated by the Derivative +Works, if and wherever such third-party notices normally appear. The contents of the NOTICE +file are for informational purposes only and do not modify the License. You may add Your own +attribution notices within Derivative Works that You distribute, alongside or as an addendum +to the NOTICE text from the Work, provided that such additional attribution notices cannot +be construed as modifying the License. You may add Your own copyright statement to Your +modifications and may provide additional or different license terms and conditions for use, +reproduction, or distribution of Your modifications, or for any such Derivative Works as a +whole, provided Your use, reproduction, and distribution of the Work otherwise complies with +the conditions stated in this License. + +5. Submission of Contributions. Unless You explicitly state otherwise, any Contribution +intentionally submitted for inclusion in the Work by You to the Licensor shall be under the +terms and conditions of this License, without any additional terms or conditions. +Notwithstanding the above, nothing herein shall supersede or modify the terms of any +separate license agreement you may have executed with Licensor regarding such Contributions. + +6. Trademarks. This License does not grant permission to use the trade names, trademarks, +service marks, or product names of the Licensor, except as required for reasonable and +customary use in describing the origin of the Work and reproducing the content of the NOTICE +file. + +7. Disclaimer of Warranty. Unless required by applicable law or agreed to in writing, +Licensor provides the Work (and each Contributor provides its Contributions) on an "AS IS" +BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied, including, +without limitation, any warranties or conditions of TITLE, NON-INFRINGEMENT, +MERCHANTABILITY, or FITNESS FOR A PARTICULAR PURPOSE. You are solely responsible for +determining the appropriateness of using or redistributing the Work and assume any risks +associated with Your exercise of permissions under this License. + +8. Limitation of Liability. In no event and under no legal theory, whether in tort +(including negligence), contract, or otherwise, unless required by applicable law (such as +deliberate and grossly negligent acts) or agreed to in writing, shall any Contributor be +liable to You for damages, including any direct, indirect, special, incidental, or +consequential damages of any character arising as a result of this License or out of the use +or inability to use the Work (including but not limited to damages for loss of goodwill, +work stoppage, computer failure or malfunction, or any and all other commercial damages or +losses), even if such Contributor has been advised of the possibility of such damages. + +9. Accepting Warranty or Additional Liability. While redistributing the Work or Derivative +Works thereof, You may choose to offer, and charge a fee for, acceptance of support, +warranty, indemnity, or other liability obligations and/or rights consistent with this +License. However, in accepting such obligations, You may act only on Your own behalf and on +Your sole responsibility, not on behalf of any other Contributor, and only if You agree to +indemnify, defend, and hold each Contributor harmless for any liability incurred by, or +claims asserted against, such Contributor by reason of your accepting any such warranty or +additional liability. + +END OF TERMS AND CONDITIONS + +========== +Notice for: stud-0.0.23 +---------- + +Copyright 2012-2013 Jordan Sissel and contributors. + +Licensed 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. + +========== +Notice for: thread_safe-0.3.6 +---------- + +Apache License + +Version 2.0, January 2004 + +http://www.apache.org/licenses/ + +TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION + +1. Definitions. + +"License" shall mean the terms and conditions for use, reproduction, and distribution as +defined by Sections 1 through 9 of this document. + +"Licensor" shall mean the copyright owner or entity authorized by the copyright owner that +is granting the License. + +"Legal Entity" shall mean the union of the acting entity and all other entities that +control, are controlled by, or are under common control with that entity. For the purposes +of this definition, "control" means (i) the power, direct or indirect, to cause the +direction or management of such entity, whether by contract or otherwise, or (ii) ownership +of fifty percent (50%) or more of the outstanding shares, or (iii) beneficial ownership of +such entity. + +"You" (or "Your") shall mean an individual or Legal Entity exercising permissions granted by +this License. + +"Source" form shall mean the preferred form for making modifications, including but not +limited to software source code, documentation source, and configuration files. + +"Object" form shall mean any form resulting from mechanical transformation or translation of +a Source form, including but not limited to compiled object code, generated documentation, +and conversions to other media types. + +"Work" shall mean the work of authorship, whether in Source or Object form, made available +under the License, as indicated by a copyright notice that is included in or attached to the +work (an example is provided in the Appendix below). + +"Derivative Works" shall mean any work, whether in Source or Object form, that is based on +(or derived from) the Work and for which the editorial revisions, annotations, elaborations, +or other modifications represent, as a whole, an original work of authorship. For the +purposes of this License, Derivative Works shall not include works that remain separable +from, or merely link (or bind by name) to the interfaces of, the Work and Derivative Works +thereof. + +"Contribution" shall mean any work of authorship, including the original version of the Work +and any modifications or additions to that Work or Derivative Works thereof, that is +intentionally submitted to Licensor for inclusion in the Work by the copyright owner or by +an individual or Legal Entity authorized to submit on behalf of the copyright owner. For the +purposes of this definition, "submitted" means any form of electronic, verbal, or written +communication sent to the Licensor or its representatives, including but not limited to +communication on electronic mailing lists, source code control systems, and issue tracking +systems that are managed by, or on behalf of, the Licensor for the purpose of discussing and +improving the Work, but excluding communication that is conspicuously marked or otherwise +designated in writing by the copyright owner as "Not a Contribution." + +"Contributor" shall mean Licensor and any individual or Legal Entity on behalf of whom a +Contribution has been received by Licensor and subsequently incorporated within the Work. + +2. Grant of Copyright License. Subject to the terms and conditions of this License, each +Contributor hereby grants to You a perpetual, worldwide, non-exclusive, no-charge, +royalty-free, irrevocable copyright license to reproduce, prepare Derivative Works of, +publicly display, publicly perform, sublicense, and distribute the Work and such Derivative +Works in Source or Object form. + +3. Grant of Patent License. Subject to the terms and conditions of this License, each +Contributor hereby grants to You a perpetual, worldwide, non-exclusive, no-charge, +royalty-free, irrevocable (except as stated in this section) patent license to make, have +made, use, offer to sell, sell, import, and otherwise transfer the Work, where such license +applies only to those patent claims licensable by such Contributor that are necessarily +infringed by their Contribution(s) alone or by combination of their Contribution(s) with the +Work to which such Contribution(s) was submitted. If You institute patent litigation against +any entity (including a cross-claim or counterclaim in a lawsuit) alleging that the Work or +a Contribution incorporated within the Work constitutes direct or contributory patent +infringement, then any patent licenses granted to You under this License for that Work shall +terminate as of the date such litigation is filed. + +4. Redistribution. You may reproduce and distribute copies of the Work or Derivative Works +thereof in any medium, with or without modifications, and in Source or Object form, provided +that You meet the following conditions: + +You must give any other recipients of the Work or Derivative Works a copy of this License; +and + +You must cause any modified files to carry prominent notices stating that You changed the +files; and + +You must retain, in the Source form of any Derivative Works that You distribute, all +copyright, patent, trademark, and attribution notices from the Source form of the Work, +excluding those notices that do not pertain to any part of the Derivative Works; and + +If the Work includes a "NOTICE" text file as part of its distribution, then any Derivative +Works that You distribute must include a readable copy of the attribution notices contained +within such NOTICE file, excluding those notices that do not pertain to any part of the +Derivative Works, in at least one of the following places: within a NOTICE text file +distributed as part of the Derivative Works; within the Source form or documentation, if +provided along with the Derivative Works; or, within a display generated by the Derivative +Works, if and wherever such third-party notices normally appear. The contents of the NOTICE +file are for informational purposes only and do not modify the License. You may add Your own +attribution notices within Derivative Works that You distribute, alongside or as an addendum +to the NOTICE text from the Work, provided that such additional attribution notices cannot +be construed as modifying the License. You may add Your own copyright statement to Your +modifications and may provide additional or different license terms and conditions for use, +reproduction, or distribution of Your modifications, or for any such Derivative Works as a +whole, provided Your use, reproduction, and distribution of the Work otherwise complies with +the conditions stated in this License. + +5. Submission of Contributions. Unless You explicitly state otherwise, any Contribution +intentionally submitted for inclusion in the Work by You to the Licensor shall be under the +terms and conditions of this License, without any additional terms or conditions. +Notwithstanding the above, nothing herein shall supersede or modify the terms of any +separate license agreement you may have executed with Licensor regarding such Contributions. + +6. Trademarks. This License does not grant permission to use the trade names, trademarks, +service marks, or product names of the Licensor, except as required for reasonable and +customary use in describing the origin of the Work and reproducing the content of the NOTICE +file. + +7. Disclaimer of Warranty. Unless required by applicable law or agreed to in writing, +Licensor provides the Work (and each Contributor provides its Contributions) on an "AS IS" +BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied, including, +without limitation, any warranties or conditions of TITLE, NON-INFRINGEMENT, +MERCHANTABILITY, or FITNESS FOR A PARTICULAR PURPOSE. You are solely responsible for +determining the appropriateness of using or redistributing the Work and assume any risks +associated with Your exercise of permissions under this License. + +8. Limitation of Liability. In no event and under no legal theory, whether in tort +(including negligence), contract, or otherwise, unless required by applicable law (such as +deliberate and grossly negligent acts) or agreed to in writing, shall any Contributor be +liable to You for damages, including any direct, indirect, special, incidental, or +consequential damages of any character arising as a result of this License or out of the use +or inability to use the Work (including but not limited to damages for loss of goodwill, +work stoppage, computer failure or malfunction, or any and all other commercial damages or +losses), even if such Contributor has been advised of the possibility of such damages. + +9. Accepting Warranty or Additional Liability. While redistributing the Work or Derivative +Works thereof, You may choose to offer, and charge a fee for, acceptance of support, +warranty, indemnity, or other liability obligations and/or rights consistent with this +License. However, in accepting such obligations, You may act only on Your own behalf and on +Your sole responsibility, not on behalf of any other Contributor, and only if You agree to +indemnify, defend, and hold each Contributor harmless for any liability incurred by, or +claims asserted against, such Contributor by reason of your accepting any such warranty or +additional liability. + +END OF TERMS AND CONDITIONS + +========== +Notice for: tilt-2.0.10 +---------- + +Copyright (c) 2010-2016 Ryan Tomayko + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to +deal in the Software without restriction, including without limitation the +rights to use, copy, modify, merge, publish, distribute, sublicense, and/or +sell copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL +THE AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER +IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN +CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + +========== +Notice for: treetop-1.6.10 +---------- + +Copyright (c) 2007 Nathan Sobo. + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE. + +========== +Notice for: twitter-6.2.0 +---------- + +Copyright (c) 2006-2015 Erik Michaels-Ober, John Nunemaker, Wynn Netherland, Steve Richert, Steve Agalloco + +Permission is hereby granted, free of charge, to any person obtaining +a copy of this software and associated documentation files (the +"Software"), to deal in the Software without restriction, including +without limitation the rights to use, copy, modify, merge, publish, +distribute, sublicense, and/or sell copies of the Software, and to +permit persons to whom the Software is furnished to do so, subject to +the following conditions: + +The above copyright notice and this permission notice shall be +included in all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + +========== +Notice for: tzinfo-2.0.1 +---------- + +Copyright (c) 2005-2018 Philip Ross + +Permission is hereby granted, free of charge, to any person obtaining a copy of +this software and associated documentation files (the "Software"), to deal in +the Software without restriction, including without limitation the rights to +use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies +of the Software, and to permit persons to whom the Software is furnished to do +so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE. + +========== +Notice for: tzinfo-data-1.2019.3 +---------- + +Copyright (c) 2005-2018 Philip Ross + +Permission is hereby granted, free of charge, to any person obtaining a copy of +this software and associated documentation files (the "Software"), to deal in +the Software without restriction, including without limitation the rights to +use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies +of the Software, and to permit persons to whom the Software is furnished to do +so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE. + +========== +Notice for: unf-0.1.4 +---------- + +Copyright (c) 2011, 2012 Akinori MUSHA + +All rights reserved. + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions +are met: +1. Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. +2. Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in the + documentation and/or other materials provided with the distribution. + +THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND +ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE +FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL +DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS +OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) +HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT +LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY +OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF +SUCH DAMAGE. + +========== +Notice for: webhdfs-0.9.0 +---------- + +Copyright (C) 2012 Fluentd Project + + Licensed 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. + +========== +Notice for: xml-simple-1.1.5 +---------- + +Readme.md: + +XmlSimple is Copyright (c) 2003-2017 Maik Schmidt. It is free software, and may +be redistributed under the terms specified in the COPYING file of the current +Ruby distribution. + +Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: + +1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. +2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. From 52327f80f992b317454abd2ff1a30c4f1ab156b5 Mon Sep 17 00:00:00 2001 From: Spencer Niemi Date: Mon, 3 Feb 2020 09:50:36 -0600 Subject: [PATCH 0343/1126] Updating the log4j2.properties file that the Docker container image uses to also log the pipeline.id. Fixes #11567 --- docker/data/logstash/config/log4j2.properties | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docker/data/logstash/config/log4j2.properties b/docker/data/logstash/config/log4j2.properties index 36bc45143..dd90d76b3 100644 --- a/docker/data/logstash/config/log4j2.properties +++ b/docker/data/logstash/config/log4j2.properties @@ -4,7 +4,7 @@ name = LogstashPropertiesConfig appender.console.type = Console appender.console.name = plain_console appender.console.layout.type = PatternLayout -appender.console.layout.pattern = [%d{ISO8601}][%-5p][%-25c] %m%n +appender.console.layout.pattern = [%d{ISO8601}][%-5p][%-25c]%notEmpty{[%X{pipeline.id}]} %m%n appender.json_console.type = Console appender.json_console.name = json_console From 07c4d9d52e99065e8eac1fe42e0db7a009c98ff7 Mon Sep 17 00:00:00 2001 From: Karen Metts Date: Fri, 3 Jan 2020 13:45:39 -0500 Subject: [PATCH 0344/1126] Remove module-only disclaimer for cloud id Fixes #11469 --- docs/static/modules.asciidoc | 6 ------ 1 file changed, 6 deletions(-) diff --git a/docs/static/modules.asciidoc b/docs/static/modules.asciidoc index 17ea9acf6..dfbade0da 100644 --- a/docs/static/modules.asciidoc +++ b/docs/static/modules.asciidoc @@ -146,12 +146,6 @@ Logstash comes with two settings that simplify using modules with https://cloud. The Elasticsearch and Kibana hostnames in Elastic Cloud may be hard to set in the Logstash config or on the commandline, so a Cloud ID can be used instead. -NOTE: Cloud ID applies only when a Logstash module is enabled, otherwise -specifying Cloud ID has no effect. Cloud ID applies to data that gets sent via -the module, to runtime metrics sent via {xpack} monitoring, and to the endpoint -used by {xpack} central management features of Logstash, unless explicit -overrides to {xpack} settings are specified in `logstash.yml`. - ==== Cloud ID The Cloud ID, which can be found in the Elastic Cloud web console, is used by From e8ffadc029b5d7106df8c7dd0d20d06344a0973e Mon Sep 17 00:00:00 2001 From: Karen Metts Date: Wed, 5 Feb 2020 14:19:26 -0500 Subject: [PATCH 0345/1126] Add Apple notarization info Fixes #11588 --- docs/static/modules.asciidoc | 25 ++++++++++++++++++ docs/static/plugin-manager.asciidoc | 26 +++++++++++++++++++ .../running-logstash-command-line.asciidoc | 26 +++++++++++++++++++ 3 files changed, 77 insertions(+) diff --git a/docs/static/modules.asciidoc b/docs/static/modules.asciidoc index dfbade0da..0308b5ca2 100644 --- a/docs/static/modules.asciidoc +++ b/docs/static/modules.asciidoc @@ -110,6 +110,31 @@ For a list of available module settings, see the documentation for the module. [[overriding-logstash-module-settings]] ==== Specify module settings at the command line +[IMPORTANT] +.macOS Gatekeeper warnings +==== +Apple's rollout of stricter notarization requirements affected the notarization +of the {version} {ls} artifacts. If macOS Catalina displays a dialog when you +first run {ls} that interrupts it, you will need to take an action to allow it +to run. +To prevent Gatekeeper checks on the {ls} files, run the following command on the +downloaded `.tar.gz` archive or the directory to which was extracted: +[source,sh] +---- +xattr -d -r com.apple.quarantine +---- +For example, if the `.tar.gz` file was extracted to the default +logstash-{version} directory, the command is: +[source,sh,subs="attributes"] +---- +xattr -d -r com.apple.quarantine logstash-{version} +---- +Alternatively, you can add a security override for both `jdk.app` and +`controller.app` by following the instructions in the _How to open an app that +hasn’t been notarized or is from an unidentified developer_ section of +https://support.apple.com/en-us/HT202491[Safely open apps on your Mac]. +==== + You can override module settings by specifying one or more configuration overrides when you start Logstash. To specify an override, you use the `-M` command line option: diff --git a/docs/static/plugin-manager.asciidoc b/docs/static/plugin-manager.asciidoc index 629ac1a24..83cc297d4 100644 --- a/docs/static/plugin-manager.asciidoc +++ b/docs/static/plugin-manager.asciidoc @@ -6,6 +6,32 @@ packages called gems and hosted on RubyGems.org. The plugin manager accessed via lifecycle of plugins in your Logstash deployment. You can install, remove and upgrade plugins using the Command Line Interface (CLI) invocations described below. +[IMPORTANT] +.macOS Gatekeeper warnings +==== +Apple's rollout of stricter notarization requirements affected the notarization +of the {version} {ls} artifacts. If macOS Catalina displays a dialog when you +first run {ls} that interrupts it, you will need to take an action to allow it +to run. +To prevent Gatekeeper checks on the {ls} files, run the following command on the +downloaded `.tar.gz` archive or the directory to which was extracted: +[source,sh] +---- +xattr -d -r com.apple.quarantine +---- +For example, if the `.tar.gz` file was extracted to the default +logstash-{version} directory, the command is: +[source,sh,subs="attributes"] +---- +xattr -d -r com.apple.quarantine logstash-{version} +---- +Alternatively, you can add a security override for both `jdk.app` and +`controller.app` by following the instructions in the _How to open an app that +hasn’t been notarized or is from an unidentified developer_ section of +https://support.apple.com/en-us/HT202491[Safely open apps on your Mac]. +==== + + [float] [[http-proxy]] === Proxy configuration diff --git a/docs/static/running-logstash-command-line.asciidoc b/docs/static/running-logstash-command-line.asciidoc index 478326d23..95e25bcbf 100644 --- a/docs/static/running-logstash-command-line.asciidoc +++ b/docs/static/running-logstash-command-line.asciidoc @@ -1,6 +1,32 @@ [[running-logstash-command-line]] === Running Logstash from the Command Line +[IMPORTANT] +.macOS Gatekeeper warnings +==== +Apple's rollout of stricter notarization requirements affected the notarization +of the {version} {ls} artifacts. If macOS Catalina displays a dialog when you +first run {ls} that interrupts it, you will need to take an action to allow it +to run. +To prevent Gatekeeper checks on the {ls} files, run the following command on the +downloaded `.tar.gz` archive or the directory to which was extracted: +[source,sh] +---- +xattr -d -r com.apple.quarantine +---- +For example, if the `.tar.gz` file was extracted to the default +logstash-{version} directory, the command is: +[source,sh,subs="attributes"] +---- +xattr -d -r com.apple.quarantine logstash-{version} +---- +Alternatively, you can add a security override for both `jdk.app` and +`controller.app` by following the instructions in the _How to open an app that +hasn’t been notarized or is from an unidentified developer_ section of +https://support.apple.com/en-us/HT202491[Safely open apps on your Mac]. +==== + + To run Logstash from the command line, use the following command: [source,shell] From 4ff6378c00d8f9d87ffc750e5a3da0a12b232597 Mon Sep 17 00:00:00 2001 From: Karen Metts Date: Thu, 6 Feb 2020 12:13:53 -0500 Subject: [PATCH 0346/1126] Clarify wording and add to another page Fixes #11588 --- .../getting-started-with-logstash.asciidoc | 27 +++++++++++++++++++ docs/static/modules.asciidoc | 6 ++--- docs/static/plugin-manager.asciidoc | 6 ++--- .../running-logstash-command-line.asciidoc | 6 ++--- 4 files changed, 36 insertions(+), 9 deletions(-) diff --git a/docs/static/getting-started-with-logstash.asciidoc b/docs/static/getting-started-with-logstash.asciidoc index 88f9ab02f..de39968f3 100644 --- a/docs/static/getting-started-with-logstash.asciidoc +++ b/docs/static/getting-started-with-logstash.asciidoc @@ -313,6 +313,33 @@ bin/logstash -e 'input { stdin { } } output { stdout {} }' NOTE: The location of the `bin` directory varies by platform. See {logstash-ref}/dir-layout.html[Directory layout] to find the location of `bin\logstash` on your system. +[IMPORTANT] +.macOS Gatekeeper warnings +==== +Apple's rollout of stricter notarization requirements affected the notarization +of the {version} {ls} artifacts. If macOS Catalina displays a dialog when you +first run {ls} that interrupts it, you will need to take an action to allow it +to run. +To prevent Gatekeeper checks on the {ls} files, run the following command on the +downloaded `.tar.gz` archive or the directory to which was extracted: +[source,sh] +---- +xattr -d -r com.apple.quarantine +---- +For example, if the `.tar.gz` file was extracted to the default +logstash-{version} directory, the command is: +[source,sh,subs="attributes"] +---- +xattr -d -r com.apple.quarantine logstash-{version} +---- +Alternatively, you can add a security override if a Gatekeeper popup appears by +following the instructions in the _How to open an app that hasn’t been notarized +or is from an unidentified developer_ section of +https://support.apple.com/en-us/HT202491[Safely open apps on your Mac]. +==== + + + The `-e` flag enables you to specify a configuration directly from the command line. Specifying configurations at the command line lets you quickly test configurations without having to edit a file between iterations. The pipeline in the example takes input from the standard input, `stdin`, and moves that input to the standard output, diff --git a/docs/static/modules.asciidoc b/docs/static/modules.asciidoc index 0308b5ca2..a9827d5bf 100644 --- a/docs/static/modules.asciidoc +++ b/docs/static/modules.asciidoc @@ -129,9 +129,9 @@ logstash-{version} directory, the command is: ---- xattr -d -r com.apple.quarantine logstash-{version} ---- -Alternatively, you can add a security override for both `jdk.app` and -`controller.app` by following the instructions in the _How to open an app that -hasn’t been notarized or is from an unidentified developer_ section of +Alternatively, you can add a security override if a Gatekeeper popup appears by +following the instructions in the _How to open an app that hasn’t been notarized +or is from an unidentified developer_ section of https://support.apple.com/en-us/HT202491[Safely open apps on your Mac]. ==== diff --git a/docs/static/plugin-manager.asciidoc b/docs/static/plugin-manager.asciidoc index 83cc297d4..d32ec3d51 100644 --- a/docs/static/plugin-manager.asciidoc +++ b/docs/static/plugin-manager.asciidoc @@ -25,9 +25,9 @@ logstash-{version} directory, the command is: ---- xattr -d -r com.apple.quarantine logstash-{version} ---- -Alternatively, you can add a security override for both `jdk.app` and -`controller.app` by following the instructions in the _How to open an app that -hasn’t been notarized or is from an unidentified developer_ section of +Alternatively, you can add a security override if a Gatekeeper popup appears by +following the instructions in the _How to open an app that hasn’t been notarized +or is from an unidentified developer_ section of https://support.apple.com/en-us/HT202491[Safely open apps on your Mac]. ==== diff --git a/docs/static/running-logstash-command-line.asciidoc b/docs/static/running-logstash-command-line.asciidoc index 95e25bcbf..3da475eea 100644 --- a/docs/static/running-logstash-command-line.asciidoc +++ b/docs/static/running-logstash-command-line.asciidoc @@ -20,9 +20,9 @@ logstash-{version} directory, the command is: ---- xattr -d -r com.apple.quarantine logstash-{version} ---- -Alternatively, you can add a security override for both `jdk.app` and -`controller.app` by following the instructions in the _How to open an app that -hasn’t been notarized or is from an unidentified developer_ section of +Alternatively, you can add a security override if a Gatekeeper popup appears by +following the instructions in the _How to open an app that hasn’t been notarized +or is from an unidentified developer_ section of https://support.apple.com/en-us/HT202491[Safely open apps on your Mac]. ==== From 72b5f295ce4e0487329ea8ed44a694da784cc6c7 Mon Sep 17 00:00:00 2001 From: Colin Surprenant Date: Fri, 7 Feb 2020 17:23:50 -0500 Subject: [PATCH 0347/1126] revert #11482 and fix redundant code generation (#11576) 7.7 backport of #11564 --- .../logstash/config/ir/CompiledPipeline.java | 122 +++++------------- .../ir/compiler/ComputeStepSyntaxElement.java | 104 ++++++++------- .../config/ir/compiler/DatasetCompiler.java | 62 ++++++--- .../ir/compiler/DatasetCompilerTest.java | 16 +-- 4 files changed, 139 insertions(+), 165 deletions(-) diff --git a/logstash-core/src/main/java/org/logstash/config/ir/CompiledPipeline.java b/logstash-core/src/main/java/org/logstash/config/ir/CompiledPipeline.java index 3dea8a4f4..207aa8a99 100644 --- a/logstash-core/src/main/java/org/logstash/config/ir/CompiledPipeline.java +++ b/logstash-core/src/main/java/org/logstash/config/ir/CompiledPipeline.java @@ -3,7 +3,6 @@ package org.logstash.config.ir; import co.elastic.logstash.api.Codec; import org.apache.logging.log4j.LogManager; import org.apache.logging.log4j.Logger; -import org.jruby.RubyArray; import org.jruby.RubyHash; import org.jruby.javasupport.JavaUtil; import org.jruby.runtime.builtin.IRubyObject; @@ -35,7 +34,6 @@ import java.util.HashSet; import java.util.List; import java.util.Map; import java.util.Objects; -import java.util.concurrent.ConcurrentHashMap; import java.util.concurrent.atomic.AtomicReference; import java.util.stream.Collectors; import java.util.stream.Stream; @@ -81,28 +79,18 @@ public final class CompiledPipeline { */ private final RubyIntegration.PluginFactory pluginFactory; - /** - * Per pipeline compiled classes cache shared across threads {@link CompiledExecution} - */ - private final Map> datasetClassCache = new ConcurrentHashMap<>(500); - - /** - * First, constructor time, compilation of the pipeline that will warm - * the {@link CompiledPipeline#datasetClassCache} in a thread safe way - * before the concurrent per worker threads {@link CompiledExecution} compilations - */ - private final AtomicReference warmedCompiledExecution = new AtomicReference<>(); - public CompiledPipeline( final PipelineIR pipelineIR, - final RubyIntegration.PluginFactory pluginFactory) { + final RubyIntegration.PluginFactory pluginFactory) + { this(pipelineIR, pluginFactory, null); } public CompiledPipeline( final PipelineIR pipelineIR, final RubyIntegration.PluginFactory pluginFactory, - final SecretStore secretStore) { + final SecretStore secretStore) + { this.pipelineIR = pipelineIR; this.pluginFactory = pluginFactory; try (ConfigVariableExpander cve = new ConfigVariableExpander( @@ -111,10 +99,6 @@ public final class CompiledPipeline { inputs = setupInputs(cve); filters = setupFilters(cve); outputs = setupOutputs(cve); - - // invoke a first compilation to warm the class cache which will prevent - // redundant compilations for each subsequent worker {@link CompiledExecution} - warmedCompiledExecution.set(new CompiledPipeline.CompiledExecution()); } catch (Exception e) { throw new IllegalStateException("Unable to configure plugins: " + e.getMessage()); } @@ -138,13 +122,10 @@ public final class CompiledPipeline { * @return Compiled {@link Dataset} representation of the underlying {@link PipelineIR} topology */ public Dataset buildExecution() { - CompiledExecution result = warmedCompiledExecution.getAndSet(null); - if (result != null) { - return result.toDataset(); - } return new CompiledPipeline.CompiledExecution().toDataset(); } + /** * Sets up all outputs learned from {@link PipelineIR}. */ @@ -155,7 +136,7 @@ public final class CompiledPipeline { final PluginDefinition def = v.getPluginDefinition(); final SourceWithMetadata source = v.getSourceWithMetadata(); res.put(v.getId(), pluginFactory.buildOutput( - RubyUtil.RUBY.newString(def.getName()), source, convertArgs(def), convertJavaArgs(def, cve) + RubyUtil.RUBY.newString(def.getName()), source, convertArgs(def), convertJavaArgs(def, cve) )); }); return res; @@ -172,7 +153,7 @@ public final class CompiledPipeline { final PluginDefinition def = vertex.getPluginDefinition(); final SourceWithMetadata source = vertex.getSourceWithMetadata(); res.put(vertex.getId(), pluginFactory.buildFilter( - RubyUtil.RUBY.newString(def.getName()), source, convertArgs(def), convertJavaArgs(def, cve) + RubyUtil.RUBY.newString(def.getName()), source, convertArgs(def), convertJavaArgs(def, cve) )); } return res; @@ -188,7 +169,7 @@ public final class CompiledPipeline { final PluginDefinition def = v.getPluginDefinition(); final SourceWithMetadata source = v.getSourceWithMetadata(); IRubyObject o = pluginFactory.buildInput( - RubyUtil.RUBY.newString(def.getName()), source, convertArgs(def), convertJavaArgs(def, cve)); + RubyUtil.RUBY.newString(def.getName()), source, convertArgs(def), convertJavaArgs(def, cve)); nodes.add(o); }); return nodes; @@ -212,8 +193,9 @@ public final class CompiledPipeline { SourceWithMetadata source = ((PluginStatement) value).getSourceWithMetadata(); toput = pluginFactory.buildCodec( RubyUtil.RUBY.newString(codec.getName()), - source, Rubyfier.deep(RubyUtil.RUBY, codec.getArguments()), - codec.getArguments() + source, + Rubyfier.deep(RubyUtil.RUBY, codec.getArguments()), + codec.getArguments() ); } else { toput = value; @@ -241,9 +223,10 @@ public final class CompiledPipeline { SourceWithMetadata source = ((PluginStatement) value).getSourceWithMetadata(); Map codecArgs = expandConfigVariables(cve, codec.getArguments()); toput = pluginFactory.buildCodec( - RubyUtil.RUBY.newString(codec.getName()), - source, Rubyfier.deep(RubyUtil.RUBY, codec.getArguments()), - codecArgs + RubyUtil.RUBY.newString(codec.getName()), + source, + Rubyfier.deep(RubyUtil.RUBY, codec.getArguments()), + codecArgs ); Codec javaCodec = (Codec)JavaUtil.unwrapJavaValue(toput); args.put(key, javaCodec); @@ -292,17 +275,6 @@ public final class CompiledPipeline { return outputs.containsKey(vertex.getId()); } - /** - * Returns an existing compiled dataset class implementation for the given {@code vertexId}, - * or compiles one from the provided {@code computeStepSyntaxElement}. - * @param vertexId a string uniquely identifying a {@link Vertex} within the current pipeline - * @param computeStepSyntaxElement the source from which to compile a dataset class - * @return an implementation of {@link Dataset} for the given vertex - */ - private Class getDatasetClass(final String vertexId, final ComputeStepSyntaxElement computeStepSyntaxElement) { - return datasetClassCache.computeIfAbsent(vertexId, _vid -> computeStepSyntaxElement.compile()); - } - /** * Instances of this class represent a fully compiled pipeline execution. Note that this class * has a separate lifecycle from {@link CompiledPipeline} because it holds per (worker-thread) @@ -342,37 +314,11 @@ public final class CompiledPipeline { if (outputNodes.isEmpty()) { return Dataset.IDENTITY; } else { - return terminalDataset(outputNodes.stream().map( + return DatasetCompiler.terminalDataset(outputNodes.stream().map( leaf -> outputDataset(leaf, flatten(Collections.emptyList(), leaf)) ).collect(Collectors.toList())); } } - /** - *

Builds a terminal {@link Dataset} from the given parent {@link Dataset}s.

- *

If the given set of parent {@link Dataset} is empty the sum is defined as the - * trivial dataset that does not invoke any computation whatsoever.

- * {@link Dataset#compute(RubyArray, boolean, boolean)} is always - * {@link Collections#emptyList()}. - * @param parents Parent {@link Dataset} to sum and terminate - * @return Dataset representing the sum of given parent {@link Dataset} - */ - public Dataset terminalDataset(final Collection parents) { - final int count = parents.size(); - final Dataset result; - if (count > 1) { - ComputeStepSyntaxElement prepared = DatasetCompiler.terminalDataset(parents); - result = prepared.instantiate(prepared.compile()); - } else if (count == 1) { - // No need for a terminal dataset here, if there is only a single parent node we can - // call it directly. - result = parents.iterator().next(); - } else { - throw new IllegalArgumentException( - "Cannot create Terminal Dataset for an empty number of parent datasets" - ); - } - return result; - } /** * Build a {@link Dataset} representing the {@link JrubyEventExtLibrary.RubyEvent}s after @@ -385,14 +331,13 @@ public final class CompiledPipeline { final String vertexId = vertex.getId(); if (!plugins.containsKey(vertexId)) { - final ComputeStepSyntaxElement prepared = DatasetCompiler.filterDataset( - flatten(datasets, vertex), - filters.get(vertexId)); - final Class clazz = getDatasetClass(vertexId, prepared); - + final ComputeStepSyntaxElement prepared = + DatasetCompiler.filterDataset( + flatten(datasets, vertex), + filters.get(vertexId)); LOGGER.debug("Compiled filter\n {} \n into \n {}", vertex, prepared); - plugins.put(vertexId, prepared.instantiate(clazz)); + plugins.put(vertexId, prepared.instantiate()); } return plugins.get(vertexId); @@ -409,16 +354,15 @@ public final class CompiledPipeline { final String vertexId = vertex.getId(); if (!plugins.containsKey(vertexId)) { - final ComputeStepSyntaxElement prepared = DatasetCompiler.outputDataset( - flatten(datasets, vertex), - outputs.get(vertexId), - outputs.size() == 1); - final Class clazz = getDatasetClass(vertexId, prepared); - + final ComputeStepSyntaxElement prepared = + DatasetCompiler.outputDataset( + flatten(datasets, vertex), + outputs.get(vertexId), + outputs.size() == 1); LOGGER.debug("Compiled output\n {} \n into \n {}", vertex, prepared); - plugins.put(vertexId, prepared.instantiate(clazz)); - } + plugins.put(vertexId, prepared.instantiate()); + } return plugins.get(vertexId); } @@ -435,23 +379,21 @@ public final class CompiledPipeline { final EventCondition condition, final Vertex vertex) { final String vertexId = vertex.getId(); SplitDataset conditional = iffs.get(vertexId); - if (conditional == null) { final Collection dependencies = flatten(datasets, vertex); conditional = iffs.get(vertexId); // Check that compiling the dependencies did not already instantiate the conditional // by requiring its else branch. if (conditional == null) { - final ComputeStepSyntaxElement prepared = DatasetCompiler.splitDataset(dependencies, condition); - final Class clazz = getDatasetClass(vertexId, prepared); - + final ComputeStepSyntaxElement prepared = + DatasetCompiler.splitDataset(dependencies, condition); LOGGER.debug("Compiled conditional\n {} \n into \n {}", vertex, prepared); - conditional = prepared.instantiate(clazz); + conditional = prepared.instantiate(); iffs.put(vertexId, conditional); } - } + } return conditional; } diff --git a/logstash-core/src/main/java/org/logstash/config/ir/compiler/ComputeStepSyntaxElement.java b/logstash-core/src/main/java/org/logstash/config/ir/compiler/ComputeStepSyntaxElement.java index 9fdc19e8b..8cfa42b96 100644 --- a/logstash-core/src/main/java/org/logstash/config/ir/compiler/ComputeStepSyntaxElement.java +++ b/logstash-core/src/main/java/org/logstash/config/ir/compiler/ComputeStepSyntaxElement.java @@ -11,13 +11,12 @@ import java.nio.file.Paths; import java.util.Arrays; import java.util.HashMap; import java.util.Map; -import java.util.concurrent.atomic.AtomicLong; import java.util.regex.Pattern; import java.util.stream.Collectors; import java.util.stream.StreamSupport; import org.codehaus.commons.compiler.CompileException; -import org.codehaus.commons.compiler.ISimpleCompiler; import org.codehaus.janino.Scanner; +import org.codehaus.commons.compiler.ISimpleCompiler; import org.codehaus.janino.SimpleCompiler; /** @@ -33,9 +32,11 @@ public final class ComputeStepSyntaxElement { private static final ISimpleCompiler COMPILER = new SimpleCompiler(); /** - * Sequential counter to generate the class name + * Global cache of runtime compiled classes to prevent duplicate classes being compiled. + * across pipelines and workers. */ - private static final AtomicLong classSeqCount = new AtomicLong(); + private static final Map, Class> CLASS_CACHE + = new HashMap<>(5000); /** * Pattern to remove redundant {@code ;} from formatted code since {@link Formatter} does not @@ -43,74 +44,94 @@ public final class ComputeStepSyntaxElement { */ private static final Pattern REDUNDANT_SEMICOLON = Pattern.compile("\n[ ]*;\n"); + private static final String CLASS_NAME_PLACEHOLDER = "CLASS_NAME_PLACEHOLDER"; + + private static final Pattern CLASS_NAME_PLACEHOLDER_REGEX = Pattern.compile(CLASS_NAME_PLACEHOLDER); + private final Iterable methods; private final ClassFields fields; private final Class type; - private final long classSeq; + private final String normalizedSource; public static ComputeStepSyntaxElement create( - final Iterable methods, final ClassFields fields, - final Class interfce) { + final Iterable methods, + final ClassFields fields, + final Class interfce) + { return new ComputeStepSyntaxElement<>(methods, fields, interfce); } - private ComputeStepSyntaxElement(final Iterable methods, - final ClassFields fields, final Class interfce) { + private ComputeStepSyntaxElement( + final Iterable methods, + final ClassFields fields, + final Class interfce) + { this.methods = methods; this.fields = fields; type = interfce; - classSeq = classSeqCount.incrementAndGet(); + + // normalizes away the name of the class so that two classes of different name but otherwise + // equivalent syntax get correctly compared by {@link #equals(Object)}. + normalizedSource = generateCode(CLASS_NAME_PLACEHOLDER); } @SuppressWarnings("unchecked") - public T instantiate(Class clazz) { - try { - return (T) clazz.getConstructor(Map.class).newInstance(ctorArguments()); + public T instantiate() { + try { + final Class clazz = compile(); + return (T) clazz.getConstructor(Map.class).newInstance(ctorArguments()); } catch (final NoSuchMethodException | InvocationTargetException | InstantiationException | IllegalAccessException ex) { throw new IllegalStateException(ex); } } - @SuppressWarnings("unchecked") - public Class compile() { - // We need to globally synchronize to avoid concurrency issues with the internal class loader - // Per https://github.com/elastic/logstash/pull/11482 we should review this lock. - synchronized (COMPILER) { - try { - final Class clazz; - final String name = String.format("CompiledDataset%d", classSeq); - final String code = generateCode(name); - if (SOURCE_DIR != null) { - final Path sourceFile = SOURCE_DIR.resolve(String.format("%s.java", name)); - Files.write(sourceFile, code.getBytes(StandardCharsets.UTF_8)); - COMPILER.cookFile(sourceFile.toFile()); - } else { - COMPILER.cook(code); - } - COMPILER.setParentClassLoader(COMPILER.getClassLoader()); - clazz = (Class)COMPILER.getClassLoader().loadClass( - String.format("org.logstash.generated.%s", name) - ); + /** + * This method is NOT thread-safe, and must have exclusive access to `COMPILER` + * so that the resulting `ClassLoader` after each `SimpleCompiler#cook()` operation + * can be teed up as the parent for the next cook operation. + * Also note that synchronizing on `COMPILER` also protects the global CLASS_CACHE. + */ + @SuppressWarnings("unchecked") + private Class compile() { + try { + synchronized (COMPILER) { + Class clazz = CLASS_CACHE.get(this); + if (clazz == null) { + final String name = String.format("CompiledDataset%d", CLASS_CACHE.size()); + final String code = CLASS_NAME_PLACEHOLDER_REGEX.matcher(normalizedSource).replaceAll(name); + if (SOURCE_DIR != null) { + final Path sourceFile = SOURCE_DIR.resolve(String.format("%s.java", name)); + Files.write(sourceFile, code.getBytes(StandardCharsets.UTF_8)); + COMPILER.cookFile(sourceFile.toFile()); + } else { + COMPILER.cook(code); + } + COMPILER.setParentClassLoader(COMPILER.getClassLoader()); + clazz = (Class) COMPILER.getClassLoader().loadClass( + String.format("org.logstash.generated.%s", name) + ); + CLASS_CACHE.put(this, clazz); + } return clazz; - } catch (final CompileException | ClassNotFoundException | IOException ex) { - throw new IllegalStateException(ex); } + } catch (final CompileException | ClassNotFoundException | IOException ex) { + throw new IllegalStateException(ex); } } @Override public int hashCode() { - return normalizedSource().hashCode(); + return normalizedSource.hashCode(); } @Override public boolean equals(final Object other) { return other instanceof ComputeStepSyntaxElement && - normalizedSource().equals(((ComputeStepSyntaxElement) other).normalizedSource()); + normalizedSource.equals(((ComputeStepSyntaxElement) other).normalizedSource); } private String generateCode(final String name) { @@ -162,15 +183,6 @@ public final class ComputeStepSyntaxElement { return result; } - /** - * Normalizes away the name of the class so that two classes of different name but otherwise - * equivalent syntax get correctly compared by {@link #equals(Object)}. - * @return Source of this class, with its name set to {@code CONSTANT}. - */ - private String normalizedSource() { - return this.generateCode("CONSTANT"); - } - /** * Generates the Java code for defining one field and constructor argument for each given value. * constructor for diff --git a/logstash-core/src/main/java/org/logstash/config/ir/compiler/DatasetCompiler.java b/logstash-core/src/main/java/org/logstash/config/ir/compiler/DatasetCompiler.java index d660ac7ce..22e6e41d5 100644 --- a/logstash-core/src/main/java/org/logstash/config/ir/compiler/DatasetCompiler.java +++ b/logstash-core/src/main/java/org/logstash/config/ir/compiler/DatasetCompiler.java @@ -90,7 +90,6 @@ public final class DatasetCompiler { final ValueSyntaxElement outputBuffer = fields.add(new ArrayList<>()); final Closure clear = Closure.wrap(); final Closure compute; - if (parents.isEmpty()) { compute = filterBody(outputBuffer, BATCH_ARG, fields, plugin); } else { @@ -117,16 +116,29 @@ public final class DatasetCompiler { * @param parents Parent {@link Dataset} to sum and terminate * @return Dataset representing the sum of given parent {@link Dataset} */ - public static ComputeStepSyntaxElement terminalDataset(final Collection parents) { - final ClassFields fields = new ClassFields(); - final Collection parentFields = - parents.stream().map(fields::add).collect(Collectors.toList()); - return compileOutput( - Closure.wrap( - parentFields.stream().map(DatasetCompiler::computeDataset) - .toArray(MethodLevelSyntaxElement[]::new) - ).add(clearSyntax(parentFields)), Closure.EMPTY, fields - ); + public static Dataset terminalDataset(final Collection parents) { + final int count = parents.size(); + final Dataset result; + if (count > 1) { + final ClassFields fields = new ClassFields(); + final Collection parentFields = + parents.stream().map(fields::add).collect(Collectors.toList()); + result = compileOutput( + Closure.wrap( + parentFields.stream().map(DatasetCompiler::computeDataset) + .toArray(MethodLevelSyntaxElement[]::new) + ).add(clearSyntax(parentFields)), Closure.EMPTY, fields + ).instantiate(); + } else if (count == 1) { + // No need for a terminal dataset here, if there is only a single parent node we can + // call it directly. + result = parents.iterator().next(); + } else { + throw new IllegalArgumentException( + "Cannot create Terminal Dataset for an empty number of parent datasets" + ); + } + return result; } /** @@ -152,9 +164,10 @@ public final class DatasetCompiler { final Closure computeSyntax; if (parents.isEmpty()) { clearSyntax = Closure.EMPTY; - computeSyntax = Closure.wrap(setPluginIdForLog4j(output), - invokeOutput(fields.add(output), BATCH_ARG), - unsetPluginIdForLog4j()); + computeSyntax = Closure.wrap( + setPluginIdForLog4j(output), + invokeOutput(fields.add(output), BATCH_ARG), + unsetPluginIdForLog4j()); } else { final Collection parentFields = parents.stream().map(fields::add).collect(Collectors.toList()); @@ -169,10 +182,13 @@ public final class DatasetCompiler { clearSyntax = clearSyntax(parentFields); } final ValueSyntaxElement inputBuffer = fields.add(buffer); - computeSyntax = withInputBuffering(Closure.wrap( + computeSyntax = withInputBuffering( + Closure.wrap( setPluginIdForLog4j(output), - invokeOutput(fields.add(output), inputBuffer), inlineClear, - unsetPluginIdForLog4j()), + invokeOutput(fields.add(output), inputBuffer), + inlineClear, + unsetPluginIdForLog4j() + ), parentFields, inputBuffer ); } @@ -188,7 +204,8 @@ public final class DatasetCompiler { final ValueSyntaxElement inputBuffer, final ClassFields fields, final AbstractFilterDelegatorExt plugin) { final ValueSyntaxElement filterField = fields.add(plugin); - final Closure body = Closure.wrap(setPluginIdForLog4j(plugin), + final Closure body = Closure.wrap( + setPluginIdForLog4j(plugin), buffer(outputBuffer, filterField.call("multiFilter", inputBuffer)) ); if (plugin.hasFlush()) { @@ -203,8 +220,13 @@ public final class DatasetCompiler { final ValueSyntaxElement ifData, final ValueSyntaxElement elseData) { final ValueSyntaxElement eventVal = event.access(); return Closure.wrap( - SyntaxFactory.value("org.logstash.config.ir.compiler.Utils") - .call("filterEvents", inputBuffer, condition, ifData, elseData) + SyntaxFactory.value("org.logstash.config.ir.compiler.Utils").call( + "filterEvents", + inputBuffer, + condition, + ifData, + elseData + ) ); } diff --git a/logstash-core/src/test/java/org/logstash/config/ir/compiler/DatasetCompilerTest.java b/logstash-core/src/test/java/org/logstash/config/ir/compiler/DatasetCompilerTest.java index 0978f0e43..231245456 100644 --- a/logstash-core/src/test/java/org/logstash/config/ir/compiler/DatasetCompilerTest.java +++ b/logstash-core/src/test/java/org/logstash/config/ir/compiler/DatasetCompilerTest.java @@ -20,13 +20,12 @@ public final class DatasetCompilerTest { */ @Test public void compilesOutputDataset() { - final ComputeStepSyntaxElement prepared = DatasetCompiler.outputDataset( - Collections.emptyList(), - PipelineTestUtil.buildOutput(events -> {}), - true - ); assertThat( - prepared.instantiate(prepared.compile()).compute(RubyUtil.RUBY.newArray(), false, false), + DatasetCompiler.outputDataset( + Collections.emptyList(), + PipelineTestUtil.buildOutput(events -> {}), + true + ).instantiate().compute(RubyUtil.RUBY.newArray(), false, false), nullValue() ); } @@ -34,10 +33,9 @@ public final class DatasetCompilerTest { @Test public void compilesSplitDataset() { final FieldReference key = FieldReference.from("foo"); - final ComputeStepSyntaxElement prepared = DatasetCompiler.splitDataset( + final SplitDataset left = DatasetCompiler.splitDataset( Collections.emptyList(), event -> event.getEvent().includes(key) - ); - final SplitDataset left = prepared.instantiate(prepared.compile()); + ).instantiate(); final Event trueEvent = new Event(); trueEvent.setField(key, "val"); final JrubyEventExtLibrary.RubyEvent falseEvent = From e070af8e43c2542649e88480d2e6bde9cb8236a1 Mon Sep 17 00:00:00 2001 From: andsel Date: Mon, 10 Feb 2020 14:26:57 +0100 Subject: [PATCH 0348/1126] Adding plugin.id to docker images Fixes #11593 --- docker/data/logstash/config/log4j2.properties | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docker/data/logstash/config/log4j2.properties b/docker/data/logstash/config/log4j2.properties index dd90d76b3..663a01580 100644 --- a/docker/data/logstash/config/log4j2.properties +++ b/docker/data/logstash/config/log4j2.properties @@ -4,7 +4,7 @@ name = LogstashPropertiesConfig appender.console.type = Console appender.console.name = plain_console appender.console.layout.type = PatternLayout -appender.console.layout.pattern = [%d{ISO8601}][%-5p][%-25c]%notEmpty{[%X{pipeline.id}]} %m%n +appender.console.layout.pattern = [%d{ISO8601}][%-5p][%-25c]%notEmpty{[%X{pipeline.id}]}%notEmpty{[%X{plugin.id}]} %m%n appender.json_console.type = Console appender.json_console.name = json_console From 8461a590a6c99254d1061fde6acf3dfa18f7a571 Mon Sep 17 00:00:00 2001 From: Karol Bucek Date: Thu, 6 Feb 2020 11:35:31 +0100 Subject: [PATCH 0349/1126] Refactor: do not keep around JRuby context reference there's no need for this and makes code base inconsistent ... also the original intent seems no longer relevant : was introduced at 57e7a8a56bdbf81647d6e116e75263796d6daf47 > allows for a massive simplification for the invocation of filters and outputs from the Java execution Fixes #11587 --- .../src/main/java/org/logstash/ConvertedMap.java | 2 +- .../ir/compiler/AbstractFilterDelegatorExt.java | 3 +-- .../logstash/config/ir/compiler/EventCondition.java | 12 +++++++----- .../config/ir/compiler/FilterDelegatorExt.java | 3 +-- .../config/ir/compiler/JavaFilterDelegatorExt.java | 5 +++-- .../config/ir/compiler/OutputDelegatorExt.java | 3 +-- .../main/java/org/logstash/execution/WorkerLoop.java | 8 -------- .../logstash/ext/JrubyMemoryReadClientExtTest.java | 2 +- 8 files changed, 15 insertions(+), 23 deletions(-) diff --git a/logstash-core/src/main/java/org/logstash/ConvertedMap.java b/logstash-core/src/main/java/org/logstash/ConvertedMap.java index 99d33a926..e00de8417 100644 --- a/logstash-core/src/main/java/org/logstash/ConvertedMap.java +++ b/logstash-core/src/main/java/org/logstash/ConvertedMap.java @@ -61,7 +61,7 @@ public final class ConvertedMap extends IdentityHashMap { } public static ConvertedMap newFromRubyHash(final RubyHash o) { - return newFromRubyHash(WorkerLoop.THREAD_CONTEXT.get(), o); + return newFromRubyHash(o.getRuntime().getCurrentContext(), o); } public static ConvertedMap newFromRubyHash(final ThreadContext context, final RubyHash o) { diff --git a/logstash-core/src/main/java/org/logstash/config/ir/compiler/AbstractFilterDelegatorExt.java b/logstash-core/src/main/java/org/logstash/config/ir/compiler/AbstractFilterDelegatorExt.java index 46bc7b1c3..17241dfb4 100644 --- a/logstash-core/src/main/java/org/logstash/config/ir/compiler/AbstractFilterDelegatorExt.java +++ b/logstash-core/src/main/java/org/logstash/config/ir/compiler/AbstractFilterDelegatorExt.java @@ -11,7 +11,6 @@ import org.jruby.anno.JRubyMethod; import org.jruby.runtime.ThreadContext; import org.jruby.runtime.builtin.IRubyObject; import org.logstash.RubyUtil; -import org.logstash.execution.WorkerLoop; import org.logstash.ext.JrubyEventExtLibrary; import org.logstash.instrument.metrics.AbstractNamespacedMetricExt; import org.logstash.instrument.metrics.MetricKeys; @@ -131,7 +130,7 @@ public abstract class AbstractFilterDelegatorExt extends RubyObject { @SuppressWarnings("rawtypes") public RubyArray flush(final IRubyObject input) { RubyHash options = (RubyHash) input; - final ThreadContext context = WorkerLoop.THREAD_CONTEXT.get(); + final ThreadContext context = options.getRuntime().getCurrentContext(); final IRubyObject newEvents = doFlush(context, options); final RubyArray result; if (newEvents.isNil()) { diff --git a/logstash-core/src/main/java/org/logstash/config/ir/compiler/EventCondition.java b/logstash-core/src/main/java/org/logstash/config/ir/compiler/EventCondition.java index 2ce320f2a..36780b665 100644 --- a/logstash-core/src/main/java/org/logstash/config/ir/compiler/EventCondition.java +++ b/logstash-core/src/main/java/org/logstash/config/ir/compiler/EventCondition.java @@ -5,6 +5,8 @@ import java.util.List; import java.util.Map; import java.util.Objects; import java.util.function.Predicate; + +import org.jruby.Ruby; import org.jruby.RubyString; import org.jruby.runtime.builtin.IRubyObject; import org.jruby.util.ByteList; @@ -33,7 +35,6 @@ import org.logstash.config.ir.expression.binary.Or; import org.logstash.config.ir.expression.binary.RegexEq; import org.logstash.config.ir.expression.unary.Not; import org.logstash.config.ir.expression.unary.Truthy; -import org.logstash.execution.WorkerLoop; import org.logstash.ext.JrubyEventExtLibrary; /** @@ -481,7 +482,7 @@ public interface EventCondition { public boolean fulfilled(final JrubyEventExtLibrary.RubyEvent event) { final Object tomatch = event.getEvent().getUnconvertedField(field); return tomatch instanceof RubyString && - !((RubyString) tomatch).match(WorkerLoop.THREAD_CONTEXT.get(), regex).isNil(); + !((RubyString) tomatch).match(RubyUtil.RUBY.getCurrentContext(), regex).isNil(); } } @@ -490,10 +491,11 @@ public interface EventCondition { private final boolean matches; private ConstantMatches(final Object constant, final String regex) { + final Ruby runtime = RubyUtil.RUBY; this.matches = constant instanceof String && - !(RubyUtil.RUBY.newString((String) constant).match( - WorkerLoop.THREAD_CONTEXT.get(), - RubyUtil.RUBY.newString(regex)).isNil()); + !(runtime.newString((String) constant).match( + runtime.getCurrentContext(), + runtime.newString(regex)).isNil()); } @Override diff --git a/logstash-core/src/main/java/org/logstash/config/ir/compiler/FilterDelegatorExt.java b/logstash-core/src/main/java/org/logstash/config/ir/compiler/FilterDelegatorExt.java index 18a44400f..1f5134e0d 100644 --- a/logstash-core/src/main/java/org/logstash/config/ir/compiler/FilterDelegatorExt.java +++ b/logstash-core/src/main/java/org/logstash/config/ir/compiler/FilterDelegatorExt.java @@ -12,7 +12,6 @@ import org.jruby.anno.JRubyMethod; import org.jruby.internal.runtime.methods.DynamicMethod; import org.jruby.runtime.ThreadContext; import org.jruby.runtime.builtin.IRubyObject; -import org.logstash.execution.WorkerLoop; import org.logstash.instrument.metrics.AbstractNamespacedMetricExt; import org.logstash.instrument.metrics.counter.LongCounter; @@ -106,7 +105,7 @@ public final class FilterDelegatorExt extends AbstractFilterDelegatorExt { org.apache.logging.log4j.ThreadContext.put("plugin.id", pluginId.toString()); try { return (RubyArray) filterMethod.call( - WorkerLoop.THREAD_CONTEXT.get(), filter, filterClass, FILTER_METHOD_NAME, batch); + getRuntime().getCurrentContext(), filter, filterClass, FILTER_METHOD_NAME, batch); } finally { org.apache.logging.log4j.ThreadContext.remove("plugin.id"); } diff --git a/logstash-core/src/main/java/org/logstash/config/ir/compiler/JavaFilterDelegatorExt.java b/logstash-core/src/main/java/org/logstash/config/ir/compiler/JavaFilterDelegatorExt.java index 0e4638ec4..f55ebb28f 100644 --- a/logstash-core/src/main/java/org/logstash/config/ir/compiler/JavaFilterDelegatorExt.java +++ b/logstash-core/src/main/java/org/logstash/config/ir/compiler/JavaFilterDelegatorExt.java @@ -76,9 +76,10 @@ public class JavaFilterDelegatorExt extends AbstractFilterDelegatorExt { protected IRubyObject doFlush(final ThreadContext context, final RubyHash options) { if (filter.requiresFlush()) { Collection outputEvents = filter.flush(filterMatchListener); - @SuppressWarnings("rawtypes") RubyArray newBatch = RubyArray.newArray(RubyUtil.RUBY, outputEvents.size()); + final Ruby runtime = context.runtime; + @SuppressWarnings("rawtypes") RubyArray newBatch = RubyArray.newArray(runtime, outputEvents.size()); for (Event outputEvent : outputEvents) { - newBatch.add(JrubyEventExtLibrary.RubyEvent.newRubyEvent(RubyUtil.RUBY, (org.logstash.Event)outputEvent)); + newBatch.add(JrubyEventExtLibrary.RubyEvent.newRubyEvent(runtime, (org.logstash.Event)outputEvent)); } return newBatch; } diff --git a/logstash-core/src/main/java/org/logstash/config/ir/compiler/OutputDelegatorExt.java b/logstash-core/src/main/java/org/logstash/config/ir/compiler/OutputDelegatorExt.java index 28db76e9c..ffa284f4d 100644 --- a/logstash-core/src/main/java/org/logstash/config/ir/compiler/OutputDelegatorExt.java +++ b/logstash-core/src/main/java/org/logstash/config/ir/compiler/OutputDelegatorExt.java @@ -12,7 +12,6 @@ import org.jruby.runtime.Block; import org.jruby.runtime.ThreadContext; import org.jruby.runtime.builtin.IRubyObject; import org.logstash.execution.ExecutionContextExt; -import org.logstash.execution.WorkerLoop; import org.logstash.ext.JrubyEventExtLibrary; import org.logstash.instrument.metrics.AbstractMetricExt; @@ -78,7 +77,7 @@ OutputDelegatorExt extends AbstractOutputDelegatorExt { try { final IRubyObject pluginId = this.getId(); org.apache.logging.log4j.ThreadContext.put("plugin.id", pluginId.toString()); - strategy.multiReceive(WorkerLoop.THREAD_CONTEXT.get(), (IRubyObject) batch); + strategy.multiReceive(getRuntime().getCurrentContext(), (IRubyObject) batch); } catch (final InterruptedException ex) { throw new IllegalStateException(ex); } finally { diff --git a/logstash-core/src/main/java/org/logstash/execution/WorkerLoop.java b/logstash-core/src/main/java/org/logstash/execution/WorkerLoop.java index 7125574bb..cda677e38 100644 --- a/logstash-core/src/main/java/org/logstash/execution/WorkerLoop.java +++ b/logstash-core/src/main/java/org/logstash/execution/WorkerLoop.java @@ -12,14 +12,6 @@ import org.logstash.config.ir.compiler.Dataset; public final class WorkerLoop implements Runnable { - /** - * Hard Reference to the Ruby {@link ThreadContext} for this thread. It is ok to keep - * a hard reference instead of Ruby's weak references here since we can expect worker threads - * to be runnable most of the time. - */ - public static final ThreadLocal THREAD_CONTEXT = - ThreadLocal.withInitial(RubyUtil.RUBY::getCurrentContext); - private static final Logger LOGGER = LogManager.getLogger(WorkerLoop.class); private final Dataset execution; diff --git a/logstash-core/src/test/java/org/logstash/ext/JrubyMemoryReadClientExtTest.java b/logstash-core/src/test/java/org/logstash/ext/JrubyMemoryReadClientExtTest.java index cb7521bc4..a458e805e 100644 --- a/logstash-core/src/test/java/org/logstash/ext/JrubyMemoryReadClientExtTest.java +++ b/logstash-core/src/test/java/org/logstash/ext/JrubyMemoryReadClientExtTest.java @@ -23,7 +23,7 @@ public final class JrubyMemoryReadClientExtTest { new ArrayBlockingQueue<>(10); final JrubyMemoryReadClientExt client = JrubyMemoryReadClientExt.create(queue, 5, 50); - final ThreadContext context = WorkerLoop.THREAD_CONTEXT.get(); + final ThreadContext context = client.getRuntime().getCurrentContext(); final QueueBatch batch = client.readBatch(); final RubyHash inflight = client.rubyGetInflightBatches(context); assertThat(inflight.size(), is(1)); From 2511347dfac869cb819555aba628440608a8c634 Mon Sep 17 00:00:00 2001 From: Karol Bucek Date: Fri, 7 Feb 2020 08:33:53 +0100 Subject: [PATCH 0350/1126] Review: more consistent getCurrentContext() Fixes #11587 --- logstash-core/src/main/java/org/logstash/ConvertedMap.java | 2 +- .../logstash/config/ir/compiler/AbstractFilterDelegatorExt.java | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/logstash-core/src/main/java/org/logstash/ConvertedMap.java b/logstash-core/src/main/java/org/logstash/ConvertedMap.java index e00de8417..3bab155da 100644 --- a/logstash-core/src/main/java/org/logstash/ConvertedMap.java +++ b/logstash-core/src/main/java/org/logstash/ConvertedMap.java @@ -61,7 +61,7 @@ public final class ConvertedMap extends IdentityHashMap { } public static ConvertedMap newFromRubyHash(final RubyHash o) { - return newFromRubyHash(o.getRuntime().getCurrentContext(), o); + return newFromRubyHash(RubyUtil.RUBY.getCurrentContext(), o); } public static ConvertedMap newFromRubyHash(final ThreadContext context, final RubyHash o) { diff --git a/logstash-core/src/main/java/org/logstash/config/ir/compiler/AbstractFilterDelegatorExt.java b/logstash-core/src/main/java/org/logstash/config/ir/compiler/AbstractFilterDelegatorExt.java index 17241dfb4..9d639fa28 100644 --- a/logstash-core/src/main/java/org/logstash/config/ir/compiler/AbstractFilterDelegatorExt.java +++ b/logstash-core/src/main/java/org/logstash/config/ir/compiler/AbstractFilterDelegatorExt.java @@ -130,7 +130,7 @@ public abstract class AbstractFilterDelegatorExt extends RubyObject { @SuppressWarnings("rawtypes") public RubyArray flush(final IRubyObject input) { RubyHash options = (RubyHash) input; - final ThreadContext context = options.getRuntime().getCurrentContext(); + final ThreadContext context = RubyUtil.RUBY.getCurrentContext(); final IRubyObject newEvents = doFlush(context, options); final RubyArray result; if (newEvents.isNil()) { From f86bf3691489971b5602ad582f6a17ca3acc4534 Mon Sep 17 00:00:00 2001 From: Karol Bucek Date: Fri, 7 Feb 2020 08:39:43 +0100 Subject: [PATCH 0351/1126] Review: more places for RUBY.getCurrentContext() Fixes #11587 --- .../org/logstash/config/ir/compiler/FilterDelegatorExt.java | 2 +- .../org/logstash/config/ir/compiler/OutputDelegatorExt.java | 4 +++- 2 files changed, 4 insertions(+), 2 deletions(-) diff --git a/logstash-core/src/main/java/org/logstash/config/ir/compiler/FilterDelegatorExt.java b/logstash-core/src/main/java/org/logstash/config/ir/compiler/FilterDelegatorExt.java index 1f5134e0d..a5d7d310e 100644 --- a/logstash-core/src/main/java/org/logstash/config/ir/compiler/FilterDelegatorExt.java +++ b/logstash-core/src/main/java/org/logstash/config/ir/compiler/FilterDelegatorExt.java @@ -105,7 +105,7 @@ public final class FilterDelegatorExt extends AbstractFilterDelegatorExt { org.apache.logging.log4j.ThreadContext.put("plugin.id", pluginId.toString()); try { return (RubyArray) filterMethod.call( - getRuntime().getCurrentContext(), filter, filterClass, FILTER_METHOD_NAME, batch); + RUBY.getCurrentContext(), filter, filterClass, FILTER_METHOD_NAME, batch); } finally { org.apache.logging.log4j.ThreadContext.remove("plugin.id"); } diff --git a/logstash-core/src/main/java/org/logstash/config/ir/compiler/OutputDelegatorExt.java b/logstash-core/src/main/java/org/logstash/config/ir/compiler/OutputDelegatorExt.java index ffa284f4d..0e8deca8d 100644 --- a/logstash-core/src/main/java/org/logstash/config/ir/compiler/OutputDelegatorExt.java +++ b/logstash-core/src/main/java/org/logstash/config/ir/compiler/OutputDelegatorExt.java @@ -15,6 +15,8 @@ import org.logstash.execution.ExecutionContextExt; import org.logstash.ext.JrubyEventExtLibrary; import org.logstash.instrument.metrics.AbstractMetricExt; +import static org.logstash.RubyUtil.RUBY; + @JRubyClass(name = "OutputDelegator") public final class OutputDelegatorExt extends AbstractOutputDelegatorExt { @@ -77,7 +79,7 @@ OutputDelegatorExt extends AbstractOutputDelegatorExt { try { final IRubyObject pluginId = this.getId(); org.apache.logging.log4j.ThreadContext.put("plugin.id", pluginId.toString()); - strategy.multiReceive(getRuntime().getCurrentContext(), (IRubyObject) batch); + strategy.multiReceive(RUBY.getCurrentContext(), (IRubyObject) batch); } catch (final InterruptedException ex) { throw new IllegalStateException(ex); } finally { From 9d6fa3215d3be8bc99bc01b711f4c29cf9fbeb23 Mon Sep 17 00:00:00 2001 From: Rob Bavey Date: Wed, 15 Jan 2020 17:22:55 -0500 Subject: [PATCH 0352/1126] Release notes for 7.6.0 Fixes #11579 --- docs/static/releasenotes.asciidoc | 103 ++++++++++++++++++++++++++++++ 1 file changed, 103 insertions(+) diff --git a/docs/static/releasenotes.asciidoc b/docs/static/releasenotes.asciidoc index 93db0cf19..10daf98f2 100644 --- a/docs/static/releasenotes.asciidoc +++ b/docs/static/releasenotes.asciidoc @@ -3,6 +3,7 @@ This section summarizes the changes in the following releases: +* <> * <> * <> * <> @@ -24,6 +25,108 @@ This section summarizes the changes in the following releases: * <> * <> +[[logstash-7-6-0]] +=== Logstash 7.6.0 Release Notes + +* Feature: Introduce deprecation logger for internal classes and plugins. https://github.com/elastic/logstash/pull/11260[#11260] and https://github.com/elastic/logstash/pull/11486[#11486] + +** The Deprecation logger is a unified way for Logstash components to log deprecation notices into a separate file, + located by default at `log/logstash-deprecation.log`. This file gives users a single location to see if they are using features that may stop working after a major upgrade. + +* Feature: Add support for cloud-id/auth for Logstash monitoring/management https://github.com/elastic/logstash/pull/11496[#11496] + +* Feature: Initial release of the https://github.com/logstash-plugins/logstash-integration-jdbc[Jdbc Integration Plugin], +which combines previously-separate Jdbc plugins and shared dependencies into a single codebase + +* Fixed: Regression where compilation of multiple pipelines experiences slowdown https://github.com/elastic/logstash/issues/11560[#11560] + +** The fix for the Java execution pipeline compilation slowdown relative to the number of workers in https://github.com/elastic/logstash/issues/11482[#11482] + introduced a regression which caused a slowdown of pipeline compilation when using multiple pipelines. This + fix solves that regression and the original issue when using multiple workers. +* Updated puma to 4.x https://github.com/elastic/logstash/pull/11241[#11241] +* Updated jruby to 9.2.9.0 https://github.com/elastic/logstash/pull/11281[#11281] +* Fixed: Correct directory for versions.yml file when building plugins https://github.com/elastic/logstash/pull/11318[#11318] +This fixes an issue where a `versions.yml` was unnecessarily required when trying to build native Java plugins + +* Updated sinatra and rack to 2.x https://github.com/elastic/logstash/pull/11354[#11354] +* Changed: base JRUBY_OPTS to default to --dev (for 'fast' scripts) https://github.com/elastic/logstash/pull/11355[#11355] +* Fixed: Removed use of deprecated Thread.exclusive method, which caused a warning message every time logstash started. https://github.com/elastic/logstash/pull/11388[#11388] +* Add Enterprise license level https://www.elastic.co/subscriptions[subscription] https://github.com/elastic/logstash/pull/11407[#11407] +* [DOC] Remove module-only disclaimer for cloud id https://github.com/elastic/logstash/pull/11469[#11469] +* [DOC] Add details about pipeline.workers https://github.com/elastic/logstash/pull/11474[#11474] +* [DOC] Add deprecation notice to internal collectors for monitoring https://github.com/elastic/logstash/pull/11526[#11526] +* Build: Fail license report job on missing licenses https://github.com/elastic/logstash/pull/11554[#11554] +* Fixed: Updated log4j2.properties file that the Docker container image uses to also log the pipeline.id. https://github.com/elastic/logstash/pull/11567[#11567] + +==== Plugins + +*Jdbc Integration* + +* Initial release of the +https://github.com/logstash-plugins/logstash-integration-jdbc[Jdbc +Integration Plugin], which combines previously-separate Jdbc plugins and shared +dependencies into a single codebase + +*Cef Codec* + +* Fixed CEF short to long name translation for ahost/agentHostName field, according to documentation https://github.com/logstash-plugins/logstash-codec-cef/pull/75[#75] + +*Fluent Codec* + +* Handle EventTime msgpack extension to handle nanosecond precision time and add its parameter https://github.com/logstash-plugins/logstash-codec-fluent/pull/18[#18] + +*Dns Filter* + +* Fixed an issue where each missed lookup could result in unreclaimed memory (https://github.com/jruby/jruby/issues/6015[jruby bug]) by handling lookup misses without raising exceptions https://github.com/logstash-plugins/logstash-filter-dns/pull/61[#61] + +* Added restriction on JRuby resolv.rb patch to versions prior to 9.2.9.0 https://github.com/logstash-plugins/logstash-filter-dns/pull/58[#58] + +* Fixed asciidoc formatting for unordered list and a code sample in docs https://github.com/logstash-plugins/logstash-filter-dns/pull/57[#57] + +* Added search domains to the `nameserver` option https://github.com/logstash-plugins/logstash-filter-dns/pull/56[#56] + +*Elasticsearch Filter* + +* Feat: support cloud_id / cloud_auth configuration https://github.com/logstash-plugins/logstash-filter-elasticsearch/pull/122[#122] + + +*Beats Input* + +* Updated Jackson dependencies + +*Elasticsearch Input* + +* Feat: Added support for cloud_id / cloud_auth configuration https://github.com/logstash-plugins/logstash-input-elasticsearch/pull/112[#112] + +* Changed Elasticsearch Client transport to use Manticore https://github.com/logstash-plugins/logstash-input-elasticsearch/pull/111[#111] + +*File Input* + +* Fix regression in `exclude` handling. Patterns are matched against the filename, not full path. + https://github.com/logstash-plugins/logstash-input-file/issues/237[#237] + +*Http Input* + +* Revert updates to netty and tcnative since CBC ciphers are still used in many contexts + +*Csv Output* + +* Docs: Correct typos https://github.com/logstash-plugins/logstash-output-csv/pull/19[#19] +* Docs: Fix formatting after code sample https://github.com/logstash-plugins/logstash-output-csv/pull/22[#22] + +*Elasticsearch Output* + +* Feat: Added support for cloud_id and cloud_auth https://github.com/logstash-plugins/logstash-output-elasticsearch/pull/906[#906] + +*S3 Output* + +* Added ability to specify https://aws.amazon.com/s3/storage-classes/#__[ONEZONE_IA] as storage_class + +*Udp Output* + +* Fixed plugin crash upon socket write exception https://github.com/logstash-plugins/logstash-output-udp/pull/10[#10] +* Added support for the 'retry_count' and 'retry_backoff_ms' options https://github.com/logstash-plugins/logstash-output-udp/pull/12[#12] + [[logstash-7-5-2]] === Logstash 7.5.2 Release Notes From 55410efccf054c2453bdcc109fe0d6bfc1c42171 Mon Sep 17 00:00:00 2001 From: Karen Metts Date: Tue, 11 Feb 2020 19:52:59 -0500 Subject: [PATCH 0353/1126] Fix setting name for monitoring Fixes #11597 --- docs/static/monitoring/monitoring-mb.asciidoc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/static/monitoring/monitoring-mb.asciidoc b/docs/static/monitoring/monitoring-mb.asciidoc index 444255aad..d267211b1 100644 --- a/docs/static/monitoring/monitoring-mb.asciidoc +++ b/docs/static/monitoring/monitoring-mb.asciidoc @@ -29,7 +29,7 @@ commented out: [source,yaml] ---------------------------------- -monitoring.enabled: false +xpack.monitoring.enabled: false ---------------------------------- Remove the `#` at the beginning of the line to enable the setting. From 91e96b1f2e44c4e4349efd553d93bb0e1bb38624 Mon Sep 17 00:00:00 2001 From: Karen Metts Date: Wed, 12 Feb 2020 18:08:49 -0500 Subject: [PATCH 0354/1126] Rework ls netflow module deprecation notice Fixes #11600 --- docs/static/releasenotes.asciidoc | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/docs/static/releasenotes.asciidoc b/docs/static/releasenotes.asciidoc index 10daf98f2..7c2e306dc 100644 --- a/docs/static/releasenotes.asciidoc +++ b/docs/static/releasenotes.asciidoc @@ -333,7 +333,10 @@ No user facing changes in this release. * Backport release notes to 7.4 branch https://github.com/elastic/logstash/pull/11159[#11159] * Docs: Fix backticks in how to docs https://github.com/elastic/logstash/pull/11018[#11018] -NOTICE: Deprecate {ls} Netflow module and point to {filebeat} Netflow module https://github.com/elastic/logstash/pull/11113[#11113] +NOTICE: {ls} Netflow module has been deprecated and replaced by the +{filebeat-ref}/filebeat-module-netflow.html[{Filebeat} Netflow Module] which is +compliant with the {ecs-ref}/index.html[Elastic Common Schema (ECS)] +https://github.com/elastic/logstash/pull/11113[#11113] ==== Plugins From 496f81c8ca48eba8228c90f4d41c5f3b01ca22f9 Mon Sep 17 00:00:00 2001 From: andsel Date: Mon, 10 Feb 2020 12:30:36 +0100 Subject: [PATCH 0355/1126] Changed PluginFactory to resolve id field with environment variables docs: plugin ids variable expansion cannot use secret store closes 10546 Fixes #11592 --- docs/include/filter.asciidoc | 2 + docs/include/input.asciidoc | 2 + docs/include/output.asciidoc | 2 + docs/static/keystore.asciidoc | 5 +- logstash-core/build.gradle | 2 + .../logstash/config/ir/CompiledPipeline.java | 1 - .../plugins/ConfigVariableExpander.java | 7 + .../logstash/plugins/PluginFactoryExt.java | 28 +++- .../plugins/PluginFactoryExtTest.java | 139 ++++++++++++++++++ 9 files changed, 184 insertions(+), 4 deletions(-) create mode 100644 logstash-core/src/test/java/org/logstash/plugins/PluginFactoryExtTest.java diff --git a/docs/include/filter.asciidoc b/docs/include/filter.asciidoc index 12b9596b0..b749ceefb 100644 --- a/docs/include/filter.asciidoc +++ b/docs/include/filter.asciidoc @@ -146,6 +146,8 @@ Adding a named ID in this case will help in monitoring Logstash when using the m } } +NOTE: Variable substitution in the `id` field only supports environment variables + and does not support the use of values from the secret store. ifeval::["{versioned_docs}"!="true"] [id="plugins-{type}s-{plugin}-periodic_flush"] diff --git a/docs/include/input.asciidoc b/docs/include/input.asciidoc index 83d7734dd..d0b9b5cd0 100644 --- a/docs/include/input.asciidoc +++ b/docs/include/input.asciidoc @@ -112,6 +112,8 @@ input { } --------------------------------------------------------------------------------------------------- +NOTE: Variable substitution in the `id` field only supports environment variables + and does not support the use of values from the secret store. ifeval::["{versioned_docs}"!="true"] [id="plugins-{type}s-{plugin}-tags"] diff --git a/docs/include/output.asciidoc b/docs/include/output.asciidoc index e546ce8ab..5d8090645 100644 --- a/docs/include/output.asciidoc +++ b/docs/include/output.asciidoc @@ -89,4 +89,6 @@ output { } --------------------------------------------------------------------------------------------------- +NOTE: Variable substitution in the `id` field only supports environment variables + and does not support the use of values from the secret store. diff --git a/docs/static/keystore.asciidoc b/docs/static/keystore.asciidoc index d40b5a07f..b3fc3decb 100644 --- a/docs/static/keystore.asciidoc +++ b/docs/static/keystore.asciidoc @@ -25,7 +25,10 @@ value `yourelasticsearchpassword`: Notice that the Logstash keystore differs from the Elasticsearch keystore. Whereas the Elasticsearch keystore lets you store `elasticsearch.yml` values by name, the Logstash keystore lets you specify arbitrary names that you -can reference in the Logstash configuration. +can reference in the Logstash configuration. + +NOTE: There are some configuration fields that have no secret meaning, so not every field could leverage +the secret store for variables substitution. Plugin's `id` field is a field of this kind NOTE: Referencing keystore data from `pipelines.yml` or the command line (`-e`) is not currently supported. diff --git a/logstash-core/build.gradle b/logstash-core/build.gradle index a5ec6a057..f327b8d34 100644 --- a/logstash-core/build.gradle +++ b/logstash-core/build.gradle @@ -74,6 +74,7 @@ task javaTests(type: Test) { exclude '/org/logstash/config/ir/compiler/JavaCodecDelegatorTest.class' exclude '/org/logstash/plugins/NamespacedMetricImplTest.class' exclude '/org/logstash/plugins/CounterMetricImplTest.class' + exclude '/org/logstash/plugins/PluginFactoryExtTest.class' } task rubyTests(type: Test) { @@ -88,6 +89,7 @@ task rubyTests(type: Test) { include '/org/logstash/config/ir/compiler/JavaCodecDelegatorTest.class' include '/org/logstash/plugins/NamespacedMetricImplTest.class' include '/org/logstash/plugins/CounterMetricImplTest.class' + include '/org/logstash/plugins/PluginFactoryExtTest.class' } test { diff --git a/logstash-core/src/main/java/org/logstash/config/ir/CompiledPipeline.java b/logstash-core/src/main/java/org/logstash/config/ir/CompiledPipeline.java index 207aa8a99..e919facac 100644 --- a/logstash-core/src/main/java/org/logstash/config/ir/CompiledPipeline.java +++ b/logstash-core/src/main/java/org/logstash/config/ir/CompiledPipeline.java @@ -34,7 +34,6 @@ import java.util.HashSet; import java.util.List; import java.util.Map; import java.util.Objects; -import java.util.concurrent.atomic.AtomicReference; import java.util.stream.Collectors; import java.util.stream.Stream; diff --git a/logstash-core/src/main/java/org/logstash/plugins/ConfigVariableExpander.java b/logstash-core/src/main/java/org/logstash/plugins/ConfigVariableExpander.java index e5732b500..c664717a4 100644 --- a/logstash-core/src/main/java/org/logstash/plugins/ConfigVariableExpander.java +++ b/logstash-core/src/main/java/org/logstash/plugins/ConfigVariableExpander.java @@ -16,6 +16,13 @@ public class ConfigVariableExpander implements AutoCloseable { private SecretStore secretStore; private EnvironmentVariableProvider envVarProvider; + /** + * Creates a ConfigVariableExpander that doesn't lookup any secreted placeholder. + * */ + static ConfigVariableExpander withoutSecret(EnvironmentVariableProvider envVarProvider) { + return new ConfigVariableExpander(null, envVarProvider); + } + public ConfigVariableExpander(SecretStore secretStore, EnvironmentVariableProvider envVarProvider) { this.secretStore = secretStore; this.envVarProvider = envVarProvider; diff --git a/logstash-core/src/main/java/org/logstash/plugins/PluginFactoryExt.java b/logstash-core/src/main/java/org/logstash/plugins/PluginFactoryExt.java index 7f36421fa..0e487e616 100644 --- a/logstash-core/src/main/java/org/logstash/plugins/PluginFactoryExt.java +++ b/logstash-core/src/main/java/org/logstash/plugins/PluginFactoryExt.java @@ -22,6 +22,7 @@ import org.jruby.runtime.builtin.IRubyObject; import org.logstash.RubyUtil; import org.logstash.common.AbstractDeadLetterQueueWriterExt; import org.logstash.common.DLQWriterAdapter; +import org.logstash.common.EnvironmentVariableProvider; import org.logstash.common.NullDeadLetterQueueWriter; import org.logstash.common.SourceWithMetadata; import org.logstash.config.ir.PipelineIR; @@ -56,6 +57,11 @@ import java.util.UUID; public final class PluginFactoryExt { + @FunctionalInterface + public interface PluginResolver { + PluginLookup.PluginClass resolve(PluginLookup.PluginType type, String name); + } + @JRubyClass(name = "PluginFactory") public static final class Plugins extends RubyBasicObject implements RubyIntegration.PluginFactory { @@ -74,6 +80,10 @@ public final class PluginFactoryExt { private RubyClass filterClass; + private ConfigVariableExpander configVariables; + + private PluginResolver pluginResolver; + @JRubyMethod(name = "filter_delegator", meta = true, required = 5) public static IRubyObject filterDelegator(final ThreadContext context, final IRubyObject recv, final IRubyObject[] args) { @@ -90,7 +100,12 @@ public final class PluginFactoryExt { } public Plugins(final Ruby runtime, final RubyClass metaClass) { + this(runtime, metaClass, PluginLookup::lookup); + } + + Plugins(final Ruby runtime, final RubyClass metaClass, PluginResolver pluginResolver) { super(runtime, metaClass); + this.pluginResolver = pluginResolver; } @JRubyMethod(required = 4) @@ -106,10 +121,18 @@ public final class PluginFactoryExt { public PluginFactoryExt.Plugins init(final PipelineIR lir, final PluginFactoryExt.Metrics metrics, final PluginFactoryExt.ExecutionContext executionContext, final RubyClass filterClass) { + return this.init(lir, metrics, executionContext, filterClass, EnvironmentVariableProvider.defaultProvider()); + } + + PluginFactoryExt.Plugins init(final PipelineIR lir, final PluginFactoryExt.Metrics metrics, + final PluginFactoryExt.ExecutionContext executionContext, + final RubyClass filterClass, + final EnvironmentVariableProvider envVars) { this.lir = lir; this.metrics = metrics; this.executionContext = executionContext; this.filterClass = filterClass; + this.configVariables = ConfigVariableExpander.withoutSecret(envVars); return this; } @@ -178,16 +201,17 @@ public final class PluginFactoryExt { SourceWithMetadata source, final Map args, Map pluginArgs) { final String id; - final PluginLookup.PluginClass pluginClass = PluginLookup.lookup(type, name); + final PluginLookup.PluginClass pluginClass = pluginResolver.resolve(type, name); if (type == PluginLookup.PluginType.CODEC) { id = UUID.randomUUID().toString(); } else { - id = lir.getGraph().vertices() + String unresolvedId = lir.getGraph().vertices() .filter(v -> v.getSourceWithMetadata() != null && v.getSourceWithMetadata().equalsWithoutText(source)) .findFirst() .map(Vertex::getId).orElse(null); + id = (String) configVariables.expand(unresolvedId); } if (id == null) { throw context.runtime.newRaiseException( diff --git a/logstash-core/src/test/java/org/logstash/plugins/PluginFactoryExtTest.java b/logstash-core/src/test/java/org/logstash/plugins/PluginFactoryExtTest.java new file mode 100644 index 000000000..a751bb392 --- /dev/null +++ b/logstash-core/src/test/java/org/logstash/plugins/PluginFactoryExtTest.java @@ -0,0 +1,139 @@ +package org.logstash.plugins; + +import co.elastic.logstash.api.*; +import org.jruby.RubyArray; +import org.jruby.RubyHash; +import org.jruby.RubyString; +import org.jruby.javasupport.JavaUtil; +import org.jruby.runtime.builtin.IRubyObject; +import org.junit.Test; +import org.logstash.RubyUtil; +import org.logstash.common.IncompleteSourceWithMetadataException; +import org.logstash.common.SourceWithMetadata; +import org.logstash.config.ir.ConfigCompiler; +import org.logstash.config.ir.PipelineIR; +import org.logstash.config.ir.RubyEnvTestCase; +import org.logstash.instrument.metrics.NamespacedMetricExt; + +import java.util.Collection; +import java.util.Collections; +import java.util.HashMap; +import java.util.Map; +import java.util.function.Consumer; + +import static org.junit.Assert.assertEquals; +import static org.logstash.RubyUtil.NAMESPACED_METRIC_CLASS; +import static org.logstash.RubyUtil.RUBY; +import static org.logstash.plugins.MetricTestCase.runRubyScript; + +/** + * Tests for {@link PluginFactoryExt.Plugins}. + */ +public final class PluginFactoryExtTest extends RubyEnvTestCase { + + static class MockInputPlugin implements Input { + private final String id; + + @SuppressWarnings("unused") + public MockInputPlugin(String id, Configuration config, Context ctx) { + this.id = id; + } + + @Override + public Collection> configSchema() { + return Collections.emptyList(); + } + + @Override + public String getId() { + return id; + } + + @Override + public void start(Consumer> writer) { + } + + @Override + public void stop() { + } + + @Override + public void awaitStop() throws InterruptedException { + } + } + + @Test + public void testPluginIdResolvedWithEnvironmentVariables() throws IncompleteSourceWithMetadataException { + PluginFactoryExt.PluginResolver mockPluginResolver = wrapWithSearchable(MockInputPlugin.class); + + SourceWithMetadata sourceWithMetadata = new SourceWithMetadata("proto", "path", 1, 8, "input {mockinput{ id => \"${CUSTOM}\"}} output{mockoutput{}}"); + final PipelineIR pipelineIR = compilePipeline(sourceWithMetadata); + + PluginFactoryExt.Metrics metricsFactory = createMetricsFactory(); + PluginFactoryExt.ExecutionContext execContextFactory = createExecutionContextFactory(); + Map envVars = new HashMap<>(); + envVars.put("CUSTOM", "test"); + PluginFactoryExt.Plugins sut = new PluginFactoryExt.Plugins(RubyUtil.RUBY, RubyUtil.PLUGIN_FACTORY_CLASS, + mockPluginResolver); + sut.init(pipelineIR, metricsFactory, execContextFactory, RubyUtil.FILTER_DELEGATOR_CLASS, envVars::get); + + RubyString pluginName = RubyUtil.RUBY.newString("mockinput"); + + // Exercise + IRubyObject pluginInstance = sut.buildInput(pluginName, sourceWithMetadata, RubyHash.newHash(RubyUtil.RUBY), + Collections.emptyMap()); + + //Verify + IRubyObject id = pluginInstance.callMethod(RUBY.getCurrentContext(), "id"); + assertEquals("Resolved config setting MUST be evaluated with substitution", envVars.get("CUSTOM"), id.toString()); + } + + @SuppressWarnings("rawtypes") + private static PipelineIR compilePipeline(SourceWithMetadata sourceWithMetadata) { + RubyArray sourcesWithMetadata = RubyUtil.RUBY.newArray(JavaUtil.convertJavaToRuby( + RubyUtil.RUBY, sourceWithMetadata)); + + return ConfigCompiler.configToPipelineIR(sourcesWithMetadata, false); + } + + private static PluginFactoryExt.ExecutionContext createExecutionContextFactory() { + PluginFactoryExt.ExecutionContext execContextFactory = new PluginFactoryExt.ExecutionContext(RubyUtil.RUBY, + RubyUtil.EXECUTION_CONTEXT_FACTORY_CLASS); + execContextFactory.initialize(RubyUtil.RUBY.getCurrentContext(), null, null, + RubyUtil.RUBY.newString("no DLQ")); + return execContextFactory; + } + + private static PluginFactoryExt.Metrics createMetricsFactory() { + final IRubyObject metricWithCollector = + runRubyScript("require \"logstash/instrument/collector\"\n" + + "metricWithCollector = LogStash::Instrument::Metric.new(LogStash::Instrument::Collector.new)"); + + NamespacedMetricExt metric = new NamespacedMetricExt(RUBY, NAMESPACED_METRIC_CLASS) + .initialize(RUBY.getCurrentContext(), metricWithCollector, RUBY.newEmptyArray()); + + + PluginFactoryExt.Metrics metricsFactory = new PluginFactoryExt.Metrics(RubyUtil.RUBY, RubyUtil.PLUGIN_METRIC_FACTORY_CLASS); + metricsFactory.initialize(RubyUtil.RUBY.getCurrentContext(), RubyUtil.RUBY.newString("main"), metric); + return metricsFactory; + } + + private static PluginFactoryExt.PluginResolver wrapWithSearchable(final Class pluginClass) { + return new PluginFactoryExt.PluginResolver() { + @Override + public PluginLookup.PluginClass resolve(PluginLookup.PluginType type, String name) { + return new PluginLookup.PluginClass() { + @Override + public PluginLookup.PluginLanguage language() { + return PluginLookup.PluginLanguage.JAVA; + } + + @Override + public Object klass() { + return pluginClass; + } + }; + } + }; + } +} \ No newline at end of file From ca635975c3d4396c719b292223e49f77ee90c5c8 Mon Sep 17 00:00:00 2001 From: Karen Metts Date: Mon, 18 Nov 2019 14:28:39 -0500 Subject: [PATCH 0356/1126] Update contributing guidelines to clarify changelog formatting MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-Authored-By: João Duarte Fixes #11316 --- CONTRIBUTING.md | 40 +++++++++++++++++++++++++--------------- 1 file changed, 25 insertions(+), 15 deletions(-) diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index ad09e1824..532481676 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -12,7 +12,7 @@ That said, some basic guidelines, which you are free to ignore :) Want to lurk about and see what others are doing with Logstash? -* The irc channel (#logstash on irc.freenode.org) is a good place for this +* The #logstash channel on Elastic Stack Community slack (https://elasticstack.slack.com/channels/logstash) is a good place to start. * The [forum](https://discuss.elastic.co/c/logstash) is also great for learning from others. @@ -21,12 +21,11 @@ Want to lurk about and see what others are doing with Logstash? Have a problem you want Logstash to solve for you? * You can ask a question in the [forum](https://discuss.elastic.co/c/logstash) -* Alternately, you are welcome to join the IRC channel #logstash on -irc.freenode.org and ask for help there! +* You are welcome to join Elastic Stack Community slack (https://elasticstack.slack.com) and ask for help on the #logstash channel. ## Have an Idea or Feature Request? -* File a ticket on [GitHub](https://github.com/elastic/logstash/issues). Please remember that GitHub is used only for issues and feature requests. If you have a general question, the [forum](https://discuss.elastic.co/c/logstash) or IRC would be the best place to ask. +* File a ticket on [GitHub](https://github.com/elastic/logstash/issues). Please remember that GitHub is used only for issues and feature requests. If you have a general question, the [forum](https://discuss.elastic.co/c/logstash) or Elastic Stack Community slack (https://elasticstack.slack.com) is the best place to ask. ## Something Not Working? Found a Bug? @@ -49,10 +48,10 @@ get in touch with our security team [here](https://www.elastic.co/community/secu If you have a bugfix or new feature that you would like to contribute to Logstash, and you think it will take more than a few minutes to produce the fix (ie; write code), it is worth discussing the change with the Logstash -users and developers first. You can reach us via [GitHub](https://github.com/elastic/logstash/issues), the [forum](https://discuss.elastic.co/c/logstash), or via IRC (#logstash on freenode irc) +users and developers first. You can reach us via [GitHub](https://github.com/elastic/logstash/issues), the [forum](https://discuss.elastic.co/c/logstash), or Elastic Stack Community slack (https://elasticstack.slack.com). Please note that Pull Requests without tests and documentation may not be merged. If you would like to contribute but do not have -experience with writing tests, please ping us on IRC/forum or create a PR and ask our help. +experience with writing tests, please ping us on the forum or create a PR and ask for our help. If you would like to contribute to Logstash, but don't know where to start, you can use the GitHub labels "adoptme" and "low hanging fruit". Issues marked with these labels are relatively easy, and provides a good starting @@ -71,7 +70,7 @@ Check our [documentation](https://www.elastic.co/guide/en/logstash/current/contr This document provides guidelines on editing a logstash plugin's CHANGELOG file. -#### What's a CHANGELOG file? +### What's a CHANGELOG file? According to [keepachangelog.com](https://keepachangelog.com/en/1.0.0/): @@ -107,14 +106,23 @@ then you should still create an entry in the changelog, using the word `Unreleas Most code in logstash-plugins comes from self-contained changes in the form of pull requests, so each entry should: -1. be a summary of the Pull Request and contain a markdown link to it. -2. start with [BREAKING], when it denotes a breaking change. - * Note: Breaking changes should warrant a major version bump. -3. after [BREAKING], start with one of the following keywords: - `Added`, `Changed`, `Deprecated`, `Removed`, `Fixed`, `Security`. -4. keep multiple entries with the same keyword in the same changelog revision together. +1. Be a summary of the Pull Request and contain a markdown link to the PR. +2. Begin your entry with an introductory label if appropriate. Labels include: + `[DOC]`, `[BREAKING]`, `[SECURITY]`. + NOTE: Your PR may not need a label. +3. After the label, start with one of the following keywords: + `Added`, `Changed`, `Deprecated`, `Removed`, `Fixed`. +4. Keep multiple entries with the same keyword in the same changelog revision together. -The meaning of the keywords is as follows (copied from [keepachangelog.com](https://keepachangelog.com/en/1.0.0/#how): +Labels: TODO: What's the right word here? Labels? Tags? Headers? Something else? +- **`[BREAKING]`** for a breaking change. + Note that breaking changes should warrant a major version bump. +- **`[DOC]`** for a change that affects only documentation, and not code. +- **`[SECURITY]`** for a security fix. If you're working on a security issue, +please make sure to follow the process outlined by our security team. +If you haven't done so already, please [get in touch with them](https://www.elastic.co/community/security) first. + +Keywords (copied from [keepachangelog.com](https://keepachangelog.com/en/1.0.0/#how)): - **`Added`** for new features. - **`Changed`** for changes in existing functionality. @@ -135,6 +143,9 @@ Example: - Changed default value of `execution_bugs` from 30 to 0 [#104](http://example.org) - [BREAKING] Removed obsolete option `enable_telnet` option [#100](http://example.org) +## 3.3.3 +- [DOC] Fixed incorrect formatting of code sample [#85](http://example.org) + ## 3.3.2 - Fixed incorrect serialization of input data when encoding was `Emacs-Mule` [#84](http://example.org) @@ -196,4 +207,3 @@ Keep these in mind as both authors and reviewers of PRs: * If no, ask for clarifications on the PR. This will usually lead to changes in the code such as renaming of variables/functions or extracting of functions or simply adding "why" inline comments. But first ask the author for clarifications before assuming any intent on their part. * I must not focus on personal preferences or nitpicks. If I understand the code in the PR but simply would've implemented the same solution a different way that's great but its not feedback that belongs in the PR. Such feedback only serves to slow down progress for little to no gain. - From 9361638b27d7caae07c2fcfeee10b4a343df78d5 Mon Sep 17 00:00:00 2001 From: Karen Metts Date: Fri, 21 Feb 2020 20:27:04 -0500 Subject: [PATCH 0357/1126] Add shared attribute for cloud trial Fixes #11621 --- docs/static/advanced-pipeline.asciidoc | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/docs/static/advanced-pipeline.asciidoc b/docs/static/advanced-pipeline.asciidoc index 7687e67ef..a83edde05 100644 --- a/docs/static/advanced-pipeline.asciidoc +++ b/docs/static/advanced-pipeline.asciidoc @@ -417,8 +417,7 @@ your data into Elasticsearch. TIP: You can run Elasticsearch on your own hardware, or use our https://www.elastic.co/cloud/elasticsearch-service[hosted {es} Service] on Elastic Cloud. The Elasticsearch Service is available on both AWS and GCP. -https://www.elastic.co/cloud/elasticsearch-service/signup[Try the {es} Service -for free]. +{ess-trial}[Try the {es} Service for free]. The Logstash pipeline can index the data into an Elasticsearch cluster. Edit the `first-pipeline.conf` file and replace the entire `output` section with the following From 239e9b0c32324166ae9b357090b7b7c0477e0849 Mon Sep 17 00:00:00 2001 From: lcawl Date: Tue, 25 Feb 2020 15:32:44 -0800 Subject: [PATCH 0358/1126] Fixes out-dated monitoring links Fixes #11629 --- .../management/configuring-centralized-pipelines.asciidoc | 2 +- docs/static/monitoring/monitoring-internal.asciidoc | 8 ++++---- docs/static/monitoring/monitoring-output.asciidoc | 4 ++-- docs/static/security/logstash.asciidoc | 4 ++-- docs/static/troubleshooting.asciidoc | 4 ++-- 5 files changed, 11 insertions(+), 11 deletions(-) diff --git a/docs/static/management/configuring-centralized-pipelines.asciidoc b/docs/static/management/configuring-centralized-pipelines.asciidoc index 57af55384..3923f1ebd 100644 --- a/docs/static/management/configuring-centralized-pipelines.asciidoc +++ b/docs/static/management/configuring-centralized-pipelines.asciidoc @@ -35,7 +35,7 @@ the `logstash_admin` role to any users who will use centralized pipeline management. See <>. NOTE: Centralized management is disabled until you configure and enable -{security}. +{security-features}. IMPORTANT: After you've configured Logstash to use centralized pipeline management, you can no longer specify local pipeline configurations. This means diff --git a/docs/static/monitoring/monitoring-internal.asciidoc b/docs/static/monitoring/monitoring-internal.asciidoc index c58fffadb..b64bba295 100644 --- a/docs/static/monitoring/monitoring-internal.asciidoc +++ b/docs/static/monitoring/monitoring-internal.asciidoc @@ -58,8 +58,8 @@ production cluster. If that setting is `false`, the collection of monitoring dat is disabled in {es} and data is ignored from all other sources. . Configure your Logstash nodes to send metrics by setting the -`xpack.monitoring.elasticsearch.hosts` in `logstash.yml`. If {security} is -enabled, you also need to specify the credentials for the +`xpack.monitoring.elasticsearch.hosts` in `logstash.yml`. If {security-features} +are enabled, you also need to specify the credentials for the {ref}/built-in-users.html[built-in `logstash_system` user]. For more information about these settings, see <>. + @@ -76,8 +76,8 @@ connect through HTTPS. As of v5.2.1, you can specify multiple Elasticsearch hosts as an array as well as specifying a single host as a string. If multiple URLs are specified, Logstash can round-robin requests to these production nodes. -<2> If {security} is disabled on the production cluster, you can omit these -`username` and `password` settings. +<2> If {security-features} are disabled on the production cluster, you can omit +these `username` and `password` settings. -- . If SSL/TLS is enabled on the production {es} cluster, specify the trusted diff --git a/docs/static/monitoring/monitoring-output.asciidoc b/docs/static/monitoring/monitoring-output.asciidoc index 08ce60ecf..16ba44ec9 100644 --- a/docs/static/monitoring/monitoring-output.asciidoc +++ b/docs/static/monitoring/monitoring-output.asciidoc @@ -32,8 +32,8 @@ All data produced by {monitoring} for Logstash is indexed in the monitoring cluster by using the `.monitoring-logstash` template, which is managed by the {ref}/es-monitoring-exporters.html[exporters] within {es}. -If you are working with a cluster that has {security} enabled, extra steps are -necessary to properly configure Logstash. For more information, see +If you are working with a cluster that has {security-features} enabled, extra +steps are necessary to properly configure Logstash. For more information, see <>. IMPORTANT: When discussing security relative to the `elasticsearch` output, it diff --git a/docs/static/security/logstash.asciidoc b/docs/static/security/logstash.asciidoc index 58113c9a9..b4a08f928 100644 --- a/docs/static/security/logstash.asciidoc +++ b/docs/static/security/logstash.asciidoc @@ -3,7 +3,7 @@ === Configuring Security in Logstash [subs="attributes"] ++++ -{security} +Configuring Security ++++ The Logstash {es} plugins ({logstash-ref}/plugins-outputs-elasticsearch.html[output], @@ -203,7 +203,7 @@ If you plan to ship Logstash {logstash-ref}/monitoring-logstash.html[monitoring] data to a secure cluster, you need to configure the username and password that Logstash uses to authenticate for shipping monitoring data. -{security} comes preconfigured with a +The {security-features} come preconfigured with a {ref}/built-in-users.html[`logstash_system` built-in user] for this purpose. This user has the minimum permissions necessary for the monitoring function, and _should not_ be used for any other purpose - it is diff --git a/docs/static/troubleshooting.asciidoc b/docs/static/troubleshooting.asciidoc index c30f54e18..2b56ba55e 100644 --- a/docs/static/troubleshooting.asciidoc +++ b/docs/static/troubleshooting.asciidoc @@ -114,8 +114,8 @@ that the bulk failed because the ingest queue is full. Logstash will retry sendi Check {es} to see if it needs attention. -* {ref}/cluster-stats.html -* {ref}/es-monitoring.html +* {ref}/cluster-stats.html[cluster stats API] +* {ref}/monitor-elasticsearch-cluster.html[Monitor a cluster] *Sample error* From 5587c9d7ac73c849d6a7ec3778d9bc6809ad53a9 Mon Sep 17 00:00:00 2001 From: Karen Metts <35154725+karenzone@users.noreply.github.com> Date: Wed, 26 Feb 2020 13:41:07 -0500 Subject: [PATCH 0359/1126] Make capitalization consistent Fixes #11629 --- docs/static/troubleshooting.asciidoc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/static/troubleshooting.asciidoc b/docs/static/troubleshooting.asciidoc index 2b56ba55e..6cabc7040 100644 --- a/docs/static/troubleshooting.asciidoc +++ b/docs/static/troubleshooting.asciidoc @@ -114,7 +114,7 @@ that the bulk failed because the ingest queue is full. Logstash will retry sendi Check {es} to see if it needs attention. -* {ref}/cluster-stats.html[cluster stats API] +* {ref}/cluster-stats.html[Cluster stats API] * {ref}/monitor-elasticsearch-cluster.html[Monitor a cluster] *Sample error* From 17c11508da6ee885e66521e66632eb3261c19c30 Mon Sep 17 00:00:00 2001 From: Karen Metts Date: Mon, 24 Feb 2020 16:33:30 -0500 Subject: [PATCH 0360/1126] Remove deprecation notices Fixes #11624 --- docs/static/monitoring/monitoring-internal.asciidoc | 4 +--- docs/static/monitoring/monitoring-mb.asciidoc | 2 +- docs/static/monitoring/monitoring-overview.asciidoc | 2 +- 3 files changed, 3 insertions(+), 5 deletions(-) diff --git a/docs/static/monitoring/monitoring-internal.asciidoc b/docs/static/monitoring/monitoring-internal.asciidoc index b64bba295..f9eb3a8f8 100644 --- a/docs/static/monitoring/monitoring-internal.asciidoc +++ b/docs/static/monitoring/monitoring-internal.asciidoc @@ -2,11 +2,9 @@ [[monitoring-internal-collection]] === Collect {ls} monitoring data using internal collectors ++++ -Internal collection (deprecated) +Internal collection ++++ -deprecated[7.7.0] - Using internal collectors for {ls} {monitoring} these components: * <> diff --git a/docs/static/monitoring/monitoring-mb.asciidoc b/docs/static/monitoring/monitoring-mb.asciidoc index d267211b1..ba54c04ad 100644 --- a/docs/static/monitoring/monitoring-mb.asciidoc +++ b/docs/static/monitoring/monitoring-mb.asciidoc @@ -6,7 +6,7 @@ {metricbeat} collection ++++ -In 7.3 and later, you can use {metricbeat} to collect data about {ls} +You can use {metricbeat} to collect data about {ls} and ship it to the monitoring cluster, rather than routing it through the production cluster as described in <>. diff --git a/docs/static/monitoring/monitoring-overview.asciidoc b/docs/static/monitoring/monitoring-overview.asciidoc index 1764aef29..1c6ff5b9b 100644 --- a/docs/static/monitoring/monitoring-overview.asciidoc +++ b/docs/static/monitoring/monitoring-overview.asciidoc @@ -17,7 +17,7 @@ Make sure monitoring is enabled on your {es} cluster. Then configure *one* of these methods to collect {ls} metrics: * <> -* <> +* <> include::monitoring-mb.asciidoc[] From 43213410ff829bb9683bf4cb7d8620d917757265 Mon Sep 17 00:00:00 2001 From: andsel Date: Thu, 20 Feb 2020 16:46:02 +0100 Subject: [PATCH 0361/1126] Fixes #11598 enabling the users to use completely commented config files Fixes #11615 --- logstash-core/lib/logstash/compiler.rb | 8 +- .../logstash/compiler/lscl/lscl_grammar.rb | 76 +++++++------------ .../compiler/lscl/lscl_grammar.treetop | 2 +- .../spec/logstash/compiler/compiler_spec.rb | 18 ++++- 4 files changed, 42 insertions(+), 62 deletions(-) diff --git a/logstash-core/lib/logstash/compiler.rb b/logstash-core/lib/logstash/compiler.rb index d22c33936..6cd68b280 100644 --- a/logstash-core/lib/logstash/compiler.rb +++ b/logstash-core/lib/logstash/compiler.rb @@ -6,14 +6,8 @@ java_import org.logstash.config.ir.graph.Graph module LogStash; class Compiler include ::LogStash::Util::Loggable - def self.empty_or_space(str) - str.match(/\A\s*\Z/).nil? == false - end - def self.compile_sources(sources_with_metadata, support_escapes) - graph_sections = sources_with_metadata.reject do |swm| - self.empty_or_space(swm.text) - end.map do |swm| + graph_sections = sources_with_metadata.map do |swm| self.compile_graph(swm, support_escapes) end diff --git a/logstash-core/lib/logstash/compiler/lscl/lscl_grammar.rb b/logstash-core/lib/logstash/compiler/lscl/lscl_grammar.rb index 6befae201..0f2c92a20 100644 --- a/logstash-core/lib/logstash/compiler/lscl/lscl_grammar.rb +++ b/logstash-core/lib/logstash/compiler/lscl/lscl_grammar.rb @@ -22,21 +22,9 @@ module LogStashCompilerLSCLGrammar end module Config1 - def _1 - elements[0] - end - - def plugin_section + def _ elements[1] end - - def _2 - elements[2] - end - - def _3 - elements[4] - end end def _nt_config @@ -51,45 +39,33 @@ module LogStashCompilerLSCLGrammar end i0, s0 = index, [] - r1 = _nt__ + s1, i1 = [], index + loop do + i2, s2 = index, [] + r3 = _nt__ + s2 << r3 + if r3 + r4 = _nt_plugin_section + s2 << r4 + end + if s2.last + r2 = instantiate_node(SyntaxNode,input, i2...index, s2) + r2.extend(Config0) + else + @index = i2 + r2 = nil + end + if r2 + s1 << r2 + else + break + end + end + r1 = instantiate_node(SyntaxNode,input, i1...index, s1) s0 << r1 if r1 - r2 = _nt_plugin_section - s0 << r2 - if r2 - r3 = _nt__ - s0 << r3 - if r3 - s4, i4 = [], index - loop do - i5, s5 = index, [] - r6 = _nt__ - s5 << r6 - if r6 - r7 = _nt_plugin_section - s5 << r7 - end - if s5.last - r5 = instantiate_node(SyntaxNode,input, i5...index, s5) - r5.extend(Config0) - else - @index = i5 - r5 = nil - end - if r5 - s4 << r5 - else - break - end - end - r4 = instantiate_node(SyntaxNode,input, i4...index, s4) - s0 << r4 - if r4 - r8 = _nt__ - s0 << r8 - end - end - end + r5 = _nt__ + s0 << r5 end if s0.last r0 = instantiate_node(LogStash::Compiler::LSCL::AST::Config,input, i0...index, s0) diff --git a/logstash-core/lib/logstash/compiler/lscl/lscl_grammar.treetop b/logstash-core/lib/logstash/compiler/lscl/lscl_grammar.treetop index 9463528a3..50109cd02 100644 --- a/logstash-core/lib/logstash/compiler/lscl/lscl_grammar.treetop +++ b/logstash-core/lib/logstash/compiler/lscl/lscl_grammar.treetop @@ -3,7 +3,7 @@ require "logstash/compiler/lscl.rb" grammar LogStashCompilerLSCLGrammar rule config - _ plugin_section _ (_ plugin_section)* _ + (_ plugin_section)* _ end rule comment diff --git a/logstash-core/spec/logstash/compiler/compiler_spec.rb b/logstash-core/spec/logstash/compiler/compiler_spec.rb index 160f1c5ed..55732b414 100644 --- a/logstash-core/spec/logstash/compiler/compiler_spec.rb +++ b/logstash-core/spec/logstash/compiler/compiler_spec.rb @@ -33,10 +33,6 @@ describe LogStash::Compiler do end describe "compile with empty source" do - subject(:source_id) { "fake_sourcefile" } - let(:source_with_metadata) { org.logstash.common.SourceWithMetadata.new(source_protocol, source_id, 0, 0, source) } - subject(:compiled) { puts "PCOMP"; described_class.compile_pipeline(source_with_metadata, settings) } - let(:sources_with_metadata) do [ org.logstash.common.SourceWithMetadata.new("str", "in_plugin", 0, 0, "input { input_0 {} } "), @@ -50,6 +46,20 @@ describe LogStash::Compiler do end end + describe "compile with fully commented source" do + let(:sources_with_metadata) do + [ + org.logstash.common.SourceWithMetadata.new("str", "in_plugin", 0, 0, "input { input_0 {} } "), + org.logstash.common.SourceWithMetadata.new("str", "commented_filter", 0, 0, "#filter{...}\n"), + org.logstash.common.SourceWithMetadata.new("str", "out_plugin", 0, 0, "output { output_0 {} } "), + ] + end + + it "should compile only non commented text parts" do + described_class.compile_sources(sources_with_metadata, false) + end + end + describe "compiling to Pipeline" do subject(:source_id) { "fake_sourcefile" } let(:source_with_metadata) { org.logstash.common.SourceWithMetadata.new(source_protocol, source_id, 0, 0, source) } From de95de3ae58c3e6af028d777bbc61f78ea805d4e Mon Sep 17 00:00:00 2001 From: Karol Bucek Date: Thu, 27 Feb 2020 13:31:42 +0100 Subject: [PATCH 0362/1126] remove TODO from CONTRIBUTING notes Fixes #11638 --- CONTRIBUTING.md | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index 532481676..4f193c383 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -114,7 +114,8 @@ Most code in logstash-plugins comes from self-contained changes in the form of p `Added`, `Changed`, `Deprecated`, `Removed`, `Fixed`. 4. Keep multiple entries with the same keyword in the same changelog revision together. -Labels: TODO: What's the right word here? Labels? Tags? Headers? Something else? +Labels (optional): + - **`[BREAKING]`** for a breaking change. Note that breaking changes should warrant a major version bump. - **`[DOC]`** for a change that affects only documentation, and not code. From b3c85356b0a8edb50128e42d5251eb6d47e24fbc Mon Sep 17 00:00:00 2001 From: andsel Date: Tue, 19 Nov 2019 15:56:15 +0100 Subject: [PATCH 0363/1126] Changed the xpack metrics pipeline to use a customized ES output plugin to put document_type for /_monitoring, closes #11312 Backport commit to 7.x Fixes #11321 Fixes #11640 --- .../outputs/elasticsearch_monitoring.rb | 16 ++++++++++++++++ x-pack/lib/template.cfg.erb | 2 +- x-pack/lib/x-pack/logstash_registry.rb | 2 ++ 3 files changed, 19 insertions(+), 1 deletion(-) create mode 100644 x-pack/lib/monitoring/outputs/elasticsearch_monitoring.rb diff --git a/x-pack/lib/monitoring/outputs/elasticsearch_monitoring.rb b/x-pack/lib/monitoring/outputs/elasticsearch_monitoring.rb new file mode 100644 index 000000000..a9b8e6084 --- /dev/null +++ b/x-pack/lib/monitoring/outputs/elasticsearch_monitoring.rb @@ -0,0 +1,16 @@ +# 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. + +module LogStash module Outputs + class ElasticSearchMonitoring < LogStash::Outputs::ElasticSearch + config_name "elasticsearch_monitoring" + + # This is need to avoid deprecation warning in output + config :document_type, :validate => :string + + def use_event_type?(client) + true + end + end +end; end diff --git a/x-pack/lib/template.cfg.erb b/x-pack/lib/template.cfg.erb index c50a03527..211bfbe5e 100644 --- a/x-pack/lib/template.cfg.erb +++ b/x-pack/lib/template.cfg.erb @@ -11,7 +11,7 @@ input { } } output { - elasticsearch { + elasticsearch_monitoring { <% if cloud_id? %> cloud_id => "<%= cloud_id %>" <% if cloud_auth %> diff --git a/x-pack/lib/x-pack/logstash_registry.rb b/x-pack/lib/x-pack/logstash_registry.rb index 60e2aa45e..e52d42391 100644 --- a/x-pack/lib/x-pack/logstash_registry.rb +++ b/x-pack/lib/x-pack/logstash_registry.rb @@ -11,11 +11,13 @@ require "logstash/plugins/registry" require "logstash/modules/util" require "monitoring/monitoring" require "monitoring/inputs/metrics" +require "monitoring/outputs/elasticsearch_monitoring" require "config_management/extension" require "modules/xpack_scaffold" require "filters/azure_event" LogStash::PLUGIN_REGISTRY.add(:input, "metrics", LogStash::Inputs::Metrics) +LogStash::PLUGIN_REGISTRY.add(:output, "elasticsearch_monitoring", LogStash::Outputs::ElasticSearchMonitoring) LogStash::PLUGIN_REGISTRY.add(:universal, "monitoring", LogStash::MonitoringExtension) LogStash::PLUGIN_REGISTRY.add(:universal, "config_management", LogStash::ConfigManagement::Extension) From 1ce7e6915bf237698e902577d1aba02213d81707 Mon Sep 17 00:00:00 2001 From: andsel Date: Fri, 28 Feb 2020 15:57:00 +0100 Subject: [PATCH 0364/1126] Fixes JDK13's javadoc build failure Fixes #11642 --- .../src/main/java/org/logstash/config/ir/CompiledPipeline.java | 2 +- .../java/org/logstash/config/ir/compiler/EventCondition.java | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/logstash-core/src/main/java/org/logstash/config/ir/CompiledPipeline.java b/logstash-core/src/main/java/org/logstash/config/ir/CompiledPipeline.java index e919facac..e7ec2fb4d 100644 --- a/logstash-core/src/main/java/org/logstash/config/ir/CompiledPipeline.java +++ b/logstash-core/src/main/java/org/logstash/config/ir/CompiledPipeline.java @@ -38,7 +38,7 @@ import java.util.stream.Collectors; import java.util.stream.Stream; /** - *

Compiled Logstash Pipeline Configuration.

+ *

Compiled Logstash Pipeline Configuration.

* This class represents an executable pipeline, compiled from the configured topology that is * learnt from {@link PipelineIR}. * Each compiled pipeline consists in graph of {@link Dataset} that represent either a diff --git a/logstash-core/src/main/java/org/logstash/config/ir/compiler/EventCondition.java b/logstash-core/src/main/java/org/logstash/config/ir/compiler/EventCondition.java index 36780b665..0e4c15ab4 100644 --- a/logstash-core/src/main/java/org/logstash/config/ir/compiler/EventCondition.java +++ b/logstash-core/src/main/java/org/logstash/config/ir/compiler/EventCondition.java @@ -51,7 +51,7 @@ public interface EventCondition { boolean fulfilled(JrubyEventExtLibrary.RubyEvent event); /** - *

EventCondition Compiler.

+ *

EventCondition Compiler.

* Compiles {@link BooleanExpression} into {@link EventCondition} globally ensuring that no * duplicate {@link EventCondition} are generated by strict synchronization on the internal * compiler cache {@link EventCondition.Compiler#cache}. From c00362868ff78c9cdedf11b683f4828b54954a5a Mon Sep 17 00:00:00 2001 From: Joao Duarte Date: Wed, 26 Feb 2020 09:43:45 +0000 Subject: [PATCH 0365/1126] Update release notes for 7.6.1 Fixes #11631 --- docs/static/releasenotes.asciidoc | 49 ++++++++++++++++++++++++++++++- 1 file changed, 48 insertions(+), 1 deletion(-) diff --git a/docs/static/releasenotes.asciidoc b/docs/static/releasenotes.asciidoc index 7c2e306dc..4f5dadcca 100644 --- a/docs/static/releasenotes.asciidoc +++ b/docs/static/releasenotes.asciidoc @@ -3,6 +3,7 @@ This section summarizes the changes in the following releases: +* <> * <> * <> * <> @@ -25,6 +26,52 @@ This section summarizes the changes in the following releases: * <> * <> +[[logstash-7-6-1]] +=== Logstash 7.6.1 Release Notes + +* [DOC] Rework ls netflow module deprecation notice https://github.com/elastic/logstash/pull/11600[#11600] +* [DOC] Clarify internal collectors deprecation status for 7.6 https://github.com/elastic/logstash/pull/11607[#11607] +* [DOC] Fix setting name for monitoring https://github.com/elastic/logstash/pull/11597[#11597] +* [DOC] Add Apple notarization info https://github.com/elastic/logstash/pull/11588[#11588] + +==== Plugins + +*Dns Filter* + +* Replaced Timeout::timeout block with `Resolv::DNS::timeouts=` https://github.com/logstash-plugins/logstash-filter-dns/pull/62[#62] +* Added restriction for ruby version > 2.0, effectively making Logstash 6.x+ a requirement https://github.com/logstash-plugins/logstash-filter-dns/pull/62[#62] + +*Memcached Filter* + +* Fixed issue with ttl not being set https://github.com/logstash-plugins/logstash-filter-memcached/pull/13[#13] + +*Split Filter* + +* Fixed issue where @target optimization would stop event.remove(@field) from being called, which can be expensive with large split fields. https://github.com/logstash-plugins/logstash-filter-split/pull/40[#40] + +*Beats Input* + +* Fixed issue where an SslContext was unnecessarily being created for each connection https://github.com/logstash-plugins/logstash-input-beats/pull/383[#383] +* Fixed issue where `end` was not being called when an Inflater was closed https://github.com/logstash-plugins/logstash-input-beats/pull/383[#383] +* Downgraded netty to 4.1.34 due to an issue in IdleStateHandler https://github.com/logstash-plugins/logstash-input-beats/pull/380[#380] + +*File Input* + +* Added configuration setting exit_after_read to read to EOF and terminate the input https://github.com/logstash-plugins/logstash-input-file/pull/240[#240] +* Fixed bug in conversion of sincedb_clean_after setting https://github.com/logstash-plugins/logstash-input-file/pull/257[#257] +* Fixed bug in delete of multiple watched files https://github.com/logstash-plugins/logstash-input-file/pull/254[#254] +* Fixed sinceDB to work spaces filename https://github.com/logstash-plugins/logstash-input-file/pull/249[#249] + +*Jdbc Integration* + +* Fixed tracking_column regression with Postgresql Numeric types https://github.com/logstash-plugins/logstash-integration-jdbc/pull/17[#17] +* Fixed driver loading when file not accessible https://github.com/logstash-plugins/logstash-integration-jdbc/pull/15[#15] + +*Elasticsearch Output* + +* Fix: handle proxy => '' as if none was set https://github.com/logstash-plugins/logstash-output-elasticsearch/pull/912[#912] + + [[logstash-7-6-0]] === Logstash 7.6.0 Release Notes @@ -1068,4 +1115,4 @@ Here are the plugin changes. - Tweaked logging statements to reduce verbosity - Fixed numerous issues relating to builds on Travis https://github.com/logstash-plugins/logstash-output-elasticsearch/pull/799[#799] * logstash-output-s3 - - Fixed issue where on restart, 0 byte files could erroneously be uploaded to s3 https://github.com/logstash-plugins/logstash-output-s3/issues/195[#195] \ No newline at end of file + - Fixed issue where on restart, 0 byte files could erroneously be uploaded to s3 https://github.com/logstash-plugins/logstash-output-s3/issues/195[#195] From 593235c162339db874c4dcb9160d42f2443a02d7 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jo=C3=A3o=20Duarte?= Date: Mon, 2 Mar 2020 17:01:40 +0000 Subject: [PATCH 0366/1126] Update rack dependency on docgen project Fixes #11644 --- tools/logstash-docgen/logstash-docgen.gemspec | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tools/logstash-docgen/logstash-docgen.gemspec b/tools/logstash-docgen/logstash-docgen.gemspec index 961492cf3..91d6b6931 100644 --- a/tools/logstash-docgen/logstash-docgen.gemspec +++ b/tools/logstash-docgen/logstash-docgen.gemspec @@ -28,7 +28,7 @@ Gem::Specification.new do |spec| # gems 1.0.0 requires Ruby 2.1.9 or newer, so we pin down. spec.add_runtime_dependency "gems", "0.8.3" - spec.add_development_dependency "rake", "~> 10.0" + spec.add_development_dependency "rake", "~> 12" spec.add_development_dependency "rspec" # Used for the dependency lookup code From 7706866fb05d6f55062301c87f5a03de5a172cce Mon Sep 17 00:00:00 2001 From: Karol Bucek Date: Wed, 26 Feb 2020 15:39:46 +0100 Subject: [PATCH 0367/1126] Fix: broken --help due sinatra 2.x upgrade Fixes #11634 --- logstash-core/lib/logstash/api/rack_app.rb | 7 +- qa/integration/fixtures/command_line_spec.yml | 3 + qa/integration/services/logstash_service.rb | 78 ++++++++++--------- qa/integration/specs/command_line_spec.rb | 23 ++++++ 4 files changed, 75 insertions(+), 36 deletions(-) create mode 100644 qa/integration/fixtures/command_line_spec.yml create mode 100644 qa/integration/specs/command_line_spec.rb diff --git a/logstash-core/lib/logstash/api/rack_app.rb b/logstash-core/lib/logstash/api/rack_app.rb index 8b2d19055..6b8a7eb6b 100644 --- a/logstash-core/lib/logstash/api/rack_app.rb +++ b/logstash-core/lib/logstash/api/rack_app.rb @@ -1,5 +1,5 @@ -require "sinatra" require "rack" +require "sinatra/base" require "logstash/api/modules/base" require "logstash/api/modules/node" require "logstash/api/modules/node_stats" @@ -74,6 +74,11 @@ module LogStash end def self.app(logger, agent, environment) + # LS should avoid loading sinatra/main.rb as it does not need the full Sinatra functionality + # such as configuration based on ARGV (actually dangerous if there's a --name collision), + # pretty much the only piece needed is the DSL but even that only for the rackup part : + Rack::Builder.send(:include, Sinatra::Delegator) unless Rack::Builder < Sinatra::Delegator + namespaces = rack_namespaces(agent) Rack::Builder.new do diff --git a/qa/integration/fixtures/command_line_spec.yml b/qa/integration/fixtures/command_line_spec.yml new file mode 100644 index 000000000..cbfc784af --- /dev/null +++ b/qa/integration/fixtures/command_line_spec.yml @@ -0,0 +1,3 @@ +--- +services: + - logstash diff --git a/qa/integration/services/logstash_service.rb b/qa/integration/services/logstash_service.rb index ca1729787..a35c46b76 100644 --- a/qa/integration/services/logstash_service.rb +++ b/qa/integration/services/logstash_service.rb @@ -20,6 +20,10 @@ class LogstashService < Service STDIN_CONFIG = "input {stdin {}} output { }" RETRY_ATTEMPTS = 60 + TIMEOUT_MAXIMUM = 60 * 10 # 10mins. + + class ProcessStatus < Struct.new(:exit_code, :stderr_and_stdout); end + @process = nil attr_reader :logstash_home @@ -202,24 +206,52 @@ class LogstashService < Service end def plugin_cli - PluginCli.new(@logstash_home) + PluginCli.new(self) end def lock_file File.join(@logstash_home, "Gemfile.lock") end - class PluginCli - class ProcessStatus < Struct.new(:exit_code, :stderr_and_stdout); end + def run_cmd(cmd_args, change_dir = true, environment = {}) + out = Tempfile.new("content") + out.sync = true + + cmd, *args = cmd_args + process = ChildProcess.build(cmd, *args) + environment.each do |k, v| + process.environment[k] = v + end + process.io.stdout = process.io.stderr = out + + Bundler.with_clean_env do + if change_dir + Dir.chdir(@logstash_home) do + process.start + end + else + process.start + end + end + + process.poll_for_exit(TIMEOUT_MAXIMUM) + out.rewind + ProcessStatus.new(process.exit_code, out.read) + end + + def run(*args) + run_cmd [ @logstash_bin, *args ] + end + + class PluginCli - TIMEOUT_MAXIMUM = 60 * 10 # 10mins. LOGSTASH_PLUGIN = File.join("bin", "logstash-plugin") attr_reader :logstash_plugin - def initialize(logstash_home) - @logstash_plugin = File.join(logstash_home, LOGSTASH_PLUGIN) - @logstash_home = logstash_home + def initialize(logstash_service) + @logstash = logstash_service + @logstash_plugin = File.join(@logstash.logstash_home, LOGSTASH_PLUGIN) end def remove(plugin_name) @@ -244,36 +276,12 @@ class LogstashService < Service run("install #{plugin_name}") end - def run_raw(cmd_parameters, change_dir = true, environment = {}) - out = Tempfile.new("content") - out.sync = true - - parts = cmd_parameters.split(" ") - cmd = parts.shift - - process = ChildProcess.build(cmd, *parts) - environment.each do |k, v| - process.environment[k] = v - end - process.io.stdout = process.io.stderr = out - - Bundler.with_clean_env do - if change_dir - Dir.chdir(@logstash_home) do - process.start - end - else - process.start - end - end - - process.poll_for_exit(TIMEOUT_MAXIMUM) - out.rewind - ProcessStatus.new(process.exit_code, out.read) - end - def run(command) run_raw("#{logstash_plugin} #{command}") end + + def run_raw(cmd, change_dir = true, environment = {}) + @logstash.run_cmd(cmd.split(' '), change_dir, environment) + end end end diff --git a/qa/integration/specs/command_line_spec.rb b/qa/integration/specs/command_line_spec.rb new file mode 100644 index 000000000..ae07e3024 --- /dev/null +++ b/qa/integration/specs/command_line_spec.rb @@ -0,0 +1,23 @@ +# encoding: utf-8 +require_relative "../framework/fixture" +require_relative "../framework/settings" +require_relative "../framework/helpers" + +describe "CLI >" do + + before(:all) do + @fixture = Fixture.new(__FILE__) + @logstash = @fixture.get_service("logstash") + end + + after(:each) { @logstash.teardown } + + it "shows --help" do + execute = @logstash.run('--help') + + expect(execute.exit_code).to eq(0) + expect(execute.stderr_and_stdout).to include('bin/logstash [OPTIONS]') + expect(execute.stderr_and_stdout).to include('--pipeline.id ID') + end + +end From d3d765a45577547cea1c1742e27c4de1fc8ece23 Mon Sep 17 00:00:00 2001 From: Karol Bucek Date: Tue, 3 Mar 2020 16:38:50 +0100 Subject: [PATCH 0368/1126] Fix: use l/w match-ing (which does not depend on frames) this was wrong on LS' end - String#match impl expects a frame (due $~) ... started failing due JRuby reducing frame usage (for blocks) Fixes #11653 --- .../config/ir/compiler/EventCondition.java | 28 +++++++++++-------- 1 file changed, 17 insertions(+), 11 deletions(-) diff --git a/logstash-core/src/main/java/org/logstash/config/ir/compiler/EventCondition.java b/logstash-core/src/main/java/org/logstash/config/ir/compiler/EventCondition.java index 0e4c15ab4..829167b9e 100644 --- a/logstash-core/src/main/java/org/logstash/config/ir/compiler/EventCondition.java +++ b/logstash-core/src/main/java/org/logstash/config/ir/compiler/EventCondition.java @@ -7,6 +7,7 @@ import java.util.Objects; import java.util.function.Predicate; import org.jruby.Ruby; +import org.jruby.RubyRegexp; import org.jruby.RubyString; import org.jruby.runtime.builtin.IRubyObject; import org.jruby.util.ByteList; @@ -467,22 +468,30 @@ public interface EventCondition { !Boolean.toString(false).equals(other); } + private static RubyRegexp newRegexp(String pattern) { + final Ruby runtime = RubyUtil.RUBY; + return RubyRegexp.newRegexpFromStr(runtime, runtime.newString(pattern), 0); + } + + private static boolean matches(RubyString str, RubyRegexp regexp) { + return regexp.match_p(RubyUtil.RUBY.getCurrentContext(), str).isTrue(); // match? returns true/false + } + private static final class FieldMatches implements EventCondition { private final FieldReference field; - private final RubyString regex; + private final RubyRegexp regexp; - private FieldMatches(final String field, final String regex) { + private FieldMatches(final String field, final String pattern) { this.field = FieldReference.from(field); - this.regex = RubyUtil.RUBY.newString(regex); + this.regexp = newRegexp(pattern); } @Override public boolean fulfilled(final JrubyEventExtLibrary.RubyEvent event) { - final Object tomatch = event.getEvent().getUnconvertedField(field); - return tomatch instanceof RubyString && - !((RubyString) tomatch).match(RubyUtil.RUBY.getCurrentContext(), regex).isNil(); + final Object toMatch = event.getEvent().getUnconvertedField(field); + return toMatch instanceof RubyString && matches((RubyString) toMatch, regexp); } } @@ -490,12 +499,9 @@ public interface EventCondition { private final boolean matches; - private ConstantMatches(final Object constant, final String regex) { - final Ruby runtime = RubyUtil.RUBY; + private ConstantMatches(final Object constant, final String pattern) { this.matches = constant instanceof String && - !(runtime.newString((String) constant).match( - runtime.getCurrentContext(), - runtime.newString(regex)).isNil()); + matches(RubyUtil.RUBY.newString((String) constant), newRegexp(pattern)); } @Override From b7a5f768593c068288c5aa1295e17dbb9122ca5c Mon Sep 17 00:00:00 2001 From: Karol Bucek Date: Tue, 3 Mar 2020 09:44:15 +0100 Subject: [PATCH 0369/1126] Updated: JRuby to 9.2.11.0 - fix: deprecation warnings due JRuby 9.2.11 - fix: compat for upgraded RubyGems 3.0 Fixes #11647 --- .ruby-version | 2 +- .../logstash/config/ir/compiler/OutputStrategyExt.java | 6 +++--- .../src/main/java/org/logstash/log/LoggableExt.java | 9 ++------- rubyUtils.gradle | 4 ++-- versions.yml | 4 ++-- 5 files changed, 10 insertions(+), 15 deletions(-) diff --git a/.ruby-version b/.ruby-version index 87d3afa18..27d180013 100644 --- a/.ruby-version +++ b/.ruby-version @@ -1 +1 @@ -jruby-9.1.12.0 +jruby-9.2.11.0 diff --git a/logstash-core/src/main/java/org/logstash/config/ir/compiler/OutputStrategyExt.java b/logstash-core/src/main/java/org/logstash/config/ir/compiler/OutputStrategyExt.java index 4f90b86a8..f60daf4f2 100644 --- a/logstash-core/src/main/java/org/logstash/config/ir/compiler/OutputStrategyExt.java +++ b/logstash-core/src/main/java/org/logstash/config/ir/compiler/OutputStrategyExt.java @@ -54,8 +54,8 @@ public final class OutputStrategyExt { } @JRubyMethod - public IRubyObject classes() { - return map.rb_values(); + public IRubyObject classes(final ThreadContext context) { + return map.values(context); } @JRubyMethod @@ -78,7 +78,7 @@ public final class OutputStrategyExt { String.format( "Could not find output delegator strategy of type '%s'. Value strategies: %s", type.asJavaString(), - map.rb_values().stream().map(v -> ((IRubyObject) v).asJavaString()) + map.values(context).stream().map(v -> ((IRubyObject) v).asJavaString()) .collect(Collectors.joining(", ")) ) ); diff --git a/logstash-core/src/main/java/org/logstash/log/LoggableExt.java b/logstash-core/src/main/java/org/logstash/log/LoggableExt.java index 7499dca62..20998599e 100644 --- a/logstash-core/src/main/java/org/logstash/log/LoggableExt.java +++ b/logstash-core/src/main/java/org/logstash/log/LoggableExt.java @@ -1,20 +1,15 @@ package org.logstash.log; -import co.elastic.logstash.api.DeprecationLogger; -import org.apache.logging.log4j.LogManager; -import org.apache.logging.log4j.Logger; import org.jruby.RubyClass; import org.jruby.RubyModule; import org.jruby.RubyString; import org.jruby.anno.JRubyMethod; import org.jruby.anno.JRubyModule; -import org.jruby.javasupport.JavaUtil; import org.jruby.runtime.Block; import org.jruby.runtime.ThreadContext; import org.jruby.runtime.builtin.IRubyObject; import org.jruby.runtime.builtin.InstanceVariables; import org.logstash.RubyUtil; -import org.logstash.common.SourceWithMetadata; import static org.logstash.RubyUtil.RUBY; @@ -50,7 +45,7 @@ public final class LoggableExt { } private static RubyString log4jName(final ThreadContext context, final RubyModule self) { - IRubyObject name = self.name19(); + IRubyObject name = self.name(context); if (name.isNil()) { final RubyClass clazz; if (self instanceof RubyClass) { @@ -58,7 +53,7 @@ public final class LoggableExt { } else { clazz = self.getMetaClass(); } - name = clazz.name19(); + name = clazz.name(context); if (name.isNil()) { name = clazz.to_s(); } diff --git a/rubyUtils.gradle b/rubyUtils.gradle index 0cecc31b6..242419ded 100644 --- a/rubyUtils.gradle +++ b/rubyUtils.gradle @@ -6,7 +6,7 @@ buildscript { dependencies { classpath 'org.yaml:snakeyaml:1.23' classpath "de.undercouch:gradle-download-task:3.2.0" - classpath "org.jruby:jruby-complete:9.2.9.0" + classpath "org.jruby:jruby-complete:9.2.11.0" } } @@ -81,7 +81,7 @@ void gem(File projectDir, File buildDir, String gem, String version, String path jruby.runScriptlet(""" require 'rubygems/commands/install_command' cmd = Gem::Commands::InstallCommand.new - cmd.handle_options ['--no-ri', '--no-rdoc', '${gem}', '-v', '${version}', '-i', '${path}'] + cmd.handle_options ['--no-document', '${gem}', '-v', '${version}', '-i', '${path}'] begin cmd.execute rescue Gem::SystemExitException => e diff --git a/versions.yml b/versions.yml index 9347d21e1..6ac7f2132 100644 --- a/versions.yml +++ b/versions.yml @@ -7,8 +7,8 @@ logstash-core-plugin-api: 2.1.16 # jruby must reference a *released* version of jruby which can be downloaded from the official download url # *and* for which jars artifacts are published for compile-time jruby: - version: 9.2.9.0 - sha1: 39ef88eb5e7319402b15c048f638f26e2b9c4f4c + version: 9.2.11.0 + sha1: c92bf2e52132b4d6d120f8dfbae15b36ab20d9d4 # jruby-runtime-override, if specified, will override the jruby version installed in vendor/jruby for logstash runtime only, # not for the compile-time jars From 229487c38e404a4838da8341c03117ab82db07e2 Mon Sep 17 00:00:00 2001 From: Lisa Cawley Date: Thu, 5 Mar 2020 16:56:59 -0800 Subject: [PATCH 0370/1126] [DOCS] Updates security API examples (#10752) (#11660) --- docs/static/security/logstash.asciidoc | 15 +++------------ 1 file changed, 3 insertions(+), 12 deletions(-) diff --git a/docs/static/security/logstash.asciidoc b/docs/static/security/logstash.asciidoc index b4a08f928..e97032d22 100644 --- a/docs/static/security/logstash.asciidoc +++ b/docs/static/security/logstash.asciidoc @@ -210,17 +210,8 @@ monitoring function, and _should not_ be used for any other purpose - it is specifically _not intended_ for use within a Logstash pipeline. By default, the `logstash_system` user does not have a password. The user will -not be enabled until you set a password. Set the password through the change -password API: - -[source,js] ---------------------------------------------------------------------- -PUT _xpack/security/user/logstash_system/_password -{ - "password": "t0p.s3cr3t" -} ---------------------------------------------------------------------- -// CONSOLE +not be enabled until you set a password. See +{ref}/built-in-users.html#set-built-in-user-passwords[Setting built-in user passwords]. Then configure the user and password in the `logstash.yml` configuration file: @@ -230,7 +221,7 @@ xpack.monitoring.elasticsearch.username: logstash_system xpack.monitoring.elasticsearch.password: t0p.s3cr3t ---------------------------------------------------------- -If you initially installed an older version of {xpack}, and then upgraded, the +If you initially installed an older version of {xpack} and then upgraded, the `logstash_system` user may have defaulted to `disabled` for security reasons. You can enable the user through the `user` API: From ce4493653c514fb6957053b0ad3896a98dd2c506 Mon Sep 17 00:00:00 2001 From: Karol Bucek Date: Fri, 6 Mar 2020 15:01:30 +0100 Subject: [PATCH 0371/1126] Changed: .ruby-version back to 9.1.12.0 .ruby-version is used to select the external jruby (for package building + acceptance tests on infra) reverts the upgraded JRuby version from #11647 Fixes #11663 --- .ruby-version | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.ruby-version b/.ruby-version index 27d180013..87d3afa18 100644 --- a/.ruby-version +++ b/.ruby-version @@ -1 +1 @@ -jruby-9.2.11.0 +jruby-9.1.12.0 From e64c6f3129f9d7c0ba6665c3f09999da5a2752ba Mon Sep 17 00:00:00 2001 From: Karen Metts <35154725+karenzone@users.noreply.github.com> Date: Fri, 6 Mar 2020 18:20:59 -0500 Subject: [PATCH 0372/1126] Backport changes from 11544 (#11665) --- CONTRIBUTING.md | 15 ++++++++++----- 1 file changed, 10 insertions(+), 5 deletions(-) diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index 4f193c383..f9b2c4470 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -53,12 +53,17 @@ users and developers first. You can reach us via [GitHub](https://github.com/ela Please note that Pull Requests without tests and documentation may not be merged. If you would like to contribute but do not have experience with writing tests, please ping us on the forum or create a PR and ask for our help. -If you would like to contribute to Logstash, but don't know where to start, you can use the GitHub labels "adoptme" -and "low hanging fruit". Issues marked with these labels are relatively easy, and provides a good starting -point to contribute to Logstash. +If you would like to contribute to Logstash, but don't know where to start, you +can use the GitHub labels "adoptme", "low hanging fruit" and "good first issue". +Issues marked with these labels are relatively easy, and provide a good +starting point to contribute to Logstash. -See: https://github.com/elastic/logstash/labels/adoptme -https://github.com/elastic/logstash/labels/low%20hanging%20fruit +See the following links: + * https://github.com/elastic/logstash/labels/adoptme + * https://github.com/elastic/logstash/labels/low%20hanging%20fruit + * https://github.com/elastic/logstash/labels/good%20first%20issue + +Or go directly here for an exhaustive list: https://github.com/elastic/logstash/contribute Using IntelliJ? See a detailed getting started guide [here](https://docs.google.com/document/d/1kqunARvYMrlfTEOgMpYHig0U-ZqCcMJfhvTtGt09iZg/pub). From 16e5f6280bceafc021bd2af679f7380c83418092 Mon Sep 17 00:00:00 2001 From: Luca Belluccini Date: Mon, 21 Oct 2019 15:02:03 +0200 Subject: [PATCH 0373/1126] Clarify reload of configuration files Logstash is not watching or monitoring any configuration files used or referenced by inputs, filters or outputs. Fixes #11255 --- docs/static/reloading-config.asciidoc | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/docs/static/reloading-config.asciidoc b/docs/static/reloading-config.asciidoc index 7b5d520ce..fee08bc8e 100644 --- a/docs/static/reloading-config.asciidoc +++ b/docs/static/reloading-config.asciidoc @@ -43,4 +43,7 @@ During automatic config reloading, the JVM is not restarted. The creating and sw pipelines all happens within the same process. Changes to <> pattern files are also reloaded, but only when -a change in the config file triggers a reload (or the pipeline is restarted). +a change in the config file triggers a reload (or the pipeline is restarted). + +In general, Logstash is not watching or monitoring any configuration files used or referenced by inputs, +filters or outputs. From 14a504f7b115de8a0dfde92792ee4a2d9df71450 Mon Sep 17 00:00:00 2001 From: 0xflotus <0xflotus@gmail.com> Date: Tue, 10 Mar 2020 06:50:03 +0100 Subject: [PATCH 0374/1126] Update logging.asciidoc - changed `2 seconds` to `2s` for consistency - exchanged *trace* with *debug* time values and vice versa to be referable to the example above Fixes #11671 --- docs/static/logging.asciidoc | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/docs/static/logging.asciidoc b/docs/static/logging.asciidoc index 8e78ff284..82f0d1c4d 100644 --- a/docs/static/logging.asciidoc +++ b/docs/static/logging.asciidoc @@ -165,10 +165,10 @@ slowlog.threshold.trace: 100ms In this example: -* If the log level is set to `warn`, the log shows events that took longer than 2 seconds to process. +* If the log level is set to `warn`, the log shows events that took longer than 2s to process. * If the log level is set to `info`, the log shows events that took longer than 1s to process. -* If the log level is set to `trace`, the log shows events that took longer than 100ms to process. * If the log level is set to `debug`, the log shows events that took longer than 500ms to process. +* If the log level is set to `trace`, the log shows events that took longer than 100ms to process. The logs include the full event and filter configuration that are responsible for the slowness. From d02e9577187c9be4225d9413cb9c6a5c7326cb6f Mon Sep 17 00:00:00 2001 From: Jonathan Bride <12625934+jonbws@users.noreply.github.com> Date: Sat, 1 Jun 2019 12:39:04 +0100 Subject: [PATCH 0375/1126] Fix grammar in enable_metric filter option Description was a run-on sentence, so split into two. Fixes #10841 --- docs/include/filter.asciidoc | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/docs/include/filter.asciidoc b/docs/include/filter.asciidoc index b749ceefb..23035490f 100644 --- a/docs/include/filter.asciidoc +++ b/docs/include/filter.asciidoc @@ -118,8 +118,8 @@ endif::[] * Value type is {logstash-ref}/configuration-file-structure.html#boolean[boolean] * Default value is `true` -Disable or enable metric logging for this specific plugin instance -by default we record all the metrics we can, but you can disable metrics collection +Disable or enable metric logging for this specific plugin instance. +By default we record all the metrics we can, but you can disable metrics collection for a specific plugin. ifeval::["{versioned_docs}"!="true"] From a2ebac33cad2a086e2cadb6f55d41e101c4545a3 Mon Sep 17 00:00:00 2001 From: meshkov Date: Wed, 26 Jun 2019 18:05:00 +0300 Subject: [PATCH 0376/1126] Update offline-plugins.asciidoc Fixes #10912 --- docs/static/offline-plugins.asciidoc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/static/offline-plugins.asciidoc b/docs/static/offline-plugins.asciidoc index ca6976b83..0fd4925b4 100644 --- a/docs/static/offline-plugins.asciidoc +++ b/docs/static/offline-plugins.asciidoc @@ -24,7 +24,7 @@ access the Internet. + [source, shell] ------------------------------------------------------------------------------- -bin/logstash-plugin prepare-offline-pack --output OUTPUT [PLUGINS] --overwrite +bin/logstash-plugin prepare-offline-pack --output OUTPUT --overwrite [PLUGINS] ------------------------------------------------------------------------------- + where: From f06b66db831be939755127a1494270c70f337b2e Mon Sep 17 00:00:00 2001 From: Ryan Earle Date: Wed, 24 Apr 2019 12:16:04 -0400 Subject: [PATCH 0377/1126] Update logging.asciidoc Fixes #10717 --- docs/static/logging.asciidoc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/static/logging.asciidoc b/docs/static/logging.asciidoc index 82f0d1c4d..38d75e23e 100644 --- a/docs/static/logging.asciidoc +++ b/docs/static/logging.asciidoc @@ -25,7 +25,7 @@ is restarted. [[log4j2]] ==== Log4j2 configuration -Logstash ships with a `log4j2.properties` file with out-of-the-box settings. You +Logstash ships with a `log4j2.properties` file with out-of-the-box settings (this includes logging to console). You can modify this file to change the rotation policy, type, and other https://logging.apache.org/log4j/2.x/manual/configuration.html#Loggers[log4j2 configuration]. From 9ef44b4c1625ac4facbc7b021ea5c96bd70a63be Mon Sep 17 00:00:00 2001 From: Karen Metts <35154725+karenzone@users.noreply.github.com> Date: Tue, 10 Mar 2020 17:15:34 -0400 Subject: [PATCH 0378/1126] Wording tweak for more emphasis Fixes #10717 --- docs/static/logging.asciidoc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/static/logging.asciidoc b/docs/static/logging.asciidoc index 38d75e23e..5fd497795 100644 --- a/docs/static/logging.asciidoc +++ b/docs/static/logging.asciidoc @@ -25,7 +25,7 @@ is restarted. [[log4j2]] ==== Log4j2 configuration -Logstash ships with a `log4j2.properties` file with out-of-the-box settings (this includes logging to console). You +Logstash ships with a `log4j2.properties` file with out-of-the-box settings, including logging to console. You can modify this file to change the rotation policy, type, and other https://logging.apache.org/log4j/2.x/manual/configuration.html#Loggers[log4j2 configuration]. From 4412073adf48684efa22eea6544d04c3b1bf8894 Mon Sep 17 00:00:00 2001 From: Kris Reberger Date: Thu, 31 Oct 2019 14:35:03 +1100 Subject: [PATCH 0379/1126] Update to include verification mode switch As of 6.4.1 (https://www.elastic.co/guide/en/logstash/6.4/logstash-6-4-1.html#logstash-6-4-1 and https://github.com/elastic/support-dev-help/issues/4770), we allow setting the monitoring and management ssl verification to either certificate or none, with certificate being the default. Fixes #11674 --- docs/static/settings/monitoring-settings.asciidoc | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/docs/static/settings/monitoring-settings.asciidoc b/docs/static/settings/monitoring-settings.asciidoc index 4309ad89d..0574663f9 100644 --- a/docs/static/settings/monitoring-settings.asciidoc +++ b/docs/static/settings/monitoring-settings.asciidoc @@ -81,6 +81,11 @@ the client’s certificate. Optional settings that provide the password to the keystore. +`xpack.monitoring.elasticsearch.ssl.verification_mode`:: + +Option to validate the server’s certificate. Defaults to `certificate`. To +disable, set to `none`. Disabling this severely compromises security. + [[monitoring-additional-settings]] ===== Additional settings @@ -99,3 +104,5 @@ If you're using {es} in {ecloud}, you can set your auth credentials here. This setting is an alternative to both `xpack.monitoring.elasticsearch.username` and `xpack.monitoring.elasticsearch.password`. If `cloud_auth` is configured, those settings should not be used. + + From 1fc169b7f638dbcb0957d49045968820f7d250fe Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jo=C3=A3o=20Duarte?= Date: Wed, 11 Mar 2020 11:53:38 +0000 Subject: [PATCH 0380/1126] Add apache and elastic license headers to source code files (#11673) * add license header to ruby and java files * add license header to erb and rake files * add license headers to gradle files --- Rakefile | 17 +++++++++++++- build.gradle | 19 +++++++++++++++ docs/static/contributing-patch.asciidoc | 5 +--- docs/static/include/pluginbody.asciidoc | 17 -------------- lib/bootstrap/bundler.rb | 17 +++++++++++++- lib/bootstrap/environment.rb | 19 +++++++++++++-- lib/bootstrap/patches/gems.rb | 19 +++++++++++++-- lib/bootstrap/patches/jar_dependencies.rb | 18 ++++++++++++++- lib/bootstrap/patches/remote_fetcher.rb | 17 ++++++++++++++ lib/bootstrap/rspec.rb | 18 ++++++++++++++- lib/bootstrap/rubygems.rb | 18 ++++++++++++++- lib/bootstrap/util/compress.rb | 18 ++++++++++++++- .../bundler/logstash_injector.rb | 18 ++++++++++++++- .../bundler/logstash_uninstall.rb | 18 ++++++++++++++- lib/pluginmanager/command.rb | 18 ++++++++++++++- lib/pluginmanager/errors.rb | 18 ++++++++++++++- lib/pluginmanager/gem_installer.rb | 18 ++++++++++++++- lib/pluginmanager/gemfile.rb | 18 ++++++++++++++- lib/pluginmanager/generate.rb | 18 ++++++++++++++- lib/pluginmanager/install.rb | 18 ++++++++++++++- lib/pluginmanager/install_strategy_factory.rb | 18 ++++++++++++++- lib/pluginmanager/list.rb | 18 ++++++++++++++- lib/pluginmanager/main.rb | 18 ++++++++++++++- lib/pluginmanager/offline_plugin_packager.rb | 18 ++++++++++++++- lib/pluginmanager/pack.rb | 18 ++++++++++++++- lib/pluginmanager/pack_command.rb | 18 ++++++++++++++- .../pack_fetch_strategy/repository.rb | 18 ++++++++++++++- lib/pluginmanager/pack_fetch_strategy/uri.rb | 18 ++++++++++++++- lib/pluginmanager/pack_installer/local.rb | 18 ++++++++++++++- lib/pluginmanager/pack_installer/pack.rb | 18 ++++++++++++++- lib/pluginmanager/pack_installer/remote.rb | 18 ++++++++++++++- lib/pluginmanager/prepare_offline_pack.rb | 19 +++++++++++++-- lib/pluginmanager/proxy_support.rb | 18 ++++++++++++++- lib/pluginmanager/remove.rb | 18 ++++++++++++++- lib/pluginmanager/settings.xml.erb | 17 ++++++++++++++ .../codec-plugin/spec/spec_helper.rb | 18 ++++++++++++++- .../filter-plugin/spec/spec_helper.rb | 18 ++++++++++++++- lib/pluginmanager/templates/render_context.rb | 17 ++++++++++++++ lib/pluginmanager/ui.rb | 18 ++++++++++++++- lib/pluginmanager/unpack.rb | 18 ++++++++++++++- lib/pluginmanager/update.rb | 18 ++++++++++++++- lib/pluginmanager/util.rb | 18 ++++++++++++++- lib/pluginmanager/utils/downloader.rb | 18 ++++++++++++++- lib/pluginmanager/utils/http_client.rb | 18 ++++++++++++++- lib/pluginmanager/x_pack_interceptor.rb | 17 +++++++++++++- lib/secretstore/cli.rb | 17 ++++++++++++++ lib/systeminstall/pleasewrap.rb | 18 ++++++++++++++- .../lib/logstash-core-plugin-api/version.rb | 17 +++++++++++++- logstash-core/benchmarks/build.gradle | 19 +++++++++++++++ .../EventSerializationBenchmark.java | 20 ++++++++++++++++ .../benchmark/EventSprintfBenchmark.java | 20 ++++++++++++++++ .../benchmark/LogPerPipelineBenchmark.java | 20 ++++++++++++++++ .../logstash/benchmark/QueueRWBenchmark.java | 20 ++++++++++++++++ .../benchmark/QueueWriteBenchmark.java | 20 ++++++++++++++++ logstash-core/build.gradle | 19 +++++++++++++++ logstash-core/lib/logstash-core.rb | 17 ++++++++++++++ .../lib/logstash-core/logstash-core.rb | 17 +++++++++++++- logstash-core/lib/logstash-core/version.rb | 17 +++++++++++++- logstash-core/lib/logstash/agent.rb | 18 ++++++++++++++- logstash-core/lib/logstash/api/app_helpers.rb | 18 ++++++++++++++- .../lib/logstash/api/command_factory.rb | 18 ++++++++++++++- .../lib/logstash/api/commands/base.rb | 17 +++++++++++++- .../logstash/api/commands/default_metadata.rb | 17 +++++++++++++- .../api/commands/hot_threads_reporter.rb | 18 ++++++++++++++- .../lib/logstash/api/commands/node.rb | 18 ++++++++++++++- .../lib/logstash/api/commands/stats.rb | 18 ++++++++++++++- .../api/commands/system/basicinfo_command.rb | 18 ++++++++++++++- .../api/commands/system/plugins_command.rb | 18 ++++++++++++++- logstash-core/lib/logstash/api/errors.rb | 18 ++++++++++++++- .../lib/logstash/api/modules/base.rb | 18 ++++++++++++++- .../lib/logstash/api/modules/logging.rb | 17 +++++++++++++- .../lib/logstash/api/modules/node.rb | 18 ++++++++++++++- .../lib/logstash/api/modules/node_stats.rb | 18 ++++++++++++++- .../lib/logstash/api/modules/plugins.rb | 18 ++++++++++++++- .../lib/logstash/api/modules/root.rb | 18 ++++++++++++++- .../lib/logstash/api/modules/stats.rb | 18 ++++++++++++++- logstash-core/lib/logstash/api/rack_app.rb | 17 ++++++++++++++ logstash-core/lib/logstash/api/service.rb | 18 ++++++++++++++- .../bootstrap_check/default_config.rb | 17 +++++++++++++- .../bootstrap_check/persisted_queue_config.rb | 17 +++++++++++++- logstash-core/lib/logstash/build.rb | 17 +++++++++++++- logstash-core/lib/logstash/codecs/base.rb | 18 ++++++++++++++- .../lib/logstash/codecs/delegator.rb | 17 ++++++++++++++ logstash-core/lib/logstash/compiler.rb | 17 ++++++++++++++ logstash-core/lib/logstash/compiler/lscl.rb | 18 ++++++++++++++- .../lib/logstash/compiler/lscl/helpers.rb | 17 +++++++++++++- .../logstash/compiler/lscl/lscl_grammar.rb | 19 ++++++++++++--- .../compiler/treetop_monkeypatches.rb | 17 ++++++++++++++ .../lib/logstash/config/config_ast.rb | 18 ++++++++++++++- .../lib/logstash/config/cpu_core_strategy.rb | 18 ++++++++++++++- logstash-core/lib/logstash/config/defaults.rb | 18 ++++++++++++++- logstash-core/lib/logstash/config/file.rb | 18 ++++++++++++++- logstash-core/lib/logstash/config/grammar.rb | 19 ++++++++++++--- .../lib/logstash/config/lir_serializer.rb | 19 +++++++++++++-- logstash-core/lib/logstash/config/mixin.rb | 18 ++++++++++++++- .../lib/logstash/config/modules_common.rb | 18 ++++++++++++++- .../lib/logstash/config/pipeline_config.rb | 18 ++++++++++++++- .../lib/logstash/config/pipelines_info.rb | 17 ++++++++++++++ .../lib/logstash/config/source/base.rb | 18 ++++++++++++++- .../lib/logstash/config/source/local.rb | 18 ++++++++++++++- .../lib/logstash/config/source/modules.rb | 18 ++++++++++++++- .../lib/logstash/config/source/multi_local.rb | 18 ++++++++++++++- .../lib/logstash/config/source_loader.rb | 18 ++++++++++++++- .../lib/logstash/config/string_escape.rb | 17 +++++++++++++- .../lib/logstash/dependency_report.rb | 18 ++++++++++++++- .../lib/logstash/dependency_report_runner.rb | 17 ++++++++++++++ .../lib/logstash/elasticsearch_client.rb | 18 ++++++++++++++- logstash-core/lib/logstash/environment.rb | 18 ++++++++++++++- logstash-core/lib/logstash/errors.rb | 17 ++++++++++++++ logstash-core/lib/logstash/event.rb | 17 +++++++++++++- .../lib/logstash/event_dispatcher.rb | 17 ++++++++++++++ .../lib/logstash/execution_context.rb | 17 ++++++++++++++ .../lib/logstash/filter_delegator.rb | 17 ++++++++++++++ logstash-core/lib/logstash/filters/base.rb | 18 ++++++++++++++- logstash-core/lib/logstash/inputs/base.rb | 18 ++++++++++++++- .../lib/logstash/inputs/threadable.rb | 18 ++++++++++++++- .../lib/logstash/instrument/collector.rb | 18 ++++++++++++++- .../lib/logstash/instrument/metric.rb | 17 ++++++++++++++ .../lib/logstash/instrument/metric_store.rb | 18 ++++++++++++++- .../lib/logstash/instrument/metric_type.rb | 18 ++++++++++++++- .../instrument/metric_type/counter.rb | 18 ++++++++++++++- .../logstash/instrument/metric_type/gauge.rb | 19 +++++++++++++-- .../logstash/instrument/namespaced_metric.rb | 17 ++++++++++++++ .../instrument/namespaced_null_metric.rb | 17 ++++++++++++++ .../lib/logstash/instrument/null_metric.rb | 17 ++++++++++++++ .../instrument/periodic_poller/base.rb | 18 ++++++++++++++- .../instrument/periodic_poller/cgroup.rb | 17 +++++++++++++- .../instrument/periodic_poller/dlq.rb | 19 +++++++++++++-- .../instrument/periodic_poller/jvm.rb | 18 ++++++++++++++- .../periodic_poller/load_average.rb | 18 ++++++++++++++- .../logstash/instrument/periodic_poller/os.rb | 18 ++++++++++++++- .../logstash/instrument/periodic_poller/pq.rb | 18 ++++++++++++++- .../logstash/instrument/periodic_pollers.rb | 18 ++++++++++++++- logstash-core/lib/logstash/java_pipeline.rb | 18 ++++++++++++++- logstash-core/lib/logstash/json.rb | 18 ++++++++++++++- logstash-core/lib/logstash/logging.rb | 17 +++++++++++++- logstash-core/lib/logstash/logging/logger.rb | 17 ++++++++++++++ .../lib/logstash/modules/cli_parser.rb | 18 ++++++++++++++- .../logstash/modules/elasticsearch_config.rb | 18 ++++++++++++++- .../modules/elasticsearch_importer.rb | 18 ++++++++++++++- .../modules/elasticsearch_resource.rb | 18 ++++++++++++++- .../lib/logstash/modules/file_reader.rb | 18 ++++++++++++++- .../lib/logstash/modules/kibana_base.rb | 18 ++++++++++++++- .../lib/logstash/modules/kibana_client.rb | 18 ++++++++++++++- .../lib/logstash/modules/kibana_config.rb | 18 ++++++++++++++- .../lib/logstash/modules/kibana_dashboards.rb | 18 ++++++++++++++- .../lib/logstash/modules/kibana_importer.rb | 18 ++++++++++++++- .../lib/logstash/modules/kibana_resource.rb | 18 ++++++++++++++- .../lib/logstash/modules/kibana_settings.rb | 18 ++++++++++++++- .../lib/logstash/modules/logstash_config.rb | 18 ++++++++++++++- .../lib/logstash/modules/resource_base.rb | 18 ++++++++++++++- .../lib/logstash/modules/scaffold.rb | 19 +++++++++++++-- .../lib/logstash/modules/settings_merger.rb | 18 ++++++++++++++- logstash-core/lib/logstash/modules/util.rb | 18 ++++++++++++++- logstash-core/lib/logstash/namespace.rb | 17 ++++++++++++++ logstash-core/lib/logstash/outputs/base.rb | 18 ++++++++++++++- logstash-core/lib/logstash/patches.rb | 18 ++++++++++++++- .../lib/logstash/patches/bugfix_jruby_2558.rb | 18 ++++++++++++++- logstash-core/lib/logstash/patches/cabin.rb | 18 ++++++++++++++- logstash-core/lib/logstash/patches/clamp.rb | 19 +++++++++++++-- .../lib/logstash/patches/exception_to_json.rb | 17 ++++++++++++++ .../logstash/patches/profile_require_calls.rb | 18 ++++++++++++++- logstash-core/lib/logstash/patches/puma.rb | 17 +++++++++++++- .../patches/stronger_openssl_defaults.rb | 18 ++++++++++++++- logstash-core/lib/logstash/pipeline.rb | 18 ++++++++++++++- logstash-core/lib/logstash/pipeline_action.rb | 18 ++++++++++++++- .../lib/logstash/pipeline_action/base.rb | 18 ++++++++++++++- .../lib/logstash/pipeline_action/create.rb | 18 ++++++++++++++- .../lib/logstash/pipeline_action/reload.rb | 18 ++++++++++++++- .../lib/logstash/pipeline_action/stop.rb | 18 ++++++++++++++- .../lib/logstash/pipeline_reporter.rb | 17 ++++++++++++++ .../lib/logstash/pipelines_registry.rb | 17 +++++++++++++- logstash-core/lib/logstash/plugin.rb | 18 ++++++++++++++- logstash-core/lib/logstash/plugin_metadata.rb | 17 +++++++++++++- logstash-core/lib/logstash/plugins.rb | 17 ++++++++++++++ logstash-core/lib/logstash/plugins/builtin.rb | 17 ++++++++++++++ .../plugins/builtin/pipeline/input.rb | 17 ++++++++++++++ .../plugins/builtin/pipeline/output.rb | 17 ++++++++++++++ .../lib/logstash/plugins/hooks_registry.rb | 17 +++++++++++++- .../lib/logstash/plugins/registry.rb | 18 ++++++++++++++- logstash-core/lib/logstash/runner.rb | 18 ++++++++++++++- logstash-core/lib/logstash/settings.rb | 18 ++++++++++++++- .../lib/logstash/shutdown_watcher.rb | 17 +++++++++++++- logstash-core/lib/logstash/state_resolver.rb | 18 ++++++++++++++- logstash-core/lib/logstash/timestamp.rb | 17 ++++++++++++++ .../lib/logstash/universal_plugin.rb | 17 ++++++++++++++ logstash-core/lib/logstash/util.rb | 18 ++++++++++++++- logstash-core/lib/logstash/util/buftok.rb | 17 ++++++++++++++ logstash-core/lib/logstash/util/byte_value.rb | 17 +++++++++++++- logstash-core/lib/logstash/util/charset.rb | 18 ++++++++++++++- .../lib/logstash/util/cloud_setting_auth.rb | 18 ++++++++++++++- .../lib/logstash/util/cloud_setting_id.rb | 18 ++++++++++++++- .../util/dead_letter_queue_manager.rb | 17 ++++++++++++++ logstash-core/lib/logstash/util/decorators.rb | 18 ++++++++++++++- .../lib/logstash/util/java_version.rb | 17 +++++++++++++- logstash-core/lib/logstash/util/loggable.rb | 17 ++++++++++++++ .../util/manticore_ssl_config_helper.rb | 17 +++++++++++++- .../logstash/util/modules_setting_array.rb | 18 ++++++++++++++- logstash-core/lib/logstash/util/password.rb | 17 +++++++++++++- .../lib/logstash/util/plugin_version.rb | 18 ++++++++++++++- logstash-core/lib/logstash/util/prctl.rb | 19 +++++++++++++-- logstash-core/lib/logstash/util/safe_uri.rb | 19 +++++++++++++-- .../lib/logstash/util/secretstore.rb | 17 ++++++++++++++ .../lib/logstash/util/settings_helper.rb | 17 ++++++++++++++ .../lib/logstash/util/socket_peer.rb | 18 ++++++++++++++- .../logstash/util/substitution_variables.rb | 17 +++++++++++++- .../lib/logstash/util/thread_dump.rb | 18 ++++++++++++++- logstash-core/lib/logstash/util/time_value.rb | 17 ++++++++++++++ .../util/worker_threads_default_printer.rb | 19 +++++++++++++-- logstash-core/lib/logstash/version.rb | 17 +++++++++++++- logstash-core/lib/logstash/webserver.rb | 18 ++++++++++++++- logstash-core/spec/conditionals_spec.rb | 18 ++++++++++++++- .../acked_queue_concurrent_stress_spec.rb | 18 ++++++++++++++- .../spec/logstash/agent/converge_spec.rb | 18 ++++++++++++++- .../spec/logstash/agent/metrics_spec.rb | 17 +++++++++++++- logstash-core/spec/logstash/agent_spec.rb | 18 ++++++++++++++- .../api/commands/default_metadata_spec.rb | 18 ++++++++++++++- .../spec/logstash/api/commands/node_spec.rb | 18 ++++++++++++++- .../spec/logstash/api/commands/stats_spec.rb | 18 ++++++++++++++- .../spec/logstash/api/errors_spec.rb | 18 ++++++++++++++- .../spec/logstash/api/modules/logging_spec.rb | 18 ++++++++++++++- .../logstash/api/modules/node_plugins_spec.rb | 18 ++++++++++++++- .../spec/logstash/api/modules/node_spec.rb | 18 ++++++++++++++- .../logstash/api/modules/node_stats_spec.rb | 18 ++++++++++++++- .../spec/logstash/api/modules/plugins_spec.rb | 18 ++++++++++++++- .../spec/logstash/api/modules/root_spec.rb | 19 +++++++++++++-- .../spec/logstash/api/rack_app_spec.rb | 17 ++++++++++++++ .../persisted_queue_config_spec.rb | 17 ++++++++++++++ .../spec/logstash/codecs/base_spec.rb | 18 ++++++++++++++- .../spec/logstash/codecs/delegator_spec.rb | 18 ++++++++++++++- .../spec/logstash/compiler/compiler_spec.rb | 17 ++++++++++++++ .../spec/logstash/config/config_ast_spec.rb | 19 +++++++++++++-- .../logstash/config/cpu_core_strategy_spec.rb | 18 ++++++++++++++- .../spec/logstash/config/defaults_spec.rb | 18 ++++++++++++++- .../spec/logstash/config/mixin_spec.rb | 18 ++++++++++++++- .../logstash/config/pipeline_config_spec.rb | 18 ++++++++++++++- .../spec/logstash/config/source/local_spec.rb | 18 ++++++++++++++- .../config/source/multi_local_spec.rb | 18 ++++++++++++++- .../logstash/config/source_loader_spec.rb | 18 ++++++++++++++- .../logstash/config/string_escape_spec.rb | 16 +++++++++++++ .../spec/logstash/converge_result_spec.rb | 18 ++++++++++++++- .../logstash/elasticsearch_client_spec.rb | 17 +++++++++++++- .../spec/logstash/environment_spec.rb | 18 ++++++++++++++- .../spec/logstash/event_dispatcher_spec.rb | 17 +++++++++++++- logstash-core/spec/logstash/event_spec.rb | 17 +++++++++++++- .../spec/logstash/execution_context_spec.rb | 18 ++++++++++++++- .../spec/logstash/filter_delegator_spec.rb | 18 ++++++++++++++- .../spec/logstash/filters/base_spec.rb | 18 ++++++++++++++- .../spec/logstash/inputs/base_spec.rb | 18 ++++++++++++++- .../logstash/instrument/collector_spec.rb | 18 ++++++++++++++- .../spec/logstash/instrument/metric_spec.rb | 18 ++++++++++++++- .../logstash/instrument/metric_store_spec.rb | 18 ++++++++++++++- .../instrument/metric_type/counter_spec.rb | 18 ++++++++++++++- .../instrument/metric_type/gauge_spec.rb | 18 ++++++++++++++- .../instrument/namespaced_metric_spec.rb | 18 ++++++++++++++- .../instrument/namespaced_null_metric_spec.rb | 18 ++++++++++++++- .../logstash/instrument/null_metric_spec.rb | 18 ++++++++++++++- .../instrument/periodic_poller/base_spec.rb | 18 ++++++++++++++- .../instrument/periodic_poller/cgroup_spec.rb | 18 ++++++++++++++- .../instrument/periodic_poller/dlq_spec.rb | 18 ++++++++++++++- .../instrument/periodic_poller/jvm_spec.rb | 18 ++++++++++++++- .../periodic_poller/load_average_spec.rb | 18 ++++++++++++++- .../instrument/periodic_poller/os_spec.rb | 18 ++++++++++++++- .../instrument/wrapped_write_client_spec.rb | 18 ++++++++++++++- .../logstash/java_filter_delegator_spec.rb | 18 ++++++++++++++- .../spec/logstash/java_integration_spec.rb | 18 ++++++++++++++- .../spec/logstash/java_pipeline_spec.rb | 18 ++++++++++++++- logstash-core/spec/logstash/json_spec.rb | 18 ++++++++++++++- .../spec/logstash/legacy_ruby_event_spec.rb | 19 +++++++++++++-- .../logstash/legacy_ruby_timestamp_spec.rb | 18 ++++++++++++++- .../spec/logstash/modules/cli_parser_spec.rb | 17 ++++++++++++++ .../logstash/modules/kibana_client_spec.rb | 18 ++++++++++++++- .../logstash/modules/logstash_config_spec.rb | 18 ++++++++++++++- .../spec/logstash/modules/scaffold_spec.rb | 17 +++++++++++++- .../logstash/modules/settings_merger_spec.rb | 18 ++++++++++++++- .../spec/logstash/outputs/base_spec.rb | 18 ++++++++++++++- logstash-core/spec/logstash/patches_spec.rb | 18 ++++++++++++++- .../logstash/pipeline_action/create_spec.rb | 18 ++++++++++++++- .../logstash/pipeline_action/reload_spec.rb | 18 ++++++++++++++- .../logstash/pipeline_action/stop_spec.rb | 18 ++++++++++++++- .../spec/logstash/pipeline_dlq_commit_spec.rb | 18 ++++++++++++++- .../spec/logstash/pipeline_pq_file_spec.rb | 18 ++++++++++++++- .../spec/logstash/pipeline_reporter_spec.rb | 18 ++++++++++++++- logstash-core/spec/logstash/pipeline_spec.rb | 18 ++++++++++++++- .../spec/logstash/pipelines_registry_spec.rb | 18 ++++++++++++++- logstash-core/spec/logstash/plugin_spec.rb | 18 ++++++++++++++- .../builtin/pipeline_input_output_spec.rb | 17 ++++++++++++++ .../logstash/plugins/hooks_registry_spec.rb | 17 +++++++++++++- .../spec/logstash/plugins/registry_spec.rb | 18 ++++++++++++++- .../spec/logstash/queue_factory_spec.rb | 18 ++++++++++++++- logstash-core/spec/logstash/runner_spec.rb | 18 ++++++++++++++- logstash-core/spec/logstash/setting_spec.rb | 18 ++++++++++++++- .../logstash/settings/array_coercible_spec.rb | 18 ++++++++++++++- .../spec/logstash/settings/bytes_spec.rb | 18 ++++++++++++++- .../spec/logstash/settings/integer_spec.rb | 18 ++++++++++++++- .../spec/logstash/settings/modules_spec.rb | 18 ++++++++++++++- .../spec/logstash/settings/numeric_spec.rb | 18 ++++++++++++++- .../spec/logstash/settings/port_range_spec.rb | 17 +++++++++++++- .../settings/splittable_string_array_spec.rb | 19 +++++++++++++-- .../spec/logstash/settings/string_spec.rb | 18 ++++++++++++++- .../spec/logstash/settings/time_value_spec.rb | 18 ++++++++++++++- .../settings/writable_directory_spec.rb | 18 ++++++++++++++- logstash-core/spec/logstash/settings_spec.rb | 18 ++++++++++++++- .../spec/logstash/shutdown_watcher_spec.rb | 18 ++++++++++++++- .../spec/logstash/state_resolver_spec.rb | 18 ++++++++++++++- .../spec/logstash/util/accessors_spec.rb | 18 ++++++++++++++- .../spec/logstash/util/buftok_spec.rb | 18 ++++++++++++++- .../spec/logstash/util/byte_value_spec.rb | 17 ++++++++++++++ .../spec/logstash/util/charset_spec.rb | 18 ++++++++++++++- .../logstash/util/cloud_setting_id_spec.rb | 18 ++++++++++++++- .../spec/logstash/util/java_version_spec.rb | 18 ++++++++++++++- .../spec/logstash/util/plugin_version_spec.rb | 18 ++++++++++++++- .../spec/logstash/util/safe_uri_spec.rb | 18 ++++++++++++++- .../spec/logstash/util/secretstore_spec.rb | 17 ++++++++++++++ .../spec/logstash/util/time_value_spec.rb | 18 ++++++++++++++- .../logstash/util/wrapped_acked_queue_spec.rb | 18 ++++++++++++++- .../util/wrapped_synchronous_queue_spec.rb | 18 ++++++++++++++- logstash-core/spec/logstash/util_spec.rb | 18 ++++++++++++++- logstash-core/spec/logstash/webserver_spec.rb | 19 +++++++++++++-- .../configuration/logstash/tester.conf.erb | 17 ++++++++++++++ logstash-core/spec/plugin_metadata_spec.rb | 17 +++++++++++++- logstash-core/spec/static/i18n_spec.rb | 18 ++++++++++++++- logstash-core/spec/support/helpers.rb | 18 ++++++++++++++- logstash-core/spec/support/matchers.rb | 19 +++++++++++++-- logstash-core/spec/support/mocks_classes.rb | 18 ++++++++++++++- .../spec/support/pipeline/pipeline_helpers.rb | 17 ++++++++++++++ logstash-core/spec/support/shared_contexts.rb | 17 ++++++++++++++ logstash-core/spec/support/shared_examples.rb | 19 +++++++++++++-- .../java/co/elastic/logstash/api/Codec.java | 20 ++++++++++++++++ .../elastic/logstash/api/Configuration.java | 20 ++++++++++++++++ .../java/co/elastic/logstash/api/Context.java | 20 ++++++++++++++++ .../elastic/logstash/api/CounterMetric.java | 20 ++++++++++++++++ .../logstash/api/DeadLetterQueueWriter.java | 20 ++++++++++++++++ .../logstash/api/DeprecationLogger.java | 20 ++++++++++++++++ .../java/co/elastic/logstash/api/Event.java | 20 ++++++++++++++++ .../co/elastic/logstash/api/EventFactory.java | 20 ++++++++++++++++ .../java/co/elastic/logstash/api/Filter.java | 20 ++++++++++++++++ .../logstash/api/FilterMatchListener.java | 20 ++++++++++++++++ .../java/co/elastic/logstash/api/Input.java | 20 ++++++++++++++++ .../elastic/logstash/api/LogstashPlugin.java | 20 ++++++++++++++++ .../java/co/elastic/logstash/api/Metric.java | 20 ++++++++++++++++ .../logstash/api/NamespacedMetric.java | 20 ++++++++++++++++ .../java/co/elastic/logstash/api/Output.java | 20 ++++++++++++++++ .../co/elastic/logstash/api/Password.java | 20 ++++++++++++++++ .../java/co/elastic/logstash/api/Plugin.java | 20 ++++++++++++++++ .../logstash/api/PluginConfigSpec.java | 20 ++++++++++++++++ .../co/elastic/logstash/api/PluginHelper.java | 20 ++++++++++++++++ .../src/main/java/org/logstash/Accessors.java | 20 ++++++++++++++++ .../src/main/java/org/logstash/Cloner.java | 20 ++++++++++++++++ .../main/java/org/logstash/ConvertedList.java | 20 ++++++++++++++++ .../main/java/org/logstash/ConvertedMap.java | 20 ++++++++++++++++ .../src/main/java/org/logstash/DLQEntry.java | 20 ++++++++++++++++ .../src/main/java/org/logstash/Event.java | 20 ++++++++++++++++ .../java/org/logstash/FieldReference.java | 20 ++++++++++++++++ .../java/org/logstash/FileLockFactory.java | 20 ++++++++++++++++ .../src/main/java/org/logstash/Javafier.java | 21 ++++++++++++++++- .../src/main/java/org/logstash/KeyNode.java | 20 ++++++++++++++++ .../main/java/org/logstash/LockException.java | 20 ++++++++++++++++ .../src/main/java/org/logstash/Logstash.java | 20 ++++++++++++++++ .../java/org/logstash/LogstashJavaCompat.java | 20 ++++++++++++++++ .../logstash/MissingConverterException.java | 20 ++++++++++++++++ .../main/java/org/logstash/ObjectMappers.java | 20 ++++++++++++++++ .../org/logstash/RubyJavaIntegration.java | 20 ++++++++++++++++ .../src/main/java/org/logstash/RubyUtil.java | 20 ++++++++++++++++ .../src/main/java/org/logstash/Rubyfier.java | 20 ++++++++++++++++ .../org/logstash/StringInterpolation.java | 20 ++++++++++++++++ .../src/main/java/org/logstash/Timestamp.java | 20 ++++++++++++++++ .../src/main/java/org/logstash/Util.java | 20 ++++++++++++++++ .../src/main/java/org/logstash/Valuefier.java | 20 ++++++++++++++++ .../org/logstash/ackedqueue/AckedBatch.java | 20 ++++++++++++++++ .../logstash/ackedqueue/AckedReadBatch.java | 20 ++++++++++++++++ .../java/org/logstash/ackedqueue/Batch.java | 20 ++++++++++++++++ .../org/logstash/ackedqueue/Checkpoint.java | 20 ++++++++++++++++ .../java/org/logstash/ackedqueue/Page.java | 20 ++++++++++++++++ .../org/logstash/ackedqueue/PageFactory.java | 20 ++++++++++++++++ .../java/org/logstash/ackedqueue/PqCheck.java | 20 ++++++++++++++++ .../org/logstash/ackedqueue/PqRepair.java | 20 ++++++++++++++++ .../java/org/logstash/ackedqueue/Queue.java | 20 ++++++++++++++++ .../logstash/ackedqueue/QueueFactoryExt.java | 20 ++++++++++++++++ .../ackedqueue/QueueRuntimeException.java | 20 ++++++++++++++++ .../org/logstash/ackedqueue/QueueUpgrade.java | 20 ++++++++++++++++ .../org/logstash/ackedqueue/Queueable.java | 20 ++++++++++++++++ .../logstash/ackedqueue/SequencedList.java | 20 ++++++++++++++++ .../org/logstash/ackedqueue/Settings.java | 20 ++++++++++++++++ .../org/logstash/ackedqueue/SettingsImpl.java | 20 ++++++++++++++++ .../ackedqueue/ext/JRubyAckedQueueExt.java | 20 ++++++++++++++++ .../ext/JRubyWrappedAckedQueueExt.java | 20 ++++++++++++++++ .../ackedqueue/io/ByteBufferCleaner.java | 20 ++++++++++++++++ .../logstash/ackedqueue/io/CheckpointIO.java | 20 ++++++++++++++++ .../ackedqueue/io/FileCheckpointIO.java | 20 ++++++++++++++++ .../org/logstash/ackedqueue/io/IntVector.java | 20 ++++++++++++++++ .../logstash/ackedqueue/io/LongVector.java | 20 ++++++++++++++++ .../logstash/ackedqueue/io/MmapPageIOV1.java | 20 ++++++++++++++++ .../logstash/ackedqueue/io/MmapPageIOV2.java | 20 ++++++++++++++++ .../org/logstash/ackedqueue/io/PageIO.java | 20 ++++++++++++++++ .../AbstractDeadLetterQueueWriterExt.java | 20 ++++++++++++++++ .../logstash/common/BufferedTokenizerExt.java | 20 ++++++++++++++++ .../org/logstash/common/DLQWriterAdapter.java | 20 ++++++++++++++++ .../common/DeadLetterQueueFactory.java | 20 ++++++++++++++++ .../common/EnvironmentVariableProvider.java | 20 ++++++++++++++++ .../main/java/org/logstash/common/FsUtil.java | 20 ++++++++++++++++ ...IncompleteSourceWithMetadataException.java | 20 ++++++++++++++++ .../org/logstash/common/LsQueueUtils.java | 20 ++++++++++++++++ .../common/NullDeadLetterQueueWriter.java | 20 ++++++++++++++++ .../logstash/common/SourceWithMetadata.java | 20 ++++++++++++++++ .../main/java/org/logstash/common/Util.java | 20 ++++++++++++++++ .../common/io/DeadLetterQueueReader.java | 20 ++++++++++++++++ .../common/io/DeadLetterQueueWriter.java | 20 ++++++++++++++++ .../org/logstash/common/io/RecordHeader.java | 20 ++++++++++++++++ .../logstash/common/io/RecordIOReader.java | 20 ++++++++++++++++ .../logstash/common/io/RecordIOWriter.java | 20 ++++++++++++++++ .../org/logstash/common/io/RecordType.java | 20 ++++++++++++++++ .../config/ir/BaseSourceComponent.java | 20 ++++++++++++++++ .../logstash/config/ir/CompiledPipeline.java | 20 ++++++++++++++++ .../logstash/config/ir/ConfigCompiler.java | 20 ++++++++++++++++ .../main/java/org/logstash/config/ir/DSL.java | 20 ++++++++++++++++ .../java/org/logstash/config/ir/Hashable.java | 20 ++++++++++++++++ .../config/ir/HashableWithSource.java | 20 ++++++++++++++++ .../config/ir/InvalidIRException.java | 20 ++++++++++++++++ .../org/logstash/config/ir/PipelineIR.java | 20 ++++++++++++++++ .../logstash/config/ir/PluginDefinition.java | 20 ++++++++++++++++ .../logstash/config/ir/SourceComponent.java | 20 ++++++++++++++++ .../compiler/AbstractFilterDelegatorExt.java | 20 ++++++++++++++++ .../compiler/AbstractOutputDelegatorExt.java | 20 ++++++++++++++++ .../config/ir/compiler/BaseDataset.java | 20 ++++++++++++++++ .../config/ir/compiler/ClassFields.java | 20 ++++++++++++++++ .../logstash/config/ir/compiler/Closure.java | 20 ++++++++++++++++ .../config/ir/compiler/CommonActions.java | 20 ++++++++++++++++ .../ir/compiler/ComputeStepSyntaxElement.java | 20 ++++++++++++++++ .../logstash/config/ir/compiler/Dataset.java | 20 ++++++++++++++++ .../config/ir/compiler/DatasetCompiler.java | 20 ++++++++++++++++ .../config/ir/compiler/EventCondition.java | 20 ++++++++++++++++ .../ir/compiler/FieldDeclarationGroup.java | 20 ++++++++++++++++ .../config/ir/compiler/FieldDefinition.java | 20 ++++++++++++++++ .../ir/compiler/FilterDelegatorExt.java | 20 ++++++++++++++++ .../ir/compiler/JavaCodecDelegator.java | 20 ++++++++++++++++ .../ir/compiler/JavaFilterDelegatorExt.java | 20 ++++++++++++++++ .../ir/compiler/JavaInputDelegatorExt.java | 20 ++++++++++++++++ .../ir/compiler/JavaOutputDelegatorExt.java | 20 ++++++++++++++++ .../ir/compiler/MethodLevelSyntaxElement.java | 20 ++++++++++++++++ .../ir/compiler/MethodSyntaxElement.java | 20 ++++++++++++++++ .../ir/compiler/OutputDelegatorExt.java | 20 ++++++++++++++++ .../config/ir/compiler/OutputStrategyExt.java | 20 ++++++++++++++++ .../config/ir/compiler/PluginFactory.java | 20 ++++++++++++++++ .../config/ir/compiler/RubyIntegration.java | 20 ++++++++++++++++ .../config/ir/compiler/SplitDataset.java | 20 ++++++++++++++++ .../config/ir/compiler/SyntaxElement.java | 20 ++++++++++++++++ .../config/ir/compiler/SyntaxFactory.java | 20 ++++++++++++++++ .../logstash/config/ir/compiler/Utils.java | 20 ++++++++++++++++ .../ir/compiler/ValueSyntaxElement.java | 20 ++++++++++++++++ .../ir/compiler/VariableDefinition.java | 20 ++++++++++++++++ .../expression/BinaryBooleanExpression.java | 20 ++++++++++++++++ .../ir/expression/BooleanExpression.java | 20 ++++++++++++++++ .../ir/expression/EventValueExpression.java | 20 ++++++++++++++++ .../config/ir/expression/Expression.java | 20 ++++++++++++++++ .../ir/expression/RegexValueExpression.java | 20 ++++++++++++++++ .../ir/expression/UnaryBooleanExpression.java | 20 ++++++++++++++++ .../config/ir/expression/ValueExpression.java | 20 ++++++++++++++++ .../config/ir/expression/binary/And.java | 20 ++++++++++++++++ .../config/ir/expression/binary/Eq.java | 20 ++++++++++++++++ .../config/ir/expression/binary/Gt.java | 20 ++++++++++++++++ .../config/ir/expression/binary/Gte.java | 20 ++++++++++++++++ .../config/ir/expression/binary/In.java | 20 ++++++++++++++++ .../config/ir/expression/binary/Lt.java | 20 ++++++++++++++++ .../config/ir/expression/binary/Lte.java | 20 ++++++++++++++++ .../config/ir/expression/binary/Neq.java | 20 ++++++++++++++++ .../config/ir/expression/binary/Or.java | 20 ++++++++++++++++ .../config/ir/expression/binary/RegexEq.java | 20 ++++++++++++++++ .../config/ir/expression/unary/Not.java | 20 ++++++++++++++++ .../config/ir/expression/unary/Truthy.java | 20 ++++++++++++++++ .../logstash/config/ir/graph/BooleanEdge.java | 20 ++++++++++++++++ .../org/logstash/config/ir/graph/Edge.java | 20 ++++++++++++++++ .../org/logstash/config/ir/graph/Graph.java | 20 ++++++++++++++++ .../logstash/config/ir/graph/IfVertex.java | 20 ++++++++++++++++ .../logstash/config/ir/graph/PlainEdge.java | 20 ++++++++++++++++ .../config/ir/graph/PluginVertex.java | 20 ++++++++++++++++ .../logstash/config/ir/graph/QueueVertex.java | 20 ++++++++++++++++ .../org/logstash/config/ir/graph/Vertex.java | 20 ++++++++++++++++ .../ir/graph/algorithms/BreadthFirst.java | 20 ++++++++++++++++ .../ir/graph/algorithms/DepthFirst.java | 20 ++++++++++++++++ .../config/ir/graph/algorithms/GraphDiff.java | 20 ++++++++++++++++ .../ir/graph/algorithms/TopologicalSort.java | 20 ++++++++++++++++ .../imperative/ComposedParallelStatement.java | 20 ++++++++++++++++ .../imperative/ComposedSequenceStatement.java | 20 ++++++++++++++++ .../ir/imperative/ComposedStatement.java | 20 ++++++++++++++++ .../config/ir/imperative/IfStatement.java | 20 ++++++++++++++++ .../config/ir/imperative/NoopStatement.java | 20 ++++++++++++++++ .../config/ir/imperative/PluginStatement.java | 20 ++++++++++++++++ .../config/ir/imperative/Statement.java | 20 ++++++++++++++++ .../execution/AbstractPipelineExt.java | 20 ++++++++++++++++ .../execution/AbstractWrappedQueueExt.java | 20 ++++++++++++++++ .../logstash/execution/ConvergeResultExt.java | 20 ++++++++++++++++ .../execution/EventDispatcherExt.java | 20 ++++++++++++++++ .../execution/ExecutionContextExt.java | 20 ++++++++++++++++ .../execution/JavaBasePipelineExt.java | 20 ++++++++++++++++ .../logstash/execution/MemoryReadBatch.java | 20 ++++++++++++++++ .../org/logstash/execution/PeriodicFlush.java | 20 ++++++++++++++++ .../execution/PipelineReporterExt.java | 20 ++++++++++++++++ .../org/logstash/execution/QueueBatch.java | 20 ++++++++++++++++ .../logstash/execution/QueueReadClient.java | 20 ++++++++++++++++ .../execution/QueueReadClientBase.java | 20 ++++++++++++++++ .../execution/ShutdownWatcherExt.java | 20 ++++++++++++++++ .../org/logstash/execution/WorkerLoop.java | 20 ++++++++++++++++ .../queue/LegacyMemoryQueueWriter.java | 20 ++++++++++++++++ .../logstash/execution/queue/QueueWriter.java | 20 ++++++++++++++++ .../ext/JRubyAbstractQueueWriteClientExt.java | 20 ++++++++++++++++ .../logstash/ext/JRubyLogstashErrorsExt.java | 20 ++++++++++++++++ .../ext/JRubyWrappedWriteClientExt.java | 20 ++++++++++++++++ .../logstash/ext/JrubyAckedReadClientExt.java | 20 ++++++++++++++++ .../ext/JrubyAckedWriteClientExt.java | 20 ++++++++++++++++ .../logstash/ext/JrubyEventExtLibrary.java | 20 ++++++++++++++++ .../ext/JrubyMemoryReadClientExt.java | 20 ++++++++++++++++ .../ext/JrubyMemoryWriteClientExt.java | 20 ++++++++++++++++ .../ext/JrubyTimestampExtLibrary.java | 20 ++++++++++++++++ .../ext/JrubyWrappedSynchronousQueueExt.java | 20 ++++++++++++++++ .../instrument/metrics/AbstractMetric.java | 20 ++++++++++++++++ .../instrument/metrics/AbstractMetricExt.java | 20 ++++++++++++++++ .../metrics/AbstractNamespacedMetricExt.java | 20 ++++++++++++++++ .../metrics/AbstractSimpleMetricExt.java | 20 ++++++++++++++++ .../logstash/instrument/metrics/Metric.java | 20 ++++++++++++++++ .../instrument/metrics/MetricExt.java | 20 ++++++++++++++++ .../instrument/metrics/MetricKeys.java | 20 ++++++++++++++++ .../instrument/metrics/MetricType.java | 20 ++++++++++++++++ .../metrics/NamespacedMetricExt.java | 20 ++++++++++++++++ .../instrument/metrics/NullMetricExt.java | 20 ++++++++++++++++ .../metrics/NullNamespacedMetricExt.java | 20 ++++++++++++++++ .../instrument/metrics/SnapshotExt.java | 20 ++++++++++++++++ .../metrics/counter/CounterMetric.java | 20 ++++++++++++++++ .../metrics/counter/LongCounter.java | 20 ++++++++++++++++ .../metrics/gauge/AbstractGaugeMetric.java | 20 ++++++++++++++++ .../metrics/gauge/BooleanGauge.java | 20 ++++++++++++++++ .../instrument/metrics/gauge/GaugeMetric.java | 20 ++++++++++++++++ .../metrics/gauge/LazyDelegatingGauge.java | 20 ++++++++++++++++ .../instrument/metrics/gauge/NumberGauge.java | 20 ++++++++++++++++ .../metrics/gauge/RubyHashGauge.java | 20 ++++++++++++++++ .../metrics/gauge/RubyTimeStampGauge.java | 20 ++++++++++++++++ .../instrument/metrics/gauge/TextGauge.java | 20 ++++++++++++++++ .../metrics/gauge/UnknownGauge.java | 20 ++++++++++++++++ .../monitors/HotThreadsMonitor.java | 20 ++++++++++++++++ .../instrument/monitors/MemoryMonitor.java | 20 ++++++++++++++++ .../instrument/monitors/ProcessMonitor.java | 20 ++++++++++++++++ .../instrument/monitors/SystemMonitor.java | 20 ++++++++++++++++ .../instrument/reports/MemoryReport.java | 21 ++++++++++++++++- .../instrument/reports/ProcessReport.java | 20 ++++++++++++++++ .../instrument/reports/ThreadsReport.java | 21 ++++++++++++++++- .../java/org/logstash/log/CustomLogEvent.java | 20 ++++++++++++++++ .../log/CustomLogEventSerializer.java | 20 ++++++++++++++++ .../log/DefaultDeprecationLogger.java | 20 ++++++++++++++++ .../logstash/log/DeprecationLoggerExt.java | 20 ++++++++++++++++ .../java/org/logstash/log/LoggableExt.java | 20 ++++++++++++++++ .../main/java/org/logstash/log/LoggerExt.java | 20 ++++++++++++++++ .../log/LogstashConfigurationFactory.java | 20 ++++++++++++++++ .../logstash/log/LogstashLogEventFactory.java | 20 ++++++++++++++++ .../log/LogstashLoggerContextFactory.java | 20 ++++++++++++++++ .../logstash/log/LogstashMessageFactory.java | 20 ++++++++++++++++ .../java/org/logstash/log/SlowLoggerExt.java | 20 ++++++++++++++++ .../org/logstash/log/StructuredMessage.java | 20 ++++++++++++++++ .../plugins/ConfigVariableExpander.java | 20 ++++++++++++++++ .../logstash/plugins/ConfigurationImpl.java | 20 ++++++++++++++++ .../org/logstash/plugins/ContextImpl.java | 20 ++++++++++++++++ .../logstash/plugins/CounterMetricImpl.java | 20 ++++++++++++++++ .../logstash/plugins/HooksRegistryExt.java | 20 ++++++++++++++++ .../plugins/NamespacedMetricImpl.java | 20 ++++++++++++++++ .../logstash/plugins/PluginClassLoader.java | 20 ++++++++++++++++ .../logstash/plugins/PluginFactoryExt.java | 20 ++++++++++++++++ .../org/logstash/plugins/PluginLookup.java | 20 ++++++++++++++++ .../java/org/logstash/plugins/PluginUtil.java | 20 ++++++++++++++++ .../org/logstash/plugins/PluginValidator.java | 20 ++++++++++++++++ .../org/logstash/plugins/RootMetricImpl.java | 20 ++++++++++++++++ .../logstash/plugins/UniversalPluginExt.java | 20 ++++++++++++++++ .../org/logstash/plugins/codecs/Dots.java | 20 ++++++++++++++++ .../org/logstash/plugins/codecs/Line.java | 20 ++++++++++++++++ .../org/logstash/plugins/codecs/Plain.java | 20 ++++++++++++++++ .../plugins/discovery/PluginRegistry.java | 20 ++++++++++++++++ .../org/logstash/plugins/filters/Uuid.java | 20 ++++++++++++++++ .../logstash/plugins/inputs/Generator.java | 20 ++++++++++++++++ .../org/logstash/plugins/inputs/Stdin.java | 20 ++++++++++++++++ .../org/logstash/plugins/outputs/Sink.java | 20 ++++++++++++++++ .../org/logstash/plugins/outputs/Stdout.java | 20 ++++++++++++++++ .../plugins/pipeline/AddressState.java | 20 ++++++++++++++++ .../plugins/pipeline/PipelineBus.java | 20 ++++++++++++++++ .../plugins/pipeline/PipelineInput.java | 20 ++++++++++++++++ .../plugins/pipeline/PipelineOutput.java | 20 ++++++++++++++++ .../org/logstash/secret/SecretIdentifier.java | 20 ++++++++++++++++ .../logstash/secret/cli/SecretStoreCli.java | 20 ++++++++++++++++ .../org/logstash/secret/cli/Terminal.java | 20 ++++++++++++++++ .../logstash/secret/store/SecretStore.java | 20 ++++++++++++++++ .../secret/store/SecretStoreException.java | 20 ++++++++++++++++ .../logstash/secret/store/SecretStoreExt.java | 20 ++++++++++++++++ .../secret/store/SecretStoreFactory.java | 20 ++++++++++++++++ .../secret/store/SecretStoreUtil.java | 20 ++++++++++++++++ .../logstash/secret/store/SecureConfig.java | 20 ++++++++++++++++ .../secret/store/backend/JavaKeyStore.java | 21 ++++++++++++++++- .../main/java/org/logstash/util/UtilExt.java | 20 ++++++++++++++++ .../test/java/org/logstash/AccessorsTest.java | 20 ++++++++++++++++ .../test/java/org/logstash/ClonerTest.java | 20 ++++++++++++++++ .../java/org/logstash/ConvertedMapTest.java | 20 ++++++++++++++++ .../test/java/org/logstash/DLQEntryTest.java | 20 ++++++++++++++++ .../src/test/java/org/logstash/EventTest.java | 20 ++++++++++++++++ .../java/org/logstash/FieldReferenceTest.java | 20 ++++++++++++++++ .../org/logstash/FileLockFactoryMain.java | 20 ++++++++++++++++ .../org/logstash/FileLockFactoryTest.java | 20 ++++++++++++++++ .../test/java/org/logstash/JavafierTest.java | 20 ++++++++++++++++ .../test/java/org/logstash/KeyNodeTest.java | 20 ++++++++++++++++ .../test/java/org/logstash/RSpecTests.java | 20 ++++++++++++++++ .../test/java/org/logstash/RubyfierTest.java | 20 ++++++++++++++++ .../org/logstash/StringInterpolationTest.java | 20 ++++++++++++++++ .../test/java/org/logstash/TimestampTest.java | 20 ++++++++++++++++ .../test/java/org/logstash/ValuefierTest.java | 20 ++++++++++++++++ .../logstash/ackedqueue/CheckpointTest.java | 20 ++++++++++++++++ .../org/logstash/ackedqueue/HeadPageTest.java | 20 ++++++++++++++++ .../org/logstash/ackedqueue/PqRepairTest.java | 20 ++++++++++++++++ .../org/logstash/ackedqueue/QueueTest.java | 20 ++++++++++++++++ .../logstash/ackedqueue/QueueTestHelpers.java | 20 ++++++++++++++++ .../logstash/ackedqueue/StringElement.java | 20 ++++++++++++++++ .../org/logstash/ackedqueue/TestSettings.java | 20 ++++++++++++++++ .../ackedqueue/io/FileCheckpointIOTest.java | 20 ++++++++++++++++ .../ackedqueue/io/FileMmapIOTest.java | 20 ++++++++++++++++ .../logstash/ackedqueue/io/IntVectorTest.java | 20 ++++++++++++++++ .../ackedqueue/io/LongVectorTest.java | 20 ++++++++++++++++ .../ackedqueue/io/MmapPageIOTest.java | 20 ++++++++++++++++ .../common/ConfigVariableExpanderTest.java | 20 ++++++++++++++++ .../common/DeadLetterQueueFactoryTest.java | 20 ++++++++++++++++ .../java/org/logstash/common/FsUtilTest.java | 20 ++++++++++++++++ .../common/SourceWithMetadataTest.java | 20 ++++++++++++++++ .../common/io/DeadLetterQueueReaderTest.java | 20 ++++++++++++++++ .../common/io/DeadLetterQueueWriterTest.java | 20 ++++++++++++++++ .../common/io/RecordIOReaderTest.java | 20 ++++++++++++++++ .../common/io/RecordIOWriterTest.java | 20 ++++++++++++++++ .../config/ir/CompiledPipelineTest.java | 20 ++++++++++++++++ .../config/ir/ConfigCompilerTest.java | 20 ++++++++++++++++ .../config/ir/EventConditionTest.java | 20 ++++++++++++++++ .../org/logstash/config/ir/IRHelpers.java | 20 ++++++++++++++++ .../logstash/config/ir/PipelineIRTest.java | 20 ++++++++++++++++ .../logstash/config/ir/PipelineTestUtil.java | 20 ++++++++++++++++ .../ir/PluginConfigNameMethodDouble.java | 20 ++++++++++++++++ .../logstash/config/ir/RubyEnvTestCase.java | 20 ++++++++++++++++ .../config/ir/compiler/CommonActionsTest.java | 20 ++++++++++++++++ .../ir/compiler/DatasetCompilerTest.java | 20 ++++++++++++++++ .../config/ir/compiler/FakeOutClass.java | 20 ++++++++++++++++ .../ir/compiler/JavaCodecDelegatorTest.java | 20 ++++++++++++++++ .../ir/compiler/OutputDelegatorTest.java | 20 ++++++++++++++++ .../ir/compiler/PluginDelegatorTestCase.java | 20 ++++++++++++++++ .../config/ir/compiler/PluginFactoryTest.java | 20 ++++++++++++++++ .../config/ir/graph/BooleanEdgeTest.java | 20 ++++++++++++++++ .../logstash/config/ir/graph/EdgeTest.java | 20 ++++++++++++++++ .../logstash/config/ir/graph/GraphTest.java | 20 ++++++++++++++++ .../config/ir/graph/IfVertexTest.java | 20 ++++++++++++++++ .../config/ir/graph/PlainEdgeTest.java | 20 ++++++++++++++++ .../config/ir/graph/PluginVertexTest.java | 20 ++++++++++++++++ .../config/ir/graph/QueueVertexTest.java | 20 ++++++++++++++++ .../logstash/config/ir/graph/VertexTest.java | 20 ++++++++++++++++ .../ir/graph/algorithms/BreadthFirstTest.java | 20 ++++++++++++++++ .../ir/graph/algorithms/DepthFirstTest.java | 20 ++++++++++++++++ .../ir/graph/algorithms/GraphDiffTest.java | 20 ++++++++++++++++ .../graph/algorithms/TopologicalSortTest.java | 20 ++++++++++++++++ .../config/ir/imperative/DSLTest.java | 20 ++++++++++++++++ .../config/ir/imperative/IfStatementTest.java | 20 ++++++++++++++++ .../ir/imperative/ImperativeToGraphtest.java | 20 ++++++++++++++++ .../execution/ShutdownWatcherExtTest.java | 20 ++++++++++++++++ .../ext/JrubyEventExtLibraryTest.java | 20 ++++++++++++++++ .../ext/JrubyMemoryReadClientExtTest.java | 20 ++++++++++++++++ .../ext/JrubyTimestampExtLibraryTest.java | 20 ++++++++++++++++ .../java/org/logstash/ext/TimestampTest.java | 20 ++++++++++++++++ .../instrument/metrics/MetricTypeTest.java | 20 ++++++++++++++++ .../metrics/counter/LongCounterTest.java | 20 ++++++++++++++++ .../metrics/gauge/BooleanGaugeTest.java | 20 ++++++++++++++++ .../gauge/LazyDelegatingGaugeTest.java | 20 ++++++++++++++++ .../metrics/gauge/NumberGaugeTest.java | 20 ++++++++++++++++ .../metrics/gauge/RubyHashGaugeTest.java | 20 ++++++++++++++++ .../metrics/gauge/RubyTimeStampGaugeTest.java | 20 ++++++++++++++++ .../metrics/gauge/TextGaugeTest.java | 20 ++++++++++++++++ .../metrics/gauge/UnknownGaugeTest.java | 20 ++++++++++++++++ .../monitors/HotThreadMonitorTest.java | 20 ++++++++++++++++ .../monitors/MemoryMonitorTest.java | 20 ++++++++++++++++ .../monitors/ProcessMonitorTest.java | 20 ++++++++++++++++ .../monitors/SystemMonitorTest.java | 20 ++++++++++++++++ .../org/logstash/log/CustomLogEventTests.java | 20 ++++++++++++++++ .../log/DefaultDeprecationLoggerTest.java | 20 ++++++++++++++++ .../java/org/logstash/log/LogTestUtils.java | 20 ++++++++++++++++ .../log/LogstashConfigurationFactoryTest.java | 20 ++++++++++++++++ .../log/LogstashLoggerContextFactoryTest.java | 20 ++++++++++++++++ .../log/PluginDeprecationLoggerTest.java | 20 ++++++++++++++++ .../log/SystemPropsSnapshotHelper.java | 20 ++++++++++++++++ .../log/TestingDeprecationPlugin.java | 20 ++++++++++++++++ .../plugins/ConfigurationImplTest.java | 20 ++++++++++++++++ .../plugins/CounterMetricImplTest.java | 20 ++++++++++++++++ .../org/logstash/plugins/MetricTestCase.java | 20 ++++++++++++++++ .../plugins/NamespacedMetricImplTest.java | 20 ++++++++++++++++ .../plugins/PluginFactoryExtTest.java | 20 ++++++++++++++++ .../plugins/PluginUtilValidateConfigTest.java | 23 ++++++++++++++++--- .../logstash/plugins/PluginValidatorTest.java | 20 ++++++++++++++++ .../org/logstash/plugins/TestContext.java | 20 ++++++++++++++++ .../logstash/plugins/TestPluginFactory.java | 20 ++++++++++++++++ .../org/logstash/plugins/TestingPlugin.java | 20 ++++++++++++++++ .../org/logstash/plugins/codecs/LineTest.java | 21 ++++++++++++++++- .../logstash/plugins/codecs/PlainTest.java | 20 ++++++++++++++++ .../plugins/codecs/TestEventConsumer.java | 20 ++++++++++++++++ .../logstash/plugins/filters/UuidTest.java | 20 ++++++++++++++++ .../logstash/plugins/inputs/StdinTest.java | 20 ++++++++++++++++ .../logstash/plugins/outputs/StdoutTest.java | 20 ++++++++++++++++ .../plugins/pipeline/PipelineBusTest.java | 20 ++++++++++++++++ .../logstash/secret/SecretIdentifierTest.java | 20 ++++++++++++++++ .../secret/cli/SecretStoreCliTest.java | 20 ++++++++++++++++ .../secret/store/SecretStoreFactoryTest.java | 20 ++++++++++++++++ .../secret/store/SecretStoreUtilTest.java | 20 ++++++++++++++++ .../secret/store/SecureConfigTest.java | 20 ++++++++++++++++ .../store/backend/JavaKeyStoreTest.java | 20 ++++++++++++++++ .../configuration/logstash/fb_apache.conf.erb | 17 ++++++++++++++ modules/fb_apache/lib/logstash_registry.rb | 17 ++++++++++++++ .../configuration/logstash/netflow.conf.erb | 17 ++++++++++++++ modules/netflow/lib/logstash_registry.rb | 17 ++++++++++++++ qa/Rakefile | 17 ++++++++++++++ qa/acceptance/spec/config_helper.rb | 18 ++++++++++++++- .../spec/lib/artifact_operation_spec.rb | 18 ++++++++++++++- qa/acceptance/spec/lib/cli_operation_spec.rb | 18 ++++++++++++++- .../cli/logstash-plugin/generate.rb | 18 ++++++++++++++- .../cli/logstash-plugin/install.rb | 18 ++++++++++++++- .../cli/logstash-plugin/integration_plugin.rb | 18 ++++++++++++++- .../cli/logstash-plugin/list.rb | 18 ++++++++++++++- .../cli/logstash-plugin/remove.rb | 18 ++++++++++++++- .../cli/logstash-plugin/uninstall.rb | 18 ++++++++++++++- .../cli/logstash-plugin/update.rb | 18 ++++++++++++++- .../shared_examples/cli/logstash/version.rb | 18 ++++++++++++++- .../spec/shared_examples/installed.rb | 17 ++++++++++++++ qa/acceptance/spec/shared_examples/running.rb | 17 ++++++++++++++ qa/acceptance/spec/shared_examples/updated.rb | 17 ++++++++++++++ qa/acceptance/spec/spec_helper.rb | 18 ++++++++++++++- qa/integration/build.gradle | 19 +++++++++++++++ .../fixtures/logstash-dummy-pack/Rakefile | 18 ++++++++++++++- .../lib/logstash/outputs/secret.rb | 18 ++++++++++++++- .../spec/outputs/secret_spec.rb | 18 ++++++++++++++- qa/integration/framework/fixture.rb | 17 ++++++++++++++ qa/integration/framework/helpers.rb | 18 ++++++++++++++- qa/integration/framework/settings.rb | 17 ++++++++++++++ .../patch/childprocess-modern-java.rb | 19 +++++++++++++-- qa/integration/rspec.rb | 17 +++++++++++++- .../services/elasticsearch_service.rb | 17 ++++++++++++++ qa/integration/services/filebeat_service.rb | 18 ++++++++++++++- qa/integration/services/http_proxy_service.rb | 18 ++++++++++++++- qa/integration/services/kafka_service.rb | 17 ++++++++++++++ qa/integration/services/logstash_service.rb | 17 ++++++++++++++ qa/integration/services/monitoring_api.rb | 17 ++++++++++++++ qa/integration/services/service.rb | 17 ++++++++++++++ qa/integration/services/service_locator.rb | 18 ++++++++++++++- .../specs/01_logstash_bin_smoke_spec.rb | 17 ++++++++++++++ qa/integration/specs/beats_input_spec.rb | 17 ++++++++++++++ .../specs/cli/http_proxy_install_spec.rb | 18 ++++++++++++++- qa/integration/specs/cli/install_spec.rb | 18 ++++++++++++++- .../specs/cli/prepare_offline_pack_spec.rb | 18 ++++++++++++++- qa/integration/specs/cli/remove_spec.rb | 18 ++++++++++++++- qa/integration/specs/command_line_spec.rb | 18 ++++++++++++++- qa/integration/specs/deprecation_log_spec.rb | 17 ++++++++++++++ qa/integration/specs/dlq_spec.rb | 17 ++++++++++++++ .../specs/env_variables_config_spec.rb | 17 ++++++++++++++ qa/integration/specs/es_output_how_spec.rb | 17 ++++++++++++++ qa/integration/specs/java_api_spec.rb | 17 ++++++++++++++ qa/integration/specs/kafka_input_spec.rb | 17 ++++++++++++++ qa/integration/specs/monitoring_api_spec.rb | 17 ++++++++++++++ .../specs/multiple_pipeline_spec.rb | 17 ++++++++++++++ qa/integration/specs/pipeline_log_spec.rb | 17 ++++++++++++++ qa/integration/specs/plugin_name_log_spec.rb | 17 ++++++++++++++ qa/integration/specs/reload_config_spec.rb | 17 ++++++++++++++ qa/integration/specs/secret_store_spec.rb | 17 ++++++++++++++ qa/integration/specs/settings_spec.rb | 17 ++++++++++++++ qa/integration/specs/slowlog_spec.rb | 17 ++++++++++++++ qa/integration/specs/spec_helper.rb | 18 ++++++++++++++- .../org/logstash/integration/RSpecTests.java | 20 ++++++++++++++++ qa/platform_config.rb | 18 ++++++++++++++- qa/rspec/commands.rb | 18 ++++++++++++++- qa/rspec/commands/base.rb | 18 ++++++++++++++- qa/rspec/commands/centos/centos-6.rb | 18 ++++++++++++++- qa/rspec/commands/debian.rb | 18 ++++++++++++++- qa/rspec/commands/oel/oel-6.rb | 18 ++++++++++++++- qa/rspec/commands/redhat.rb | 18 ++++++++++++++- qa/rspec/commands/suse.rb | 18 ++++++++++++++- qa/rspec/commands/suse/sles-11.rb | 18 ++++++++++++++- qa/rspec/commands/system_helpers.rb | 17 ++++++++++++++ qa/rspec/commands/ubuntu.rb | 18 ++++++++++++++- qa/rspec/commands/ubuntu/ubuntu-1604.rb | 18 ++++++++++++++- qa/rspec/helpers.rb | 18 ++++++++++++++- qa/rspec/matchers.rb | 18 ++++++++++++++- qa/rspec/matchers/be_installed.rb | 18 ++++++++++++++- qa/rspec/matchers/be_running.rb | 18 ++++++++++++++- qa/rspec/matchers/cli_matchers.rb | 18 ++++++++++++++- qa/vagrant/command.rb | 18 ++++++++++++++- qa/vagrant/helpers.rb | 18 ++++++++++++++- rakelib/artifacts.rake | 17 ++++++++++++++ rakelib/bootstrap.rake | 17 ++++++++++++++ rakelib/build.rake | 17 ++++++++++++++ rakelib/childprocess_patch.rb | 17 ++++++++++++++ rakelib/compile.rake | 16 +++++++++++++ rakelib/default_plugins.rb | 17 ++++++++++++++ rakelib/dependency.rake | 17 ++++++++++++++ rakelib/docs.rake | 18 ++++++++++++++- rakelib/gems.rake | 17 ++++++++++++++ rakelib/modules.rake | 17 ++++++++++++++ rakelib/plugin.rake | 17 ++++++++++++++ rakelib/plugins_docs_dependencies.rake | 18 ++++++++++++++- rakelib/test.rake | 17 ++++++++++++++ rakelib/vendor.rake | 17 ++++++++++++++ rakelib/version.rake | 17 ++++++++++++++ rakelib/z_rubycheck.rake | 17 ++++++++++++++ rubyUtils.gradle | 19 +++++++++++++++ spec/bootstrap/environment_spec.rb | 18 ++++++++++++++- spec/compliance/license_spec.rb | 17 +++++++++++++- spec/spec_helper.rb | 18 +++++++++++++-- spec/support/resource_dsl_methods.rb | 17 ++++++++++++++ spec/unit/bootstrap/bundler_spec.rb | 18 ++++++++++++++- .../unit/plugin_manager/gem_installer_spec.rb | 18 ++++++++++++++- spec/unit/plugin_manager/gemfile_spec.rb | 18 ++++++++++++++- spec/unit/plugin_manager/install_spec.rb | 18 ++++++++++++++- .../install_strategy_factory_spec.rb | 18 ++++++++++++++- .../offline_plugin_packager_spec.rb | 18 ++++++++++++++- .../pack_fetch_strategy/repository_spec.rb | 18 ++++++++++++++- .../pack_fetch_strategy/uri_spec.rb | 18 ++++++++++++++- .../pack_installer/local_spec.rb | 18 ++++++++++++++- .../pack_installer/pack_spec.rb | 18 ++++++++++++++- .../pack_installer/remote_spec.rb | 18 ++++++++++++++- .../prepare_offline_pack_spec.rb | 18 ++++++++++++++- .../unit/plugin_manager/proxy_support_spec.rb | 18 ++++++++++++++- spec/unit/plugin_manager/ui_spec.rb | 18 ++++++++++++++- spec/unit/plugin_manager/update_spec.rb | 18 ++++++++++++++- spec/unit/plugin_manager/util_spec.rb | 18 ++++++++++++++- .../plugin_manager/utils/downloader_spec.rb | 18 ++++++++++++++- .../plugin_manager/utils/http_client_spec.rb | 18 ++++++++++++++- spec/unit/util/compress_spec.rb | 18 ++++++++++++++- tools/benchmark-cli/build.gradle | 19 +++++++++++++++ .../logstash/benchmark/cli/BenchmarkMeta.java | 20 ++++++++++++++++ .../org/logstash/benchmark/cli/DataStore.java | 20 ++++++++++++++++ .../benchmark/cli/JRubyInstallation.java | 20 ++++++++++++++++ .../benchmark/cli/LogstashInstallation.java | 20 ++++++++++++++++ .../benchmark/cli/LsBenchSettings.java | 20 ++++++++++++++++ .../benchmark/cli/LsMetricsMonitor.java | 20 ++++++++++++++++ .../java/org/logstash/benchmark/cli/Main.java | 20 ++++++++++++++++ .../cli/cases/ApacheLogsComplex.java | 20 ++++++++++++++++ .../logstash/benchmark/cli/cases/Case.java | 20 ++++++++++++++++ .../benchmark/cli/cases/CustomTestCase.java | 20 ++++++++++++++++ .../cli/cases/GeneratorToStdout.java | 20 ++++++++++++++++ .../benchmark/cli/ui/LsMetricStats.java | 20 ++++++++++++++++ .../benchmark/cli/ui/LsVersionType.java | 20 ++++++++++++++++ .../logstash/benchmark/cli/ui/UserInput.java | 20 ++++++++++++++++ .../logstash/benchmark/cli/ui/UserOutput.java | 20 ++++++++++++++++ .../cli/util/LsBenchCompressUtil.java | 20 ++++++++++++++++ .../benchmark/cli/util/LsBenchDownloader.java | 20 ++++++++++++++++ .../benchmark/cli/util/LsBenchFileUtil.java | 20 ++++++++++++++++ .../benchmark/cli/util/LsBenchJsonUtil.java | 20 ++++++++++++++++ .../benchmark/cli/util/LsBenchLsSetup.java | 20 ++++++++++++++++ .../benchmark/cli/LsMetricsMonitorTest.java | 20 ++++++++++++++++ .../benchmark/cli/MainEsStorageTest.java | 20 ++++++++++++++++ .../org/logstash/benchmark/cli/MainTest.java | 20 ++++++++++++++++ tools/dependencies-report/build.gradle | 19 +++++++++++++++ .../org/logstash/dependencies/Dependency.java | 20 ++++++++++++++++ .../java/org/logstash/dependencies/Main.java | 20 ++++++++++++++++ .../dependencies/ReportGenerator.java | 20 ++++++++++++++++ .../dependencies/ReportGeneratorTest.java | 21 ++++++++++++++++- tools/ingest-converter/build.gradle | 19 +++++++++++++++ .../main/java/org/logstash/ingest/Append.java | 20 ++++++++++++++++ .../java/org/logstash/ingest/Convert.java | 20 ++++++++++++++++ .../main/java/org/logstash/ingest/Date.java | 20 ++++++++++++++++ .../main/java/org/logstash/ingest/GeoIp.java | 20 ++++++++++++++++ .../main/java/org/logstash/ingest/Grok.java | 20 ++++++++++++++++ .../main/java/org/logstash/ingest/Gsub.java | 20 ++++++++++++++++ .../main/java/org/logstash/ingest/JsUtil.java | 20 ++++++++++++++++ .../main/java/org/logstash/ingest/Json.java | 20 ++++++++++++++++ .../java/org/logstash/ingest/Lowercase.java | 20 ++++++++++++++++ .../java/org/logstash/ingest/Pipeline.java | 20 ++++++++++++++++ .../main/java/org/logstash/ingest/Rename.java | 20 ++++++++++++++++ .../main/java/org/logstash/ingest/Set.java | 20 ++++++++++++++++ .../java/org/logstash/ingest/AppendTest.java | 20 ++++++++++++++++ .../java/org/logstash/ingest/ConvertTest.java | 20 ++++++++++++++++ .../java/org/logstash/ingest/DateTest.java | 20 ++++++++++++++++ .../java/org/logstash/ingest/GeoIpTest.java | 20 ++++++++++++++++ .../java/org/logstash/ingest/GrokTest.java | 20 ++++++++++++++++ .../java/org/logstash/ingest/GsubTest.java | 20 ++++++++++++++++ .../java/org/logstash/ingest/IngestTest.java | 20 ++++++++++++++++ .../java/org/logstash/ingest/JsonTest.java | 20 ++++++++++++++++ .../org/logstash/ingest/LowercaseTest.java | 20 ++++++++++++++++ .../org/logstash/ingest/PipelineTest.java | 20 ++++++++++++++++ .../java/org/logstash/ingest/RenameTest.java | 20 ++++++++++++++++ .../java/org/logstash/ingest/SetTest.java | 20 ++++++++++++++++ tools/logstash-docgen/Rakefile | 17 ++++++++++++++ tools/logstash-docgen/bin/extract_doc.rb | 18 ++++++++++++++- tools/logstash-docgen/lib/logstash/docgen.rb | 17 ++++++++++++++ .../lib/logstash/docgen/asciidoc_format.rb | 18 ++++++++++++++- .../lib/logstash/docgen/dependency_lookup.rb | 18 ++++++++++++++- .../lib/logstash/docgen/dynamic_parser.rb | 18 ++++++++++++++- .../lib/logstash/docgen/github_generator.rb | 18 ++++++++++++++- .../lib/logstash/docgen/index.rb | 18 ++++++++++++++- .../lib/logstash/docgen/logstash_generator.rb | 18 ++++++++++++++- .../lib/logstash/docgen/parser.rb | 18 ++++++++++++++- .../lib/logstash/docgen/plugin_doc.rb | 18 ++++++++++++++- .../lib/logstash/docgen/runner.rb | 18 ++++++++++++++- .../lib/logstash/docgen/static_parser.rb | 18 ++++++++++++++- .../lib/logstash/docgen/task_runner.rb | 18 ++++++++++++++- .../lib/logstash/docgen/util.rb | 18 ++++++++++++++- .../lib/logstash/docgen/version.rb | 17 ++++++++++++++ .../spec/fixtures/plugins_source/base.rb | 17 ++++++++++++++ .../plugins_source/config_from_mixin.rb | 17 +++++++++++++- .../plugins_source/new_style_header.rb | 20 +++++++++++++--- .../plugins_source/old_style_header.rb | 20 +++++++++++++--- .../logstash/docgen/dependency_lookup_spec.rb | 17 +++++++++++++- .../spec/logstash/docgen/task_runner_spec.rb | 18 ++++++++++++++- .../spec/logstash/docgen/util_spec.rb | 18 ++++++++++++++- tools/logstash-docgen/spec/spec_helper.rb | 17 +++++++++++++- tools/logstash-docgen/spec/support/helpers.rb | 17 +++++++++++++- .../templates/index-codecs.asciidoc.erb | 17 ++++++++++++++ .../templates/index-filters.asciidoc.erb | 17 ++++++++++++++ .../templates/index-inputs.asciidoc.erb | 17 ++++++++++++++ .../templates/index-outputs.asciidoc.erb | 17 ++++++++++++++ .../templates/plugin-doc.asciidoc.erb | 17 ++++++++++++++ tools/paquet/README.md | 1 - tools/paquet/Rakefile | 17 ++++++++++++++ tools/paquet/lib/paquet.rb | 18 ++++++++++++++- tools/paquet/lib/paquet/dependency.rb | 17 ++++++++++++++ tools/paquet/lib/paquet/gem.rb | 18 ++++++++++++++- tools/paquet/lib/paquet/rspec/tasks.rb | 18 ++++++++++++++- tools/paquet/lib/paquet/shell_ui.rb | 18 ++++++++++++++- tools/paquet/lib/paquet/utils.rb | 18 ++++++++++++++- tools/paquet/lib/paquet/version.rb | 17 ++++++++++++++ tools/paquet/spec/integration/paquet_spec.rb | 18 ++++++++++++++- tools/paquet/spec/paquet/dependency_spec.rb | 18 ++++++++++++++- tools/paquet/spec/paquet/gem_spec.rb | 18 ++++++++++++++- tools/paquet/spec/paquet/shell_ui_spec.rb | 18 ++++++++++++++- tools/paquet/spec/paquet/utils_spec.rb | 18 ++++++++++++++- tools/paquet/spec/spec_helper.rb | 18 ++++++++++++++- tools/paquet/spec/support/Rakefile | 18 ++++++++++++++- tools/release/bump_plugin_versions.rb | 18 ++++++++++++++- tools/release/generate_release_notes.rb | 20 ++++++++++++++-- x-pack/build.gradle | 6 +++++ .../inputs/metrics/state_event_factory.rb | 3 +-- .../inputs/metrics/stats_event_factory.rb | 2 +- .../configuration/logstash/arcsight.conf.erb | 2 +- .../modules/azure/lib/filters/azure_event.rb | 1 - x-pack/qa/integration/spec_helper.rb | 1 - .../arcsight_module_config_helper_spec.rb | 4 ---- .../xpack/test/RSpecIntegrationTests.java | 7 ++++++ .../org/logstash/xpack/test/RSpecTests.java | 7 ++++++ 938 files changed, 17047 insertions(+), 446 deletions(-) diff --git a/Rakefile b/Rakefile index 71f49fe54..c5001c177 100644 --- a/Rakefile +++ b/Rakefile @@ -1,4 +1,19 @@ -# encoding: utf-8 +# 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. $: << File.join(File.dirname(__FILE__), "lib") $: << File.join(File.dirname(__FILE__), "logstash-core/lib") diff --git a/build.gradle b/build.gradle index 22d217363..8928e8abd 100644 --- a/build.gradle +++ b/build.gradle @@ -1,3 +1,22 @@ +/* + * 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. + */ + buildscript { repositories { mavenCentral() diff --git a/docs/static/contributing-patch.asciidoc b/docs/static/contributing-patch.asciidoc index c126e0bdc..011c82464 100644 --- a/docs/static/contributing-patch.asciidoc +++ b/docs/static/contributing-patch.asciidoc @@ -90,7 +90,6 @@ sources. . Rspec Example [source,ruby] - 1 # encoding: utf-8 2 require "logstash/devutils/rspec/spec_helper" 3 require "logstash/plugin" 4 @@ -252,11 +251,10 @@ https://howistart.org/posts/ruby/1[environment]. The `chruby` tool manages Ruby + NOTE: Line 21 of `util/zeromq.rb` reads `@logger.info("0mq: #{server? ? 'connected' : 'bound'}", :address => address)` -. In the text editor, set the file encoding and require `zeromq.rb` for the file `zeromq_spec.rb` by adding the following +. In the text editor, require `zeromq.rb` for the file `zeromq_spec.rb` by adding the following lines: + [source,ruby] -# encoding: utf-8 require "logstash/outputs/zeromq" require "logstash/devutils/rspec/spec_helper" @@ -303,7 +301,6 @@ At the end of the modifications, the relevant code section reads: [source,ruby] -------- -# encoding: utf-8 require "logstash/outputs/zeromq" require "logstash/devutils/rspec/spec_helper" diff --git a/docs/static/include/pluginbody.asciidoc b/docs/static/include/pluginbody.asciidoc index 66475d822..892e9b8c9 100644 --- a/docs/static/include/pluginbody.asciidoc +++ b/docs/static/include/pluginbody.asciidoc @@ -105,7 +105,6 @@ ifndef::blockinput[] [source,ruby] [subs="attributes"] ---------------------------------- -# encoding: utf-8 require "logstash/{plugintype}s/base" require "logstash/namespace" require "stud/interval" @@ -157,7 +156,6 @@ ifndef::blockcodec[] [source,ruby] [subs="attributes"] ---------------------------------- -# encoding: utf-8 require "logstash/{plugintype}s/base" require "logstash/codecs/line" @@ -216,7 +214,6 @@ ifndef::blockfilter[] [source,ruby] [subs="attributes"] ---------------------------------- -# encoding: utf-8 require "logstash/{plugintype}s/base" require "logstash/namespace" @@ -270,7 +267,6 @@ ifdef::multi_receive_method[] [source,ruby] [subs="attributes"] ---------------------------------- -# encoding: utf-8 require "logstash/{plugintype}s/base" require "logstash/namespace" @@ -312,19 +308,6 @@ endif::multi_receive_method[] Now let's take a line-by-line look at the example plugin. -===== `encoding` - -It seems like a small thing, but remember to specify the encoding at the -beginning of your plugin code: - -[source,sh] ----------------------------------- -# encoding: utf-8 ----------------------------------- - -Logstash depends on things being in UTF-8, so we put this here to tell the Ruby -interpreter that we’re going to be using the UTF-8 encoding. - ===== `require` Statements Logstash {plugintype} plugins require parent classes defined in diff --git a/lib/bootstrap/bundler.rb b/lib/bootstrap/bundler.rb index 88fe8a3a8..19a16f7d5 100644 --- a/lib/bootstrap/bundler.rb +++ b/lib/bootstrap/bundler.rb @@ -1,4 +1,19 @@ -# encoding: utf-8 +# 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 "fileutils" diff --git a/lib/bootstrap/environment.rb b/lib/bootstrap/environment.rb index 513ef7711..cd86574b1 100644 --- a/lib/bootstrap/environment.rb +++ b/lib/bootstrap/environment.rb @@ -1,8 +1,23 @@ -# encoding: utf-8 +# 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. + # bootstrap.rb contains the minimal code to be able to launch Bundler to eventually be able # to retrieve the core code in the logstash-core gem which can live under different paths # depending on the launch context (local dev, packaged, etc) - require_relative "bundler" require_relative "rubygems" require "pathname" diff --git a/lib/bootstrap/patches/gems.rb b/lib/bootstrap/patches/gems.rb index 94154a513..8c15eeae1 100644 --- a/lib/bootstrap/patches/gems.rb +++ b/lib/bootstrap/patches/gems.rb @@ -1,4 +1,20 @@ -# encoding: utf-8 +# 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 "gems" # This patch is necessary to avoid encoding problems when Net:HTTP return stuff in ASCII format, but @@ -13,4 +29,3 @@ module Gems end end end - diff --git a/lib/bootstrap/patches/jar_dependencies.rb b/lib/bootstrap/patches/jar_dependencies.rb index 2908ab73a..07b6c04b7 100644 --- a/lib/bootstrap/patches/jar_dependencies.rb +++ b/lib/bootstrap/patches/jar_dependencies.rb @@ -1,4 +1,20 @@ -# encoding: utf-8 +# 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 "jar_dependencies" def require_jar( *args ) diff --git a/lib/bootstrap/patches/remote_fetcher.rb b/lib/bootstrap/patches/remote_fetcher.rb index d780d15c4..7598278dc 100644 --- a/lib/bootstrap/patches/remote_fetcher.rb +++ b/lib/bootstrap/patches/remote_fetcher.rb @@ -1,3 +1,20 @@ +# 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 'rubygems/remote_fetcher' class Gem::RemoteFetcher diff --git a/lib/bootstrap/rspec.rb b/lib/bootstrap/rspec.rb index 4bda1ac38..14f370388 100755 --- a/lib/bootstrap/rspec.rb +++ b/lib/bootstrap/rspec.rb @@ -1,4 +1,20 @@ -# encoding: utf-8 +# 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 "environment" LogStash::Bundler.setup!({:without => [:build]}) require "logstash-core" diff --git a/lib/bootstrap/rubygems.rb b/lib/bootstrap/rubygems.rb index 985b2cf88..433e9fc46 100644 --- a/lib/bootstrap/rubygems.rb +++ b/lib/bootstrap/rubygems.rb @@ -1,4 +1,20 @@ -# encoding: utf-8 +# 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. + module LogStash module Rubygems extend self diff --git a/lib/bootstrap/util/compress.rb b/lib/bootstrap/util/compress.rb index 1d9f04b22..db016aaab 100644 --- a/lib/bootstrap/util/compress.rb +++ b/lib/bootstrap/util/compress.rb @@ -1,4 +1,20 @@ -# encoding: utf-8 +# 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 "zip" require "rubygems/package" require "fileutils" diff --git a/lib/pluginmanager/bundler/logstash_injector.rb b/lib/pluginmanager/bundler/logstash_injector.rb index 33286a74a..dc0b89dd7 100644 --- a/lib/pluginmanager/bundler/logstash_injector.rb +++ b/lib/pluginmanager/bundler/logstash_injector.rb @@ -1,4 +1,20 @@ -# encoding: utf-8 +# 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 "bootstrap/environment" require "bundler" require "bundler/definition" diff --git a/lib/pluginmanager/bundler/logstash_uninstall.rb b/lib/pluginmanager/bundler/logstash_uninstall.rb index d77bd9512..792a7def2 100644 --- a/lib/pluginmanager/bundler/logstash_uninstall.rb +++ b/lib/pluginmanager/bundler/logstash_uninstall.rb @@ -1,4 +1,20 @@ -# encoding: utf-8 +# 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 "bootstrap/environment" require "bundler" require "bundler/definition" diff --git a/lib/pluginmanager/command.rb b/lib/pluginmanager/command.rb index fa4d40dc8..1e37fae93 100644 --- a/lib/pluginmanager/command.rb +++ b/lib/pluginmanager/command.rb @@ -1,4 +1,20 @@ -# encoding: utf-8 +# 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. + class LogStash::PluginManager::Command < Clamp::Command def gemfile @gemfile ||= LogStash::Gemfile.new(File.new(LogStash::Environment::GEMFILE_PATH, 'r+')).load diff --git a/lib/pluginmanager/errors.rb b/lib/pluginmanager/errors.rb index 691c8b675..7a10957ff 100644 --- a/lib/pluginmanager/errors.rb +++ b/lib/pluginmanager/errors.rb @@ -1,4 +1,20 @@ -# encoding: utf-8 +# 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. + module LogStash module PluginManager class PluginManagerError < StandardError; end class PluginNotFoundError < PluginManagerError; end diff --git a/lib/pluginmanager/gem_installer.rb b/lib/pluginmanager/gem_installer.rb index 4e2ccec51..bcf961205 100644 --- a/lib/pluginmanager/gem_installer.rb +++ b/lib/pluginmanager/gem_installer.rb @@ -1,4 +1,20 @@ -# encoding: utf-8 +# 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 "pluginmanager/ui" require "pathname" require "rubygems/package" diff --git a/lib/pluginmanager/gemfile.rb b/lib/pluginmanager/gemfile.rb index d0ab77048..3a0d3a55b 100644 --- a/lib/pluginmanager/gemfile.rb +++ b/lib/pluginmanager/gemfile.rb @@ -1,4 +1,20 @@ -# encoding: utf-8 +# 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. + module LogStash class GemfileError < StandardError; end diff --git a/lib/pluginmanager/generate.rb b/lib/pluginmanager/generate.rb index 6717682e0..a536f4913 100644 --- a/lib/pluginmanager/generate.rb +++ b/lib/pluginmanager/generate.rb @@ -1,4 +1,20 @@ -# encoding: utf-8 +# 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 "pluginmanager/command" require "pluginmanager/templates/render_context" require "erb" diff --git a/lib/pluginmanager/install.rb b/lib/pluginmanager/install.rb index 43631a8c6..a6f080fea 100644 --- a/lib/pluginmanager/install.rb +++ b/lib/pluginmanager/install.rb @@ -1,4 +1,20 @@ -# encoding: utf-8 +# 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 "pluginmanager/command" require "pluginmanager/install_strategy_factory" require "pluginmanager/ui" diff --git a/lib/pluginmanager/install_strategy_factory.rb b/lib/pluginmanager/install_strategy_factory.rb index 81da776e1..01e657305 100644 --- a/lib/pluginmanager/install_strategy_factory.rb +++ b/lib/pluginmanager/install_strategy_factory.rb @@ -1,4 +1,20 @@ -# encoding: utf-8 +# 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 "pluginmanager/ui" require "pluginmanager/x_pack_interceptor" require "pluginmanager/pack_fetch_strategy/repository" diff --git a/lib/pluginmanager/list.rb b/lib/pluginmanager/list.rb index c87332bd3..f89647f29 100644 --- a/lib/pluginmanager/list.rb +++ b/lib/pluginmanager/list.rb @@ -1,4 +1,20 @@ -# encoding: utf-8 +# 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 'rubygems/spec_fetcher' require "pluginmanager/command" diff --git a/lib/pluginmanager/main.rb b/lib/pluginmanager/main.rb index 598df0d38..5be3b9a83 100644 --- a/lib/pluginmanager/main.rb +++ b/lib/pluginmanager/main.rb @@ -1,4 +1,20 @@ -# encoding: utf-8 +# 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. + $LOAD_PATH.unshift(File.expand_path(File.join(__FILE__, "..", ".."))) require "bootstrap/environment" diff --git a/lib/pluginmanager/offline_plugin_packager.rb b/lib/pluginmanager/offline_plugin_packager.rb index 568f21d3e..305adb588 100644 --- a/lib/pluginmanager/offline_plugin_packager.rb +++ b/lib/pluginmanager/offline_plugin_packager.rb @@ -1,4 +1,20 @@ -# encoding: utf-8 +# 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 "pluginmanager/ui" require "pluginmanager/errors" require "bootstrap/environment" diff --git a/lib/pluginmanager/pack.rb b/lib/pluginmanager/pack.rb index 925216a36..134752787 100644 --- a/lib/pluginmanager/pack.rb +++ b/lib/pluginmanager/pack.rb @@ -1,4 +1,20 @@ -# encoding: utf-8 +# 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 "pack_command" class LogStash::PluginManager::Pack < LogStash::PluginManager::PackCommand diff --git a/lib/pluginmanager/pack_command.rb b/lib/pluginmanager/pack_command.rb index 3f4ed0b38..d9d2200fc 100644 --- a/lib/pluginmanager/pack_command.rb +++ b/lib/pluginmanager/pack_command.rb @@ -1,4 +1,20 @@ -# encoding: utf-8 +# 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 "bootstrap/util/compress" require "fileutils" diff --git a/lib/pluginmanager/pack_fetch_strategy/repository.rb b/lib/pluginmanager/pack_fetch_strategy/repository.rb index 52d1e3cee..dd13f9a20 100644 --- a/lib/pluginmanager/pack_fetch_strategy/repository.rb +++ b/lib/pluginmanager/pack_fetch_strategy/repository.rb @@ -1,4 +1,20 @@ -# encoding: utf-8 +# 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. + # In the context of the plugin manager no dependencies are currently loaded. # So we have to manually require the version file require_relative "../../../logstash-core/lib/logstash/version" diff --git a/lib/pluginmanager/pack_fetch_strategy/uri.rb b/lib/pluginmanager/pack_fetch_strategy/uri.rb index 9dfc19828..74c432886 100644 --- a/lib/pluginmanager/pack_fetch_strategy/uri.rb +++ b/lib/pluginmanager/pack_fetch_strategy/uri.rb @@ -1,4 +1,20 @@ -# encoding: utf-8 +# 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 "pluginmanager/utils/http_client" require "pluginmanager/pack_installer/local" require "pluginmanager/pack_installer/remote" diff --git a/lib/pluginmanager/pack_installer/local.rb b/lib/pluginmanager/pack_installer/local.rb index d5df1f1c5..7d7f82892 100644 --- a/lib/pluginmanager/pack_installer/local.rb +++ b/lib/pluginmanager/pack_installer/local.rb @@ -1,4 +1,20 @@ -# encoding: utf-8 +# 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 "pluginmanager/ui" require "pluginmanager/bundler/logstash_injector" require "pluginmanager/gem_installer" diff --git a/lib/pluginmanager/pack_installer/pack.rb b/lib/pluginmanager/pack_installer/pack.rb index 3090472db..7b05db598 100644 --- a/lib/pluginmanager/pack_installer/pack.rb +++ b/lib/pluginmanager/pack_installer/pack.rb @@ -1,4 +1,20 @@ -# encoding: utf-8 +# 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 "pluginmanager/errors" module LogStash module PluginManager module PackInstaller diff --git a/lib/pluginmanager/pack_installer/remote.rb b/lib/pluginmanager/pack_installer/remote.rb index 37cb52973..8e60e0e75 100644 --- a/lib/pluginmanager/pack_installer/remote.rb +++ b/lib/pluginmanager/pack_installer/remote.rb @@ -1,4 +1,20 @@ -# encoding: utf-8 +# 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 "pluginmanager/pack_installer/local" require "pluginmanager/utils/downloader" require "fileutils" diff --git a/lib/pluginmanager/prepare_offline_pack.rb b/lib/pluginmanager/prepare_offline_pack.rb index 45197b2b3..974a5b260 100644 --- a/lib/pluginmanager/prepare_offline_pack.rb +++ b/lib/pluginmanager/prepare_offline_pack.rb @@ -1,4 +1,20 @@ -# encoding: utf-8 +# 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 "pluginmanager/command" require "pluginmanager/errors" @@ -73,4 +89,3 @@ EOS end end end - diff --git a/lib/pluginmanager/proxy_support.rb b/lib/pluginmanager/proxy_support.rb index 14688c80a..7c1115a9f 100644 --- a/lib/pluginmanager/proxy_support.rb +++ b/lib/pluginmanager/proxy_support.rb @@ -1,4 +1,20 @@ -# encoding: utf-8 +# 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 "uri" require "java" require "erb" diff --git a/lib/pluginmanager/remove.rb b/lib/pluginmanager/remove.rb index f193bcd52..72fb35835 100644 --- a/lib/pluginmanager/remove.rb +++ b/lib/pluginmanager/remove.rb @@ -1,4 +1,20 @@ -# encoding: utf-8 +# 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 "pluginmanager/bundler/logstash_uninstall" require "pluginmanager/x_pack_interceptor.rb" require "pluginmanager/command" diff --git a/lib/pluginmanager/settings.xml.erb b/lib/pluginmanager/settings.xml.erb index 43df773d9..701bf5faa 100644 --- a/lib/pluginmanager/settings.xml.erb +++ b/lib/pluginmanager/settings.xml.erb @@ -1,3 +1,20 @@ +# 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. + [:build, :development]}) diff --git a/lib/systeminstall/pleasewrap.rb b/lib/systeminstall/pleasewrap.rb index f7ee00bd4..026bf8366 100755 --- a/lib/systeminstall/pleasewrap.rb +++ b/lib/systeminstall/pleasewrap.rb @@ -1,4 +1,20 @@ -# encoding: utf-8 +# 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. + $LOAD_PATH.unshift(File.expand_path(File.join(__FILE__, "..", ".."))) require "bootstrap/environment" diff --git a/logstash-core-plugin-api/lib/logstash-core-plugin-api/version.rb b/logstash-core-plugin-api/lib/logstash-core-plugin-api/version.rb index f240d0075..c21b973fd 100644 --- a/logstash-core-plugin-api/lib/logstash-core-plugin-api/version.rb +++ b/logstash-core-plugin-api/lib/logstash-core-plugin-api/version.rb @@ -1,4 +1,19 @@ -# encoding: utf-8 +# 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. # The version of logstash core plugin api gem. # diff --git a/logstash-core/benchmarks/build.gradle b/logstash-core/benchmarks/build.gradle index 99efbd904..00b6e4f8c 100644 --- a/logstash-core/benchmarks/build.gradle +++ b/logstash-core/benchmarks/build.gradle @@ -1,3 +1,22 @@ +/* + * 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. + */ + import org.yaml.snakeyaml.Yaml // fetch version from Logstash's master versions.yml file diff --git a/logstash-core/benchmarks/src/main/java/org/logstash/benchmark/EventSerializationBenchmark.java b/logstash-core/benchmarks/src/main/java/org/logstash/benchmark/EventSerializationBenchmark.java index 182cbe075..af7f62ade 100644 --- a/logstash-core/benchmarks/src/main/java/org/logstash/benchmark/EventSerializationBenchmark.java +++ b/logstash-core/benchmarks/src/main/java/org/logstash/benchmark/EventSerializationBenchmark.java @@ -1,3 +1,23 @@ +/* + * 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. + */ + + package org.logstash.benchmark; import java.io.DataOutputStream; diff --git a/logstash-core/benchmarks/src/main/java/org/logstash/benchmark/EventSprintfBenchmark.java b/logstash-core/benchmarks/src/main/java/org/logstash/benchmark/EventSprintfBenchmark.java index a55e39230..0d640328b 100644 --- a/logstash-core/benchmarks/src/main/java/org/logstash/benchmark/EventSprintfBenchmark.java +++ b/logstash-core/benchmarks/src/main/java/org/logstash/benchmark/EventSprintfBenchmark.java @@ -1,3 +1,23 @@ +/* + * 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. + */ + + package org.logstash.benchmark; import java.util.concurrent.TimeUnit; diff --git a/logstash-core/benchmarks/src/main/java/org/logstash/benchmark/LogPerPipelineBenchmark.java b/logstash-core/benchmarks/src/main/java/org/logstash/benchmark/LogPerPipelineBenchmark.java index d86566254..ad1b7f33c 100644 --- a/logstash-core/benchmarks/src/main/java/org/logstash/benchmark/LogPerPipelineBenchmark.java +++ b/logstash-core/benchmarks/src/main/java/org/logstash/benchmark/LogPerPipelineBenchmark.java @@ -1,3 +1,23 @@ +/* + * 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. + */ + + package org.logstash.benchmark; import org.apache.logging.log4j.LogManager; diff --git a/logstash-core/benchmarks/src/main/java/org/logstash/benchmark/QueueRWBenchmark.java b/logstash-core/benchmarks/src/main/java/org/logstash/benchmark/QueueRWBenchmark.java index 316025371..9ec20db66 100644 --- a/logstash-core/benchmarks/src/main/java/org/logstash/benchmark/QueueRWBenchmark.java +++ b/logstash-core/benchmarks/src/main/java/org/logstash/benchmark/QueueRWBenchmark.java @@ -1,3 +1,23 @@ +/* + * 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. + */ + + package org.logstash.benchmark; import com.google.common.io.Files; diff --git a/logstash-core/benchmarks/src/main/java/org/logstash/benchmark/QueueWriteBenchmark.java b/logstash-core/benchmarks/src/main/java/org/logstash/benchmark/QueueWriteBenchmark.java index c35c37f99..82ecfa215 100644 --- a/logstash-core/benchmarks/src/main/java/org/logstash/benchmark/QueueWriteBenchmark.java +++ b/logstash-core/benchmarks/src/main/java/org/logstash/benchmark/QueueWriteBenchmark.java @@ -1,3 +1,23 @@ +/* + * 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. + */ + + package org.logstash.benchmark; import com.google.common.io.Files; diff --git a/logstash-core/build.gradle b/logstash-core/build.gradle index f327b8d34..14ee22de0 100644 --- a/logstash-core/build.gradle +++ b/logstash-core/build.gradle @@ -1,3 +1,22 @@ +/* + * 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. + */ + import java.nio.file.Files import java.nio.file.Paths import org.yaml.snakeyaml.Yaml diff --git a/logstash-core/lib/logstash-core.rb b/logstash-core/lib/logstash-core.rb index c2e4557af..df1dfd645 100644 --- a/logstash-core/lib/logstash-core.rb +++ b/logstash-core/lib/logstash-core.rb @@ -1 +1,18 @@ +# 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 "logstash-core/logstash-core" diff --git a/logstash-core/lib/logstash-core/logstash-core.rb b/logstash-core/lib/logstash-core/logstash-core.rb index 36b8e906c..d58bbb0a5 100644 --- a/logstash-core/lib/logstash-core/logstash-core.rb +++ b/logstash-core/lib/logstash-core/logstash-core.rb @@ -1,4 +1,19 @@ -# encoding: utf-8 +# 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 "java" diff --git a/logstash-core/lib/logstash-core/version.rb b/logstash-core/lib/logstash-core/version.rb index 8907e466d..c8340b1d6 100644 --- a/logstash-core/lib/logstash-core/version.rb +++ b/logstash-core/lib/logstash-core/version.rb @@ -1,4 +1,19 @@ -# encoding: utf-8 +# 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. # The version of logstash core gem. # diff --git a/logstash-core/lib/logstash/agent.rb b/logstash-core/lib/logstash/agent.rb index 098fc417d..f0eb7123d 100644 --- a/logstash-core/lib/logstash/agent.rb +++ b/logstash-core/lib/logstash/agent.rb @@ -1,4 +1,20 @@ -# encoding: utf-8 +# 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 "logstash/environment" require "logstash/config/cpu_core_strategy" require "logstash/instrument/collector" diff --git a/logstash-core/lib/logstash/api/app_helpers.rb b/logstash-core/lib/logstash/api/app_helpers.rb index 98e6c3775..3a6aa8829 100644 --- a/logstash-core/lib/logstash/api/app_helpers.rb +++ b/logstash-core/lib/logstash/api/app_helpers.rb @@ -1,4 +1,20 @@ -# encoding: utf-8 +# 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 "logstash/json" require "logstash/api/errors" diff --git a/logstash-core/lib/logstash/api/command_factory.rb b/logstash-core/lib/logstash/api/command_factory.rb index 2d790b5ee..962d87367 100644 --- a/logstash-core/lib/logstash/api/command_factory.rb +++ b/logstash-core/lib/logstash/api/command_factory.rb @@ -1,4 +1,20 @@ -# encoding: utf-8 +# 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 "logstash/api/service" require "logstash/api/commands/system/basicinfo_command" require "logstash/api/commands/system/plugins_command" diff --git a/logstash-core/lib/logstash/api/commands/base.rb b/logstash-core/lib/logstash/api/commands/base.rb index d2bef44e6..60df18735 100644 --- a/logstash-core/lib/logstash/api/commands/base.rb +++ b/logstash-core/lib/logstash/api/commands/base.rb @@ -1,4 +1,19 @@ -# encoding: utf-8 +# 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. module LogStash module Api diff --git a/logstash-core/lib/logstash/api/commands/default_metadata.rb b/logstash-core/lib/logstash/api/commands/default_metadata.rb index 3835d9b5b..26f4af313 100644 --- a/logstash-core/lib/logstash/api/commands/default_metadata.rb +++ b/logstash-core/lib/logstash/api/commands/default_metadata.rb @@ -1,4 +1,19 @@ -# encoding: utf-8 +# 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 "logstash/api/commands/base" diff --git a/logstash-core/lib/logstash/api/commands/hot_threads_reporter.rb b/logstash-core/lib/logstash/api/commands/hot_threads_reporter.rb index b9b1e06a6..5d51111cf 100644 --- a/logstash-core/lib/logstash/api/commands/hot_threads_reporter.rb +++ b/logstash-core/lib/logstash/api/commands/hot_threads_reporter.rb @@ -1,4 +1,20 @@ -# encoding: utf-8 +# 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. + java_import 'org.logstash.instrument.reports.ThreadsReport' class HotThreadsReport diff --git a/logstash-core/lib/logstash/api/commands/node.rb b/logstash-core/lib/logstash/api/commands/node.rb index e76b41675..0b7fdaa4f 100644 --- a/logstash-core/lib/logstash/api/commands/node.rb +++ b/logstash-core/lib/logstash/api/commands/node.rb @@ -1,4 +1,20 @@ -# encoding: utf-8 +# 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 "logstash/api/commands/base" require_relative "hot_threads_reporter" diff --git a/logstash-core/lib/logstash/api/commands/stats.rb b/logstash-core/lib/logstash/api/commands/stats.rb index a473d5ed0..9b3282f2e 100644 --- a/logstash-core/lib/logstash/api/commands/stats.rb +++ b/logstash-core/lib/logstash/api/commands/stats.rb @@ -1,4 +1,20 @@ -# encoding: utf-8 +# 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 "logstash/api/commands/base" require 'logstash/util/thread_dump' require 'logstash/config/pipelines_info' diff --git a/logstash-core/lib/logstash/api/commands/system/basicinfo_command.rb b/logstash-core/lib/logstash/api/commands/system/basicinfo_command.rb index 6eacdbd5b..0a5255d8f 100644 --- a/logstash-core/lib/logstash/api/commands/system/basicinfo_command.rb +++ b/logstash-core/lib/logstash/api/commands/system/basicinfo_command.rb @@ -1,4 +1,20 @@ -# encoding: utf-8 +# 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 'logstash/api/commands/base' require "logstash/util/duration_formatter" require 'logstash/build' diff --git a/logstash-core/lib/logstash/api/commands/system/plugins_command.rb b/logstash-core/lib/logstash/api/commands/system/plugins_command.rb index 378f65e85..051a0feb7 100644 --- a/logstash-core/lib/logstash/api/commands/system/plugins_command.rb +++ b/logstash-core/lib/logstash/api/commands/system/plugins_command.rb @@ -1,4 +1,20 @@ -# encoding: utf-8 +# 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 "logstash/api/commands/base" module LogStash diff --git a/logstash-core/lib/logstash/api/errors.rb b/logstash-core/lib/logstash/api/errors.rb index e080305d9..ad783c63a 100644 --- a/logstash-core/lib/logstash/api/errors.rb +++ b/logstash-core/lib/logstash/api/errors.rb @@ -1,4 +1,20 @@ -# encoding: utf-8 +# 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. + module LogStash module Api class ApiError < StandardError; diff --git a/logstash-core/lib/logstash/api/modules/base.rb b/logstash-core/lib/logstash/api/modules/base.rb index d8ad5e0c7..7c6b38ec1 100644 --- a/logstash-core/lib/logstash/api/modules/base.rb +++ b/logstash-core/lib/logstash/api/modules/base.rb @@ -1,4 +1,20 @@ -# encoding: utf-8 +# 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 "logstash/api/app_helpers" require "logstash/api/command_factory" require "logstash/api/errors" diff --git a/logstash-core/lib/logstash/api/modules/logging.rb b/logstash-core/lib/logstash/api/modules/logging.rb index 440cbacc8..bbac0bea3 100644 --- a/logstash-core/lib/logstash/api/modules/logging.rb +++ b/logstash-core/lib/logstash/api/modules/logging.rb @@ -1,5 +1,20 @@ -# encoding: utf-8 +# 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. + java_import org.apache.logging.log4j.core.LoggerContext java_import java.lang.IllegalArgumentException diff --git a/logstash-core/lib/logstash/api/modules/node.rb b/logstash-core/lib/logstash/api/modules/node.rb index 1846df5d4..a607726f3 100644 --- a/logstash-core/lib/logstash/api/modules/node.rb +++ b/logstash-core/lib/logstash/api/modules/node.rb @@ -1,4 +1,20 @@ -# encoding: utf-8 +# 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 "logstash/api/modules/base" require "logstash/api/errors" diff --git a/logstash-core/lib/logstash/api/modules/node_stats.rb b/logstash-core/lib/logstash/api/modules/node_stats.rb index 42b02690c..f8f8c1120 100644 --- a/logstash-core/lib/logstash/api/modules/node_stats.rb +++ b/logstash-core/lib/logstash/api/modules/node_stats.rb @@ -1,4 +1,20 @@ -# encoding: utf-8 +# 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. + module LogStash module Api module Modules diff --git a/logstash-core/lib/logstash/api/modules/plugins.rb b/logstash-core/lib/logstash/api/modules/plugins.rb index 7edd3da15..129492a8c 100644 --- a/logstash-core/lib/logstash/api/modules/plugins.rb +++ b/logstash-core/lib/logstash/api/modules/plugins.rb @@ -1,4 +1,20 @@ -# encoding: utf-8 +# 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. + module LogStash module Api module Modules diff --git a/logstash-core/lib/logstash/api/modules/root.rb b/logstash-core/lib/logstash/api/modules/root.rb index 10a414187..260319e78 100644 --- a/logstash-core/lib/logstash/api/modules/root.rb +++ b/logstash-core/lib/logstash/api/modules/root.rb @@ -1,4 +1,20 @@ -# encoding: utf-8 +# 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. + module LogStash module Api module Modules diff --git a/logstash-core/lib/logstash/api/modules/stats.rb b/logstash-core/lib/logstash/api/modules/stats.rb index 03175b33b..11e63a0c3 100644 --- a/logstash-core/lib/logstash/api/modules/stats.rb +++ b/logstash-core/lib/logstash/api/modules/stats.rb @@ -1,4 +1,20 @@ -# encoding: utf-8 +# 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. + module LogStash module Api module Modules diff --git a/logstash-core/lib/logstash/api/rack_app.rb b/logstash-core/lib/logstash/api/rack_app.rb index 6b8a7eb6b..c14bdf26a 100644 --- a/logstash-core/lib/logstash/api/rack_app.rb +++ b/logstash-core/lib/logstash/api/rack_app.rb @@ -1,3 +1,20 @@ +# 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 "rack" require "sinatra/base" require "logstash/api/modules/base" diff --git a/logstash-core/lib/logstash/api/service.rb b/logstash-core/lib/logstash/api/service.rb index c49e609e1..0c0aedc66 100644 --- a/logstash-core/lib/logstash/api/service.rb +++ b/logstash-core/lib/logstash/api/service.rb @@ -1,4 +1,20 @@ -# encoding: utf-8 +# 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 "logstash/instrument/collector" module LogStash diff --git a/logstash-core/lib/logstash/bootstrap_check/default_config.rb b/logstash-core/lib/logstash/bootstrap_check/default_config.rb index da058917d..aa7d69e6a 100644 --- a/logstash-core/lib/logstash/bootstrap_check/default_config.rb +++ b/logstash-core/lib/logstash/bootstrap_check/default_config.rb @@ -1,4 +1,19 @@ -# encoding: utf-8 +# 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. module LogStash module BootstrapCheck class DefaultConfig diff --git a/logstash-core/lib/logstash/bootstrap_check/persisted_queue_config.rb b/logstash-core/lib/logstash/bootstrap_check/persisted_queue_config.rb index 0c0292d29..f227bb117 100644 --- a/logstash-core/lib/logstash/bootstrap_check/persisted_queue_config.rb +++ b/logstash-core/lib/logstash/bootstrap_check/persisted_queue_config.rb @@ -1,4 +1,19 @@ -# encoding: utf-8 +# 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. module LogStash module BootstrapCheck diff --git a/logstash-core/lib/logstash/build.rb b/logstash-core/lib/logstash/build.rb index fb2132c22..3d9476216 100644 --- a/logstash-core/lib/logstash/build.rb +++ b/logstash-core/lib/logstash/build.rb @@ -1,4 +1,19 @@ -# encoding: utf-8 +# 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. # DO NOT EDIT # this file acts as a placeholder for build information when executing diff --git a/logstash-core/lib/logstash/codecs/base.rb b/logstash-core/lib/logstash/codecs/base.rb index f9a9e636b..db4cde703 100644 --- a/logstash-core/lib/logstash/codecs/base.rb +++ b/logstash-core/lib/logstash/codecs/base.rb @@ -1,4 +1,20 @@ -# encoding: utf-8 +# 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 "logstash/event" require "logstash/plugin" diff --git a/logstash-core/lib/logstash/codecs/delegator.rb b/logstash-core/lib/logstash/codecs/delegator.rb index 2cbb440c5..24df77651 100644 --- a/logstash-core/lib/logstash/codecs/delegator.rb +++ b/logstash-core/lib/logstash/codecs/delegator.rb @@ -1,3 +1,20 @@ +# 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. + module LogStash::Codecs class Delegator < SimpleDelegator def initialize(obj) diff --git a/logstash-core/lib/logstash/compiler.rb b/logstash-core/lib/logstash/compiler.rb index 6cd68b280..9a9cf8c2c 100644 --- a/logstash-core/lib/logstash/compiler.rb +++ b/logstash-core/lib/logstash/compiler.rb @@ -1,3 +1,20 @@ +# 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 'logstash/compiler/lscl/lscl_grammar' java_import org.logstash.config.ir.PipelineIR diff --git a/logstash-core/lib/logstash/compiler/lscl.rb b/logstash-core/lib/logstash/compiler/lscl.rb index d658bf257..6b5d8f5b0 100644 --- a/logstash-core/lib/logstash/compiler/lscl.rb +++ b/logstash-core/lib/logstash/compiler/lscl.rb @@ -1,4 +1,20 @@ -# encoding: utf-8 +# 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 "treetop" require "logstash/compiler/treetop_monkeypatches" require "logstash/compiler/lscl/helpers" diff --git a/logstash-core/lib/logstash/compiler/lscl/helpers.rb b/logstash-core/lib/logstash/compiler/lscl/helpers.rb index 8cded0a4d..3362f1c98 100644 --- a/logstash-core/lib/logstash/compiler/lscl/helpers.rb +++ b/logstash-core/lib/logstash/compiler/lscl/helpers.rb @@ -1,4 +1,19 @@ -# encoding: utf-8 +# 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. module LogStashCompilerLSCLGrammar; module LogStash; module Compiler; module LSCL; module AST # Helpers for parsing LSCL files diff --git a/logstash-core/lib/logstash/compiler/lscl/lscl_grammar.rb b/logstash-core/lib/logstash/compiler/lscl/lscl_grammar.rb index 0f2c92a20..d1a3cb9d6 100644 --- a/logstash-core/lib/logstash/compiler/lscl/lscl_grammar.rb +++ b/logstash-core/lib/logstash/compiler/lscl/lscl_grammar.rb @@ -1,5 +1,19 @@ -# Autogenerated from a Treetop grammar. Edits may be lost. - +# 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 "treetop" require "logstash/compiler/lscl.rb" @@ -3553,4 +3567,3 @@ end class LogStashCompilerLSCLGrammarParser < Treetop::Runtime::CompiledParser include LogStashCompilerLSCLGrammar end - diff --git a/logstash-core/lib/logstash/compiler/treetop_monkeypatches.rb b/logstash-core/lib/logstash/compiler/treetop_monkeypatches.rb index 48c3f0c7c..6ad1823b3 100644 --- a/logstash-core/lib/logstash/compiler/treetop_monkeypatches.rb +++ b/logstash-core/lib/logstash/compiler/treetop_monkeypatches.rb @@ -1,3 +1,20 @@ +# 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. + class Treetop::Runtime::SyntaxNode def get_meta(key) @ast_metadata ||= {} diff --git a/logstash-core/lib/logstash/config/config_ast.rb b/logstash-core/lib/logstash/config/config_ast.rb index 67e88ff6e..e3d413bf5 100644 --- a/logstash-core/lib/logstash/config/config_ast.rb +++ b/logstash-core/lib/logstash/config/config_ast.rb @@ -1,4 +1,20 @@ -# encoding: utf-8 +# 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 "logstash/compiler/lscl/helpers" require "treetop" diff --git a/logstash-core/lib/logstash/config/cpu_core_strategy.rb b/logstash-core/lib/logstash/config/cpu_core_strategy.rb index 5ad9ec34e..a0280b4da 100644 --- a/logstash-core/lib/logstash/config/cpu_core_strategy.rb +++ b/logstash-core/lib/logstash/config/cpu_core_strategy.rb @@ -1,4 +1,20 @@ -# encoding: utf-8 +# 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 "logstash/config/defaults" module LogStash module Config module CpuCoreStrategy diff --git a/logstash-core/lib/logstash/config/defaults.rb b/logstash-core/lib/logstash/config/defaults.rb index ee77065d2..abb1c3749 100644 --- a/logstash-core/lib/logstash/config/defaults.rb +++ b/logstash-core/lib/logstash/config/defaults.rb @@ -1,4 +1,20 @@ -# encoding: utf-8 +# 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 "concurrent" module LogStash module Config module Defaults diff --git a/logstash-core/lib/logstash/config/file.rb b/logstash-core/lib/logstash/config/file.rb index 3dd6289f5..11cb5ade5 100644 --- a/logstash-core/lib/logstash/config/file.rb +++ b/logstash-core/lib/logstash/config/file.rb @@ -1,4 +1,20 @@ -# encoding: utf-8 +# 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 "logstash/config/grammar" require "logstash/config/config_ast" require "logger" diff --git a/logstash-core/lib/logstash/config/grammar.rb b/logstash-core/lib/logstash/config/grammar.rb index 5e4effe51..7007fee74 100644 --- a/logstash-core/lib/logstash/config/grammar.rb +++ b/logstash-core/lib/logstash/config/grammar.rb @@ -1,5 +1,19 @@ -# Autogenerated from a Treetop grammar. Edits may be lost. - +# 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 "treetop" require "logstash/config/config_ast" @@ -3577,4 +3591,3 @@ end class LogStashConfigParser < Treetop::Runtime::CompiledParser include LogStashConfig end - diff --git a/logstash-core/lib/logstash/config/lir_serializer.rb b/logstash-core/lib/logstash/config/lir_serializer.rb index 025055113..e19049eef 100644 --- a/logstash-core/lib/logstash/config/lir_serializer.rb +++ b/logstash-core/lib/logstash/config/lir_serializer.rb @@ -1,4 +1,20 @@ -# encoding: utf-8 +# 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 'logstash-core' require 'logstash/compiler' @@ -124,4 +140,3 @@ module LogStash; end end end - diff --git a/logstash-core/lib/logstash/config/mixin.rb b/logstash-core/lib/logstash/config/mixin.rb index 621ef9e0c..57de589bc 100644 --- a/logstash-core/lib/logstash/config/mixin.rb +++ b/logstash-core/lib/logstash/config/mixin.rb @@ -1,4 +1,20 @@ -# encoding: utf-8 +# 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 "logstash/util/password" require "logstash/util/safe_uri" require "logstash/version" diff --git a/logstash-core/lib/logstash/config/modules_common.rb b/logstash-core/lib/logstash/config/modules_common.rb index 28a9f22c9..b1769542f 100644 --- a/logstash-core/lib/logstash/config/modules_common.rb +++ b/logstash-core/lib/logstash/config/modules_common.rb @@ -1,4 +1,20 @@ -# encoding: utf-8 +# 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 "logstash/elasticsearch_client" require "logstash/modules/kibana_client" require "logstash/modules/elasticsearch_importer" diff --git a/logstash-core/lib/logstash/config/pipeline_config.rb b/logstash-core/lib/logstash/config/pipeline_config.rb index 268345271..66ca1aa4a 100644 --- a/logstash-core/lib/logstash/config/pipeline_config.rb +++ b/logstash-core/lib/logstash/config/pipeline_config.rb @@ -1,4 +1,20 @@ -# encoding: utf-8 +# 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 "digest" module LogStash module Config diff --git a/logstash-core/lib/logstash/config/pipelines_info.rb b/logstash-core/lib/logstash/config/pipelines_info.rb index 58f93daa3..5deadbcec 100644 --- a/logstash-core/lib/logstash/config/pipelines_info.rb +++ b/logstash-core/lib/logstash/config/pipelines_info.rb @@ -1,3 +1,20 @@ +# 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. + module LogStash; module Config; class PipelinesInfo def self.format_pipelines_info(agent, metric_store, extended_performance_collection) diff --git a/logstash-core/lib/logstash/config/source/base.rb b/logstash-core/lib/logstash/config/source/base.rb index b9a5e5530..0db79bc47 100644 --- a/logstash-core/lib/logstash/config/source/base.rb +++ b/logstash-core/lib/logstash/config/source/base.rb @@ -1,4 +1,20 @@ -# encoding: utf-8 +# 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. + module LogStash module Config module Source class Base attr_reader :conflict_messages diff --git a/logstash-core/lib/logstash/config/source/local.rb b/logstash-core/lib/logstash/config/source/local.rb index a4beefb76..d23ae69de 100644 --- a/logstash-core/lib/logstash/config/source/local.rb +++ b/logstash-core/lib/logstash/config/source/local.rb @@ -1,4 +1,20 @@ -# encoding: utf-8 +# 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 "logstash/config/source/base" require "logstash/config/pipeline_config" require "uri" diff --git a/logstash-core/lib/logstash/config/source/modules.rb b/logstash-core/lib/logstash/config/source/modules.rb index 6f88033ef..9bddbd977 100644 --- a/logstash-core/lib/logstash/config/source/modules.rb +++ b/logstash-core/lib/logstash/config/source/modules.rb @@ -1,4 +1,20 @@ -# encoding: utf-8 +# 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 "logstash/config/source/base" require "logstash/config/modules_common" require "logstash/config/pipeline_config" diff --git a/logstash-core/lib/logstash/config/source/multi_local.rb b/logstash-core/lib/logstash/config/source/multi_local.rb index 74ea8e97b..39f728234 100644 --- a/logstash-core/lib/logstash/config/source/multi_local.rb +++ b/logstash-core/lib/logstash/config/source/multi_local.rb @@ -1,4 +1,20 @@ -# encoding: utf-8 +# 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 "logstash/config/source/local" require "logstash/settings" diff --git a/logstash-core/lib/logstash/config/source_loader.rb b/logstash-core/lib/logstash/config/source_loader.rb index 1da3619f5..11959eb2a 100644 --- a/logstash-core/lib/logstash/config/source_loader.rb +++ b/logstash-core/lib/logstash/config/source_loader.rb @@ -1,4 +1,20 @@ -# encoding: utf-8 +# 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 "logstash/config/source/local" require "logstash/config/source/modules" require "logstash/config/source/multi_local" diff --git a/logstash-core/lib/logstash/config/string_escape.rb b/logstash-core/lib/logstash/config/string_escape.rb index 84126407a..9f1a31e18 100644 --- a/logstash-core/lib/logstash/config/string_escape.rb +++ b/logstash-core/lib/logstash/config/string_escape.rb @@ -1,4 +1,19 @@ - +# 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. module LogStash; module Config; module StringEscape class << self diff --git a/logstash-core/lib/logstash/dependency_report.rb b/logstash-core/lib/logstash/dependency_report.rb index c0535aba9..9b35153a2 100644 --- a/logstash-core/lib/logstash/dependency_report.rb +++ b/logstash-core/lib/logstash/dependency_report.rb @@ -1,4 +1,20 @@ -# encoding: utf-8 +# 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. + Thread.abort_on_exception = true Encoding.default_external = Encoding::UTF_8 $DEBUGLIST = (ENV["DEBUG"] || "").split(",") diff --git a/logstash-core/lib/logstash/dependency_report_runner.rb b/logstash-core/lib/logstash/dependency_report_runner.rb index 880c3c5c3..f30aed7f9 100644 --- a/logstash-core/lib/logstash/dependency_report_runner.rb +++ b/logstash-core/lib/logstash/dependency_report_runner.rb @@ -1,3 +1,20 @@ +# 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 "../../../lib/bootstrap/environment" if $0 == __FILE__ diff --git a/logstash-core/lib/logstash/elasticsearch_client.rb b/logstash-core/lib/logstash/elasticsearch_client.rb index ef61d7781..7953d4f27 100644 --- a/logstash-core/lib/logstash/elasticsearch_client.rb +++ b/logstash-core/lib/logstash/elasticsearch_client.rb @@ -1,4 +1,20 @@ -# encoding: utf-8 +# 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 "elasticsearch" require "elasticsearch/transport/transport/http/manticore" require 'logstash/util/manticore_ssl_config_helper' diff --git a/logstash-core/lib/logstash/environment.rb b/logstash-core/lib/logstash/environment.rb index 8addd84cd..27d6f1160 100644 --- a/logstash-core/lib/logstash/environment.rb +++ b/logstash-core/lib/logstash/environment.rb @@ -1,4 +1,20 @@ -# encoding: utf-8 +# 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 "logstash-core/logstash-core" require "logstash/config/cpu_core_strategy" require "logstash/settings" diff --git a/logstash-core/lib/logstash/errors.rb b/logstash-core/lib/logstash/errors.rb index cf7879f56..dd0059212 100644 --- a/logstash-core/lib/logstash/errors.rb +++ b/logstash-core/lib/logstash/errors.rb @@ -1 +1,18 @@ +# 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. + # Keeping this file for backwards compatibility with plugins that include it directly. diff --git a/logstash-core/lib/logstash/event.rb b/logstash-core/lib/logstash/event.rb index 577ece5fb..4ee5665d3 100644 --- a/logstash-core/lib/logstash/event.rb +++ b/logstash-core/lib/logstash/event.rb @@ -1,4 +1,19 @@ -# encoding: utf-8 +# 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. # used only in the Ruby execution engine module LogStash diff --git a/logstash-core/lib/logstash/event_dispatcher.rb b/logstash-core/lib/logstash/event_dispatcher.rb index cf7879f56..dd0059212 100644 --- a/logstash-core/lib/logstash/event_dispatcher.rb +++ b/logstash-core/lib/logstash/event_dispatcher.rb @@ -1 +1,18 @@ +# 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. + # Keeping this file for backwards compatibility with plugins that include it directly. diff --git a/logstash-core/lib/logstash/execution_context.rb b/logstash-core/lib/logstash/execution_context.rb index 548cf47a6..0f4032e3a 100644 --- a/logstash-core/lib/logstash/execution_context.rb +++ b/logstash-core/lib/logstash/execution_context.rb @@ -1,2 +1,19 @@ +# 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. + # The contents of this file have been ported to Java. It is included for for compatibility # with plugins that directly include it. diff --git a/logstash-core/lib/logstash/filter_delegator.rb b/logstash-core/lib/logstash/filter_delegator.rb index 548cf47a6..0f4032e3a 100644 --- a/logstash-core/lib/logstash/filter_delegator.rb +++ b/logstash-core/lib/logstash/filter_delegator.rb @@ -1,2 +1,19 @@ +# 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. + # The contents of this file have been ported to Java. It is included for for compatibility # with plugins that directly include it. diff --git a/logstash-core/lib/logstash/filters/base.rb b/logstash-core/lib/logstash/filters/base.rb index 39036bf9f..0b09ae69f 100644 --- a/logstash-core/lib/logstash/filters/base.rb +++ b/logstash-core/lib/logstash/filters/base.rb @@ -1,4 +1,20 @@ -# encoding: utf-8 +# 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 "logstash/event" require "logstash/plugin" require "logstash/config/mixin" diff --git a/logstash-core/lib/logstash/inputs/base.rb b/logstash-core/lib/logstash/inputs/base.rb index f0afaca94..a01b011e3 100644 --- a/logstash-core/lib/logstash/inputs/base.rb +++ b/logstash-core/lib/logstash/inputs/base.rb @@ -1,4 +1,20 @@ -# encoding: utf-8 +# 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 "logstash/event" require "logstash/plugin" require "logstash/config/mixin" diff --git a/logstash-core/lib/logstash/inputs/threadable.rb b/logstash-core/lib/logstash/inputs/threadable.rb index 7348c1edf..a61c9bb0f 100644 --- a/logstash-core/lib/logstash/inputs/threadable.rb +++ b/logstash-core/lib/logstash/inputs/threadable.rb @@ -1,4 +1,20 @@ -# encoding: utf-8 +# 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 "logstash/inputs/base" # This is the threadable class for logstash inputs. diff --git a/logstash-core/lib/logstash/instrument/collector.rb b/logstash-core/lib/logstash/instrument/collector.rb index 5c2a8f4c0..797dd4713 100644 --- a/logstash-core/lib/logstash/instrument/collector.rb +++ b/logstash-core/lib/logstash/instrument/collector.rb @@ -1,4 +1,20 @@ -# encoding: utf-8 +# 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 "logstash/instrument/metric_store" require "concurrent/timer_task" require "observer" diff --git a/logstash-core/lib/logstash/instrument/metric.rb b/logstash-core/lib/logstash/instrument/metric.rb index 6abbe7ce3..e93dce784 100644 --- a/logstash-core/lib/logstash/instrument/metric.rb +++ b/logstash-core/lib/logstash/instrument/metric.rb @@ -1 +1,18 @@ +# 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. + # This file is kept for backwards compatibility with plugins that include it. diff --git a/logstash-core/lib/logstash/instrument/metric_store.rb b/logstash-core/lib/logstash/instrument/metric_store.rb index 864f2c01a..4cdbc9bcf 100644 --- a/logstash-core/lib/logstash/instrument/metric_store.rb +++ b/logstash-core/lib/logstash/instrument/metric_store.rb @@ -1,4 +1,20 @@ -# encoding: utf-8 +# 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 "concurrent" require "logstash/instrument/metric_type" require "thread" diff --git a/logstash-core/lib/logstash/instrument/metric_type.rb b/logstash-core/lib/logstash/instrument/metric_type.rb index 85b82de4c..395323658 100644 --- a/logstash-core/lib/logstash/instrument/metric_type.rb +++ b/logstash-core/lib/logstash/instrument/metric_type.rb @@ -1,4 +1,20 @@ -# encoding: utf-8 +# 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 "logstash/instrument/metric_type/counter" require "logstash/instrument/metric_type/gauge" diff --git a/logstash-core/lib/logstash/instrument/metric_type/counter.rb b/logstash-core/lib/logstash/instrument/metric_type/counter.rb index 2feeb2d77..21f101b91 100644 --- a/logstash-core/lib/logstash/instrument/metric_type/counter.rb +++ b/logstash-core/lib/logstash/instrument/metric_type/counter.rb @@ -1,4 +1,20 @@ -#encoding: utf-8 +# 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. + java_import org.logstash.instrument.metrics.counter.LongCounter module LogStash module Instrument module MetricType diff --git a/logstash-core/lib/logstash/instrument/metric_type/gauge.rb b/logstash-core/lib/logstash/instrument/metric_type/gauge.rb index e6492305e..390182d7b 100644 --- a/logstash-core/lib/logstash/instrument/metric_type/gauge.rb +++ b/logstash-core/lib/logstash/instrument/metric_type/gauge.rb @@ -1,4 +1,20 @@ -# encoding: utf-8 +# 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. + java_import org.logstash.instrument.metrics.gauge.LazyDelegatingGauge module LogStash module Instrument module MetricType class Gauge < LazyDelegatingGauge @@ -13,4 +29,3 @@ module LogStash module Instrument module MetricType end end; end; end - diff --git a/logstash-core/lib/logstash/instrument/namespaced_metric.rb b/logstash-core/lib/logstash/instrument/namespaced_metric.rb index 6abbe7ce3..e93dce784 100644 --- a/logstash-core/lib/logstash/instrument/namespaced_metric.rb +++ b/logstash-core/lib/logstash/instrument/namespaced_metric.rb @@ -1 +1,18 @@ +# 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. + # This file is kept for backwards compatibility with plugins that include it. diff --git a/logstash-core/lib/logstash/instrument/namespaced_null_metric.rb b/logstash-core/lib/logstash/instrument/namespaced_null_metric.rb index 63524d225..b298135de 100644 --- a/logstash-core/lib/logstash/instrument/namespaced_null_metric.rb +++ b/logstash-core/lib/logstash/instrument/namespaced_null_metric.rb @@ -1 +1,18 @@ +# 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. + # This file is kept for backwards compatibility with plugins that include it directly. diff --git a/logstash-core/lib/logstash/instrument/null_metric.rb b/logstash-core/lib/logstash/instrument/null_metric.rb index 4dfe43e4c..220365a0f 100644 --- a/logstash-core/lib/logstash/instrument/null_metric.rb +++ b/logstash-core/lib/logstash/instrument/null_metric.rb @@ -1,2 +1,19 @@ +# 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. + # The contents of this file have been ported to Java. It is included for for compatibility # with plugins that directly require it. diff --git a/logstash-core/lib/logstash/instrument/periodic_poller/base.rb b/logstash-core/lib/logstash/instrument/periodic_poller/base.rb index 338162172..987506757 100644 --- a/logstash-core/lib/logstash/instrument/periodic_poller/base.rb +++ b/logstash-core/lib/logstash/instrument/periodic_poller/base.rb @@ -1,4 +1,20 @@ -# encoding: utf-8 +# 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 "logstash/util" require "concurrent" diff --git a/logstash-core/lib/logstash/instrument/periodic_poller/cgroup.rb b/logstash-core/lib/logstash/instrument/periodic_poller/cgroup.rb index 4a5739ba8..c84b6cbbe 100644 --- a/logstash-core/lib/logstash/instrument/periodic_poller/cgroup.rb +++ b/logstash-core/lib/logstash/instrument/periodic_poller/cgroup.rb @@ -1,4 +1,19 @@ -# encoding: utf-8 +# 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. # Logic from elasticsearch/core/src/main/java/org/elasticsearch/monitor/os/OsProbe.java # Move to ruby to remove any existing dependency diff --git a/logstash-core/lib/logstash/instrument/periodic_poller/dlq.rb b/logstash-core/lib/logstash/instrument/periodic_poller/dlq.rb index c2d92e97b..b92ed5e5f 100644 --- a/logstash-core/lib/logstash/instrument/periodic_poller/dlq.rb +++ b/logstash-core/lib/logstash/instrument/periodic_poller/dlq.rb @@ -1,4 +1,20 @@ -# encoding: utf-8 +# 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 'logstash/instrument/periodic_poller/base' module LogStash module Instrument module PeriodicPoller @@ -19,4 +35,3 @@ module LogStash module Instrument module PeriodicPoller end end end end end - diff --git a/logstash-core/lib/logstash/instrument/periodic_poller/jvm.rb b/logstash-core/lib/logstash/instrument/periodic_poller/jvm.rb index 0c6f59844..e7f5ae884 100644 --- a/logstash-core/lib/logstash/instrument/periodic_poller/jvm.rb +++ b/logstash-core/lib/logstash/instrument/periodic_poller/jvm.rb @@ -1,4 +1,20 @@ -# encoding: utf-8 +# 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 "logstash/instrument/periodic_poller/base" require "logstash/instrument/periodic_poller/load_average" require "logstash/environment" diff --git a/logstash-core/lib/logstash/instrument/periodic_poller/load_average.rb b/logstash-core/lib/logstash/instrument/periodic_poller/load_average.rb index 1e13f1a9c..f26f8687b 100644 --- a/logstash-core/lib/logstash/instrument/periodic_poller/load_average.rb +++ b/logstash-core/lib/logstash/instrument/periodic_poller/load_average.rb @@ -1,4 +1,20 @@ -# encoding: utf-8 +# 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. + java_import "java.lang.management.ManagementFactory" module LogStash module Instrument module PeriodicPoller diff --git a/logstash-core/lib/logstash/instrument/periodic_poller/os.rb b/logstash-core/lib/logstash/instrument/periodic_poller/os.rb index 7f2a334b5..64fa87a13 100644 --- a/logstash-core/lib/logstash/instrument/periodic_poller/os.rb +++ b/logstash-core/lib/logstash/instrument/periodic_poller/os.rb @@ -1,4 +1,20 @@ -# encoding: utf-8 +# 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 "logstash/instrument/periodic_poller/base" require "logstash/instrument/periodic_poller/cgroup" diff --git a/logstash-core/lib/logstash/instrument/periodic_poller/pq.rb b/logstash-core/lib/logstash/instrument/periodic_poller/pq.rb index 0ef82247c..68ebdbf89 100644 --- a/logstash-core/lib/logstash/instrument/periodic_poller/pq.rb +++ b/logstash-core/lib/logstash/instrument/periodic_poller/pq.rb @@ -1,4 +1,20 @@ -# encoding: utf-8 +# 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 "logstash/instrument/periodic_poller/base" module LogStash module Instrument module PeriodicPoller diff --git a/logstash-core/lib/logstash/instrument/periodic_pollers.rb b/logstash-core/lib/logstash/instrument/periodic_pollers.rb index 812075b03..345dc7c3d 100644 --- a/logstash-core/lib/logstash/instrument/periodic_pollers.rb +++ b/logstash-core/lib/logstash/instrument/periodic_pollers.rb @@ -1,4 +1,20 @@ -# encoding: utf-8 +# 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 "logstash/instrument/periodic_poller/dlq" require "logstash/instrument/periodic_poller/os" require "logstash/instrument/periodic_poller/jvm" diff --git a/logstash-core/lib/logstash/java_pipeline.rb b/logstash-core/lib/logstash/java_pipeline.rb index 8332e6638..1ae774e0a 100644 --- a/logstash-core/lib/logstash/java_pipeline.rb +++ b/logstash-core/lib/logstash/java_pipeline.rb @@ -1,4 +1,20 @@ -# encoding: utf-8 +# 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 "thread" require "concurrent" require "logstash/filters/base" diff --git a/logstash-core/lib/logstash/json.rb b/logstash-core/lib/logstash/json.rb index f2dc0e0a9..9df87f64a 100644 --- a/logstash-core/lib/logstash/json.rb +++ b/logstash-core/lib/logstash/json.rb @@ -1,4 +1,20 @@ -# encoding: utf-8 +# 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 "logstash/environment" require "jrjackson" diff --git a/logstash-core/lib/logstash/logging.rb b/logstash-core/lib/logstash/logging.rb index bca5f6749..e249288bf 100644 --- a/logstash-core/lib/logstash/logging.rb +++ b/logstash-core/lib/logstash/logging.rb @@ -1 +1,16 @@ -# encoding: utf-8 +# 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. diff --git a/logstash-core/lib/logstash/logging/logger.rb b/logstash-core/lib/logstash/logging/logger.rb index 647fe2307..a019eb116 100644 --- a/logstash-core/lib/logstash/logging/logger.rb +++ b/logstash-core/lib/logstash/logging/logger.rb @@ -1 +1,18 @@ +# 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. + # Keeping this file for backwards compatibility with plugins that include it directly. \ No newline at end of file diff --git a/logstash-core/lib/logstash/modules/cli_parser.rb b/logstash-core/lib/logstash/modules/cli_parser.rb index 3942d1434..e75b3c041 100644 --- a/logstash-core/lib/logstash/modules/cli_parser.rb +++ b/logstash-core/lib/logstash/modules/cli_parser.rb @@ -1,4 +1,20 @@ -# encoding: utf-8 +# 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. + module LogStash module Modules class CLIParser include LogStash::Util::Loggable diff --git a/logstash-core/lib/logstash/modules/elasticsearch_config.rb b/logstash-core/lib/logstash/modules/elasticsearch_config.rb index 0fa54ffd8..683442122 100644 --- a/logstash-core/lib/logstash/modules/elasticsearch_config.rb +++ b/logstash-core/lib/logstash/modules/elasticsearch_config.rb @@ -1,4 +1,20 @@ -# encoding: utf-8 +# 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 "elasticsearch_resource" module LogStash module Modules class ElasticsearchConfig diff --git a/logstash-core/lib/logstash/modules/elasticsearch_importer.rb b/logstash-core/lib/logstash/modules/elasticsearch_importer.rb index 6d957a709..2a27f22dd 100644 --- a/logstash-core/lib/logstash/modules/elasticsearch_importer.rb +++ b/logstash-core/lib/logstash/modules/elasticsearch_importer.rb @@ -1,4 +1,20 @@ -# encoding: utf-8 +# 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. + module LogStash module Modules class ElasticsearchImporter include LogStash::Util::Loggable diff --git a/logstash-core/lib/logstash/modules/elasticsearch_resource.rb b/logstash-core/lib/logstash/modules/elasticsearch_resource.rb index 90744cd09..21ccbc369 100644 --- a/logstash-core/lib/logstash/modules/elasticsearch_resource.rb +++ b/logstash-core/lib/logstash/modules/elasticsearch_resource.rb @@ -1,4 +1,20 @@ -# encoding: utf-8 +# 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 "resource_base" module LogStash module Modules class ElasticsearchResource diff --git a/logstash-core/lib/logstash/modules/file_reader.rb b/logstash-core/lib/logstash/modules/file_reader.rb index 75c14f692..e43a9133e 100644 --- a/logstash-core/lib/logstash/modules/file_reader.rb +++ b/logstash-core/lib/logstash/modules/file_reader.rb @@ -1,4 +1,20 @@ -# encoding: utf-8 +# 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 "logstash/json" module LogStash module Modules class FileReader diff --git a/logstash-core/lib/logstash/modules/kibana_base.rb b/logstash-core/lib/logstash/modules/kibana_base.rb index 635909d91..54e23d98a 100644 --- a/logstash-core/lib/logstash/modules/kibana_base.rb +++ b/logstash-core/lib/logstash/modules/kibana_base.rb @@ -1,4 +1,20 @@ -# encoding: utf-8 +# 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 "logstash/json" module LogStash module Modules class KibanaBase diff --git a/logstash-core/lib/logstash/modules/kibana_client.rb b/logstash-core/lib/logstash/modules/kibana_client.rb index b5a6a174c..4de1205dd 100644 --- a/logstash-core/lib/logstash/modules/kibana_client.rb +++ b/logstash-core/lib/logstash/modules/kibana_client.rb @@ -1,4 +1,20 @@ -# encoding: utf-8 +# 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 "logstash/json" require "manticore" require 'logstash/util/manticore_ssl_config_helper' diff --git a/logstash-core/lib/logstash/modules/kibana_config.rb b/logstash-core/lib/logstash/modules/kibana_config.rb index 528eed6af..6c651cc37 100644 --- a/logstash-core/lib/logstash/modules/kibana_config.rb +++ b/logstash-core/lib/logstash/modules/kibana_config.rb @@ -1,4 +1,20 @@ -# encoding: utf-8 +# 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 "file_reader" require_relative "kibana_settings" require_relative "kibana_dashboards" diff --git a/logstash-core/lib/logstash/modules/kibana_dashboards.rb b/logstash-core/lib/logstash/modules/kibana_dashboards.rb index d8f345a17..c34fceb4e 100644 --- a/logstash-core/lib/logstash/modules/kibana_dashboards.rb +++ b/logstash-core/lib/logstash/modules/kibana_dashboards.rb @@ -1,4 +1,20 @@ -# encoding: utf-8 +# 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 "kibana_base" module LogStash module Modules class KibanaDashboards < KibanaBase diff --git a/logstash-core/lib/logstash/modules/kibana_importer.rb b/logstash-core/lib/logstash/modules/kibana_importer.rb index 268f4827b..403217f53 100644 --- a/logstash-core/lib/logstash/modules/kibana_importer.rb +++ b/logstash-core/lib/logstash/modules/kibana_importer.rb @@ -1,4 +1,20 @@ -# encoding: utf-8 +# 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. + module LogStash module Modules class KibanaImporter include LogStash::Util::Loggable diff --git a/logstash-core/lib/logstash/modules/kibana_resource.rb b/logstash-core/lib/logstash/modules/kibana_resource.rb index d512765a0..ef98c3d36 100644 --- a/logstash-core/lib/logstash/modules/kibana_resource.rb +++ b/logstash-core/lib/logstash/modules/kibana_resource.rb @@ -1,4 +1,20 @@ -# encoding: utf-8 +# 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 "resource_base" module LogStash module Modules class KibanaResource diff --git a/logstash-core/lib/logstash/modules/kibana_settings.rb b/logstash-core/lib/logstash/modules/kibana_settings.rb index af3383360..0fd5d3cf9 100644 --- a/logstash-core/lib/logstash/modules/kibana_settings.rb +++ b/logstash-core/lib/logstash/modules/kibana_settings.rb @@ -1,4 +1,20 @@ -# encoding: utf-8 +# 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 "kibana_base" module LogStash module Modules class KibanaSettings < KibanaBase diff --git a/logstash-core/lib/logstash/modules/logstash_config.rb b/logstash-core/lib/logstash/modules/logstash_config.rb index 14801a17b..b7bd34fca 100644 --- a/logstash-core/lib/logstash/modules/logstash_config.rb +++ b/logstash-core/lib/logstash/modules/logstash_config.rb @@ -1,4 +1,20 @@ -# encoding: utf-8 +# 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 "file_reader" require "logstash/settings" diff --git a/logstash-core/lib/logstash/modules/resource_base.rb b/logstash-core/lib/logstash/modules/resource_base.rb index 7951e6cd1..c680902fa 100644 --- a/logstash-core/lib/logstash/modules/resource_base.rb +++ b/logstash-core/lib/logstash/modules/resource_base.rb @@ -1,4 +1,20 @@ -# encoding: utf-8 +# 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 "logstash/json" require_relative "file_reader" diff --git a/logstash-core/lib/logstash/modules/scaffold.rb b/logstash-core/lib/logstash/modules/scaffold.rb index dfe16f972..05bbc4de0 100644 --- a/logstash-core/lib/logstash/modules/scaffold.rb +++ b/logstash-core/lib/logstash/modules/scaffold.rb @@ -1,4 +1,20 @@ -# encoding: utf-8 +# 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 "erb" require_relative "elasticsearch_config" @@ -52,4 +68,3 @@ module LogStash module Modules class Scaffold end end end end # class LogStash::Modules::Scaffold - diff --git a/logstash-core/lib/logstash/modules/settings_merger.rb b/logstash-core/lib/logstash/modules/settings_merger.rb index 628bfc520..ccf854bc1 100644 --- a/logstash-core/lib/logstash/modules/settings_merger.rb +++ b/logstash-core/lib/logstash/modules/settings_merger.rb @@ -1,4 +1,20 @@ -# encoding: utf-8 +# 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 "logstash/util" module LogStash module Modules module SettingsMerger diff --git a/logstash-core/lib/logstash/modules/util.rb b/logstash-core/lib/logstash/modules/util.rb index 0e52ca156..64dea4996 100644 --- a/logstash-core/lib/logstash/modules/util.rb +++ b/logstash-core/lib/logstash/modules/util.rb @@ -1,4 +1,20 @@ -# encoding: utf-8 +# 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 "scaffold" # This module function should be used when gems or diff --git a/logstash-core/lib/logstash/namespace.rb b/logstash-core/lib/logstash/namespace.rb index 4dfe43e4c..220365a0f 100644 --- a/logstash-core/lib/logstash/namespace.rb +++ b/logstash-core/lib/logstash/namespace.rb @@ -1,2 +1,19 @@ +# 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. + # The contents of this file have been ported to Java. It is included for for compatibility # with plugins that directly require it. diff --git a/logstash-core/lib/logstash/outputs/base.rb b/logstash-core/lib/logstash/outputs/base.rb index 34abe972c..c52dad18f 100644 --- a/logstash-core/lib/logstash/outputs/base.rb +++ b/logstash-core/lib/logstash/outputs/base.rb @@ -1,4 +1,20 @@ -# encoding: utf-8 +# 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 "logstash/event" require "logstash/plugin" require "logstash/config/mixin" diff --git a/logstash-core/lib/logstash/patches.rb b/logstash-core/lib/logstash/patches.rb index 283d74aa3..f458b821c 100644 --- a/logstash-core/lib/logstash/patches.rb +++ b/logstash-core/lib/logstash/patches.rb @@ -1,4 +1,20 @@ -# encoding: utf-8 +# 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 "logstash/patches/bugfix_jruby_2558" require "logstash/patches/cabin" require "logstash/patches/profile_require_calls" diff --git a/logstash-core/lib/logstash/patches/bugfix_jruby_2558.rb b/logstash-core/lib/logstash/patches/bugfix_jruby_2558.rb index 7f6533018..05458a037 100644 --- a/logstash-core/lib/logstash/patches/bugfix_jruby_2558.rb +++ b/logstash-core/lib/logstash/patches/bugfix_jruby_2558.rb @@ -1,4 +1,20 @@ -# encoding: utf-8 +# 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 "logstash/environment" if LogStash::Environment.windows? diff --git a/logstash-core/lib/logstash/patches/cabin.rb b/logstash-core/lib/logstash/patches/cabin.rb index 5d5fc7121..1d009e96b 100644 --- a/logstash-core/lib/logstash/patches/cabin.rb +++ b/logstash-core/lib/logstash/patches/cabin.rb @@ -1,4 +1,20 @@ -# encoding: utf-8 +# 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. + if ENV["PROFILE_BAD_LOG_CALLS"] || ($DEBUGLIST || []).include?("log") # Set PROFILE_BAD_LOG_CALLS=1 in your environment if you want # to track down logger calls that cause performance problems diff --git a/logstash-core/lib/logstash/patches/clamp.rb b/logstash-core/lib/logstash/patches/clamp.rb index df40c0d2d..f21e66583 100644 --- a/logstash-core/lib/logstash/patches/clamp.rb +++ b/logstash-core/lib/logstash/patches/clamp.rb @@ -1,3 +1,20 @@ +# 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 'clamp' require 'logstash/environment' @@ -98,5 +115,3 @@ module Clamp end end end - - diff --git a/logstash-core/lib/logstash/patches/exception_to_json.rb b/logstash-core/lib/logstash/patches/exception_to_json.rb index 00de79f25..dcc351b03 100644 --- a/logstash-core/lib/logstash/patches/exception_to_json.rb +++ b/logstash-core/lib/logstash/patches/exception_to_json.rb @@ -1,3 +1,20 @@ +# 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. + class Exception def to_json {"exception_name" => self.class.name, "message" => message} diff --git a/logstash-core/lib/logstash/patches/profile_require_calls.rb b/logstash-core/lib/logstash/patches/profile_require_calls.rb index 0eb2f2fcc..ab74cb9e8 100644 --- a/logstash-core/lib/logstash/patches/profile_require_calls.rb +++ b/logstash-core/lib/logstash/patches/profile_require_calls.rb @@ -1,4 +1,20 @@ -# encoding: utf-8 +# 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. + if ($DEBUGLIST || []).include?("require") ROOT = File.dirname(__FILE__) module Kernel diff --git a/logstash-core/lib/logstash/patches/puma.rb b/logstash-core/lib/logstash/patches/puma.rb index b8507db18..f3b309c4d 100644 --- a/logstash-core/lib/logstash/patches/puma.rb +++ b/logstash-core/lib/logstash/patches/puma.rb @@ -1,5 +1,20 @@ -# encoding: utf-8 +# 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. + # Patch to replace the usage of STDERR and STDOUT # see: https://github.com/elastic/logstash/issues/5912 module LogStash diff --git a/logstash-core/lib/logstash/patches/stronger_openssl_defaults.rb b/logstash-core/lib/logstash/patches/stronger_openssl_defaults.rb index eeb841dd8..c0c581c5a 100644 --- a/logstash-core/lib/logstash/patches/stronger_openssl_defaults.rb +++ b/logstash-core/lib/logstash/patches/stronger_openssl_defaults.rb @@ -1,4 +1,20 @@ -# encoding: utf-8 +# 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 "openssl" # :nodoc: diff --git a/logstash-core/lib/logstash/pipeline.rb b/logstash-core/lib/logstash/pipeline.rb index cf5fc40d9..b60c0b9f4 100644 --- a/logstash-core/lib/logstash/pipeline.rb +++ b/logstash-core/lib/logstash/pipeline.rb @@ -1,4 +1,20 @@ -# encoding: utf-8 +# 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 "thread" require "stud/interval" require "concurrent" diff --git a/logstash-core/lib/logstash/pipeline_action.rb b/logstash-core/lib/logstash/pipeline_action.rb index 79ce2fb80..f4c1ba9d9 100644 --- a/logstash-core/lib/logstash/pipeline_action.rb +++ b/logstash-core/lib/logstash/pipeline_action.rb @@ -1,4 +1,20 @@ -# encoding: utf-8 +# 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 "logstash/pipeline_action/base" require "logstash/pipeline_action/create" require "logstash/pipeline_action/stop" diff --git a/logstash-core/lib/logstash/pipeline_action/base.rb b/logstash-core/lib/logstash/pipeline_action/base.rb index 364f20ddd..8060cbcc9 100644 --- a/logstash-core/lib/logstash/pipeline_action/base.rb +++ b/logstash-core/lib/logstash/pipeline_action/base.rb @@ -1,4 +1,20 @@ -# encoding: utf-8 +# 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. + # I've decided to take the action strategy, I think this make the code a bit easier to understand. # maybe in the context of config management we will want to have force kill on the # threads instead of waiting forever or sending feedback to the host diff --git a/logstash-core/lib/logstash/pipeline_action/create.rb b/logstash-core/lib/logstash/pipeline_action/create.rb index ede2eb3ef..55c8c6ecf 100644 --- a/logstash-core/lib/logstash/pipeline_action/create.rb +++ b/logstash-core/lib/logstash/pipeline_action/create.rb @@ -1,4 +1,20 @@ -# encoding: utf-8 +# 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 "logstash/pipeline_action/base" require "logstash/pipeline" require "logstash/java_pipeline" diff --git a/logstash-core/lib/logstash/pipeline_action/reload.rb b/logstash-core/lib/logstash/pipeline_action/reload.rb index 2ce5c2921..78001e827 100644 --- a/logstash-core/lib/logstash/pipeline_action/reload.rb +++ b/logstash-core/lib/logstash/pipeline_action/reload.rb @@ -1,4 +1,20 @@ -# encoding: utf-8 +# 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 "logstash/pipeline_action/base" require "logstash/pipeline_action/create" require "logstash/pipeline_action/stop" diff --git a/logstash-core/lib/logstash/pipeline_action/stop.rb b/logstash-core/lib/logstash/pipeline_action/stop.rb index 0bb405629..50d6367fa 100644 --- a/logstash-core/lib/logstash/pipeline_action/stop.rb +++ b/logstash-core/lib/logstash/pipeline_action/stop.rb @@ -1,4 +1,20 @@ -# encoding: utf-8 +# 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 "logstash/pipeline_action/base" module LogStash module PipelineAction diff --git a/logstash-core/lib/logstash/pipeline_reporter.rb b/logstash-core/lib/logstash/pipeline_reporter.rb index 4dfe43e4c..220365a0f 100644 --- a/logstash-core/lib/logstash/pipeline_reporter.rb +++ b/logstash-core/lib/logstash/pipeline_reporter.rb @@ -1,2 +1,19 @@ +# 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. + # The contents of this file have been ported to Java. It is included for for compatibility # with plugins that directly require it. diff --git a/logstash-core/lib/logstash/pipelines_registry.rb b/logstash-core/lib/logstash/pipelines_registry.rb index 6ba13679f..433a397e6 100644 --- a/logstash-core/lib/logstash/pipelines_registry.rb +++ b/logstash-core/lib/logstash/pipelines_registry.rb @@ -1,4 +1,19 @@ -# encoding: utf-8 +# 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. module LogStash class PipelineState diff --git a/logstash-core/lib/logstash/plugin.rb b/logstash-core/lib/logstash/plugin.rb index 1bf346446..2e45b66d9 100644 --- a/logstash-core/lib/logstash/plugin.rb +++ b/logstash-core/lib/logstash/plugin.rb @@ -1,4 +1,20 @@ -# encoding: utf-8 +# 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 "logstash/config/mixin" require "concurrent" require "securerandom" diff --git a/logstash-core/lib/logstash/plugin_metadata.rb b/logstash-core/lib/logstash/plugin_metadata.rb index c3c1df913..edd4ceebb 100644 --- a/logstash-core/lib/logstash/plugin_metadata.rb +++ b/logstash-core/lib/logstash/plugin_metadata.rb @@ -1,4 +1,19 @@ -# encoding: utf-8 +# 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 'thread_safe/cache' diff --git a/logstash-core/lib/logstash/plugins.rb b/logstash-core/lib/logstash/plugins.rb index 215f71f2c..990cae806 100644 --- a/logstash-core/lib/logstash/plugins.rb +++ b/logstash-core/lib/logstash/plugins.rb @@ -1,2 +1,19 @@ +# 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 "logstash/plugins/registry" require 'logstash/plugins/builtin' \ No newline at end of file diff --git a/logstash-core/lib/logstash/plugins/builtin.rb b/logstash-core/lib/logstash/plugins/builtin.rb index 9f84ca37a..1fb4c9fcb 100644 --- a/logstash-core/lib/logstash/plugins/builtin.rb +++ b/logstash-core/lib/logstash/plugins/builtin.rb @@ -1,3 +1,20 @@ +# 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. + module ::LogStash::Plugins::Builtin require 'logstash/plugins/builtin/pipeline/input' require 'logstash/plugins/builtin/pipeline/output' diff --git a/logstash-core/lib/logstash/plugins/builtin/pipeline/input.rb b/logstash-core/lib/logstash/plugins/builtin/pipeline/input.rb index 3e6e01cdb..25dec93a5 100644 --- a/logstash-core/lib/logstash/plugins/builtin/pipeline/input.rb +++ b/logstash-core/lib/logstash/plugins/builtin/pipeline/input.rb @@ -1,3 +1,20 @@ +# 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. + module ::LogStash; module Plugins; module Builtin; module Pipeline; class Input < ::LogStash::Inputs::Base include org.logstash.plugins.pipeline.PipelineInput diff --git a/logstash-core/lib/logstash/plugins/builtin/pipeline/output.rb b/logstash-core/lib/logstash/plugins/builtin/pipeline/output.rb index 5f9e6a810..05835f8e2 100644 --- a/logstash-core/lib/logstash/plugins/builtin/pipeline/output.rb +++ b/logstash-core/lib/logstash/plugins/builtin/pipeline/output.rb @@ -1,3 +1,20 @@ +# 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. + module ::LogStash; module Plugins; module Builtin; module Pipeline; class Output < ::LogStash::Outputs::Base include org.logstash.plugins.pipeline.PipelineOutput diff --git a/logstash-core/lib/logstash/plugins/hooks_registry.rb b/logstash-core/lib/logstash/plugins/hooks_registry.rb index 8bf9c3d84..e249288bf 100644 --- a/logstash-core/lib/logstash/plugins/hooks_registry.rb +++ b/logstash-core/lib/logstash/plugins/hooks_registry.rb @@ -1 +1,16 @@ -# encoding: utf-8 \ No newline at end of file +# 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. diff --git a/logstash-core/lib/logstash/plugins/registry.rb b/logstash-core/lib/logstash/plugins/registry.rb index 8c7435632..9a8de174e 100644 --- a/logstash-core/lib/logstash/plugins/registry.rb +++ b/logstash-core/lib/logstash/plugins/registry.rb @@ -1,4 +1,20 @@ -# encoding: utf-8 +# 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 "rubygems/package" require "logstash/plugin" require "logstash/modules/scaffold" diff --git a/logstash-core/lib/logstash/runner.rb b/logstash-core/lib/logstash/runner.rb index 0728562ab..d0324b822 100644 --- a/logstash-core/lib/logstash/runner.rb +++ b/logstash-core/lib/logstash/runner.rb @@ -1,4 +1,20 @@ -# encoding: utf-8 +# 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. + Thread.abort_on_exception = true Encoding.default_external = Encoding::UTF_8 $DEBUGLIST = (ENV["DEBUG"] || "").split(",") diff --git a/logstash-core/lib/logstash/settings.rb b/logstash-core/lib/logstash/settings.rb index 5d14a2bd9..7994b058a 100644 --- a/logstash-core/lib/logstash/settings.rb +++ b/logstash-core/lib/logstash/settings.rb @@ -1,4 +1,20 @@ -# encoding: utf-8 +# 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 "fileutils" require "logstash/util/byte_value" require "logstash/util/substitution_variables" diff --git a/logstash-core/lib/logstash/shutdown_watcher.rb b/logstash-core/lib/logstash/shutdown_watcher.rb index bca5f6749..e249288bf 100644 --- a/logstash-core/lib/logstash/shutdown_watcher.rb +++ b/logstash-core/lib/logstash/shutdown_watcher.rb @@ -1 +1,16 @@ -# encoding: utf-8 +# 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. diff --git a/logstash-core/lib/logstash/state_resolver.rb b/logstash-core/lib/logstash/state_resolver.rb index ec32d23ba..72e177978 100644 --- a/logstash-core/lib/logstash/state_resolver.rb +++ b/logstash-core/lib/logstash/state_resolver.rb @@ -1,4 +1,20 @@ -# encoding: utf-8 +# 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. + module LogStash # In the beginning I was using this code as a method in the Agent class directly # But with the plugins system I think we should be able to swap what kind of action would be run. diff --git a/logstash-core/lib/logstash/timestamp.rb b/logstash-core/lib/logstash/timestamp.rb index 60f9a95db..9bed6ac90 100644 --- a/logstash-core/lib/logstash/timestamp.rb +++ b/logstash-core/lib/logstash/timestamp.rb @@ -1,2 +1,19 @@ +# 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. + # The contents of this file have been ported to Java. It is included for for compatibility # with plugins that directly require "logstash/timestamp". diff --git a/logstash-core/lib/logstash/universal_plugin.rb b/logstash-core/lib/logstash/universal_plugin.rb index cf7879f56..dd0059212 100644 --- a/logstash-core/lib/logstash/universal_plugin.rb +++ b/logstash-core/lib/logstash/universal_plugin.rb @@ -1 +1,18 @@ +# 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. + # Keeping this file for backwards compatibility with plugins that include it directly. diff --git a/logstash-core/lib/logstash/util.rb b/logstash-core/lib/logstash/util.rb index 614dcf1ea..091151101 100644 --- a/logstash-core/lib/logstash/util.rb +++ b/logstash-core/lib/logstash/util.rb @@ -1,4 +1,20 @@ -# encoding: utf-8 +# 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 "logstash/environment" module LogStash::Util diff --git a/logstash-core/lib/logstash/util/buftok.rb b/logstash-core/lib/logstash/util/buftok.rb index cf7879f56..dd0059212 100644 --- a/logstash-core/lib/logstash/util/buftok.rb +++ b/logstash-core/lib/logstash/util/buftok.rb @@ -1 +1,18 @@ +# 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. + # Keeping this file for backwards compatibility with plugins that include it directly. diff --git a/logstash-core/lib/logstash/util/byte_value.rb b/logstash-core/lib/logstash/util/byte_value.rb index 593a1e034..77a44208d 100644 --- a/logstash-core/lib/logstash/util/byte_value.rb +++ b/logstash-core/lib/logstash/util/byte_value.rb @@ -1,4 +1,19 @@ -# encoding: utf-8 +# 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. module LogStash; module Util; module ByteValue module_function diff --git a/logstash-core/lib/logstash/util/charset.rb b/logstash-core/lib/logstash/util/charset.rb index 38cf1a6a4..76db34205 100644 --- a/logstash-core/lib/logstash/util/charset.rb +++ b/logstash-core/lib/logstash/util/charset.rb @@ -1,4 +1,20 @@ -# encoding: utf-8 +# 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 "logstash/util" class LogStash::Util::Charset diff --git a/logstash-core/lib/logstash/util/cloud_setting_auth.rb b/logstash-core/lib/logstash/util/cloud_setting_auth.rb index e3284f918..c36672dd4 100644 --- a/logstash-core/lib/logstash/util/cloud_setting_auth.rb +++ b/logstash-core/lib/logstash/util/cloud_setting_auth.rb @@ -1,4 +1,20 @@ -# encoding: utf-8 +# 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 "logstash/util/password" module LogStash module Util class CloudSettingAuth diff --git a/logstash-core/lib/logstash/util/cloud_setting_id.rb b/logstash-core/lib/logstash/util/cloud_setting_id.rb index a333447a6..0a47bdbc8 100644 --- a/logstash-core/lib/logstash/util/cloud_setting_id.rb +++ b/logstash-core/lib/logstash/util/cloud_setting_id.rb @@ -1,4 +1,20 @@ -# encoding: utf-8 +# 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 "base64" module LogStash module Util class CloudSettingId diff --git a/logstash-core/lib/logstash/util/dead_letter_queue_manager.rb b/logstash-core/lib/logstash/util/dead_letter_queue_manager.rb index 548cf47a6..0f4032e3a 100644 --- a/logstash-core/lib/logstash/util/dead_letter_queue_manager.rb +++ b/logstash-core/lib/logstash/util/dead_letter_queue_manager.rb @@ -1,2 +1,19 @@ +# 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. + # The contents of this file have been ported to Java. It is included for for compatibility # with plugins that directly include it. diff --git a/logstash-core/lib/logstash/util/decorators.rb b/logstash-core/lib/logstash/util/decorators.rb index bb98a081c..15f52e4b8 100644 --- a/logstash-core/lib/logstash/util/decorators.rb +++ b/logstash-core/lib/logstash/util/decorators.rb @@ -1,4 +1,20 @@ -# encoding: utf-8 +# 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 "logstash/util" module LogStash::Util diff --git a/logstash-core/lib/logstash/util/java_version.rb b/logstash-core/lib/logstash/util/java_version.rb index ba87c2b4e..7582425e8 100644 --- a/logstash-core/lib/logstash/util/java_version.rb +++ b/logstash-core/lib/logstash/util/java_version.rb @@ -1,4 +1,19 @@ -# encoding: utf-8 +# 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. module LogStash::Util::JavaVersion # Return the current java version string. Returns nil if this is a non-java platform (e.g. MRI). diff --git a/logstash-core/lib/logstash/util/loggable.rb b/logstash-core/lib/logstash/util/loggable.rb index cf7879f56..dd0059212 100644 --- a/logstash-core/lib/logstash/util/loggable.rb +++ b/logstash-core/lib/logstash/util/loggable.rb @@ -1 +1,18 @@ +# 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. + # Keeping this file for backwards compatibility with plugins that include it directly. diff --git a/logstash-core/lib/logstash/util/manticore_ssl_config_helper.rb b/logstash-core/lib/logstash/util/manticore_ssl_config_helper.rb index f91bdc424..2654c05d4 100644 --- a/logstash-core/lib/logstash/util/manticore_ssl_config_helper.rb +++ b/logstash-core/lib/logstash/util/manticore_ssl_config_helper.rb @@ -1,4 +1,19 @@ -# encoding: utf-8 +# 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. module LogStash; module Util; module ManticoreSSLConfigHelper extend self diff --git a/logstash-core/lib/logstash/util/modules_setting_array.rb b/logstash-core/lib/logstash/util/modules_setting_array.rb index 5b4b2da8c..84be32fc5 100644 --- a/logstash-core/lib/logstash/util/modules_setting_array.rb +++ b/logstash-core/lib/logstash/util/modules_setting_array.rb @@ -1,4 +1,20 @@ -# encoding: utf-8 +# 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 "forwardable" require "logstash/util/password" diff --git a/logstash-core/lib/logstash/util/password.rb b/logstash-core/lib/logstash/util/password.rb index c84adbe33..bb55ff1d0 100644 --- a/logstash-core/lib/logstash/util/password.rb +++ b/logstash-core/lib/logstash/util/password.rb @@ -1,4 +1,19 @@ -# encoding: utf-8 +# 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. # This class exists to quietly wrap a password string so that, when printed or # logged, you don't accidentally print the password itself. diff --git a/logstash-core/lib/logstash/util/plugin_version.rb b/logstash-core/lib/logstash/util/plugin_version.rb index ab296bdef..033d33f54 100644 --- a/logstash-core/lib/logstash/util/plugin_version.rb +++ b/logstash-core/lib/logstash/util/plugin_version.rb @@ -1,4 +1,20 @@ -# encoding: utf-8 +# 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 'rubygems/version' require 'forwardable' diff --git a/logstash-core/lib/logstash/util/prctl.rb b/logstash-core/lib/logstash/util/prctl.rb index ffb572014..2022cfbc1 100644 --- a/logstash-core/lib/logstash/util/prctl.rb +++ b/logstash-core/lib/logstash/util/prctl.rb @@ -1,4 +1,20 @@ -# encoding: utf-8 +# 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. + module LibC require "ffi" extend FFI::Library @@ -7,4 +23,3 @@ module LibC # Ok so the 2nd arg isn't really a string... but whatever attach_function :prctl, [:int, :string, :long, :long, :long], :int end - diff --git a/logstash-core/lib/logstash/util/safe_uri.rb b/logstash-core/lib/logstash/util/safe_uri.rb index 63684f606..f2f095432 100644 --- a/logstash-core/lib/logstash/util/safe_uri.rb +++ b/logstash-core/lib/logstash/util/safe_uri.rb @@ -1,4 +1,20 @@ -# encoding: utf-8 +# 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 "logstash/util" require "forwardable" @@ -193,4 +209,3 @@ class LogStash::Util::SafeURI java.net.URI.new(scheme, user_info, host, port || -1, prefixed_path, query, fragment) end end - diff --git a/logstash-core/lib/logstash/util/secretstore.rb b/logstash-core/lib/logstash/util/secretstore.rb index cf7879f56..dd0059212 100644 --- a/logstash-core/lib/logstash/util/secretstore.rb +++ b/logstash-core/lib/logstash/util/secretstore.rb @@ -1 +1,18 @@ +# 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. + # Keeping this file for backwards compatibility with plugins that include it directly. diff --git a/logstash-core/lib/logstash/util/settings_helper.rb b/logstash-core/lib/logstash/util/settings_helper.rb index 77b5c003c..1c0dbd6c7 100644 --- a/logstash-core/lib/logstash/util/settings_helper.rb +++ b/logstash-core/lib/logstash/util/settings_helper.rb @@ -1,3 +1,20 @@ +# 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 "logstash/settings" require "logstash-core/logstash-core" require "logstash/environment" diff --git a/logstash-core/lib/logstash/util/socket_peer.rb b/logstash-core/lib/logstash/util/socket_peer.rb index 56ea2f3e2..7220e34cd 100644 --- a/logstash-core/lib/logstash/util/socket_peer.rb +++ b/logstash-core/lib/logstash/util/socket_peer.rb @@ -1,4 +1,20 @@ -# encoding: utf-8 +# 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. + module ::LogStash::Util::SocketPeer public def peer diff --git a/logstash-core/lib/logstash/util/substitution_variables.rb b/logstash-core/lib/logstash/util/substitution_variables.rb index 41ff14a7e..e21bdfc82 100644 --- a/logstash-core/lib/logstash/util/substitution_variables.rb +++ b/logstash-core/lib/logstash/util/substitution_variables.rb @@ -1,4 +1,19 @@ -# encoding: utf-8 +# 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. java_import "org.logstash.secret.store.SecretStoreExt" diff --git a/logstash-core/lib/logstash/util/thread_dump.rb b/logstash-core/lib/logstash/util/thread_dump.rb index bd61874af..8f18e56c3 100644 --- a/logstash-core/lib/logstash/util/thread_dump.rb +++ b/logstash-core/lib/logstash/util/thread_dump.rb @@ -1,4 +1,20 @@ -# encoding: utf-8 +# 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. + java_import 'org.logstash.instrument.reports.ThreadsReport' module LogStash diff --git a/logstash-core/lib/logstash/util/time_value.rb b/logstash-core/lib/logstash/util/time_value.rb index 63e19ce02..f1291f232 100644 --- a/logstash-core/lib/logstash/util/time_value.rb +++ b/logstash-core/lib/logstash/util/time_value.rb @@ -1,3 +1,20 @@ +# 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. + module LogStash module Util class TimeValue diff --git a/logstash-core/lib/logstash/util/worker_threads_default_printer.rb b/logstash-core/lib/logstash/util/worker_threads_default_printer.rb index 11c5f687c..a45184cc1 100644 --- a/logstash-core/lib/logstash/util/worker_threads_default_printer.rb +++ b/logstash-core/lib/logstash/util/worker_threads_default_printer.rb @@ -1,4 +1,20 @@ -# encoding: utf-8 +# 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 "logstash/util" # This class exists to format the settings for default worker threads @@ -25,4 +41,3 @@ module LogStash module Util class WorkerThreadsDefaultPrinter end end end end - diff --git a/logstash-core/lib/logstash/version.rb b/logstash-core/lib/logstash/version.rb index 5ec0f8d5e..75f3bc0af 100644 --- a/logstash-core/lib/logstash/version.rb +++ b/logstash-core/lib/logstash/version.rb @@ -1,4 +1,19 @@ -# encoding: utf-8 +# 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. # The version of the logstash package (not the logstash-core gem version). # diff --git a/logstash-core/lib/logstash/webserver.rb b/logstash-core/lib/logstash/webserver.rb index 0531cb843..c07989d9b 100644 --- a/logstash-core/lib/logstash/webserver.rb +++ b/logstash-core/lib/logstash/webserver.rb @@ -1,4 +1,20 @@ -# encoding: utf-8 +# 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 "logstash/api/rack_app" require "puma" require "puma/server" diff --git a/logstash-core/spec/conditionals_spec.rb b/logstash-core/spec/conditionals_spec.rb index fd7f94718..c7507ed11 100644 --- a/logstash-core/spec/conditionals_spec.rb +++ b/logstash-core/spec/conditionals_spec.rb @@ -1,4 +1,20 @@ -# encoding: utf-8 +# 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 'spec_helper' require 'support/pipeline/pipeline_helpers' diff --git a/logstash-core/spec/logstash/acked_queue_concurrent_stress_spec.rb b/logstash-core/spec/logstash/acked_queue_concurrent_stress_spec.rb index 06435f1f3..06a013d06 100644 --- a/logstash-core/spec/logstash/acked_queue_concurrent_stress_spec.rb +++ b/logstash-core/spec/logstash/acked_queue_concurrent_stress_spec.rb @@ -1,4 +1,20 @@ -# encoding: utf-8 +# 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 "logstash/event" require "logstash/instrument/namespaced_metric" diff --git a/logstash-core/spec/logstash/agent/converge_spec.rb b/logstash-core/spec/logstash/agent/converge_spec.rb index 0e0f8941f..85d4f264b 100644 --- a/logstash-core/spec/logstash/agent/converge_spec.rb +++ b/logstash-core/spec/logstash/agent/converge_spec.rb @@ -1,4 +1,20 @@ -# encoding: utf-8 +# 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 "logstash/agent" require_relative "../../support/helpers" require_relative "../../support/matchers" diff --git a/logstash-core/spec/logstash/agent/metrics_spec.rb b/logstash-core/spec/logstash/agent/metrics_spec.rb index cdf33ef74..5e14b007d 100644 --- a/logstash-core/spec/logstash/agent/metrics_spec.rb +++ b/logstash-core/spec/logstash/agent/metrics_spec.rb @@ -1,5 +1,20 @@ -# encoding: utf-8 +# 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 "logstash/agent" require_relative "../../support/helpers" require_relative "../../support/matchers" diff --git a/logstash-core/spec/logstash/agent_spec.rb b/logstash-core/spec/logstash/agent_spec.rb index 9af834913..d69c8671b 100644 --- a/logstash-core/spec/logstash/agent_spec.rb +++ b/logstash-core/spec/logstash/agent_spec.rb @@ -1,4 +1,20 @@ -# encoding: utf-8 +# 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 "spec_helper" require "stud/temporary" require "logstash/inputs/generator" diff --git a/logstash-core/spec/logstash/api/commands/default_metadata_spec.rb b/logstash-core/spec/logstash/api/commands/default_metadata_spec.rb index db4a39757..f38316529 100644 --- a/logstash-core/spec/logstash/api/commands/default_metadata_spec.rb +++ b/logstash-core/spec/logstash/api/commands/default_metadata_spec.rb @@ -1,4 +1,20 @@ -# encoding: utf-8 +# 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 "spec_helper" describe LogStash::Api::Commands::DefaultMetadata do diff --git a/logstash-core/spec/logstash/api/commands/node_spec.rb b/logstash-core/spec/logstash/api/commands/node_spec.rb index 0077519bc..4e0f6c865 100644 --- a/logstash-core/spec/logstash/api/commands/node_spec.rb +++ b/logstash-core/spec/logstash/api/commands/node_spec.rb @@ -1,4 +1,20 @@ -# encoding: utf-8 +# 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 "spec_helper" describe LogStash::Api::Commands::Node do diff --git a/logstash-core/spec/logstash/api/commands/stats_spec.rb b/logstash-core/spec/logstash/api/commands/stats_spec.rb index 792a1d6df..cfe5767aa 100644 --- a/logstash-core/spec/logstash/api/commands/stats_spec.rb +++ b/logstash-core/spec/logstash/api/commands/stats_spec.rb @@ -1,4 +1,20 @@ -# encoding: utf-8 +# 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 "spec_helper" describe LogStash::Api::Commands::Stats do diff --git a/logstash-core/spec/logstash/api/errors_spec.rb b/logstash-core/spec/logstash/api/errors_spec.rb index 49e6e1462..ec3c719e8 100644 --- a/logstash-core/spec/logstash/api/errors_spec.rb +++ b/logstash-core/spec/logstash/api/errors_spec.rb @@ -1,4 +1,20 @@ -# encoding: utf-8 +# 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 "spec_helper" require "logstash/api/errors" diff --git a/logstash-core/spec/logstash/api/modules/logging_spec.rb b/logstash-core/spec/logstash/api/modules/logging_spec.rb index 9d67a4fe1..9efb290c6 100644 --- a/logstash-core/spec/logstash/api/modules/logging_spec.rb +++ b/logstash-core/spec/logstash/api/modules/logging_spec.rb @@ -1,4 +1,20 @@ -# encoding: utf-8 +# 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 "spec_helper" require "json-schema" require "sinatra" diff --git a/logstash-core/spec/logstash/api/modules/node_plugins_spec.rb b/logstash-core/spec/logstash/api/modules/node_plugins_spec.rb index 01eede56d..d252ba71a 100644 --- a/logstash-core/spec/logstash/api/modules/node_plugins_spec.rb +++ b/logstash-core/spec/logstash/api/modules/node_plugins_spec.rb @@ -1,4 +1,20 @@ -# encoding: utf-8 +# 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 "spec_helper" require "json-schema" require "sinatra" diff --git a/logstash-core/spec/logstash/api/modules/node_spec.rb b/logstash-core/spec/logstash/api/modules/node_spec.rb index 0f6a71113..bf34e365c 100644 --- a/logstash-core/spec/logstash/api/modules/node_spec.rb +++ b/logstash-core/spec/logstash/api/modules/node_spec.rb @@ -1,4 +1,20 @@ -# encoding: utf-8 +# 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 "spec_helper" require "json-schema" require "sinatra" diff --git a/logstash-core/spec/logstash/api/modules/node_stats_spec.rb b/logstash-core/spec/logstash/api/modules/node_stats_spec.rb index 825604a4e..247ef5136 100644 --- a/logstash-core/spec/logstash/api/modules/node_stats_spec.rb +++ b/logstash-core/spec/logstash/api/modules/node_stats_spec.rb @@ -1,4 +1,20 @@ -# encoding: utf-8 +# 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 "spec_helper" require "sinatra" diff --git a/logstash-core/spec/logstash/api/modules/plugins_spec.rb b/logstash-core/spec/logstash/api/modules/plugins_spec.rb index 265a7b2b9..b65fb8ec5 100644 --- a/logstash-core/spec/logstash/api/modules/plugins_spec.rb +++ b/logstash-core/spec/logstash/api/modules/plugins_spec.rb @@ -1,4 +1,20 @@ -# encoding: utf-8 +# 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 "spec_helper" require "json-schema" require "sinatra" diff --git a/logstash-core/spec/logstash/api/modules/root_spec.rb b/logstash-core/spec/logstash/api/modules/root_spec.rb index 6c2d950b9..22fbfe44d 100644 --- a/logstash-core/spec/logstash/api/modules/root_spec.rb +++ b/logstash-core/spec/logstash/api/modules/root_spec.rb @@ -1,4 +1,20 @@ -# encoding: utf-8 +# 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 "spec_helper" require "sinatra" @@ -14,4 +30,3 @@ describe LogStash::Api::Modules::Root do include_examples "not found" end - diff --git a/logstash-core/spec/logstash/api/rack_app_spec.rb b/logstash-core/spec/logstash/api/rack_app_spec.rb index 5b31dc8c8..24f085f14 100644 --- a/logstash-core/spec/logstash/api/rack_app_spec.rb +++ b/logstash-core/spec/logstash/api/rack_app_spec.rb @@ -1,3 +1,20 @@ +# 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 "logstash/api/rack_app" require "json-schema" require "rack/test" diff --git a/logstash-core/spec/logstash/bootstrap_check/persisted_queue_config_spec.rb b/logstash-core/spec/logstash/bootstrap_check/persisted_queue_config_spec.rb index 09d589a6c..ea614e4a9 100644 --- a/logstash-core/spec/logstash/bootstrap_check/persisted_queue_config_spec.rb +++ b/logstash-core/spec/logstash/bootstrap_check/persisted_queue_config_spec.rb @@ -1,3 +1,20 @@ +# 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 "spec_helper" require "tmpdir" require "logstash/bootstrap_check/persisted_queue_config" diff --git a/logstash-core/spec/logstash/codecs/base_spec.rb b/logstash-core/spec/logstash/codecs/base_spec.rb index 42b07b5d4..e8cf44587 100644 --- a/logstash-core/spec/logstash/codecs/base_spec.rb +++ b/logstash-core/spec/logstash/codecs/base_spec.rb @@ -1,4 +1,20 @@ -# encoding: utf-8 +# 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 "spec_helper" DATA_DOUBLE = "data".freeze diff --git a/logstash-core/spec/logstash/codecs/delegator_spec.rb b/logstash-core/spec/logstash/codecs/delegator_spec.rb index c5702ee94..7a7da19dc 100644 --- a/logstash-core/spec/logstash/codecs/delegator_spec.rb +++ b/logstash-core/spec/logstash/codecs/delegator_spec.rb @@ -1,4 +1,20 @@ -# encoding: utf-8 +# 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 "spec_helper" class LogStash::Codecs::MockCodec < LogStash::Codecs::Base diff --git a/logstash-core/spec/logstash/compiler/compiler_spec.rb b/logstash-core/spec/logstash/compiler/compiler_spec.rb index 55732b414..35f4b48fb 100644 --- a/logstash-core/spec/logstash/compiler/compiler_spec.rb +++ b/logstash-core/spec/logstash/compiler/compiler_spec.rb @@ -1,3 +1,20 @@ +# 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 "spec_helper" require "logstash/compiler" require "support/helpers" diff --git a/logstash-core/spec/logstash/config/config_ast_spec.rb b/logstash-core/spec/logstash/config/config_ast_spec.rb index 7e1d5edf2..8a9ed6dea 100644 --- a/logstash-core/spec/logstash/config/config_ast_spec.rb +++ b/logstash-core/spec/logstash/config/config_ast_spec.rb @@ -1,6 +1,21 @@ -# encoding: utf-8 -# config syntax tests +# 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. + +# config syntax tests require "spec_helper" require "logstash/config/grammar" require "logstash/config/config_ast" diff --git a/logstash-core/spec/logstash/config/cpu_core_strategy_spec.rb b/logstash-core/spec/logstash/config/cpu_core_strategy_spec.rb index c9b69fd26..8c6608e11 100644 --- a/logstash-core/spec/logstash/config/cpu_core_strategy_spec.rb +++ b/logstash-core/spec/logstash/config/cpu_core_strategy_spec.rb @@ -1,4 +1,20 @@ -# encoding: utf-8 +# 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 "spec_helper" require "logstash/config/cpu_core_strategy" diff --git a/logstash-core/spec/logstash/config/defaults_spec.rb b/logstash-core/spec/logstash/config/defaults_spec.rb index 6fb363f48..6451d9286 100644 --- a/logstash-core/spec/logstash/config/defaults_spec.rb +++ b/logstash-core/spec/logstash/config/defaults_spec.rb @@ -1,4 +1,20 @@ -# encoding: utf-8 +# 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 "spec_helper" require "logstash/config/defaults" diff --git a/logstash-core/spec/logstash/config/mixin_spec.rb b/logstash-core/spec/logstash/config/mixin_spec.rb index c4cdfe180..a860d0f7f 100644 --- a/logstash-core/spec/logstash/config/mixin_spec.rb +++ b/logstash-core/spec/logstash/config/mixin_spec.rb @@ -1,4 +1,20 @@ -# encoding: utf-8 +# 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 "spec_helper" require "logstash/config/mixin" diff --git a/logstash-core/spec/logstash/config/pipeline_config_spec.rb b/logstash-core/spec/logstash/config/pipeline_config_spec.rb index fa76e1719..a7011b372 100644 --- a/logstash-core/spec/logstash/config/pipeline_config_spec.rb +++ b/logstash-core/spec/logstash/config/pipeline_config_spec.rb @@ -1,4 +1,20 @@ -# encoding: utf-8 +# 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 "logstash/config/pipeline_config" require "logstash/config/source/local" diff --git a/logstash-core/spec/logstash/config/source/local_spec.rb b/logstash-core/spec/logstash/config/source/local_spec.rb index 2d5574839..f44b35ab5 100644 --- a/logstash-core/spec/logstash/config/source/local_spec.rb +++ b/logstash-core/spec/logstash/config/source/local_spec.rb @@ -1,4 +1,20 @@ -# encoding: utf-8 +# 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 "logstash/config/source/local" require "rspec/expectations" require "stud/temporary" diff --git a/logstash-core/spec/logstash/config/source/multi_local_spec.rb b/logstash-core/spec/logstash/config/source/multi_local_spec.rb index b4d6de0ca..4746cd5f9 100644 --- a/logstash-core/spec/logstash/config/source/multi_local_spec.rb +++ b/logstash-core/spec/logstash/config/source/multi_local_spec.rb @@ -1,4 +1,20 @@ -# encoding: utf-8 +# 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 "logstash/config/source/multi_local" require "rspec/expectations" require "stud/temporary" diff --git a/logstash-core/spec/logstash/config/source_loader_spec.rb b/logstash-core/spec/logstash/config/source_loader_spec.rb index 8f3fad052..309900ee8 100644 --- a/logstash-core/spec/logstash/config/source_loader_spec.rb +++ b/logstash-core/spec/logstash/config/source_loader_spec.rb @@ -1,4 +1,20 @@ -# encoding: utf-8 +# 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 "logstash/config/source_loader" require "logstash/config/source/base" require_relative "../../support/helpers" diff --git a/logstash-core/spec/logstash/config/string_escape_spec.rb b/logstash-core/spec/logstash/config/string_escape_spec.rb index a5f345688..e2b0c1924 100644 --- a/logstash-core/spec/logstash/config/string_escape_spec.rb +++ b/logstash-core/spec/logstash/config/string_escape_spec.rb @@ -1,3 +1,19 @@ +# 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 "logstash/config/string_escape" diff --git a/logstash-core/spec/logstash/converge_result_spec.rb b/logstash-core/spec/logstash/converge_result_spec.rb index ea13a0bb1..bd590e6ad 100644 --- a/logstash-core/spec/logstash/converge_result_spec.rb +++ b/logstash-core/spec/logstash/converge_result_spec.rb @@ -1,4 +1,20 @@ -# encoding: utf-8 +# 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 "logstash/pipeline_action/stop" require "spec_helper" diff --git a/logstash-core/spec/logstash/elasticsearch_client_spec.rb b/logstash-core/spec/logstash/elasticsearch_client_spec.rb index 52356aa48..7a2964cdd 100644 --- a/logstash-core/spec/logstash/elasticsearch_client_spec.rb +++ b/logstash-core/spec/logstash/elasticsearch_client_spec.rb @@ -1,5 +1,20 @@ -# encoding: utf-8 +# 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 "logstash/elasticsearch_client" describe LogStash::ElasticsearchClient do diff --git a/logstash-core/spec/logstash/environment_spec.rb b/logstash-core/spec/logstash/environment_spec.rb index 79d05fbea..111747660 100644 --- a/logstash-core/spec/logstash/environment_spec.rb +++ b/logstash-core/spec/logstash/environment_spec.rb @@ -1,4 +1,20 @@ -# encoding: utf-8 +# 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 "spec_helper" require "logstash/environment" diff --git a/logstash-core/spec/logstash/event_dispatcher_spec.rb b/logstash-core/spec/logstash/event_dispatcher_spec.rb index dfe24131e..b1f5431d0 100644 --- a/logstash-core/spec/logstash/event_dispatcher_spec.rb +++ b/logstash-core/spec/logstash/event_dispatcher_spec.rb @@ -1,5 +1,20 @@ -# encoding: utf-8 +# 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. + describe LogStash::EventDispatcher do class DummyEmitter attr_reader :dispatcher diff --git a/logstash-core/spec/logstash/event_spec.rb b/logstash-core/spec/logstash/event_spec.rb index c4aa25f2b..2e10ff1f2 100644 --- a/logstash-core/spec/logstash/event_spec.rb +++ b/logstash-core/spec/logstash/event_spec.rb @@ -1,4 +1,19 @@ -# encoding: utf-8 +# 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 "spec_helper" require "logstash/util" diff --git a/logstash-core/spec/logstash/execution_context_spec.rb b/logstash-core/spec/logstash/execution_context_spec.rb index a34c03779..d1e529cbf 100644 --- a/logstash-core/spec/logstash/execution_context_spec.rb +++ b/logstash-core/spec/logstash/execution_context_spec.rb @@ -1,4 +1,20 @@ -# encoding: utf-8 +# 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 "spec_helper" describe LogStash::ExecutionContext do diff --git a/logstash-core/spec/logstash/filter_delegator_spec.rb b/logstash-core/spec/logstash/filter_delegator_spec.rb index 36d7605b2..792208c69 100644 --- a/logstash-core/spec/logstash/filter_delegator_spec.rb +++ b/logstash-core/spec/logstash/filter_delegator_spec.rb @@ -1,4 +1,20 @@ -# encoding: utf-8 +# 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 "spec_helper" require 'logstash/instrument/collector' require "logstash/filter_delegator" diff --git a/logstash-core/spec/logstash/filters/base_spec.rb b/logstash-core/spec/logstash/filters/base_spec.rb index 6baf71d6b..f1d46bfe2 100644 --- a/logstash-core/spec/logstash/filters/base_spec.rb +++ b/logstash-core/spec/logstash/filters/base_spec.rb @@ -1,4 +1,20 @@ -# encoding: utf-8 +# 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 "spec_helper" require "logstash/json" require 'support/pipeline/pipeline_helpers' diff --git a/logstash-core/spec/logstash/inputs/base_spec.rb b/logstash-core/spec/logstash/inputs/base_spec.rb index 445c22104..9540bbe38 100644 --- a/logstash-core/spec/logstash/inputs/base_spec.rb +++ b/logstash-core/spec/logstash/inputs/base_spec.rb @@ -1,4 +1,20 @@ -# encoding: utf-8 +# 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 "spec_helper" require "logstash/inputs/base" require "support/shared_contexts" diff --git a/logstash-core/spec/logstash/instrument/collector_spec.rb b/logstash-core/spec/logstash/instrument/collector_spec.rb index b5c9b3073..f679aa213 100644 --- a/logstash-core/spec/logstash/instrument/collector_spec.rb +++ b/logstash-core/spec/logstash/instrument/collector_spec.rb @@ -1,4 +1,20 @@ -# encoding: utf-8 +# 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 "logstash/instrument/collector" require "spec_helper" diff --git a/logstash-core/spec/logstash/instrument/metric_spec.rb b/logstash-core/spec/logstash/instrument/metric_spec.rb index 1e1397bdd..b46068045 100644 --- a/logstash-core/spec/logstash/instrument/metric_spec.rb +++ b/logstash-core/spec/logstash/instrument/metric_spec.rb @@ -1,4 +1,20 @@ -# encoding: utf-8 +# 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 "logstash/instrument/collector" require_relative "../../support/matchers" require "spec_helper" diff --git a/logstash-core/spec/logstash/instrument/metric_store_spec.rb b/logstash-core/spec/logstash/instrument/metric_store_spec.rb index dac026643..f7b8d1c8d 100644 --- a/logstash-core/spec/logstash/instrument/metric_store_spec.rb +++ b/logstash-core/spec/logstash/instrument/metric_store_spec.rb @@ -1,4 +1,20 @@ -# encoding: utf-8 +# 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 "logstash/instrument/metric_store" describe LogStash::Instrument::MetricStore do diff --git a/logstash-core/spec/logstash/instrument/metric_type/counter_spec.rb b/logstash-core/spec/logstash/instrument/metric_type/counter_spec.rb index 82b7c581a..2cbb8bf03 100644 --- a/logstash-core/spec/logstash/instrument/metric_type/counter_spec.rb +++ b/logstash-core/spec/logstash/instrument/metric_type/counter_spec.rb @@ -1,4 +1,20 @@ -# encoding: utf-8 +# 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 "logstash/instrument/metric_type/counter" require "spec_helper" diff --git a/logstash-core/spec/logstash/instrument/metric_type/gauge_spec.rb b/logstash-core/spec/logstash/instrument/metric_type/gauge_spec.rb index 69ee278a0..4aab9db4d 100644 --- a/logstash-core/spec/logstash/instrument/metric_type/gauge_spec.rb +++ b/logstash-core/spec/logstash/instrument/metric_type/gauge_spec.rb @@ -1,4 +1,20 @@ -# encoding: utf-8 +# 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 "logstash/instrument/metric_type/gauge" require "logstash/json" require "spec_helper" diff --git a/logstash-core/spec/logstash/instrument/namespaced_metric_spec.rb b/logstash-core/spec/logstash/instrument/namespaced_metric_spec.rb index d850d5c01..2bf90602c 100644 --- a/logstash-core/spec/logstash/instrument/namespaced_metric_spec.rb +++ b/logstash-core/spec/logstash/instrument/namespaced_metric_spec.rb @@ -1,4 +1,20 @@ -# encoding: utf-8 +# 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 "../../support/matchers" require_relative "../../support/shared_examples" require "spec_helper" diff --git a/logstash-core/spec/logstash/instrument/namespaced_null_metric_spec.rb b/logstash-core/spec/logstash/instrument/namespaced_null_metric_spec.rb index 3e97c330f..991e95647 100644 --- a/logstash-core/spec/logstash/instrument/namespaced_null_metric_spec.rb +++ b/logstash-core/spec/logstash/instrument/namespaced_null_metric_spec.rb @@ -1,4 +1,20 @@ -# encoding: utf-8 +# 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 "../../support/matchers" require "spec_helper" diff --git a/logstash-core/spec/logstash/instrument/null_metric_spec.rb b/logstash-core/spec/logstash/instrument/null_metric_spec.rb index a01ed8372..382fc408d 100644 --- a/logstash-core/spec/logstash/instrument/null_metric_spec.rb +++ b/logstash-core/spec/logstash/instrument/null_metric_spec.rb @@ -1,4 +1,20 @@ -# encoding: utf-8 +# 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 "../../support/shared_examples" require_relative "../../support/matchers" require "spec_helper" diff --git a/logstash-core/spec/logstash/instrument/periodic_poller/base_spec.rb b/logstash-core/spec/logstash/instrument/periodic_poller/base_spec.rb index 63be505b4..197693329 100644 --- a/logstash-core/spec/logstash/instrument/periodic_poller/base_spec.rb +++ b/logstash-core/spec/logstash/instrument/periodic_poller/base_spec.rb @@ -1,4 +1,20 @@ -# encoding: utf-8 +# 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 "logstash/instrument/periodic_poller/base" require "logstash/instrument/collector" diff --git a/logstash-core/spec/logstash/instrument/periodic_poller/cgroup_spec.rb b/logstash-core/spec/logstash/instrument/periodic_poller/cgroup_spec.rb index 735e6732e..696050edc 100644 --- a/logstash-core/spec/logstash/instrument/periodic_poller/cgroup_spec.rb +++ b/logstash-core/spec/logstash/instrument/periodic_poller/cgroup_spec.rb @@ -1,4 +1,20 @@ -# encoding: utf-8 +# 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 "logstash/instrument/periodic_poller/cgroup" require "spec_helper" diff --git a/logstash-core/spec/logstash/instrument/periodic_poller/dlq_spec.rb b/logstash-core/spec/logstash/instrument/periodic_poller/dlq_spec.rb index a818dd113..64d55475a 100644 --- a/logstash-core/spec/logstash/instrument/periodic_poller/dlq_spec.rb +++ b/logstash-core/spec/logstash/instrument/periodic_poller/dlq_spec.rb @@ -1,4 +1,20 @@ -# encoding: utf-8 +# 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 "spec_helper" require "logstash/instrument/periodic_poller/dlq" require "logstash/instrument/collector" diff --git a/logstash-core/spec/logstash/instrument/periodic_poller/jvm_spec.rb b/logstash-core/spec/logstash/instrument/periodic_poller/jvm_spec.rb index f7edb2f02..b6452b005 100644 --- a/logstash-core/spec/logstash/instrument/periodic_poller/jvm_spec.rb +++ b/logstash-core/spec/logstash/instrument/periodic_poller/jvm_spec.rb @@ -1,4 +1,20 @@ -# encoding: utf-8 +# 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 "spec_helper" require "logstash/instrument/periodic_poller/jvm" require "logstash/instrument/collector" diff --git a/logstash-core/spec/logstash/instrument/periodic_poller/load_average_spec.rb b/logstash-core/spec/logstash/instrument/periodic_poller/load_average_spec.rb index 7063466e3..b75e11647 100644 --- a/logstash-core/spec/logstash/instrument/periodic_poller/load_average_spec.rb +++ b/logstash-core/spec/logstash/instrument/periodic_poller/load_average_spec.rb @@ -1,4 +1,20 @@ -# encoding: utf-8 +# 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 "logstash/instrument/periodic_poller/load_average" describe LogStash::Instrument::PeriodicPoller::LoadAverage do subject { described_class.create } diff --git a/logstash-core/spec/logstash/instrument/periodic_poller/os_spec.rb b/logstash-core/spec/logstash/instrument/periodic_poller/os_spec.rb index 9c489d74b..a8a8f5c2d 100644 --- a/logstash-core/spec/logstash/instrument/periodic_poller/os_spec.rb +++ b/logstash-core/spec/logstash/instrument/periodic_poller/os_spec.rb @@ -1,4 +1,20 @@ -# encoding: utf-8 +# 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 "logstash/instrument/periodic_poller/os" require "logstash/instrument/collector" diff --git a/logstash-core/spec/logstash/instrument/wrapped_write_client_spec.rb b/logstash-core/spec/logstash/instrument/wrapped_write_client_spec.rb index 3ebd2e375..35ab01e0c 100644 --- a/logstash-core/spec/logstash/instrument/wrapped_write_client_spec.rb +++ b/logstash-core/spec/logstash/instrument/wrapped_write_client_spec.rb @@ -1,4 +1,20 @@ -# encoding: utf-8 +# 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 "logstash/event" require_relative "../../support/mocks_classes" require "spec_helper" diff --git a/logstash-core/spec/logstash/java_filter_delegator_spec.rb b/logstash-core/spec/logstash/java_filter_delegator_spec.rb index c9d24b492..419f44bb2 100644 --- a/logstash-core/spec/logstash/java_filter_delegator_spec.rb +++ b/logstash-core/spec/logstash/java_filter_delegator_spec.rb @@ -1,4 +1,20 @@ -# encoding: utf-8 +# 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 "spec_helper" require "logstash/filter_delegator" require "logstash/event" diff --git a/logstash-core/spec/logstash/java_integration_spec.rb b/logstash-core/spec/logstash/java_integration_spec.rb index 0d4fd9c87..bf471b0d2 100644 --- a/logstash-core/spec/logstash/java_integration_spec.rb +++ b/logstash-core/spec/logstash/java_integration_spec.rb @@ -1,4 +1,20 @@ -# encoding: utf-8 +# 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 "spec_helper" describe "Java integration" do diff --git a/logstash-core/spec/logstash/java_pipeline_spec.rb b/logstash-core/spec/logstash/java_pipeline_spec.rb index 7d8592819..a82a63460 100644 --- a/logstash-core/spec/logstash/java_pipeline_spec.rb +++ b/logstash-core/spec/logstash/java_pipeline_spec.rb @@ -1,4 +1,20 @@ -# encoding: utf-8 +# 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 "spec_helper" require "logstash/inputs/generator" require "logstash/filters/drop" diff --git a/logstash-core/spec/logstash/json_spec.rb b/logstash-core/spec/logstash/json_spec.rb index 8ad341c2b..45c79b12b 100644 --- a/logstash-core/spec/logstash/json_spec.rb +++ b/logstash-core/spec/logstash/json_spec.rb @@ -1,4 +1,20 @@ -# encoding: utf-8 +# 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 "spec_helper" require "logstash/json" require "logstash/environment" diff --git a/logstash-core/spec/logstash/legacy_ruby_event_spec.rb b/logstash-core/spec/logstash/legacy_ruby_event_spec.rb index 5c1a75e1e..cc49001f5 100644 --- a/logstash-core/spec/logstash/legacy_ruby_event_spec.rb +++ b/logstash-core/spec/logstash/legacy_ruby_event_spec.rb @@ -1,4 +1,20 @@ -# encoding: utf-8 +# 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 "spec_helper" require "logstash/util/decorators" require "json" @@ -625,4 +641,3 @@ describe LogStash::Event do end end end - diff --git a/logstash-core/spec/logstash/legacy_ruby_timestamp_spec.rb b/logstash-core/spec/logstash/legacy_ruby_timestamp_spec.rb index 512bfe8fb..3d2372551 100644 --- a/logstash-core/spec/logstash/legacy_ruby_timestamp_spec.rb +++ b/logstash-core/spec/logstash/legacy_ruby_timestamp_spec.rb @@ -1,4 +1,20 @@ -# encoding: utf-8 +# 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 "spec_helper" require "bigdecimal" diff --git a/logstash-core/spec/logstash/modules/cli_parser_spec.rb b/logstash-core/spec/logstash/modules/cli_parser_spec.rb index 03a036f05..ed670d8d0 100644 --- a/logstash-core/spec/logstash/modules/cli_parser_spec.rb +++ b/logstash-core/spec/logstash/modules/cli_parser_spec.rb @@ -1,3 +1,20 @@ +# 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 "spec_helper" require "logstash/modules/cli_parser" diff --git a/logstash-core/spec/logstash/modules/kibana_client_spec.rb b/logstash-core/spec/logstash/modules/kibana_client_spec.rb index 946c28240..f2ed11ae8 100644 --- a/logstash-core/spec/logstash/modules/kibana_client_spec.rb +++ b/logstash-core/spec/logstash/modules/kibana_client_spec.rb @@ -1,4 +1,20 @@ -# encoding: utf-8 +# 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 "spec_helper" require "logstash/modules/kibana_client" module LogStash module Modules diff --git a/logstash-core/spec/logstash/modules/logstash_config_spec.rb b/logstash-core/spec/logstash/modules/logstash_config_spec.rb index a862f8957..24577f77b 100644 --- a/logstash-core/spec/logstash/modules/logstash_config_spec.rb +++ b/logstash-core/spec/logstash/modules/logstash_config_spec.rb @@ -1,4 +1,20 @@ -# encoding: utf-8 +# 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 "logstash/modules/logstash_config" describe LogStash::Modules::LogStashConfig do diff --git a/logstash-core/spec/logstash/modules/scaffold_spec.rb b/logstash-core/spec/logstash/modules/scaffold_spec.rb index e08eb4a27..aa6cb878d 100644 --- a/logstash-core/spec/logstash/modules/scaffold_spec.rb +++ b/logstash-core/spec/logstash/modules/scaffold_spec.rb @@ -1,5 +1,20 @@ -# encoding: utf-8 +# 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 "logstash/elasticsearch_client" require "logstash/modules/kibana_client" require "logstash/modules/kibana_config" diff --git a/logstash-core/spec/logstash/modules/settings_merger_spec.rb b/logstash-core/spec/logstash/modules/settings_merger_spec.rb index 25e1ea8e9..4f0792901 100644 --- a/logstash-core/spec/logstash/modules/settings_merger_spec.rb +++ b/logstash-core/spec/logstash/modules/settings_merger_spec.rb @@ -1,4 +1,20 @@ -# encoding: utf-8 +# 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 "spec_helper" require "logstash/util/cloud_setting_id" require "logstash/util/cloud_setting_auth" diff --git a/logstash-core/spec/logstash/outputs/base_spec.rb b/logstash-core/spec/logstash/outputs/base_spec.rb index 904e91493..191d82751 100644 --- a/logstash-core/spec/logstash/outputs/base_spec.rb +++ b/logstash-core/spec/logstash/outputs/base_spec.rb @@ -1,4 +1,20 @@ -# encoding: utf-8 +# 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 "spec_helper" require "logstash/outputs/base" require "support/shared_contexts" diff --git a/logstash-core/spec/logstash/patches_spec.rb b/logstash-core/spec/logstash/patches_spec.rb index e9c7739bd..2014300d2 100644 --- a/logstash-core/spec/logstash/patches_spec.rb +++ b/logstash-core/spec/logstash/patches_spec.rb @@ -1,4 +1,20 @@ -# encoding: utf-8 +# 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 "socket" require "logstash/patches" require "flores/pki" diff --git a/logstash-core/spec/logstash/pipeline_action/create_spec.rb b/logstash-core/spec/logstash/pipeline_action/create_spec.rb index 0624d0775..1aadf7dc0 100644 --- a/logstash-core/spec/logstash/pipeline_action/create_spec.rb +++ b/logstash-core/spec/logstash/pipeline_action/create_spec.rb @@ -1,4 +1,20 @@ -# encoding: utf-8 +# 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 "spec_helper" require_relative "../../support/helpers" require_relative "../../support/matchers" diff --git a/logstash-core/spec/logstash/pipeline_action/reload_spec.rb b/logstash-core/spec/logstash/pipeline_action/reload_spec.rb index 791b5dde2..d51c5a9d7 100644 --- a/logstash-core/spec/logstash/pipeline_action/reload_spec.rb +++ b/logstash-core/spec/logstash/pipeline_action/reload_spec.rb @@ -1,4 +1,20 @@ -# encoding: utf-8 +# 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 "spec_helper" require_relative "../../support/helpers" require_relative "../../support/matchers" diff --git a/logstash-core/spec/logstash/pipeline_action/stop_spec.rb b/logstash-core/spec/logstash/pipeline_action/stop_spec.rb index 75648c50b..5e1613c66 100644 --- a/logstash-core/spec/logstash/pipeline_action/stop_spec.rb +++ b/logstash-core/spec/logstash/pipeline_action/stop_spec.rb @@ -1,4 +1,20 @@ -# encoding: utf-8 +# 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 "spec_helper" require_relative "../../support/helpers" require "logstash/pipelines_registry" diff --git a/logstash-core/spec/logstash/pipeline_dlq_commit_spec.rb b/logstash-core/spec/logstash/pipeline_dlq_commit_spec.rb index 1222ac2c8..03fdaeabc 100644 --- a/logstash-core/spec/logstash/pipeline_dlq_commit_spec.rb +++ b/logstash-core/spec/logstash/pipeline_dlq_commit_spec.rb @@ -1,4 +1,20 @@ -# encoding: utf-8 +# 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 "tmpdir" require "spec_helper" require "logstash/codecs/plain" diff --git a/logstash-core/spec/logstash/pipeline_pq_file_spec.rb b/logstash-core/spec/logstash/pipeline_pq_file_spec.rb index 59f23ce07..50c33a46c 100644 --- a/logstash-core/spec/logstash/pipeline_pq_file_spec.rb +++ b/logstash-core/spec/logstash/pipeline_pq_file_spec.rb @@ -1,4 +1,20 @@ -# encoding: utf-8 +# 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 "spec_helper" require "logstash/inputs/generator" require_relative "../support/helpers" diff --git a/logstash-core/spec/logstash/pipeline_reporter_spec.rb b/logstash-core/spec/logstash/pipeline_reporter_spec.rb index 2753be480..54a865d59 100644 --- a/logstash-core/spec/logstash/pipeline_reporter_spec.rb +++ b/logstash-core/spec/logstash/pipeline_reporter_spec.rb @@ -1,4 +1,20 @@ -# encoding: utf-8 +# 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 "spec_helper" require "logstash/pipeline" require_relative "../support/helpers" diff --git a/logstash-core/spec/logstash/pipeline_spec.rb b/logstash-core/spec/logstash/pipeline_spec.rb index 8a57b59cb..cf21e1136 100644 --- a/logstash-core/spec/logstash/pipeline_spec.rb +++ b/logstash-core/spec/logstash/pipeline_spec.rb @@ -1,4 +1,20 @@ -# encoding: utf-8 +# 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 "spec_helper" require "logstash/inputs/generator" require "logstash/filters/drop" diff --git a/logstash-core/spec/logstash/pipelines_registry_spec.rb b/logstash-core/spec/logstash/pipelines_registry_spec.rb index eca53483b..7a7183544 100644 --- a/logstash-core/spec/logstash/pipelines_registry_spec.rb +++ b/logstash-core/spec/logstash/pipelines_registry_spec.rb @@ -1,4 +1,20 @@ -# encoding: utf-8 +# 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 "spec_helper" require "logstash/pipelines_registry" diff --git a/logstash-core/spec/logstash/plugin_spec.rb b/logstash-core/spec/logstash/plugin_spec.rb index 91808a98f..e56299dd5 100644 --- a/logstash-core/spec/logstash/plugin_spec.rb +++ b/logstash-core/spec/logstash/plugin_spec.rb @@ -1,4 +1,20 @@ -# encoding: utf-8 +# 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 "spec_helper" require "logstash/plugin" require "logstash/outputs/base" diff --git a/logstash-core/spec/logstash/plugins/builtin/pipeline_input_output_spec.rb b/logstash-core/spec/logstash/plugins/builtin/pipeline_input_output_spec.rb index d8bcebe8d..f1184842d 100644 --- a/logstash-core/spec/logstash/plugins/builtin/pipeline_input_output_spec.rb +++ b/logstash-core/spec/logstash/plugins/builtin/pipeline_input_output_spec.rb @@ -1,3 +1,20 @@ +# 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 'spec_helper' describe ::LogStash::Plugins::Builtin::Pipeline do diff --git a/logstash-core/spec/logstash/plugins/hooks_registry_spec.rb b/logstash-core/spec/logstash/plugins/hooks_registry_spec.rb index 300516a6c..45d19565b 100644 --- a/logstash-core/spec/logstash/plugins/hooks_registry_spec.rb +++ b/logstash-core/spec/logstash/plugins/hooks_registry_spec.rb @@ -1,4 +1,19 @@ -# encoding: utf-8 +# 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. describe LogStash::Plugins::HooksRegistry do class DummyEmitter diff --git a/logstash-core/spec/logstash/plugins/registry_spec.rb b/logstash-core/spec/logstash/plugins/registry_spec.rb index 01ded2406..827f33a54 100644 --- a/logstash-core/spec/logstash/plugins/registry_spec.rb +++ b/logstash-core/spec/logstash/plugins/registry_spec.rb @@ -1,4 +1,20 @@ -# encoding: utf-8 +# 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 "spec_helper" require "logstash/plugins/registry" require "logstash/inputs/base" diff --git a/logstash-core/spec/logstash/queue_factory_spec.rb b/logstash-core/spec/logstash/queue_factory_spec.rb index 5741c234d..56fdf1384 100644 --- a/logstash-core/spec/logstash/queue_factory_spec.rb +++ b/logstash-core/spec/logstash/queue_factory_spec.rb @@ -1,4 +1,20 @@ -# encoding: utf-8 +# 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 "logstash/settings" require "stud/temporary" diff --git a/logstash-core/spec/logstash/runner_spec.rb b/logstash-core/spec/logstash/runner_spec.rb index 6a591e308..68f5fb45d 100644 --- a/logstash-core/spec/logstash/runner_spec.rb +++ b/logstash-core/spec/logstash/runner_spec.rb @@ -1,4 +1,20 @@ -# encoding: utf-8 +# 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 "spec_helper" require "logstash/runner" require "stud/task" diff --git a/logstash-core/spec/logstash/setting_spec.rb b/logstash-core/spec/logstash/setting_spec.rb index 3c1f43847..92bd617af 100644 --- a/logstash-core/spec/logstash/setting_spec.rb +++ b/logstash-core/spec/logstash/setting_spec.rb @@ -1,4 +1,20 @@ -# encoding: utf-8 +# 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 "spec_helper" require "logstash/settings" diff --git a/logstash-core/spec/logstash/settings/array_coercible_spec.rb b/logstash-core/spec/logstash/settings/array_coercible_spec.rb index 780f18cca..8fcff33b1 100644 --- a/logstash-core/spec/logstash/settings/array_coercible_spec.rb +++ b/logstash-core/spec/logstash/settings/array_coercible_spec.rb @@ -1,4 +1,20 @@ -# encoding: utf-8 +# 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 "spec_helper" require "logstash/settings" diff --git a/logstash-core/spec/logstash/settings/bytes_spec.rb b/logstash-core/spec/logstash/settings/bytes_spec.rb index 084a252aa..3095736b3 100644 --- a/logstash-core/spec/logstash/settings/bytes_spec.rb +++ b/logstash-core/spec/logstash/settings/bytes_spec.rb @@ -1,4 +1,20 @@ -# encoding: utf-8 +# 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 "spec_helper" require "logstash/settings" diff --git a/logstash-core/spec/logstash/settings/integer_spec.rb b/logstash-core/spec/logstash/settings/integer_spec.rb index f7097d961..c301576fd 100644 --- a/logstash-core/spec/logstash/settings/integer_spec.rb +++ b/logstash-core/spec/logstash/settings/integer_spec.rb @@ -1,4 +1,20 @@ -# encoding: utf-8 +# 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 "spec_helper" require "logstash/settings" diff --git a/logstash-core/spec/logstash/settings/modules_spec.rb b/logstash-core/spec/logstash/settings/modules_spec.rb index 68a6b366a..dd3404c64 100644 --- a/logstash-core/spec/logstash/settings/modules_spec.rb +++ b/logstash-core/spec/logstash/settings/modules_spec.rb @@ -1,4 +1,20 @@ -# encoding: utf-8 +# 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 "spec_helper" require "logstash/settings" require "logstash/util/cloud_setting_id" diff --git a/logstash-core/spec/logstash/settings/numeric_spec.rb b/logstash-core/spec/logstash/settings/numeric_spec.rb index cab162fce..29bbe2f78 100644 --- a/logstash-core/spec/logstash/settings/numeric_spec.rb +++ b/logstash-core/spec/logstash/settings/numeric_spec.rb @@ -1,4 +1,20 @@ -# encoding: utf-8 +# 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 "spec_helper" require "logstash/settings" diff --git a/logstash-core/spec/logstash/settings/port_range_spec.rb b/logstash-core/spec/logstash/settings/port_range_spec.rb index 8a5fb6e53..a5117378e 100644 --- a/logstash-core/spec/logstash/settings/port_range_spec.rb +++ b/logstash-core/spec/logstash/settings/port_range_spec.rb @@ -1,5 +1,20 @@ -# encoding: utf-8 +# 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 "logstash/settings" require "spec_helper" diff --git a/logstash-core/spec/logstash/settings/splittable_string_array_spec.rb b/logstash-core/spec/logstash/settings/splittable_string_array_spec.rb index b24f629aa..d5526e4f6 100644 --- a/logstash-core/spec/logstash/settings/splittable_string_array_spec.rb +++ b/logstash-core/spec/logstash/settings/splittable_string_array_spec.rb @@ -1,4 +1,20 @@ -# encoding: utf-8 +# 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 "spec_helper" require "logstash/settings" @@ -48,4 +64,3 @@ describe LogStash::Setting::SplittableStringArray do end end end - diff --git a/logstash-core/spec/logstash/settings/string_spec.rb b/logstash-core/spec/logstash/settings/string_spec.rb index 69d835649..583f05395 100644 --- a/logstash-core/spec/logstash/settings/string_spec.rb +++ b/logstash-core/spec/logstash/settings/string_spec.rb @@ -1,4 +1,20 @@ -# encoding: utf-8 +# 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 "spec_helper" require "logstash/settings" diff --git a/logstash-core/spec/logstash/settings/time_value_spec.rb b/logstash-core/spec/logstash/settings/time_value_spec.rb index e1e4940d3..e71ca7b66 100644 --- a/logstash-core/spec/logstash/settings/time_value_spec.rb +++ b/logstash-core/spec/logstash/settings/time_value_spec.rb @@ -1,4 +1,20 @@ -# encoding: utf-8 +# 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 "spec_helper" require "logstash/settings" diff --git a/logstash-core/spec/logstash/settings/writable_directory_spec.rb b/logstash-core/spec/logstash/settings/writable_directory_spec.rb index be00ce9f0..d1dd8ad4d 100644 --- a/logstash-core/spec/logstash/settings/writable_directory_spec.rb +++ b/logstash-core/spec/logstash/settings/writable_directory_spec.rb @@ -1,4 +1,20 @@ -# encoding: utf-8 +# 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 "spec_helper" require "logstash/settings" require "tmpdir" diff --git a/logstash-core/spec/logstash/settings_spec.rb b/logstash-core/spec/logstash/settings_spec.rb index 3e9ed5fda..88047834e 100644 --- a/logstash-core/spec/logstash/settings_spec.rb +++ b/logstash-core/spec/logstash/settings_spec.rb @@ -1,4 +1,20 @@ -# encoding: utf-8 +# 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 "spec_helper" require "logstash/util/substitution_variables" require "logstash/settings" diff --git a/logstash-core/spec/logstash/shutdown_watcher_spec.rb b/logstash-core/spec/logstash/shutdown_watcher_spec.rb index 6d2f2fc2b..b563a798e 100644 --- a/logstash-core/spec/logstash/shutdown_watcher_spec.rb +++ b/logstash-core/spec/logstash/shutdown_watcher_spec.rb @@ -1,4 +1,20 @@ -# encoding: utf-8 +# 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 "spec_helper" describe LogStash::ShutdownWatcher do diff --git a/logstash-core/spec/logstash/state_resolver_spec.rb b/logstash-core/spec/logstash/state_resolver_spec.rb index 28abd8999..0d301fb16 100644 --- a/logstash-core/spec/logstash/state_resolver_spec.rb +++ b/logstash-core/spec/logstash/state_resolver_spec.rb @@ -1,4 +1,20 @@ -# encoding: utf-8 +# 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 "spec_helper" require_relative "../support/helpers" require_relative "../support/matchers" diff --git a/logstash-core/spec/logstash/util/accessors_spec.rb b/logstash-core/spec/logstash/util/accessors_spec.rb index e3c1a73e6..fe61fcd9a 100644 --- a/logstash-core/spec/logstash/util/accessors_spec.rb +++ b/logstash-core/spec/logstash/util/accessors_spec.rb @@ -1,4 +1,20 @@ -# encoding: utf-8 +# 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 "spec_helper" # this is to skip specs when running agains an alternate logstash-core-event implementation diff --git a/logstash-core/spec/logstash/util/buftok_spec.rb b/logstash-core/spec/logstash/util/buftok_spec.rb index bcb37a6aa..33fdf3682 100644 --- a/logstash-core/spec/logstash/util/buftok_spec.rb +++ b/logstash-core/spec/logstash/util/buftok_spec.rb @@ -1,4 +1,20 @@ -# encoding: utf-8 +# 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 "spec_helper" describe FileWatch::BufferedTokenizer do diff --git a/logstash-core/spec/logstash/util/byte_value_spec.rb b/logstash-core/spec/logstash/util/byte_value_spec.rb index a18e4ff11..cacb8b1fd 100644 --- a/logstash-core/spec/logstash/util/byte_value_spec.rb +++ b/logstash-core/spec/logstash/util/byte_value_spec.rb @@ -1,3 +1,20 @@ +# 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 "logstash/util/byte_value" require "flores/random" diff --git a/logstash-core/spec/logstash/util/charset_spec.rb b/logstash-core/spec/logstash/util/charset_spec.rb index 5111a0c7e..061e66534 100644 --- a/logstash-core/spec/logstash/util/charset_spec.rb +++ b/logstash-core/spec/logstash/util/charset_spec.rb @@ -1,4 +1,20 @@ -# encoding: utf-8 +# 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 "spec_helper" require "logstash/util/charset" diff --git a/logstash-core/spec/logstash/util/cloud_setting_id_spec.rb b/logstash-core/spec/logstash/util/cloud_setting_id_spec.rb index 996eb92ba..9f2d397cc 100644 --- a/logstash-core/spec/logstash/util/cloud_setting_id_spec.rb +++ b/logstash-core/spec/logstash/util/cloud_setting_id_spec.rb @@ -1,4 +1,20 @@ -# encoding: utf-8 +# 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 "spec_helper" require "logstash/util/cloud_setting_id" diff --git a/logstash-core/spec/logstash/util/java_version_spec.rb b/logstash-core/spec/logstash/util/java_version_spec.rb index 9383e4941..6718ce15f 100644 --- a/logstash-core/spec/logstash/util/java_version_spec.rb +++ b/logstash-core/spec/logstash/util/java_version_spec.rb @@ -1,4 +1,20 @@ -# encoding: utf-8 +# 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 'spec_helper' require 'logstash/util/java_version' diff --git a/logstash-core/spec/logstash/util/plugin_version_spec.rb b/logstash-core/spec/logstash/util/plugin_version_spec.rb index 684c8bc5e..589292d7c 100644 --- a/logstash-core/spec/logstash/util/plugin_version_spec.rb +++ b/logstash-core/spec/logstash/util/plugin_version_spec.rb @@ -1,4 +1,20 @@ -# encoding: utf-8 +# 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 "spec_helper" require "logstash/util/plugin_version" diff --git a/logstash-core/spec/logstash/util/safe_uri_spec.rb b/logstash-core/spec/logstash/util/safe_uri_spec.rb index 9105d238a..a50a197c8 100644 --- a/logstash-core/spec/logstash/util/safe_uri_spec.rb +++ b/logstash-core/spec/logstash/util/safe_uri_spec.rb @@ -1,4 +1,20 @@ -# encoding: utf-8 +# 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 "logstash/util/safe_uri" require "spec_helper" diff --git a/logstash-core/spec/logstash/util/secretstore_spec.rb b/logstash-core/spec/logstash/util/secretstore_spec.rb index 9ba0417bd..143602a02 100644 --- a/logstash-core/spec/logstash/util/secretstore_spec.rb +++ b/logstash-core/spec/logstash/util/secretstore_spec.rb @@ -1,3 +1,20 @@ +# 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 "logstash/settings" java_import "org.logstash.secret.store.SecretStoreExt" diff --git a/logstash-core/spec/logstash/util/time_value_spec.rb b/logstash-core/spec/logstash/util/time_value_spec.rb index c263a322a..79b4a0229 100644 --- a/logstash-core/spec/logstash/util/time_value_spec.rb +++ b/logstash-core/spec/logstash/util/time_value_spec.rb @@ -1,4 +1,20 @@ -# encoding: utf-8 +# 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 "logstash/util/time_value" require "spec_helper" diff --git a/logstash-core/spec/logstash/util/wrapped_acked_queue_spec.rb b/logstash-core/spec/logstash/util/wrapped_acked_queue_spec.rb index 6ba924d7d..2a8e9b676 100644 --- a/logstash-core/spec/logstash/util/wrapped_acked_queue_spec.rb +++ b/logstash-core/spec/logstash/util/wrapped_acked_queue_spec.rb @@ -1,4 +1,20 @@ -# encoding: utf-8 +# 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 "spec_helper" describe LogStash::WrappedAckedQueue do diff --git a/logstash-core/spec/logstash/util/wrapped_synchronous_queue_spec.rb b/logstash-core/spec/logstash/util/wrapped_synchronous_queue_spec.rb index 22b3098de..0e7c0bae8 100644 --- a/logstash-core/spec/logstash/util/wrapped_synchronous_queue_spec.rb +++ b/logstash-core/spec/logstash/util/wrapped_synchronous_queue_spec.rb @@ -1,4 +1,20 @@ -# encoding: utf-8 +# 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 "spec_helper" require "logstash/instrument/collector" diff --git a/logstash-core/spec/logstash/util_spec.rb b/logstash-core/spec/logstash/util_spec.rb index b86f879be..c3297ed77 100644 --- a/logstash-core/spec/logstash/util_spec.rb +++ b/logstash-core/spec/logstash/util_spec.rb @@ -1,4 +1,20 @@ -# encoding: utf-8 +# 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 'spec_helper' require "logstash/util" diff --git a/logstash-core/spec/logstash/webserver_spec.rb b/logstash-core/spec/logstash/webserver_spec.rb index 285f922ba..bca54ba7a 100644 --- a/logstash-core/spec/logstash/webserver_spec.rb +++ b/logstash-core/spec/logstash/webserver_spec.rb @@ -1,5 +1,20 @@ -# encoding: utf-8 -# require "logstash/json" +# 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 "logstash/webserver" require_relative "../support/helpers" require "socket" diff --git a/logstash-core/spec/modules_test_files/modules/tester/configuration/logstash/tester.conf.erb b/logstash-core/spec/modules_test_files/modules/tester/configuration/logstash/tester.conf.erb index 2a963d79b..f2adf60ed 100755 --- a/logstash-core/spec/modules_test_files/modules/tester/configuration/logstash/tester.conf.erb +++ b/logstash-core/spec/modules_test_files/modules/tester/configuration/logstash/tester.conf.erb @@ -1,3 +1,20 @@ +# 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. + input { tcp { codec => json diff --git a/logstash-core/spec/plugin_metadata_spec.rb b/logstash-core/spec/plugin_metadata_spec.rb index b2d165efa..b5f3af1fd 100644 --- a/logstash-core/spec/plugin_metadata_spec.rb +++ b/logstash-core/spec/plugin_metadata_spec.rb @@ -1,4 +1,19 @@ -# encoding: utf-8 +# 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 'spec_helper' require 'logstash/plugin_metadata' diff --git a/logstash-core/spec/static/i18n_spec.rb b/logstash-core/spec/static/i18n_spec.rb index b2cd76377..4df6e65f7 100644 --- a/logstash-core/spec/static/i18n_spec.rb +++ b/logstash-core/spec/static/i18n_spec.rb @@ -1,4 +1,20 @@ -# encoding: utf-8 +# 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 "spec_helper" require "i18n" diff --git a/logstash-core/spec/support/helpers.rb b/logstash-core/spec/support/helpers.rb index 97785d807..9d0e77c9d 100644 --- a/logstash-core/spec/support/helpers.rb +++ b/logstash-core/spec/support/helpers.rb @@ -1,4 +1,20 @@ -# encoding: utf-8 +# 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 "stud/task" def silence_warnings diff --git a/logstash-core/spec/support/matchers.rb b/logstash-core/spec/support/matchers.rb index da0948ddd..b87f08c17 100644 --- a/logstash-core/spec/support/matchers.rb +++ b/logstash-core/spec/support/matchers.rb @@ -1,4 +1,20 @@ -# encoding: utf-8 +# 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 "rspec" require "rspec/expectations" require "logstash/config/pipeline_config" @@ -153,4 +169,3 @@ RSpec::Matchers.define :be_a_config_loading_error_hash do |regex| raise "Not implemented" end end - diff --git a/logstash-core/spec/support/mocks_classes.rb b/logstash-core/spec/support/mocks_classes.rb index ef4129153..eb673fe3b 100644 --- a/logstash-core/spec/support/mocks_classes.rb +++ b/logstash-core/spec/support/mocks_classes.rb @@ -1,4 +1,20 @@ -# encoding: utf-8 +# 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 "logstash/outputs/base" require "logstash/config/source_loader" require "logstash/inputs/base" diff --git a/logstash-core/spec/support/pipeline/pipeline_helpers.rb b/logstash-core/spec/support/pipeline/pipeline_helpers.rb index d9afd0924..0fccded8a 100644 --- a/logstash-core/spec/support/pipeline/pipeline_helpers.rb +++ b/logstash-core/spec/support/pipeline/pipeline_helpers.rb @@ -1,3 +1,20 @@ +# 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 "logstash/agent" require "logstash/java_pipeline" require "logstash/event" diff --git a/logstash-core/spec/support/shared_contexts.rb b/logstash-core/spec/support/shared_contexts.rb index b2ac83f90..0dce17993 100644 --- a/logstash-core/spec/support/shared_contexts.rb +++ b/logstash-core/spec/support/shared_contexts.rb @@ -1,3 +1,20 @@ +# 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. + shared_context "execution_context" do let(:pipeline) { double("pipeline") } let(:pipeline_id) { :main } diff --git a/logstash-core/spec/support/shared_examples.rb b/logstash-core/spec/support/shared_examples.rb index 04a409d2b..d71b5cf45 100644 --- a/logstash-core/spec/support/shared_examples.rb +++ b/logstash-core/spec/support/shared_examples.rb @@ -1,4 +1,20 @@ -# encoding: utf-8 +# 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. + # Define the common operation that both the `NullMetric` class and the Namespaced class should answer. shared_examples "metrics commons operations" do let(:key) { "galaxy" } @@ -105,4 +121,3 @@ shared_examples "not found" do expect(LogStash::Json.load(last_response.body)["path"]).not_to be_nil end end - diff --git a/logstash-core/src/main/java/co/elastic/logstash/api/Codec.java b/logstash-core/src/main/java/co/elastic/logstash/api/Codec.java index 4efa43c51..1cceea7ab 100644 --- a/logstash-core/src/main/java/co/elastic/logstash/api/Codec.java +++ b/logstash-core/src/main/java/co/elastic/logstash/api/Codec.java @@ -1,3 +1,23 @@ +/* + * 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. + */ + + package co.elastic.logstash.api; import java.io.IOException; diff --git a/logstash-core/src/main/java/co/elastic/logstash/api/Configuration.java b/logstash-core/src/main/java/co/elastic/logstash/api/Configuration.java index 21f4673b2..8aff9d2ae 100644 --- a/logstash-core/src/main/java/co/elastic/logstash/api/Configuration.java +++ b/logstash-core/src/main/java/co/elastic/logstash/api/Configuration.java @@ -1,3 +1,23 @@ +/* + * 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. + */ + + package co.elastic.logstash.api; import java.util.Collection; diff --git a/logstash-core/src/main/java/co/elastic/logstash/api/Context.java b/logstash-core/src/main/java/co/elastic/logstash/api/Context.java index 4fb6db6fc..80851186b 100644 --- a/logstash-core/src/main/java/co/elastic/logstash/api/Context.java +++ b/logstash-core/src/main/java/co/elastic/logstash/api/Context.java @@ -1,3 +1,23 @@ +/* + * 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. + */ + + package co.elastic.logstash.api; import org.apache.logging.log4j.Logger; diff --git a/logstash-core/src/main/java/co/elastic/logstash/api/CounterMetric.java b/logstash-core/src/main/java/co/elastic/logstash/api/CounterMetric.java index e58949ab7..d9c3a1f85 100644 --- a/logstash-core/src/main/java/co/elastic/logstash/api/CounterMetric.java +++ b/logstash-core/src/main/java/co/elastic/logstash/api/CounterMetric.java @@ -1,3 +1,23 @@ +/* + * 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. + */ + + package co.elastic.logstash.api; /** diff --git a/logstash-core/src/main/java/co/elastic/logstash/api/DeadLetterQueueWriter.java b/logstash-core/src/main/java/co/elastic/logstash/api/DeadLetterQueueWriter.java index 81dce1160..123b4be82 100644 --- a/logstash-core/src/main/java/co/elastic/logstash/api/DeadLetterQueueWriter.java +++ b/logstash-core/src/main/java/co/elastic/logstash/api/DeadLetterQueueWriter.java @@ -1,3 +1,23 @@ +/* + * 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. + */ + + package co.elastic.logstash.api; import java.io.IOException; diff --git a/logstash-core/src/main/java/co/elastic/logstash/api/DeprecationLogger.java b/logstash-core/src/main/java/co/elastic/logstash/api/DeprecationLogger.java index 61827aa2e..c206d9cb5 100644 --- a/logstash-core/src/main/java/co/elastic/logstash/api/DeprecationLogger.java +++ b/logstash-core/src/main/java/co/elastic/logstash/api/DeprecationLogger.java @@ -1,3 +1,23 @@ +/* + * 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. + */ + + package co.elastic.logstash.api; /** diff --git a/logstash-core/src/main/java/co/elastic/logstash/api/Event.java b/logstash-core/src/main/java/co/elastic/logstash/api/Event.java index 491b3748c..b15f3aca2 100644 --- a/logstash-core/src/main/java/co/elastic/logstash/api/Event.java +++ b/logstash-core/src/main/java/co/elastic/logstash/api/Event.java @@ -1,3 +1,23 @@ +/* + * 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. + */ + + package co.elastic.logstash.api; import java.io.IOException; diff --git a/logstash-core/src/main/java/co/elastic/logstash/api/EventFactory.java b/logstash-core/src/main/java/co/elastic/logstash/api/EventFactory.java index fb4a5c0ae..8e111a96a 100644 --- a/logstash-core/src/main/java/co/elastic/logstash/api/EventFactory.java +++ b/logstash-core/src/main/java/co/elastic/logstash/api/EventFactory.java @@ -1,3 +1,23 @@ +/* + * 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. + */ + + package co.elastic.logstash.api; import java.io.Serializable; diff --git a/logstash-core/src/main/java/co/elastic/logstash/api/Filter.java b/logstash-core/src/main/java/co/elastic/logstash/api/Filter.java index 8cf2dc293..7c55402e6 100644 --- a/logstash-core/src/main/java/co/elastic/logstash/api/Filter.java +++ b/logstash-core/src/main/java/co/elastic/logstash/api/Filter.java @@ -1,3 +1,23 @@ +/* + * 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. + */ + + package co.elastic.logstash.api; import java.util.Collection; diff --git a/logstash-core/src/main/java/co/elastic/logstash/api/FilterMatchListener.java b/logstash-core/src/main/java/co/elastic/logstash/api/FilterMatchListener.java index d5addb16b..d9c639986 100644 --- a/logstash-core/src/main/java/co/elastic/logstash/api/FilterMatchListener.java +++ b/logstash-core/src/main/java/co/elastic/logstash/api/FilterMatchListener.java @@ -1,3 +1,23 @@ +/* + * 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. + */ + + package co.elastic.logstash.api; /** diff --git a/logstash-core/src/main/java/co/elastic/logstash/api/Input.java b/logstash-core/src/main/java/co/elastic/logstash/api/Input.java index 11848779e..8d991602c 100644 --- a/logstash-core/src/main/java/co/elastic/logstash/api/Input.java +++ b/logstash-core/src/main/java/co/elastic/logstash/api/Input.java @@ -1,3 +1,23 @@ +/* + * 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. + */ + + package co.elastic.logstash.api; import java.util.Map; diff --git a/logstash-core/src/main/java/co/elastic/logstash/api/LogstashPlugin.java b/logstash-core/src/main/java/co/elastic/logstash/api/LogstashPlugin.java index d338be00a..644f991d1 100644 --- a/logstash-core/src/main/java/co/elastic/logstash/api/LogstashPlugin.java +++ b/logstash-core/src/main/java/co/elastic/logstash/api/LogstashPlugin.java @@ -1,3 +1,23 @@ +/* + * 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. + */ + + package co.elastic.logstash.api; import java.lang.annotation.ElementType; diff --git a/logstash-core/src/main/java/co/elastic/logstash/api/Metric.java b/logstash-core/src/main/java/co/elastic/logstash/api/Metric.java index 8f96a52eb..ba9efd17a 100644 --- a/logstash-core/src/main/java/co/elastic/logstash/api/Metric.java +++ b/logstash-core/src/main/java/co/elastic/logstash/api/Metric.java @@ -1,3 +1,23 @@ +/* + * 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. + */ + + package co.elastic.logstash.api; /** diff --git a/logstash-core/src/main/java/co/elastic/logstash/api/NamespacedMetric.java b/logstash-core/src/main/java/co/elastic/logstash/api/NamespacedMetric.java index ec487c413..e0c01d531 100644 --- a/logstash-core/src/main/java/co/elastic/logstash/api/NamespacedMetric.java +++ b/logstash-core/src/main/java/co/elastic/logstash/api/NamespacedMetric.java @@ -1,3 +1,23 @@ +/* + * 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. + */ + + package co.elastic.logstash.api; import java.util.function.Supplier; diff --git a/logstash-core/src/main/java/co/elastic/logstash/api/Output.java b/logstash-core/src/main/java/co/elastic/logstash/api/Output.java index 4c133999a..7f9b35c96 100644 --- a/logstash-core/src/main/java/co/elastic/logstash/api/Output.java +++ b/logstash-core/src/main/java/co/elastic/logstash/api/Output.java @@ -1,3 +1,23 @@ +/* + * 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. + */ + + package co.elastic.logstash.api; import java.util.Collection; diff --git a/logstash-core/src/main/java/co/elastic/logstash/api/Password.java b/logstash-core/src/main/java/co/elastic/logstash/api/Password.java index 9cf0e231c..a80ae6378 100644 --- a/logstash-core/src/main/java/co/elastic/logstash/api/Password.java +++ b/logstash-core/src/main/java/co/elastic/logstash/api/Password.java @@ -1,3 +1,23 @@ +/* + * 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. + */ + + package co.elastic.logstash.api; /** diff --git a/logstash-core/src/main/java/co/elastic/logstash/api/Plugin.java b/logstash-core/src/main/java/co/elastic/logstash/api/Plugin.java index d070acaaf..e602383dc 100644 --- a/logstash-core/src/main/java/co/elastic/logstash/api/Plugin.java +++ b/logstash-core/src/main/java/co/elastic/logstash/api/Plugin.java @@ -1,3 +1,23 @@ +/* + * 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. + */ + + package co.elastic.logstash.api; import java.util.Collection; diff --git a/logstash-core/src/main/java/co/elastic/logstash/api/PluginConfigSpec.java b/logstash-core/src/main/java/co/elastic/logstash/api/PluginConfigSpec.java index dad40b273..988fd0eb2 100644 --- a/logstash-core/src/main/java/co/elastic/logstash/api/PluginConfigSpec.java +++ b/logstash-core/src/main/java/co/elastic/logstash/api/PluginConfigSpec.java @@ -1,3 +1,23 @@ +/* + * 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. + */ + + package co.elastic.logstash.api; import java.net.URI; diff --git a/logstash-core/src/main/java/co/elastic/logstash/api/PluginHelper.java b/logstash-core/src/main/java/co/elastic/logstash/api/PluginHelper.java index 7dee3a8a4..352d98830 100644 --- a/logstash-core/src/main/java/co/elastic/logstash/api/PluginHelper.java +++ b/logstash-core/src/main/java/co/elastic/logstash/api/PluginHelper.java @@ -1,3 +1,23 @@ +/* + * 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. + */ + + package co.elastic.logstash.api; import java.util.ArrayList; diff --git a/logstash-core/src/main/java/org/logstash/Accessors.java b/logstash-core/src/main/java/org/logstash/Accessors.java index 0489bcc26..979489ca3 100644 --- a/logstash-core/src/main/java/org/logstash/Accessors.java +++ b/logstash-core/src/main/java/org/logstash/Accessors.java @@ -1,3 +1,23 @@ +/* + * 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. + */ + + package org.logstash; public final class Accessors { diff --git a/logstash-core/src/main/java/org/logstash/Cloner.java b/logstash-core/src/main/java/org/logstash/Cloner.java index 536bcdcb6..65bb2f87f 100644 --- a/logstash-core/src/main/java/org/logstash/Cloner.java +++ b/logstash-core/src/main/java/org/logstash/Cloner.java @@ -1,3 +1,23 @@ +/* + * 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. + */ + + package org.logstash; import org.jruby.RubyString; diff --git a/logstash-core/src/main/java/org/logstash/ConvertedList.java b/logstash-core/src/main/java/org/logstash/ConvertedList.java index c67b87b2d..a26d8fbd4 100644 --- a/logstash-core/src/main/java/org/logstash/ConvertedList.java +++ b/logstash-core/src/main/java/org/logstash/ConvertedList.java @@ -1,3 +1,23 @@ +/* + * 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. + */ + + package org.logstash; import java.util.ArrayList; diff --git a/logstash-core/src/main/java/org/logstash/ConvertedMap.java b/logstash-core/src/main/java/org/logstash/ConvertedMap.java index 3bab155da..6fe983c25 100644 --- a/logstash-core/src/main/java/org/logstash/ConvertedMap.java +++ b/logstash-core/src/main/java/org/logstash/ConvertedMap.java @@ -1,3 +1,23 @@ +/* + * 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. + */ + + package org.logstash; import java.io.Serializable; diff --git a/logstash-core/src/main/java/org/logstash/DLQEntry.java b/logstash-core/src/main/java/org/logstash/DLQEntry.java index db524ab4e..dd1aff303 100644 --- a/logstash-core/src/main/java/org/logstash/DLQEntry.java +++ b/logstash-core/src/main/java/org/logstash/DLQEntry.java @@ -1,3 +1,23 @@ +/* + * 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. + */ + + /* * Licensed to Elasticsearch under one or more contributor * license agreements. See the NOTICE file distributed with diff --git a/logstash-core/src/main/java/org/logstash/Event.java b/logstash-core/src/main/java/org/logstash/Event.java index ea8450191..c5cb31f6d 100644 --- a/logstash-core/src/main/java/org/logstash/Event.java +++ b/logstash-core/src/main/java/org/logstash/Event.java @@ -1,3 +1,23 @@ +/* + * 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. + */ + + package org.logstash; import com.fasterxml.jackson.core.JsonProcessingException; diff --git a/logstash-core/src/main/java/org/logstash/FieldReference.java b/logstash-core/src/main/java/org/logstash/FieldReference.java index 2f4923cc8..03a476dd2 100644 --- a/logstash-core/src/main/java/org/logstash/FieldReference.java +++ b/logstash-core/src/main/java/org/logstash/FieldReference.java @@ -1,3 +1,23 @@ +/* + * 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. + */ + + package org.logstash; import java.util.ArrayList; diff --git a/logstash-core/src/main/java/org/logstash/FileLockFactory.java b/logstash-core/src/main/java/org/logstash/FileLockFactory.java index 8b41315e1..3063a1f33 100644 --- a/logstash-core/src/main/java/org/logstash/FileLockFactory.java +++ b/logstash-core/src/main/java/org/logstash/FileLockFactory.java @@ -1,3 +1,23 @@ +/* + * 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. + */ + + // this class is largely inspired by Lucene FSLockFactory and friends, below is the Lucene original Apache 2.0 license: /* diff --git a/logstash-core/src/main/java/org/logstash/Javafier.java b/logstash-core/src/main/java/org/logstash/Javafier.java index dc98cfb11..8ee6b91fd 100644 --- a/logstash-core/src/main/java/org/logstash/Javafier.java +++ b/logstash-core/src/main/java/org/logstash/Javafier.java @@ -1,3 +1,23 @@ +/* + * 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. + */ + + package org.logstash; import java.math.BigDecimal; @@ -83,4 +103,3 @@ public final class Javafier { return converters; } } - diff --git a/logstash-core/src/main/java/org/logstash/KeyNode.java b/logstash-core/src/main/java/org/logstash/KeyNode.java index a5774e854..6c4e54ff6 100644 --- a/logstash-core/src/main/java/org/logstash/KeyNode.java +++ b/logstash-core/src/main/java/org/logstash/KeyNode.java @@ -1,3 +1,23 @@ +/* + * 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. + */ + + package org.logstash; import java.util.List; diff --git a/logstash-core/src/main/java/org/logstash/LockException.java b/logstash-core/src/main/java/org/logstash/LockException.java index 1da4469cd..217bf240b 100644 --- a/logstash-core/src/main/java/org/logstash/LockException.java +++ b/logstash-core/src/main/java/org/logstash/LockException.java @@ -1,3 +1,23 @@ +/* + * 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. + */ + + package org.logstash; import java.io.IOException; diff --git a/logstash-core/src/main/java/org/logstash/Logstash.java b/logstash-core/src/main/java/org/logstash/Logstash.java index cf156c856..4acf602db 100644 --- a/logstash-core/src/main/java/org/logstash/Logstash.java +++ b/logstash-core/src/main/java/org/logstash/Logstash.java @@ -1,3 +1,23 @@ +/* + * 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. + */ + + package org.logstash; import java.io.IOException; diff --git a/logstash-core/src/main/java/org/logstash/LogstashJavaCompat.java b/logstash-core/src/main/java/org/logstash/LogstashJavaCompat.java index 6be9bfb49..636b9452e 100644 --- a/logstash-core/src/main/java/org/logstash/LogstashJavaCompat.java +++ b/logstash-core/src/main/java/org/logstash/LogstashJavaCompat.java @@ -1,3 +1,23 @@ +/* + * 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. + */ + + package org.logstash; import java.io.StringReader; diff --git a/logstash-core/src/main/java/org/logstash/MissingConverterException.java b/logstash-core/src/main/java/org/logstash/MissingConverterException.java index 04b07938e..1674ab9ca 100644 --- a/logstash-core/src/main/java/org/logstash/MissingConverterException.java +++ b/logstash-core/src/main/java/org/logstash/MissingConverterException.java @@ -1,3 +1,23 @@ +/* + * 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. + */ + + package org.logstash; /** diff --git a/logstash-core/src/main/java/org/logstash/ObjectMappers.java b/logstash-core/src/main/java/org/logstash/ObjectMappers.java index d6e0fbd1c..704b2ceca 100644 --- a/logstash-core/src/main/java/org/logstash/ObjectMappers.java +++ b/logstash-core/src/main/java/org/logstash/ObjectMappers.java @@ -1,3 +1,23 @@ +/* + * 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. + */ + + package org.logstash; import com.fasterxml.jackson.core.JsonGenerator; diff --git a/logstash-core/src/main/java/org/logstash/RubyJavaIntegration.java b/logstash-core/src/main/java/org/logstash/RubyJavaIntegration.java index 093d66cfa..8a854af90 100644 --- a/logstash-core/src/main/java/org/logstash/RubyJavaIntegration.java +++ b/logstash-core/src/main/java/org/logstash/RubyJavaIntegration.java @@ -1,3 +1,23 @@ +/* + * 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. + */ + + package org.logstash; import java.util.ArrayList; diff --git a/logstash-core/src/main/java/org/logstash/RubyUtil.java b/logstash-core/src/main/java/org/logstash/RubyUtil.java index df207064f..d5c8ed817 100644 --- a/logstash-core/src/main/java/org/logstash/RubyUtil.java +++ b/logstash-core/src/main/java/org/logstash/RubyUtil.java @@ -1,3 +1,23 @@ +/* + * 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. + */ + + package org.logstash; import org.jruby.Ruby; diff --git a/logstash-core/src/main/java/org/logstash/Rubyfier.java b/logstash-core/src/main/java/org/logstash/Rubyfier.java index d788c1875..41604ada4 100644 --- a/logstash-core/src/main/java/org/logstash/Rubyfier.java +++ b/logstash-core/src/main/java/org/logstash/Rubyfier.java @@ -1,3 +1,23 @@ +/* + * 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. + */ + + package org.logstash; import java.math.BigDecimal; diff --git a/logstash-core/src/main/java/org/logstash/StringInterpolation.java b/logstash-core/src/main/java/org/logstash/StringInterpolation.java index dbf3a86f4..cec82b4ec 100644 --- a/logstash-core/src/main/java/org/logstash/StringInterpolation.java +++ b/logstash-core/src/main/java/org/logstash/StringInterpolation.java @@ -1,3 +1,23 @@ +/* + * 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. + */ + + package org.logstash; import com.fasterxml.jackson.core.JsonProcessingException; diff --git a/logstash-core/src/main/java/org/logstash/Timestamp.java b/logstash-core/src/main/java/org/logstash/Timestamp.java index 0f2142b8d..893dba3f7 100644 --- a/logstash-core/src/main/java/org/logstash/Timestamp.java +++ b/logstash-core/src/main/java/org/logstash/Timestamp.java @@ -1,3 +1,23 @@ +/* + * 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. + */ + + package org.logstash; import com.fasterxml.jackson.databind.annotation.JsonDeserialize; diff --git a/logstash-core/src/main/java/org/logstash/Util.java b/logstash-core/src/main/java/org/logstash/Util.java index 14db07769..325b93ce6 100644 --- a/logstash-core/src/main/java/org/logstash/Util.java +++ b/logstash-core/src/main/java/org/logstash/Util.java @@ -1,3 +1,23 @@ +/* + * 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. + */ + + package org.logstash; import java.util.ArrayList; diff --git a/logstash-core/src/main/java/org/logstash/Valuefier.java b/logstash-core/src/main/java/org/logstash/Valuefier.java index e6ece76f0..e103ba3c1 100644 --- a/logstash-core/src/main/java/org/logstash/Valuefier.java +++ b/logstash-core/src/main/java/org/logstash/Valuefier.java @@ -1,3 +1,23 @@ +/* + * 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. + */ + + package org.logstash; import java.math.BigDecimal; diff --git a/logstash-core/src/main/java/org/logstash/ackedqueue/AckedBatch.java b/logstash-core/src/main/java/org/logstash/ackedqueue/AckedBatch.java index 07eade228..8daceb2b4 100644 --- a/logstash-core/src/main/java/org/logstash/ackedqueue/AckedBatch.java +++ b/logstash-core/src/main/java/org/logstash/ackedqueue/AckedBatch.java @@ -1,3 +1,23 @@ +/* + * 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. + */ + + package org.logstash.ackedqueue; import java.io.IOException; diff --git a/logstash-core/src/main/java/org/logstash/ackedqueue/AckedReadBatch.java b/logstash-core/src/main/java/org/logstash/ackedqueue/AckedReadBatch.java index 09e025b47..dbc8c686a 100644 --- a/logstash-core/src/main/java/org/logstash/ackedqueue/AckedReadBatch.java +++ b/logstash-core/src/main/java/org/logstash/ackedqueue/AckedReadBatch.java @@ -1,3 +1,23 @@ +/* + * 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. + */ + + package org.logstash.ackedqueue; import org.jruby.RubyArray; diff --git a/logstash-core/src/main/java/org/logstash/ackedqueue/Batch.java b/logstash-core/src/main/java/org/logstash/ackedqueue/Batch.java index 3e582786a..302a6ab55 100644 --- a/logstash-core/src/main/java/org/logstash/ackedqueue/Batch.java +++ b/logstash-core/src/main/java/org/logstash/ackedqueue/Batch.java @@ -1,3 +1,23 @@ +/* + * 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. + */ + + package org.logstash.ackedqueue; import java.io.Closeable; diff --git a/logstash-core/src/main/java/org/logstash/ackedqueue/Checkpoint.java b/logstash-core/src/main/java/org/logstash/ackedqueue/Checkpoint.java index 6fc26dcc1..ad6bf764e 100644 --- a/logstash-core/src/main/java/org/logstash/ackedqueue/Checkpoint.java +++ b/logstash-core/src/main/java/org/logstash/ackedqueue/Checkpoint.java @@ -1,3 +1,23 @@ +/* + * 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. + */ + + package org.logstash.ackedqueue; public class Checkpoint { diff --git a/logstash-core/src/main/java/org/logstash/ackedqueue/Page.java b/logstash-core/src/main/java/org/logstash/ackedqueue/Page.java index 6d0509227..a64c525be 100644 --- a/logstash-core/src/main/java/org/logstash/ackedqueue/Page.java +++ b/logstash-core/src/main/java/org/logstash/ackedqueue/Page.java @@ -1,3 +1,23 @@ +/* + * 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. + */ + + package org.logstash.ackedqueue; import com.google.common.primitives.Ints; diff --git a/logstash-core/src/main/java/org/logstash/ackedqueue/PageFactory.java b/logstash-core/src/main/java/org/logstash/ackedqueue/PageFactory.java index 403ec3e00..2240da306 100644 --- a/logstash-core/src/main/java/org/logstash/ackedqueue/PageFactory.java +++ b/logstash-core/src/main/java/org/logstash/ackedqueue/PageFactory.java @@ -1,3 +1,23 @@ +/* + * 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. + */ + + package org.logstash.ackedqueue; import org.logstash.ackedqueue.io.PageIO; diff --git a/logstash-core/src/main/java/org/logstash/ackedqueue/PqCheck.java b/logstash-core/src/main/java/org/logstash/ackedqueue/PqCheck.java index 6e27c152d..0d02d258b 100644 --- a/logstash-core/src/main/java/org/logstash/ackedqueue/PqCheck.java +++ b/logstash-core/src/main/java/org/logstash/ackedqueue/PqCheck.java @@ -1,3 +1,23 @@ +/* + * 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. + */ + + package org.logstash.ackedqueue; import java.io.IOException; diff --git a/logstash-core/src/main/java/org/logstash/ackedqueue/PqRepair.java b/logstash-core/src/main/java/org/logstash/ackedqueue/PqRepair.java index a713a8b0a..ab91a3b98 100644 --- a/logstash-core/src/main/java/org/logstash/ackedqueue/PqRepair.java +++ b/logstash-core/src/main/java/org/logstash/ackedqueue/PqRepair.java @@ -1,3 +1,23 @@ +/* + * 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. + */ + + package org.logstash.ackedqueue; import java.io.File; diff --git a/logstash-core/src/main/java/org/logstash/ackedqueue/Queue.java b/logstash-core/src/main/java/org/logstash/ackedqueue/Queue.java index f11aa7534..4e39e7586 100644 --- a/logstash-core/src/main/java/org/logstash/ackedqueue/Queue.java +++ b/logstash-core/src/main/java/org/logstash/ackedqueue/Queue.java @@ -1,3 +1,23 @@ +/* + * 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. + */ + + package org.logstash.ackedqueue; import java.io.Closeable; diff --git a/logstash-core/src/main/java/org/logstash/ackedqueue/QueueFactoryExt.java b/logstash-core/src/main/java/org/logstash/ackedqueue/QueueFactoryExt.java index 0b965b173..dad620067 100644 --- a/logstash-core/src/main/java/org/logstash/ackedqueue/QueueFactoryExt.java +++ b/logstash-core/src/main/java/org/logstash/ackedqueue/QueueFactoryExt.java @@ -1,3 +1,23 @@ +/* + * 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. + */ + + package org.logstash.ackedqueue; import java.io.IOException; diff --git a/logstash-core/src/main/java/org/logstash/ackedqueue/QueueRuntimeException.java b/logstash-core/src/main/java/org/logstash/ackedqueue/QueueRuntimeException.java index d4d994ffd..70098bd3c 100644 --- a/logstash-core/src/main/java/org/logstash/ackedqueue/QueueRuntimeException.java +++ b/logstash-core/src/main/java/org/logstash/ackedqueue/QueueRuntimeException.java @@ -1,3 +1,23 @@ +/* + * 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. + */ + + package org.logstash.ackedqueue; public class QueueRuntimeException extends RuntimeException { diff --git a/logstash-core/src/main/java/org/logstash/ackedqueue/QueueUpgrade.java b/logstash-core/src/main/java/org/logstash/ackedqueue/QueueUpgrade.java index 7192a39ff..8147c092f 100644 --- a/logstash-core/src/main/java/org/logstash/ackedqueue/QueueUpgrade.java +++ b/logstash-core/src/main/java/org/logstash/ackedqueue/QueueUpgrade.java @@ -1,3 +1,23 @@ +/* + * 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. + */ + + package org.logstash.ackedqueue; import com.google.common.primitives.Ints; diff --git a/logstash-core/src/main/java/org/logstash/ackedqueue/Queueable.java b/logstash-core/src/main/java/org/logstash/ackedqueue/Queueable.java index 2becec11d..e4896e9b7 100644 --- a/logstash-core/src/main/java/org/logstash/ackedqueue/Queueable.java +++ b/logstash-core/src/main/java/org/logstash/ackedqueue/Queueable.java @@ -1,3 +1,23 @@ +/* + * 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. + */ + + package org.logstash.ackedqueue; import java.io.IOException; diff --git a/logstash-core/src/main/java/org/logstash/ackedqueue/SequencedList.java b/logstash-core/src/main/java/org/logstash/ackedqueue/SequencedList.java index abbcbe015..1b07afa9f 100644 --- a/logstash-core/src/main/java/org/logstash/ackedqueue/SequencedList.java +++ b/logstash-core/src/main/java/org/logstash/ackedqueue/SequencedList.java @@ -1,3 +1,23 @@ +/* + * 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. + */ + + package org.logstash.ackedqueue; import java.util.List; diff --git a/logstash-core/src/main/java/org/logstash/ackedqueue/Settings.java b/logstash-core/src/main/java/org/logstash/ackedqueue/Settings.java index e52436e75..3444a05b0 100644 --- a/logstash-core/src/main/java/org/logstash/ackedqueue/Settings.java +++ b/logstash-core/src/main/java/org/logstash/ackedqueue/Settings.java @@ -1,3 +1,23 @@ +/* + * 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. + */ + + package org.logstash.ackedqueue; public interface Settings { diff --git a/logstash-core/src/main/java/org/logstash/ackedqueue/SettingsImpl.java b/logstash-core/src/main/java/org/logstash/ackedqueue/SettingsImpl.java index 18559e5c8..b1e1e6c6d 100644 --- a/logstash-core/src/main/java/org/logstash/ackedqueue/SettingsImpl.java +++ b/logstash-core/src/main/java/org/logstash/ackedqueue/SettingsImpl.java @@ -1,3 +1,23 @@ +/* + * 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. + */ + + package org.logstash.ackedqueue; public class SettingsImpl implements Settings { diff --git a/logstash-core/src/main/java/org/logstash/ackedqueue/ext/JRubyAckedQueueExt.java b/logstash-core/src/main/java/org/logstash/ackedqueue/ext/JRubyAckedQueueExt.java index 86afee76b..c7d1257e4 100644 --- a/logstash-core/src/main/java/org/logstash/ackedqueue/ext/JRubyAckedQueueExt.java +++ b/logstash-core/src/main/java/org/logstash/ackedqueue/ext/JRubyAckedQueueExt.java @@ -1,3 +1,23 @@ +/* + * 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. + */ + + package org.logstash.ackedqueue.ext; import java.io.IOException; diff --git a/logstash-core/src/main/java/org/logstash/ackedqueue/ext/JRubyWrappedAckedQueueExt.java b/logstash-core/src/main/java/org/logstash/ackedqueue/ext/JRubyWrappedAckedQueueExt.java index 452d77714..6bc03d1fe 100644 --- a/logstash-core/src/main/java/org/logstash/ackedqueue/ext/JRubyWrappedAckedQueueExt.java +++ b/logstash-core/src/main/java/org/logstash/ackedqueue/ext/JRubyWrappedAckedQueueExt.java @@ -1,3 +1,23 @@ +/* + * 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. + */ + + package org.logstash.ackedqueue.ext; import java.io.IOException; diff --git a/logstash-core/src/main/java/org/logstash/ackedqueue/io/ByteBufferCleaner.java b/logstash-core/src/main/java/org/logstash/ackedqueue/io/ByteBufferCleaner.java index 176c3c63b..ed211a11a 100644 --- a/logstash-core/src/main/java/org/logstash/ackedqueue/io/ByteBufferCleaner.java +++ b/logstash-core/src/main/java/org/logstash/ackedqueue/io/ByteBufferCleaner.java @@ -1,3 +1,23 @@ +/* + * 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. + */ + + package org.logstash.ackedqueue.io; import java.nio.MappedByteBuffer; diff --git a/logstash-core/src/main/java/org/logstash/ackedqueue/io/CheckpointIO.java b/logstash-core/src/main/java/org/logstash/ackedqueue/io/CheckpointIO.java index c3b2e5de6..a8e3153c0 100644 --- a/logstash-core/src/main/java/org/logstash/ackedqueue/io/CheckpointIO.java +++ b/logstash-core/src/main/java/org/logstash/ackedqueue/io/CheckpointIO.java @@ -1,3 +1,23 @@ +/* + * 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. + */ + + package org.logstash.ackedqueue.io; import org.logstash.ackedqueue.Checkpoint; diff --git a/logstash-core/src/main/java/org/logstash/ackedqueue/io/FileCheckpointIO.java b/logstash-core/src/main/java/org/logstash/ackedqueue/io/FileCheckpointIO.java index d82c94713..db40f65d0 100644 --- a/logstash-core/src/main/java/org/logstash/ackedqueue/io/FileCheckpointIO.java +++ b/logstash-core/src/main/java/org/logstash/ackedqueue/io/FileCheckpointIO.java @@ -1,3 +1,23 @@ +/* + * 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. + */ + + package org.logstash.ackedqueue.io; import java.io.FileOutputStream; diff --git a/logstash-core/src/main/java/org/logstash/ackedqueue/io/IntVector.java b/logstash-core/src/main/java/org/logstash/ackedqueue/io/IntVector.java index 3845bf6b6..2f756be7e 100644 --- a/logstash-core/src/main/java/org/logstash/ackedqueue/io/IntVector.java +++ b/logstash-core/src/main/java/org/logstash/ackedqueue/io/IntVector.java @@ -1,3 +1,23 @@ +/* + * 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. + */ + + package org.logstash.ackedqueue.io; final class IntVector { diff --git a/logstash-core/src/main/java/org/logstash/ackedqueue/io/LongVector.java b/logstash-core/src/main/java/org/logstash/ackedqueue/io/LongVector.java index 033bf9fe2..18b312179 100644 --- a/logstash-core/src/main/java/org/logstash/ackedqueue/io/LongVector.java +++ b/logstash-core/src/main/java/org/logstash/ackedqueue/io/LongVector.java @@ -1,3 +1,23 @@ +/* + * 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. + */ + + package org.logstash.ackedqueue.io; public final class LongVector { diff --git a/logstash-core/src/main/java/org/logstash/ackedqueue/io/MmapPageIOV1.java b/logstash-core/src/main/java/org/logstash/ackedqueue/io/MmapPageIOV1.java index 3aa56354c..3c306ac03 100644 --- a/logstash-core/src/main/java/org/logstash/ackedqueue/io/MmapPageIOV1.java +++ b/logstash-core/src/main/java/org/logstash/ackedqueue/io/MmapPageIOV1.java @@ -1,3 +1,23 @@ +/* + * 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. + */ + + package org.logstash.ackedqueue.io; import java.io.File; diff --git a/logstash-core/src/main/java/org/logstash/ackedqueue/io/MmapPageIOV2.java b/logstash-core/src/main/java/org/logstash/ackedqueue/io/MmapPageIOV2.java index ee0035a85..2c8dd403a 100644 --- a/logstash-core/src/main/java/org/logstash/ackedqueue/io/MmapPageIOV2.java +++ b/logstash-core/src/main/java/org/logstash/ackedqueue/io/MmapPageIOV2.java @@ -1,3 +1,23 @@ +/* + * 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. + */ + + package org.logstash.ackedqueue.io; import java.io.File; diff --git a/logstash-core/src/main/java/org/logstash/ackedqueue/io/PageIO.java b/logstash-core/src/main/java/org/logstash/ackedqueue/io/PageIO.java index 6560b5a4c..bee69a31a 100644 --- a/logstash-core/src/main/java/org/logstash/ackedqueue/io/PageIO.java +++ b/logstash-core/src/main/java/org/logstash/ackedqueue/io/PageIO.java @@ -1,3 +1,23 @@ +/* + * 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. + */ + + package org.logstash.ackedqueue.io; import org.logstash.ackedqueue.SequencedList; diff --git a/logstash-core/src/main/java/org/logstash/common/AbstractDeadLetterQueueWriterExt.java b/logstash-core/src/main/java/org/logstash/common/AbstractDeadLetterQueueWriterExt.java index 48d45142a..53a881e95 100644 --- a/logstash-core/src/main/java/org/logstash/common/AbstractDeadLetterQueueWriterExt.java +++ b/logstash-core/src/main/java/org/logstash/common/AbstractDeadLetterQueueWriterExt.java @@ -1,3 +1,23 @@ +/* + * 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. + */ + + package org.logstash.common; import java.io.IOException; diff --git a/logstash-core/src/main/java/org/logstash/common/BufferedTokenizerExt.java b/logstash-core/src/main/java/org/logstash/common/BufferedTokenizerExt.java index f3602f7ed..9bc0bc69a 100644 --- a/logstash-core/src/main/java/org/logstash/common/BufferedTokenizerExt.java +++ b/logstash-core/src/main/java/org/logstash/common/BufferedTokenizerExt.java @@ -1,3 +1,23 @@ +/* + * 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. + */ + + package org.logstash.common; import org.jruby.Ruby; diff --git a/logstash-core/src/main/java/org/logstash/common/DLQWriterAdapter.java b/logstash-core/src/main/java/org/logstash/common/DLQWriterAdapter.java index 6f4e93042..1fbc906ba 100644 --- a/logstash-core/src/main/java/org/logstash/common/DLQWriterAdapter.java +++ b/logstash-core/src/main/java/org/logstash/common/DLQWriterAdapter.java @@ -1,3 +1,23 @@ +/* + * 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. + */ + + package org.logstash.common; import co.elastic.logstash.api.DeadLetterQueueWriter; diff --git a/logstash-core/src/main/java/org/logstash/common/DeadLetterQueueFactory.java b/logstash-core/src/main/java/org/logstash/common/DeadLetterQueueFactory.java index 2a884b668..0e07c80a4 100644 --- a/logstash-core/src/main/java/org/logstash/common/DeadLetterQueueFactory.java +++ b/logstash-core/src/main/java/org/logstash/common/DeadLetterQueueFactory.java @@ -1,3 +1,23 @@ +/* + * 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. + */ + + /* * Licensed to Elasticsearch under one or more contributor * license agreements. See the NOTICE file distributed with diff --git a/logstash-core/src/main/java/org/logstash/common/EnvironmentVariableProvider.java b/logstash-core/src/main/java/org/logstash/common/EnvironmentVariableProvider.java index b576cdf3e..9788c8efc 100644 --- a/logstash-core/src/main/java/org/logstash/common/EnvironmentVariableProvider.java +++ b/logstash-core/src/main/java/org/logstash/common/EnvironmentVariableProvider.java @@ -1,3 +1,23 @@ +/* + * 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. + */ + + package org.logstash.common; public interface EnvironmentVariableProvider { diff --git a/logstash-core/src/main/java/org/logstash/common/FsUtil.java b/logstash-core/src/main/java/org/logstash/common/FsUtil.java index 24a60525a..eb0fb74b0 100644 --- a/logstash-core/src/main/java/org/logstash/common/FsUtil.java +++ b/logstash-core/src/main/java/org/logstash/common/FsUtil.java @@ -1,3 +1,23 @@ +/* + * 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. + */ + + package org.logstash.common; import java.nio.file.Path; diff --git a/logstash-core/src/main/java/org/logstash/common/IncompleteSourceWithMetadataException.java b/logstash-core/src/main/java/org/logstash/common/IncompleteSourceWithMetadataException.java index 11f0d9099..90bfc8178 100644 --- a/logstash-core/src/main/java/org/logstash/common/IncompleteSourceWithMetadataException.java +++ b/logstash-core/src/main/java/org/logstash/common/IncompleteSourceWithMetadataException.java @@ -1,3 +1,23 @@ +/* + * 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. + */ + + package org.logstash.common; import org.logstash.config.ir.InvalidIRException; diff --git a/logstash-core/src/main/java/org/logstash/common/LsQueueUtils.java b/logstash-core/src/main/java/org/logstash/common/LsQueueUtils.java index 9266f549a..938b8c60b 100644 --- a/logstash-core/src/main/java/org/logstash/common/LsQueueUtils.java +++ b/logstash-core/src/main/java/org/logstash/common/LsQueueUtils.java @@ -1,3 +1,23 @@ +/* + * 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. + */ + + package org.logstash.common; import java.util.Collection; diff --git a/logstash-core/src/main/java/org/logstash/common/NullDeadLetterQueueWriter.java b/logstash-core/src/main/java/org/logstash/common/NullDeadLetterQueueWriter.java index 339b94175..20eb74195 100644 --- a/logstash-core/src/main/java/org/logstash/common/NullDeadLetterQueueWriter.java +++ b/logstash-core/src/main/java/org/logstash/common/NullDeadLetterQueueWriter.java @@ -1,3 +1,23 @@ +/* + * 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. + */ + + package org.logstash.common; import co.elastic.logstash.api.DeadLetterQueueWriter; diff --git a/logstash-core/src/main/java/org/logstash/common/SourceWithMetadata.java b/logstash-core/src/main/java/org/logstash/common/SourceWithMetadata.java index 76562a564..f8fba5614 100644 --- a/logstash-core/src/main/java/org/logstash/common/SourceWithMetadata.java +++ b/logstash-core/src/main/java/org/logstash/common/SourceWithMetadata.java @@ -1,3 +1,23 @@ +/* + * 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. + */ + + package org.logstash.common; import org.logstash.config.ir.HashableWithSource; diff --git a/logstash-core/src/main/java/org/logstash/common/Util.java b/logstash-core/src/main/java/org/logstash/common/Util.java index a832b1275..0c47a5313 100644 --- a/logstash-core/src/main/java/org/logstash/common/Util.java +++ b/logstash-core/src/main/java/org/logstash/common/Util.java @@ -1,3 +1,23 @@ +/* + * 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. + */ + + package org.logstash.common; import java.nio.charset.StandardCharsets; diff --git a/logstash-core/src/main/java/org/logstash/common/io/DeadLetterQueueReader.java b/logstash-core/src/main/java/org/logstash/common/io/DeadLetterQueueReader.java index 8a83ca718..75110249a 100644 --- a/logstash-core/src/main/java/org/logstash/common/io/DeadLetterQueueReader.java +++ b/logstash-core/src/main/java/org/logstash/common/io/DeadLetterQueueReader.java @@ -1,3 +1,23 @@ +/* + * 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. + */ + + /* * Licensed to Elasticsearch under one or more contributor * license agreements. See the NOTICE file distributed with diff --git a/logstash-core/src/main/java/org/logstash/common/io/DeadLetterQueueWriter.java b/logstash-core/src/main/java/org/logstash/common/io/DeadLetterQueueWriter.java index d9159e201..3b9d665e6 100644 --- a/logstash-core/src/main/java/org/logstash/common/io/DeadLetterQueueWriter.java +++ b/logstash-core/src/main/java/org/logstash/common/io/DeadLetterQueueWriter.java @@ -1,3 +1,23 @@ +/* + * 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. + */ + + /* * Licensed to Elasticsearch under one or more contributor * license agreements. See the NOTICE file distributed with diff --git a/logstash-core/src/main/java/org/logstash/common/io/RecordHeader.java b/logstash-core/src/main/java/org/logstash/common/io/RecordHeader.java index 178f77d23..e143db2d0 100644 --- a/logstash-core/src/main/java/org/logstash/common/io/RecordHeader.java +++ b/logstash-core/src/main/java/org/logstash/common/io/RecordHeader.java @@ -1,3 +1,23 @@ +/* + * 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. + */ + + /* * Licensed to Elasticsearch under one or more contributor * license agreements. See the NOTICE file distributed with diff --git a/logstash-core/src/main/java/org/logstash/common/io/RecordIOReader.java b/logstash-core/src/main/java/org/logstash/common/io/RecordIOReader.java index 390f93a09..e10625ea1 100644 --- a/logstash-core/src/main/java/org/logstash/common/io/RecordIOReader.java +++ b/logstash-core/src/main/java/org/logstash/common/io/RecordIOReader.java @@ -1,3 +1,23 @@ +/* + * 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. + */ + + /* * Licensed to Elasticsearch under one or more contributor * license agreements. See the NOTICE file distributed with diff --git a/logstash-core/src/main/java/org/logstash/common/io/RecordIOWriter.java b/logstash-core/src/main/java/org/logstash/common/io/RecordIOWriter.java index d8bbcb562..bbfb2b644 100644 --- a/logstash-core/src/main/java/org/logstash/common/io/RecordIOWriter.java +++ b/logstash-core/src/main/java/org/logstash/common/io/RecordIOWriter.java @@ -1,3 +1,23 @@ +/* + * 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. + */ + + /* * Licensed to Elasticsearch under one or more contributor * license agreements. See the NOTICE file distributed with diff --git a/logstash-core/src/main/java/org/logstash/common/io/RecordType.java b/logstash-core/src/main/java/org/logstash/common/io/RecordType.java index 3b2e90e3a..d9b5647d5 100644 --- a/logstash-core/src/main/java/org/logstash/common/io/RecordType.java +++ b/logstash-core/src/main/java/org/logstash/common/io/RecordType.java @@ -1,3 +1,23 @@ +/* + * 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. + */ + + /* * Licensed to Elasticsearch under one or more contributor * license agreements. See the NOTICE file distributed with diff --git a/logstash-core/src/main/java/org/logstash/config/ir/BaseSourceComponent.java b/logstash-core/src/main/java/org/logstash/config/ir/BaseSourceComponent.java index ac65a3d2b..e9949b1ca 100644 --- a/logstash-core/src/main/java/org/logstash/config/ir/BaseSourceComponent.java +++ b/logstash-core/src/main/java/org/logstash/config/ir/BaseSourceComponent.java @@ -1,3 +1,23 @@ +/* + * 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. + */ + + package org.logstash.config.ir; import org.logstash.common.SourceWithMetadata; diff --git a/logstash-core/src/main/java/org/logstash/config/ir/CompiledPipeline.java b/logstash-core/src/main/java/org/logstash/config/ir/CompiledPipeline.java index e7ec2fb4d..872fbbb6c 100644 --- a/logstash-core/src/main/java/org/logstash/config/ir/CompiledPipeline.java +++ b/logstash-core/src/main/java/org/logstash/config/ir/CompiledPipeline.java @@ -1,3 +1,23 @@ +/* + * 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. + */ + + package org.logstash.config.ir; import co.elastic.logstash.api.Codec; diff --git a/logstash-core/src/main/java/org/logstash/config/ir/ConfigCompiler.java b/logstash-core/src/main/java/org/logstash/config/ir/ConfigCompiler.java index 5fc2414e0..09a51d6e7 100644 --- a/logstash-core/src/main/java/org/logstash/config/ir/ConfigCompiler.java +++ b/logstash-core/src/main/java/org/logstash/config/ir/ConfigCompiler.java @@ -1,3 +1,23 @@ +/* + * 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. + */ + + package org.logstash.config.ir; import org.jruby.RubyArray; diff --git a/logstash-core/src/main/java/org/logstash/config/ir/DSL.java b/logstash-core/src/main/java/org/logstash/config/ir/DSL.java index be5905a72..a4f64edb7 100644 --- a/logstash-core/src/main/java/org/logstash/config/ir/DSL.java +++ b/logstash-core/src/main/java/org/logstash/config/ir/DSL.java @@ -1,3 +1,23 @@ +/* + * 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. + */ + + package org.logstash.config.ir; import java.util.Arrays; diff --git a/logstash-core/src/main/java/org/logstash/config/ir/Hashable.java b/logstash-core/src/main/java/org/logstash/config/ir/Hashable.java index b8da11f39..a1285d6d6 100644 --- a/logstash-core/src/main/java/org/logstash/config/ir/Hashable.java +++ b/logstash-core/src/main/java/org/logstash/config/ir/Hashable.java @@ -1,3 +1,23 @@ +/* + * 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. + */ + + package org.logstash.config.ir; public interface Hashable { diff --git a/logstash-core/src/main/java/org/logstash/config/ir/HashableWithSource.java b/logstash-core/src/main/java/org/logstash/config/ir/HashableWithSource.java index c8ec08dbf..351930062 100644 --- a/logstash-core/src/main/java/org/logstash/config/ir/HashableWithSource.java +++ b/logstash-core/src/main/java/org/logstash/config/ir/HashableWithSource.java @@ -1,3 +1,23 @@ +/* + * 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. + */ + + package org.logstash.config.ir; import org.logstash.common.Util; diff --git a/logstash-core/src/main/java/org/logstash/config/ir/InvalidIRException.java b/logstash-core/src/main/java/org/logstash/config/ir/InvalidIRException.java index 17342a385..1cfe1e60e 100644 --- a/logstash-core/src/main/java/org/logstash/config/ir/InvalidIRException.java +++ b/logstash-core/src/main/java/org/logstash/config/ir/InvalidIRException.java @@ -1,3 +1,23 @@ +/* + * 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. + */ + + package org.logstash.config.ir; public class InvalidIRException extends Exception { diff --git a/logstash-core/src/main/java/org/logstash/config/ir/PipelineIR.java b/logstash-core/src/main/java/org/logstash/config/ir/PipelineIR.java index f227b3e96..f7b89aad0 100644 --- a/logstash-core/src/main/java/org/logstash/config/ir/PipelineIR.java +++ b/logstash-core/src/main/java/org/logstash/config/ir/PipelineIR.java @@ -1,3 +1,23 @@ +/* + * 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. + */ + + package org.logstash.config.ir; import java.util.List; diff --git a/logstash-core/src/main/java/org/logstash/config/ir/PluginDefinition.java b/logstash-core/src/main/java/org/logstash/config/ir/PluginDefinition.java index 4c6e12baf..eda84f68b 100644 --- a/logstash-core/src/main/java/org/logstash/config/ir/PluginDefinition.java +++ b/logstash-core/src/main/java/org/logstash/config/ir/PluginDefinition.java @@ -1,3 +1,23 @@ +/* + * 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. + */ + + package org.logstash.config.ir; import com.fasterxml.jackson.core.JsonProcessingException; diff --git a/logstash-core/src/main/java/org/logstash/config/ir/SourceComponent.java b/logstash-core/src/main/java/org/logstash/config/ir/SourceComponent.java index 9d0bd997b..bd7482481 100644 --- a/logstash-core/src/main/java/org/logstash/config/ir/SourceComponent.java +++ b/logstash-core/src/main/java/org/logstash/config/ir/SourceComponent.java @@ -1,3 +1,23 @@ +/* + * 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. + */ + + package org.logstash.config.ir; import org.logstash.common.SourceWithMetadata; diff --git a/logstash-core/src/main/java/org/logstash/config/ir/compiler/AbstractFilterDelegatorExt.java b/logstash-core/src/main/java/org/logstash/config/ir/compiler/AbstractFilterDelegatorExt.java index 9d639fa28..d79c2d8c3 100644 --- a/logstash-core/src/main/java/org/logstash/config/ir/compiler/AbstractFilterDelegatorExt.java +++ b/logstash-core/src/main/java/org/logstash/config/ir/compiler/AbstractFilterDelegatorExt.java @@ -1,3 +1,23 @@ +/* + * 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. + */ + + package org.logstash.config.ir.compiler; import org.jruby.Ruby; diff --git a/logstash-core/src/main/java/org/logstash/config/ir/compiler/AbstractOutputDelegatorExt.java b/logstash-core/src/main/java/org/logstash/config/ir/compiler/AbstractOutputDelegatorExt.java index 2df5c678c..7dd28e955 100644 --- a/logstash-core/src/main/java/org/logstash/config/ir/compiler/AbstractOutputDelegatorExt.java +++ b/logstash-core/src/main/java/org/logstash/config/ir/compiler/AbstractOutputDelegatorExt.java @@ -1,3 +1,23 @@ +/* + * 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. + */ + + package org.logstash.config.ir.compiler; import java.util.Collection; diff --git a/logstash-core/src/main/java/org/logstash/config/ir/compiler/BaseDataset.java b/logstash-core/src/main/java/org/logstash/config/ir/compiler/BaseDataset.java index 7b4c2a011..0e3cc4bee 100644 --- a/logstash-core/src/main/java/org/logstash/config/ir/compiler/BaseDataset.java +++ b/logstash-core/src/main/java/org/logstash/config/ir/compiler/BaseDataset.java @@ -1,3 +1,23 @@ +/* + * 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. + */ + + package org.logstash.config.ir.compiler; /** diff --git a/logstash-core/src/main/java/org/logstash/config/ir/compiler/ClassFields.java b/logstash-core/src/main/java/org/logstash/config/ir/compiler/ClassFields.java index e2712648e..b34131bcd 100644 --- a/logstash-core/src/main/java/org/logstash/config/ir/compiler/ClassFields.java +++ b/logstash-core/src/main/java/org/logstash/config/ir/compiler/ClassFields.java @@ -1,3 +1,23 @@ +/* + * 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. + */ + + package org.logstash.config.ir.compiler; import java.util.ArrayList; diff --git a/logstash-core/src/main/java/org/logstash/config/ir/compiler/Closure.java b/logstash-core/src/main/java/org/logstash/config/ir/compiler/Closure.java index 6173a8c35..86479cf74 100644 --- a/logstash-core/src/main/java/org/logstash/config/ir/compiler/Closure.java +++ b/logstash-core/src/main/java/org/logstash/config/ir/compiler/Closure.java @@ -1,3 +1,23 @@ +/* + * 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. + */ + + package org.logstash.config.ir.compiler; import java.util.ArrayList; diff --git a/logstash-core/src/main/java/org/logstash/config/ir/compiler/CommonActions.java b/logstash-core/src/main/java/org/logstash/config/ir/compiler/CommonActions.java index 3db6ef5dc..a1cd558b7 100644 --- a/logstash-core/src/main/java/org/logstash/config/ir/compiler/CommonActions.java +++ b/logstash-core/src/main/java/org/logstash/config/ir/compiler/CommonActions.java @@ -1,3 +1,23 @@ +/* + * 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. + */ + + package org.logstash.config.ir.compiler; import co.elastic.logstash.api.Event; diff --git a/logstash-core/src/main/java/org/logstash/config/ir/compiler/ComputeStepSyntaxElement.java b/logstash-core/src/main/java/org/logstash/config/ir/compiler/ComputeStepSyntaxElement.java index 8cfa42b96..0381435bd 100644 --- a/logstash-core/src/main/java/org/logstash/config/ir/compiler/ComputeStepSyntaxElement.java +++ b/logstash-core/src/main/java/org/logstash/config/ir/compiler/ComputeStepSyntaxElement.java @@ -1,3 +1,23 @@ +/* + * 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. + */ + + package org.logstash.config.ir.compiler; import com.google.googlejavaformat.java.Formatter; diff --git a/logstash-core/src/main/java/org/logstash/config/ir/compiler/Dataset.java b/logstash-core/src/main/java/org/logstash/config/ir/compiler/Dataset.java index a3478ae56..4f28aa710 100644 --- a/logstash-core/src/main/java/org/logstash/config/ir/compiler/Dataset.java +++ b/logstash-core/src/main/java/org/logstash/config/ir/compiler/Dataset.java @@ -1,3 +1,23 @@ +/* + * 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. + */ + + package org.logstash.config.ir.compiler; import java.util.Collection; diff --git a/logstash-core/src/main/java/org/logstash/config/ir/compiler/DatasetCompiler.java b/logstash-core/src/main/java/org/logstash/config/ir/compiler/DatasetCompiler.java index 22e6e41d5..74bd7eb46 100644 --- a/logstash-core/src/main/java/org/logstash/config/ir/compiler/DatasetCompiler.java +++ b/logstash-core/src/main/java/org/logstash/config/ir/compiler/DatasetCompiler.java @@ -1,3 +1,23 @@ +/* + * 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. + */ + + package org.logstash.config.ir.compiler; import java.util.ArrayList; diff --git a/logstash-core/src/main/java/org/logstash/config/ir/compiler/EventCondition.java b/logstash-core/src/main/java/org/logstash/config/ir/compiler/EventCondition.java index 829167b9e..0b2848d8d 100644 --- a/logstash-core/src/main/java/org/logstash/config/ir/compiler/EventCondition.java +++ b/logstash-core/src/main/java/org/logstash/config/ir/compiler/EventCondition.java @@ -1,3 +1,23 @@ +/* + * 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. + */ + + package org.logstash.config.ir.compiler; import java.util.HashMap; diff --git a/logstash-core/src/main/java/org/logstash/config/ir/compiler/FieldDeclarationGroup.java b/logstash-core/src/main/java/org/logstash/config/ir/compiler/FieldDeclarationGroup.java index 457f88563..5d39b3310 100644 --- a/logstash-core/src/main/java/org/logstash/config/ir/compiler/FieldDeclarationGroup.java +++ b/logstash-core/src/main/java/org/logstash/config/ir/compiler/FieldDeclarationGroup.java @@ -1,3 +1,23 @@ +/* + * 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. + */ + + package org.logstash.config.ir.compiler; import java.util.Collection; diff --git a/logstash-core/src/main/java/org/logstash/config/ir/compiler/FieldDefinition.java b/logstash-core/src/main/java/org/logstash/config/ir/compiler/FieldDefinition.java index 06a361908..b3e481e6f 100644 --- a/logstash-core/src/main/java/org/logstash/config/ir/compiler/FieldDefinition.java +++ b/logstash-core/src/main/java/org/logstash/config/ir/compiler/FieldDefinition.java @@ -1,3 +1,23 @@ +/* + * 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. + */ + + package org.logstash.config.ir.compiler; /** diff --git a/logstash-core/src/main/java/org/logstash/config/ir/compiler/FilterDelegatorExt.java b/logstash-core/src/main/java/org/logstash/config/ir/compiler/FilterDelegatorExt.java index a5d7d310e..d61e0c132 100644 --- a/logstash-core/src/main/java/org/logstash/config/ir/compiler/FilterDelegatorExt.java +++ b/logstash-core/src/main/java/org/logstash/config/ir/compiler/FilterDelegatorExt.java @@ -1,3 +1,23 @@ +/* + * 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. + */ + + package org.logstash.config.ir.compiler; import com.google.common.annotations.VisibleForTesting; diff --git a/logstash-core/src/main/java/org/logstash/config/ir/compiler/JavaCodecDelegator.java b/logstash-core/src/main/java/org/logstash/config/ir/compiler/JavaCodecDelegator.java index afa91d538..ea3b9f72a 100644 --- a/logstash-core/src/main/java/org/logstash/config/ir/compiler/JavaCodecDelegator.java +++ b/logstash-core/src/main/java/org/logstash/config/ir/compiler/JavaCodecDelegator.java @@ -1,3 +1,23 @@ +/* + * 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. + */ + + package org.logstash.config.ir.compiler; import co.elastic.logstash.api.Codec; diff --git a/logstash-core/src/main/java/org/logstash/config/ir/compiler/JavaFilterDelegatorExt.java b/logstash-core/src/main/java/org/logstash/config/ir/compiler/JavaFilterDelegatorExt.java index f55ebb28f..043af3f9f 100644 --- a/logstash-core/src/main/java/org/logstash/config/ir/compiler/JavaFilterDelegatorExt.java +++ b/logstash-core/src/main/java/org/logstash/config/ir/compiler/JavaFilterDelegatorExt.java @@ -1,3 +1,23 @@ +/* + * 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. + */ + + package org.logstash.config.ir.compiler; import co.elastic.logstash.api.Event; diff --git a/logstash-core/src/main/java/org/logstash/config/ir/compiler/JavaInputDelegatorExt.java b/logstash-core/src/main/java/org/logstash/config/ir/compiler/JavaInputDelegatorExt.java index fecfc6055..f99c0a5bc 100644 --- a/logstash-core/src/main/java/org/logstash/config/ir/compiler/JavaInputDelegatorExt.java +++ b/logstash-core/src/main/java/org/logstash/config/ir/compiler/JavaInputDelegatorExt.java @@ -1,3 +1,23 @@ +/* + * 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. + */ + + package org.logstash.config.ir.compiler; import co.elastic.logstash.api.Input; diff --git a/logstash-core/src/main/java/org/logstash/config/ir/compiler/JavaOutputDelegatorExt.java b/logstash-core/src/main/java/org/logstash/config/ir/compiler/JavaOutputDelegatorExt.java index 3edcc2bb4..380341ec2 100644 --- a/logstash-core/src/main/java/org/logstash/config/ir/compiler/JavaOutputDelegatorExt.java +++ b/logstash-core/src/main/java/org/logstash/config/ir/compiler/JavaOutputDelegatorExt.java @@ -1,3 +1,23 @@ +/* + * 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. + */ + + package org.logstash.config.ir.compiler; import java.util.Collection; diff --git a/logstash-core/src/main/java/org/logstash/config/ir/compiler/MethodLevelSyntaxElement.java b/logstash-core/src/main/java/org/logstash/config/ir/compiler/MethodLevelSyntaxElement.java index 213a4ba1e..88b514b0c 100644 --- a/logstash-core/src/main/java/org/logstash/config/ir/compiler/MethodLevelSyntaxElement.java +++ b/logstash-core/src/main/java/org/logstash/config/ir/compiler/MethodLevelSyntaxElement.java @@ -1,3 +1,23 @@ +/* + * 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. + */ + + package org.logstash.config.ir.compiler; /** diff --git a/logstash-core/src/main/java/org/logstash/config/ir/compiler/MethodSyntaxElement.java b/logstash-core/src/main/java/org/logstash/config/ir/compiler/MethodSyntaxElement.java index 9ff96d014..ed419e954 100644 --- a/logstash-core/src/main/java/org/logstash/config/ir/compiler/MethodSyntaxElement.java +++ b/logstash-core/src/main/java/org/logstash/config/ir/compiler/MethodSyntaxElement.java @@ -1,3 +1,23 @@ +/* + * 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. + */ + + package org.logstash.config.ir.compiler; import java.util.Arrays; diff --git a/logstash-core/src/main/java/org/logstash/config/ir/compiler/OutputDelegatorExt.java b/logstash-core/src/main/java/org/logstash/config/ir/compiler/OutputDelegatorExt.java index 0e8deca8d..6979d6d24 100644 --- a/logstash-core/src/main/java/org/logstash/config/ir/compiler/OutputDelegatorExt.java +++ b/logstash-core/src/main/java/org/logstash/config/ir/compiler/OutputDelegatorExt.java @@ -1,3 +1,23 @@ +/* + * 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. + */ + + package org.logstash.config.ir.compiler; import com.google.common.annotations.VisibleForTesting; diff --git a/logstash-core/src/main/java/org/logstash/config/ir/compiler/OutputStrategyExt.java b/logstash-core/src/main/java/org/logstash/config/ir/compiler/OutputStrategyExt.java index f60daf4f2..c5afaac05 100644 --- a/logstash-core/src/main/java/org/logstash/config/ir/compiler/OutputStrategyExt.java +++ b/logstash-core/src/main/java/org/logstash/config/ir/compiler/OutputStrategyExt.java @@ -1,3 +1,23 @@ +/* + * 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. + */ + + package org.logstash.config.ir.compiler; import java.util.concurrent.ArrayBlockingQueue; diff --git a/logstash-core/src/main/java/org/logstash/config/ir/compiler/PluginFactory.java b/logstash-core/src/main/java/org/logstash/config/ir/compiler/PluginFactory.java index 766eabc73..e476ad436 100644 --- a/logstash-core/src/main/java/org/logstash/config/ir/compiler/PluginFactory.java +++ b/logstash-core/src/main/java/org/logstash/config/ir/compiler/PluginFactory.java @@ -1,3 +1,23 @@ +/* + * 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. + */ + + package org.logstash.config.ir.compiler; import co.elastic.logstash.api.Codec; diff --git a/logstash-core/src/main/java/org/logstash/config/ir/compiler/RubyIntegration.java b/logstash-core/src/main/java/org/logstash/config/ir/compiler/RubyIntegration.java index 835da3ebd..faac9f66d 100644 --- a/logstash-core/src/main/java/org/logstash/config/ir/compiler/RubyIntegration.java +++ b/logstash-core/src/main/java/org/logstash/config/ir/compiler/RubyIntegration.java @@ -1,3 +1,23 @@ +/* + * 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. + */ + + package org.logstash.config.ir.compiler; import co.elastic.logstash.api.Codec; diff --git a/logstash-core/src/main/java/org/logstash/config/ir/compiler/SplitDataset.java b/logstash-core/src/main/java/org/logstash/config/ir/compiler/SplitDataset.java index 8a83cd75b..05b32e48e 100644 --- a/logstash-core/src/main/java/org/logstash/config/ir/compiler/SplitDataset.java +++ b/logstash-core/src/main/java/org/logstash/config/ir/compiler/SplitDataset.java @@ -1,3 +1,23 @@ +/* + * 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. + */ + + package org.logstash.config.ir.compiler; /** diff --git a/logstash-core/src/main/java/org/logstash/config/ir/compiler/SyntaxElement.java b/logstash-core/src/main/java/org/logstash/config/ir/compiler/SyntaxElement.java index 167472164..cd025b5e0 100644 --- a/logstash-core/src/main/java/org/logstash/config/ir/compiler/SyntaxElement.java +++ b/logstash-core/src/main/java/org/logstash/config/ir/compiler/SyntaxElement.java @@ -1,3 +1,23 @@ +/* + * 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. + */ + + package org.logstash.config.ir.compiler; /** diff --git a/logstash-core/src/main/java/org/logstash/config/ir/compiler/SyntaxFactory.java b/logstash-core/src/main/java/org/logstash/config/ir/compiler/SyntaxFactory.java index f95652434..f40765602 100644 --- a/logstash-core/src/main/java/org/logstash/config/ir/compiler/SyntaxFactory.java +++ b/logstash-core/src/main/java/org/logstash/config/ir/compiler/SyntaxFactory.java @@ -1,3 +1,23 @@ +/* + * 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. + */ + + package org.logstash.config.ir.compiler; import java.util.Arrays; diff --git a/logstash-core/src/main/java/org/logstash/config/ir/compiler/Utils.java b/logstash-core/src/main/java/org/logstash/config/ir/compiler/Utils.java index b47d268fd..3bf64beb0 100644 --- a/logstash-core/src/main/java/org/logstash/config/ir/compiler/Utils.java +++ b/logstash-core/src/main/java/org/logstash/config/ir/compiler/Utils.java @@ -1,3 +1,23 @@ +/* + * 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. + */ + + package org.logstash.config.ir.compiler; import org.logstash.ext.JrubyEventExtLibrary; diff --git a/logstash-core/src/main/java/org/logstash/config/ir/compiler/ValueSyntaxElement.java b/logstash-core/src/main/java/org/logstash/config/ir/compiler/ValueSyntaxElement.java index e5c7e36e7..cb7632050 100644 --- a/logstash-core/src/main/java/org/logstash/config/ir/compiler/ValueSyntaxElement.java +++ b/logstash-core/src/main/java/org/logstash/config/ir/compiler/ValueSyntaxElement.java @@ -1,3 +1,23 @@ +/* + * 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. + */ + + package org.logstash.config.ir.compiler; /** diff --git a/logstash-core/src/main/java/org/logstash/config/ir/compiler/VariableDefinition.java b/logstash-core/src/main/java/org/logstash/config/ir/compiler/VariableDefinition.java index 86d9a189d..e6644cca6 100644 --- a/logstash-core/src/main/java/org/logstash/config/ir/compiler/VariableDefinition.java +++ b/logstash-core/src/main/java/org/logstash/config/ir/compiler/VariableDefinition.java @@ -1,3 +1,23 @@ +/* + * 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. + */ + + package org.logstash.config.ir.compiler; import org.jruby.internal.runtime.methods.DynamicMethod; diff --git a/logstash-core/src/main/java/org/logstash/config/ir/expression/BinaryBooleanExpression.java b/logstash-core/src/main/java/org/logstash/config/ir/expression/BinaryBooleanExpression.java index a64cceb12..43a893c76 100644 --- a/logstash-core/src/main/java/org/logstash/config/ir/expression/BinaryBooleanExpression.java +++ b/logstash-core/src/main/java/org/logstash/config/ir/expression/BinaryBooleanExpression.java @@ -1,3 +1,23 @@ +/* + * 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. + */ + + package org.logstash.config.ir.expression; import org.logstash.common.SourceWithMetadata; diff --git a/logstash-core/src/main/java/org/logstash/config/ir/expression/BooleanExpression.java b/logstash-core/src/main/java/org/logstash/config/ir/expression/BooleanExpression.java index 4a0f62ffe..0393b67b1 100644 --- a/logstash-core/src/main/java/org/logstash/config/ir/expression/BooleanExpression.java +++ b/logstash-core/src/main/java/org/logstash/config/ir/expression/BooleanExpression.java @@ -1,3 +1,23 @@ +/* + * 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. + */ + + package org.logstash.config.ir.expression; import org.logstash.common.SourceWithMetadata; diff --git a/logstash-core/src/main/java/org/logstash/config/ir/expression/EventValueExpression.java b/logstash-core/src/main/java/org/logstash/config/ir/expression/EventValueExpression.java index 59376f058..fcc2d6b82 100644 --- a/logstash-core/src/main/java/org/logstash/config/ir/expression/EventValueExpression.java +++ b/logstash-core/src/main/java/org/logstash/config/ir/expression/EventValueExpression.java @@ -1,3 +1,23 @@ +/* + * 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. + */ + + package org.logstash.config.ir.expression; import org.logstash.config.ir.SourceComponent; diff --git a/logstash-core/src/main/java/org/logstash/config/ir/expression/Expression.java b/logstash-core/src/main/java/org/logstash/config/ir/expression/Expression.java index 7c33f82a5..f3368a14a 100644 --- a/logstash-core/src/main/java/org/logstash/config/ir/expression/Expression.java +++ b/logstash-core/src/main/java/org/logstash/config/ir/expression/Expression.java @@ -1,3 +1,23 @@ +/* + * 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. + */ + + package org.logstash.config.ir.expression; import org.logstash.common.SourceWithMetadata; diff --git a/logstash-core/src/main/java/org/logstash/config/ir/expression/RegexValueExpression.java b/logstash-core/src/main/java/org/logstash/config/ir/expression/RegexValueExpression.java index 0d93310d8..6c1437ab2 100644 --- a/logstash-core/src/main/java/org/logstash/config/ir/expression/RegexValueExpression.java +++ b/logstash-core/src/main/java/org/logstash/config/ir/expression/RegexValueExpression.java @@ -1,3 +1,23 @@ +/* + * 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. + */ + + package org.logstash.config.ir.expression; import org.logstash.common.SourceWithMetadata; diff --git a/logstash-core/src/main/java/org/logstash/config/ir/expression/UnaryBooleanExpression.java b/logstash-core/src/main/java/org/logstash/config/ir/expression/UnaryBooleanExpression.java index 78018fa57..9d9bdbb71 100644 --- a/logstash-core/src/main/java/org/logstash/config/ir/expression/UnaryBooleanExpression.java +++ b/logstash-core/src/main/java/org/logstash/config/ir/expression/UnaryBooleanExpression.java @@ -1,3 +1,23 @@ +/* + * 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. + */ + + package org.logstash.config.ir.expression; import org.logstash.config.ir.InvalidIRException; diff --git a/logstash-core/src/main/java/org/logstash/config/ir/expression/ValueExpression.java b/logstash-core/src/main/java/org/logstash/config/ir/expression/ValueExpression.java index 760d7853c..2b0a6db33 100644 --- a/logstash-core/src/main/java/org/logstash/config/ir/expression/ValueExpression.java +++ b/logstash-core/src/main/java/org/logstash/config/ir/expression/ValueExpression.java @@ -1,3 +1,23 @@ +/* + * 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. + */ + + package org.logstash.config.ir.expression; import java.math.BigDecimal; diff --git a/logstash-core/src/main/java/org/logstash/config/ir/expression/binary/And.java b/logstash-core/src/main/java/org/logstash/config/ir/expression/binary/And.java index cd1134333..eddae8738 100644 --- a/logstash-core/src/main/java/org/logstash/config/ir/expression/binary/And.java +++ b/logstash-core/src/main/java/org/logstash/config/ir/expression/binary/And.java @@ -1,3 +1,23 @@ +/* + * 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. + */ + + package org.logstash.config.ir.expression.binary; import org.logstash.common.SourceWithMetadata; diff --git a/logstash-core/src/main/java/org/logstash/config/ir/expression/binary/Eq.java b/logstash-core/src/main/java/org/logstash/config/ir/expression/binary/Eq.java index 0af8e6e2c..b73477103 100644 --- a/logstash-core/src/main/java/org/logstash/config/ir/expression/binary/Eq.java +++ b/logstash-core/src/main/java/org/logstash/config/ir/expression/binary/Eq.java @@ -1,3 +1,23 @@ +/* + * 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. + */ + + package org.logstash.config.ir.expression.binary; import org.logstash.common.SourceWithMetadata; diff --git a/logstash-core/src/main/java/org/logstash/config/ir/expression/binary/Gt.java b/logstash-core/src/main/java/org/logstash/config/ir/expression/binary/Gt.java index 6d10434e4..5836f8f0a 100644 --- a/logstash-core/src/main/java/org/logstash/config/ir/expression/binary/Gt.java +++ b/logstash-core/src/main/java/org/logstash/config/ir/expression/binary/Gt.java @@ -1,3 +1,23 @@ +/* + * 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. + */ + + package org.logstash.config.ir.expression.binary; import org.logstash.common.SourceWithMetadata; diff --git a/logstash-core/src/main/java/org/logstash/config/ir/expression/binary/Gte.java b/logstash-core/src/main/java/org/logstash/config/ir/expression/binary/Gte.java index 4961dc00e..214f06dfe 100644 --- a/logstash-core/src/main/java/org/logstash/config/ir/expression/binary/Gte.java +++ b/logstash-core/src/main/java/org/logstash/config/ir/expression/binary/Gte.java @@ -1,3 +1,23 @@ +/* + * 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. + */ + + package org.logstash.config.ir.expression.binary; import org.logstash.common.SourceWithMetadata; diff --git a/logstash-core/src/main/java/org/logstash/config/ir/expression/binary/In.java b/logstash-core/src/main/java/org/logstash/config/ir/expression/binary/In.java index 7c50efad8..07da9a605 100644 --- a/logstash-core/src/main/java/org/logstash/config/ir/expression/binary/In.java +++ b/logstash-core/src/main/java/org/logstash/config/ir/expression/binary/In.java @@ -1,3 +1,23 @@ +/* + * 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. + */ + + package org.logstash.config.ir.expression.binary; import org.logstash.common.SourceWithMetadata; diff --git a/logstash-core/src/main/java/org/logstash/config/ir/expression/binary/Lt.java b/logstash-core/src/main/java/org/logstash/config/ir/expression/binary/Lt.java index becc96f6b..3fd762232 100644 --- a/logstash-core/src/main/java/org/logstash/config/ir/expression/binary/Lt.java +++ b/logstash-core/src/main/java/org/logstash/config/ir/expression/binary/Lt.java @@ -1,3 +1,23 @@ +/* + * 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. + */ + + package org.logstash.config.ir.expression.binary; import org.logstash.common.SourceWithMetadata; diff --git a/logstash-core/src/main/java/org/logstash/config/ir/expression/binary/Lte.java b/logstash-core/src/main/java/org/logstash/config/ir/expression/binary/Lte.java index 6d5814a1c..455deade6 100644 --- a/logstash-core/src/main/java/org/logstash/config/ir/expression/binary/Lte.java +++ b/logstash-core/src/main/java/org/logstash/config/ir/expression/binary/Lte.java @@ -1,3 +1,23 @@ +/* + * 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. + */ + + package org.logstash.config.ir.expression.binary; import org.logstash.common.SourceWithMetadata; diff --git a/logstash-core/src/main/java/org/logstash/config/ir/expression/binary/Neq.java b/logstash-core/src/main/java/org/logstash/config/ir/expression/binary/Neq.java index 9e23e53c7..3c0579299 100644 --- a/logstash-core/src/main/java/org/logstash/config/ir/expression/binary/Neq.java +++ b/logstash-core/src/main/java/org/logstash/config/ir/expression/binary/Neq.java @@ -1,3 +1,23 @@ +/* + * 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. + */ + + package org.logstash.config.ir.expression.binary; import org.logstash.common.SourceWithMetadata; diff --git a/logstash-core/src/main/java/org/logstash/config/ir/expression/binary/Or.java b/logstash-core/src/main/java/org/logstash/config/ir/expression/binary/Or.java index b4019975a..688a68e34 100644 --- a/logstash-core/src/main/java/org/logstash/config/ir/expression/binary/Or.java +++ b/logstash-core/src/main/java/org/logstash/config/ir/expression/binary/Or.java @@ -1,3 +1,23 @@ +/* + * 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. + */ + + package org.logstash.config.ir.expression.binary; import org.logstash.common.SourceWithMetadata; diff --git a/logstash-core/src/main/java/org/logstash/config/ir/expression/binary/RegexEq.java b/logstash-core/src/main/java/org/logstash/config/ir/expression/binary/RegexEq.java index b6a5d9c2c..35186a213 100644 --- a/logstash-core/src/main/java/org/logstash/config/ir/expression/binary/RegexEq.java +++ b/logstash-core/src/main/java/org/logstash/config/ir/expression/binary/RegexEq.java @@ -1,3 +1,23 @@ +/* + * 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. + */ + + package org.logstash.config.ir.expression.binary; import org.logstash.config.ir.InvalidIRException; diff --git a/logstash-core/src/main/java/org/logstash/config/ir/expression/unary/Not.java b/logstash-core/src/main/java/org/logstash/config/ir/expression/unary/Not.java index 04dd3ccb7..764c93790 100644 --- a/logstash-core/src/main/java/org/logstash/config/ir/expression/unary/Not.java +++ b/logstash-core/src/main/java/org/logstash/config/ir/expression/unary/Not.java @@ -1,3 +1,23 @@ +/* + * 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. + */ + + package org.logstash.config.ir.expression.unary; import org.logstash.config.ir.SourceComponent; diff --git a/logstash-core/src/main/java/org/logstash/config/ir/expression/unary/Truthy.java b/logstash-core/src/main/java/org/logstash/config/ir/expression/unary/Truthy.java index 3f9d655a7..79e118517 100644 --- a/logstash-core/src/main/java/org/logstash/config/ir/expression/unary/Truthy.java +++ b/logstash-core/src/main/java/org/logstash/config/ir/expression/unary/Truthy.java @@ -1,3 +1,23 @@ +/* + * 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. + */ + + package org.logstash.config.ir.expression.unary; import org.logstash.config.ir.SourceComponent; diff --git a/logstash-core/src/main/java/org/logstash/config/ir/graph/BooleanEdge.java b/logstash-core/src/main/java/org/logstash/config/ir/graph/BooleanEdge.java index f1f6dbd09..420e09334 100644 --- a/logstash-core/src/main/java/org/logstash/config/ir/graph/BooleanEdge.java +++ b/logstash-core/src/main/java/org/logstash/config/ir/graph/BooleanEdge.java @@ -1,3 +1,23 @@ +/* + * 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. + */ + + package org.logstash.config.ir.graph; import org.logstash.common.Util; diff --git a/logstash-core/src/main/java/org/logstash/config/ir/graph/Edge.java b/logstash-core/src/main/java/org/logstash/config/ir/graph/Edge.java index 8efa7806a..4d5c17c63 100644 --- a/logstash-core/src/main/java/org/logstash/config/ir/graph/Edge.java +++ b/logstash-core/src/main/java/org/logstash/config/ir/graph/Edge.java @@ -1,3 +1,23 @@ +/* + * 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. + */ + + package org.logstash.config.ir.graph; import java.util.stream.Stream; diff --git a/logstash-core/src/main/java/org/logstash/config/ir/graph/Graph.java b/logstash-core/src/main/java/org/logstash/config/ir/graph/Graph.java index 38554f022..f41558ad7 100644 --- a/logstash-core/src/main/java/org/logstash/config/ir/graph/Graph.java +++ b/logstash-core/src/main/java/org/logstash/config/ir/graph/Graph.java @@ -1,3 +1,23 @@ +/* + * 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. + */ + + package org.logstash.config.ir.graph; import org.logstash.common.Util; diff --git a/logstash-core/src/main/java/org/logstash/config/ir/graph/IfVertex.java b/logstash-core/src/main/java/org/logstash/config/ir/graph/IfVertex.java index 6163d5186..531e7f41b 100644 --- a/logstash-core/src/main/java/org/logstash/config/ir/graph/IfVertex.java +++ b/logstash-core/src/main/java/org/logstash/config/ir/graph/IfVertex.java @@ -1,3 +1,23 @@ +/* + * 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. + */ + + package org.logstash.config.ir.graph; import java.util.Collection; diff --git a/logstash-core/src/main/java/org/logstash/config/ir/graph/PlainEdge.java b/logstash-core/src/main/java/org/logstash/config/ir/graph/PlainEdge.java index 519b1f064..7fc477fcd 100644 --- a/logstash-core/src/main/java/org/logstash/config/ir/graph/PlainEdge.java +++ b/logstash-core/src/main/java/org/logstash/config/ir/graph/PlainEdge.java @@ -1,3 +1,23 @@ +/* + * 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. + */ + + package org.logstash.config.ir.graph; import org.logstash.common.Util; diff --git a/logstash-core/src/main/java/org/logstash/config/ir/graph/PluginVertex.java b/logstash-core/src/main/java/org/logstash/config/ir/graph/PluginVertex.java index 4187c0ae9..506de94b8 100644 --- a/logstash-core/src/main/java/org/logstash/config/ir/graph/PluginVertex.java +++ b/logstash-core/src/main/java/org/logstash/config/ir/graph/PluginVertex.java @@ -1,3 +1,23 @@ +/* + * 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. + */ + + package org.logstash.config.ir.graph; import org.logstash.common.SourceWithMetadata; diff --git a/logstash-core/src/main/java/org/logstash/config/ir/graph/QueueVertex.java b/logstash-core/src/main/java/org/logstash/config/ir/graph/QueueVertex.java index ed66e79a3..d6e2b2549 100644 --- a/logstash-core/src/main/java/org/logstash/config/ir/graph/QueueVertex.java +++ b/logstash-core/src/main/java/org/logstash/config/ir/graph/QueueVertex.java @@ -1,3 +1,23 @@ +/* + * 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. + */ + + package org.logstash.config.ir.graph; import org.logstash.common.IncompleteSourceWithMetadataException; diff --git a/logstash-core/src/main/java/org/logstash/config/ir/graph/Vertex.java b/logstash-core/src/main/java/org/logstash/config/ir/graph/Vertex.java index 15b7e604c..e5b73b080 100644 --- a/logstash-core/src/main/java/org/logstash/config/ir/graph/Vertex.java +++ b/logstash-core/src/main/java/org/logstash/config/ir/graph/Vertex.java @@ -1,3 +1,23 @@ +/* + * 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. + */ + + package org.logstash.config.ir.graph; import java.util.concurrent.atomic.AtomicInteger; diff --git a/logstash-core/src/main/java/org/logstash/config/ir/graph/algorithms/BreadthFirst.java b/logstash-core/src/main/java/org/logstash/config/ir/graph/algorithms/BreadthFirst.java index 8e878c66a..0c16c1716 100644 --- a/logstash-core/src/main/java/org/logstash/config/ir/graph/algorithms/BreadthFirst.java +++ b/logstash-core/src/main/java/org/logstash/config/ir/graph/algorithms/BreadthFirst.java @@ -1,3 +1,23 @@ +/* + * 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. + */ + + package org.logstash.config.ir.graph.algorithms; import org.logstash.config.ir.graph.Vertex; diff --git a/logstash-core/src/main/java/org/logstash/config/ir/graph/algorithms/DepthFirst.java b/logstash-core/src/main/java/org/logstash/config/ir/graph/algorithms/DepthFirst.java index 40c7bc6ad..96c758a40 100644 --- a/logstash-core/src/main/java/org/logstash/config/ir/graph/algorithms/DepthFirst.java +++ b/logstash-core/src/main/java/org/logstash/config/ir/graph/algorithms/DepthFirst.java @@ -1,3 +1,23 @@ +/* + * 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. + */ + + package org.logstash.config.ir.graph.algorithms; import org.logstash.config.ir.graph.Graph; diff --git a/logstash-core/src/main/java/org/logstash/config/ir/graph/algorithms/GraphDiff.java b/logstash-core/src/main/java/org/logstash/config/ir/graph/algorithms/GraphDiff.java index c6c973721..afc19b3ac 100644 --- a/logstash-core/src/main/java/org/logstash/config/ir/graph/algorithms/GraphDiff.java +++ b/logstash-core/src/main/java/org/logstash/config/ir/graph/algorithms/GraphDiff.java @@ -1,3 +1,23 @@ +/* + * 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. + */ + + package org.logstash.config.ir.graph.algorithms; import java.util.Collection; diff --git a/logstash-core/src/main/java/org/logstash/config/ir/graph/algorithms/TopologicalSort.java b/logstash-core/src/main/java/org/logstash/config/ir/graph/algorithms/TopologicalSort.java index 48b7405bd..21b95966c 100644 --- a/logstash-core/src/main/java/org/logstash/config/ir/graph/algorithms/TopologicalSort.java +++ b/logstash-core/src/main/java/org/logstash/config/ir/graph/algorithms/TopologicalSort.java @@ -1,3 +1,23 @@ +/* + * 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. + */ + + package org.logstash.config.ir.graph.algorithms; import org.logstash.config.ir.graph.Edge; diff --git a/logstash-core/src/main/java/org/logstash/config/ir/imperative/ComposedParallelStatement.java b/logstash-core/src/main/java/org/logstash/config/ir/imperative/ComposedParallelStatement.java index 7b0a1e5c4..f45a6981f 100644 --- a/logstash-core/src/main/java/org/logstash/config/ir/imperative/ComposedParallelStatement.java +++ b/logstash-core/src/main/java/org/logstash/config/ir/imperative/ComposedParallelStatement.java @@ -1,3 +1,23 @@ +/* + * 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. + */ + + package org.logstash.config.ir.imperative; import org.logstash.config.ir.InvalidIRException; diff --git a/logstash-core/src/main/java/org/logstash/config/ir/imperative/ComposedSequenceStatement.java b/logstash-core/src/main/java/org/logstash/config/ir/imperative/ComposedSequenceStatement.java index 37d5b18ce..6cd2a44ac 100644 --- a/logstash-core/src/main/java/org/logstash/config/ir/imperative/ComposedSequenceStatement.java +++ b/logstash-core/src/main/java/org/logstash/config/ir/imperative/ComposedSequenceStatement.java @@ -1,3 +1,23 @@ +/* + * 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. + */ + + package org.logstash.config.ir.imperative; import org.logstash.config.ir.InvalidIRException; diff --git a/logstash-core/src/main/java/org/logstash/config/ir/imperative/ComposedStatement.java b/logstash-core/src/main/java/org/logstash/config/ir/imperative/ComposedStatement.java index d4f838f35..777fb79d6 100644 --- a/logstash-core/src/main/java/org/logstash/config/ir/imperative/ComposedStatement.java +++ b/logstash-core/src/main/java/org/logstash/config/ir/imperative/ComposedStatement.java @@ -1,3 +1,23 @@ +/* + * 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. + */ + + package org.logstash.config.ir.imperative; import org.logstash.config.ir.SourceComponent; diff --git a/logstash-core/src/main/java/org/logstash/config/ir/imperative/IfStatement.java b/logstash-core/src/main/java/org/logstash/config/ir/imperative/IfStatement.java index 35e3c7b83..158859607 100644 --- a/logstash-core/src/main/java/org/logstash/config/ir/imperative/IfStatement.java +++ b/logstash-core/src/main/java/org/logstash/config/ir/imperative/IfStatement.java @@ -1,3 +1,23 @@ +/* + * 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. + */ + + package org.logstash.config.ir.imperative; import org.logstash.config.ir.SourceComponent; diff --git a/logstash-core/src/main/java/org/logstash/config/ir/imperative/NoopStatement.java b/logstash-core/src/main/java/org/logstash/config/ir/imperative/NoopStatement.java index b8290214e..10f2eef6a 100644 --- a/logstash-core/src/main/java/org/logstash/config/ir/imperative/NoopStatement.java +++ b/logstash-core/src/main/java/org/logstash/config/ir/imperative/NoopStatement.java @@ -1,3 +1,23 @@ +/* + * 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. + */ + + package org.logstash.config.ir.imperative; import org.logstash.config.ir.SourceComponent; diff --git a/logstash-core/src/main/java/org/logstash/config/ir/imperative/PluginStatement.java b/logstash-core/src/main/java/org/logstash/config/ir/imperative/PluginStatement.java index 934ab536d..9eef4d651 100644 --- a/logstash-core/src/main/java/org/logstash/config/ir/imperative/PluginStatement.java +++ b/logstash-core/src/main/java/org/logstash/config/ir/imperative/PluginStatement.java @@ -1,3 +1,23 @@ +/* + * 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. + */ + + package org.logstash.config.ir.imperative; import org.logstash.config.ir.SourceComponent; diff --git a/logstash-core/src/main/java/org/logstash/config/ir/imperative/Statement.java b/logstash-core/src/main/java/org/logstash/config/ir/imperative/Statement.java index 3152a0eb9..56a5f51ae 100644 --- a/logstash-core/src/main/java/org/logstash/config/ir/imperative/Statement.java +++ b/logstash-core/src/main/java/org/logstash/config/ir/imperative/Statement.java @@ -1,3 +1,23 @@ +/* + * 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. + */ + + package org.logstash.config.ir.imperative; import org.logstash.config.ir.InvalidIRException; diff --git a/logstash-core/src/main/java/org/logstash/execution/AbstractPipelineExt.java b/logstash-core/src/main/java/org/logstash/execution/AbstractPipelineExt.java index 6d8b21339..376f967e9 100644 --- a/logstash-core/src/main/java/org/logstash/execution/AbstractPipelineExt.java +++ b/logstash-core/src/main/java/org/logstash/execution/AbstractPipelineExt.java @@ -1,3 +1,23 @@ +/* + * 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. + */ + + package org.logstash.execution; import java.io.IOException; diff --git a/logstash-core/src/main/java/org/logstash/execution/AbstractWrappedQueueExt.java b/logstash-core/src/main/java/org/logstash/execution/AbstractWrappedQueueExt.java index d5ea0e700..0a16fb896 100644 --- a/logstash-core/src/main/java/org/logstash/execution/AbstractWrappedQueueExt.java +++ b/logstash-core/src/main/java/org/logstash/execution/AbstractWrappedQueueExt.java @@ -1,3 +1,23 @@ +/* + * 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. + */ + + package org.logstash.execution; import org.jruby.Ruby; diff --git a/logstash-core/src/main/java/org/logstash/execution/ConvergeResultExt.java b/logstash-core/src/main/java/org/logstash/execution/ConvergeResultExt.java index 1e715984c..4d912a0f3 100644 --- a/logstash-core/src/main/java/org/logstash/execution/ConvergeResultExt.java +++ b/logstash-core/src/main/java/org/logstash/execution/ConvergeResultExt.java @@ -1,3 +1,23 @@ +/* + * 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. + */ + + package org.logstash.execution; import org.jruby.*; diff --git a/logstash-core/src/main/java/org/logstash/execution/EventDispatcherExt.java b/logstash-core/src/main/java/org/logstash/execution/EventDispatcherExt.java index 04ca5721d..507015e87 100644 --- a/logstash-core/src/main/java/org/logstash/execution/EventDispatcherExt.java +++ b/logstash-core/src/main/java/org/logstash/execution/EventDispatcherExt.java @@ -1,3 +1,23 @@ +/* + * 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. + */ + + package org.logstash.execution; import java.util.Collection; diff --git a/logstash-core/src/main/java/org/logstash/execution/ExecutionContextExt.java b/logstash-core/src/main/java/org/logstash/execution/ExecutionContextExt.java index 4bef02b28..e99cd52aa 100644 --- a/logstash-core/src/main/java/org/logstash/execution/ExecutionContextExt.java +++ b/logstash-core/src/main/java/org/logstash/execution/ExecutionContextExt.java @@ -1,3 +1,23 @@ +/* + * 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. + */ + + package org.logstash.execution; import org.jruby.Ruby; diff --git a/logstash-core/src/main/java/org/logstash/execution/JavaBasePipelineExt.java b/logstash-core/src/main/java/org/logstash/execution/JavaBasePipelineExt.java index 16e576dd0..75a78ad70 100644 --- a/logstash-core/src/main/java/org/logstash/execution/JavaBasePipelineExt.java +++ b/logstash-core/src/main/java/org/logstash/execution/JavaBasePipelineExt.java @@ -1,3 +1,23 @@ +/* + * 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. + */ + + package org.logstash.execution; import org.apache.logging.log4j.LogManager; diff --git a/logstash-core/src/main/java/org/logstash/execution/MemoryReadBatch.java b/logstash-core/src/main/java/org/logstash/execution/MemoryReadBatch.java index 814bca75a..7764fd4af 100644 --- a/logstash-core/src/main/java/org/logstash/execution/MemoryReadBatch.java +++ b/logstash-core/src/main/java/org/logstash/execution/MemoryReadBatch.java @@ -1,3 +1,23 @@ +/* + * 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. + */ + + package org.logstash.execution; import org.jruby.RubyArray; diff --git a/logstash-core/src/main/java/org/logstash/execution/PeriodicFlush.java b/logstash-core/src/main/java/org/logstash/execution/PeriodicFlush.java index f8ad489f1..329f51013 100644 --- a/logstash-core/src/main/java/org/logstash/execution/PeriodicFlush.java +++ b/logstash-core/src/main/java/org/logstash/execution/PeriodicFlush.java @@ -1,3 +1,23 @@ +/* + * 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. + */ + + package org.logstash.execution; import java.util.concurrent.Executors; diff --git a/logstash-core/src/main/java/org/logstash/execution/PipelineReporterExt.java b/logstash-core/src/main/java/org/logstash/execution/PipelineReporterExt.java index 677b19bda..46e4f6720 100644 --- a/logstash-core/src/main/java/org/logstash/execution/PipelineReporterExt.java +++ b/logstash-core/src/main/java/org/logstash/execution/PipelineReporterExt.java @@ -1,3 +1,23 @@ +/* + * 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. + */ + + package org.logstash.execution; import org.jruby.Ruby; diff --git a/logstash-core/src/main/java/org/logstash/execution/QueueBatch.java b/logstash-core/src/main/java/org/logstash/execution/QueueBatch.java index c2c68f57d..1ae819029 100644 --- a/logstash-core/src/main/java/org/logstash/execution/QueueBatch.java +++ b/logstash-core/src/main/java/org/logstash/execution/QueueBatch.java @@ -1,3 +1,23 @@ +/* + * 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. + */ + + package org.logstash.execution; import org.jruby.RubyArray; diff --git a/logstash-core/src/main/java/org/logstash/execution/QueueReadClient.java b/logstash-core/src/main/java/org/logstash/execution/QueueReadClient.java index d1f0d45d7..ac78034eb 100644 --- a/logstash-core/src/main/java/org/logstash/execution/QueueReadClient.java +++ b/logstash-core/src/main/java/org/logstash/execution/QueueReadClient.java @@ -1,3 +1,23 @@ +/* + * 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. + */ + + package org.logstash.execution; import java.io.IOException; diff --git a/logstash-core/src/main/java/org/logstash/execution/QueueReadClientBase.java b/logstash-core/src/main/java/org/logstash/execution/QueueReadClientBase.java index 6b51d125d..d4eb6a05f 100644 --- a/logstash-core/src/main/java/org/logstash/execution/QueueReadClientBase.java +++ b/logstash-core/src/main/java/org/logstash/execution/QueueReadClientBase.java @@ -1,3 +1,23 @@ +/* + * 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. + */ + + package org.logstash.execution; import org.jruby.Ruby; diff --git a/logstash-core/src/main/java/org/logstash/execution/ShutdownWatcherExt.java b/logstash-core/src/main/java/org/logstash/execution/ShutdownWatcherExt.java index 0682215ed..adbafc4aa 100644 --- a/logstash-core/src/main/java/org/logstash/execution/ShutdownWatcherExt.java +++ b/logstash-core/src/main/java/org/logstash/execution/ShutdownWatcherExt.java @@ -1,3 +1,23 @@ +/* + * 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. + */ + + package org.logstash.execution; import java.util.ArrayList; diff --git a/logstash-core/src/main/java/org/logstash/execution/WorkerLoop.java b/logstash-core/src/main/java/org/logstash/execution/WorkerLoop.java index cda677e38..5c1266e3a 100644 --- a/logstash-core/src/main/java/org/logstash/execution/WorkerLoop.java +++ b/logstash-core/src/main/java/org/logstash/execution/WorkerLoop.java @@ -1,3 +1,23 @@ +/* + * 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. + */ + + package org.logstash.execution; import java.util.concurrent.atomic.AtomicBoolean; diff --git a/logstash-core/src/main/java/org/logstash/execution/queue/LegacyMemoryQueueWriter.java b/logstash-core/src/main/java/org/logstash/execution/queue/LegacyMemoryQueueWriter.java index f17cd118c..15f3a7b1e 100644 --- a/logstash-core/src/main/java/org/logstash/execution/queue/LegacyMemoryQueueWriter.java +++ b/logstash-core/src/main/java/org/logstash/execution/queue/LegacyMemoryQueueWriter.java @@ -1,3 +1,23 @@ +/* + * 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. + */ + + package org.logstash.execution.queue; import java.util.Map; diff --git a/logstash-core/src/main/java/org/logstash/execution/queue/QueueWriter.java b/logstash-core/src/main/java/org/logstash/execution/queue/QueueWriter.java index 854cb1e49..5e9f95818 100644 --- a/logstash-core/src/main/java/org/logstash/execution/queue/QueueWriter.java +++ b/logstash-core/src/main/java/org/logstash/execution/queue/QueueWriter.java @@ -1,3 +1,23 @@ +/* + * 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. + */ + + package org.logstash.execution.queue; import java.util.Map; diff --git a/logstash-core/src/main/java/org/logstash/ext/JRubyAbstractQueueWriteClientExt.java b/logstash-core/src/main/java/org/logstash/ext/JRubyAbstractQueueWriteClientExt.java index f36266227..b0f65d1ce 100644 --- a/logstash-core/src/main/java/org/logstash/ext/JRubyAbstractQueueWriteClientExt.java +++ b/logstash-core/src/main/java/org/logstash/ext/JRubyAbstractQueueWriteClientExt.java @@ -1,3 +1,23 @@ +/* + * 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. + */ + + package org.logstash.ext; import java.util.Collection; diff --git a/logstash-core/src/main/java/org/logstash/ext/JRubyLogstashErrorsExt.java b/logstash-core/src/main/java/org/logstash/ext/JRubyLogstashErrorsExt.java index dc63b6d34..fea90adaf 100644 --- a/logstash-core/src/main/java/org/logstash/ext/JRubyLogstashErrorsExt.java +++ b/logstash-core/src/main/java/org/logstash/ext/JRubyLogstashErrorsExt.java @@ -1,3 +1,23 @@ +/* + * 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. + */ + + package org.logstash.ext; import org.jruby.Ruby; diff --git a/logstash-core/src/main/java/org/logstash/ext/JRubyWrappedWriteClientExt.java b/logstash-core/src/main/java/org/logstash/ext/JRubyWrappedWriteClientExt.java index 8b2c3ad56..af336ad4a 100644 --- a/logstash-core/src/main/java/org/logstash/ext/JRubyWrappedWriteClientExt.java +++ b/logstash-core/src/main/java/org/logstash/ext/JRubyWrappedWriteClientExt.java @@ -1,3 +1,23 @@ +/* + * 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. + */ + + package org.logstash.ext; import java.util.Collection; diff --git a/logstash-core/src/main/java/org/logstash/ext/JrubyAckedReadClientExt.java b/logstash-core/src/main/java/org/logstash/ext/JrubyAckedReadClientExt.java index 0edc14da8..3ddec0bcb 100644 --- a/logstash-core/src/main/java/org/logstash/ext/JrubyAckedReadClientExt.java +++ b/logstash-core/src/main/java/org/logstash/ext/JrubyAckedReadClientExt.java @@ -1,3 +1,23 @@ +/* + * 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. + */ + + package org.logstash.ext; import org.jruby.Ruby; diff --git a/logstash-core/src/main/java/org/logstash/ext/JrubyAckedWriteClientExt.java b/logstash-core/src/main/java/org/logstash/ext/JrubyAckedWriteClientExt.java index 0012d189c..7103fc809 100644 --- a/logstash-core/src/main/java/org/logstash/ext/JrubyAckedWriteClientExt.java +++ b/logstash-core/src/main/java/org/logstash/ext/JrubyAckedWriteClientExt.java @@ -1,3 +1,23 @@ +/* + * 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. + */ + + package org.logstash.ext; import java.io.IOException; diff --git a/logstash-core/src/main/java/org/logstash/ext/JrubyEventExtLibrary.java b/logstash-core/src/main/java/org/logstash/ext/JrubyEventExtLibrary.java index dcd1b6b0e..515ce55c4 100644 --- a/logstash-core/src/main/java/org/logstash/ext/JrubyEventExtLibrary.java +++ b/logstash-core/src/main/java/org/logstash/ext/JrubyEventExtLibrary.java @@ -1,3 +1,23 @@ +/* + * 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. + */ + + package org.logstash.ext; import java.io.IOException; diff --git a/logstash-core/src/main/java/org/logstash/ext/JrubyMemoryReadClientExt.java b/logstash-core/src/main/java/org/logstash/ext/JrubyMemoryReadClientExt.java index 60bd9c1d8..9d7df1699 100644 --- a/logstash-core/src/main/java/org/logstash/ext/JrubyMemoryReadClientExt.java +++ b/logstash-core/src/main/java/org/logstash/ext/JrubyMemoryReadClientExt.java @@ -1,3 +1,23 @@ +/* + * 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. + */ + + package org.logstash.ext; import java.util.concurrent.BlockingQueue; diff --git a/logstash-core/src/main/java/org/logstash/ext/JrubyMemoryWriteClientExt.java b/logstash-core/src/main/java/org/logstash/ext/JrubyMemoryWriteClientExt.java index 32728219c..30d686ef9 100644 --- a/logstash-core/src/main/java/org/logstash/ext/JrubyMemoryWriteClientExt.java +++ b/logstash-core/src/main/java/org/logstash/ext/JrubyMemoryWriteClientExt.java @@ -1,3 +1,23 @@ +/* + * 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. + */ + + package org.logstash.ext; import java.util.Collection; diff --git a/logstash-core/src/main/java/org/logstash/ext/JrubyTimestampExtLibrary.java b/logstash-core/src/main/java/org/logstash/ext/JrubyTimestampExtLibrary.java index 0d357a0bb..6557746ea 100644 --- a/logstash-core/src/main/java/org/logstash/ext/JrubyTimestampExtLibrary.java +++ b/logstash-core/src/main/java/org/logstash/ext/JrubyTimestampExtLibrary.java @@ -1,3 +1,23 @@ +/* + * 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. + */ + + package org.logstash.ext; import com.fasterxml.jackson.databind.annotation.JsonSerialize; diff --git a/logstash-core/src/main/java/org/logstash/ext/JrubyWrappedSynchronousQueueExt.java b/logstash-core/src/main/java/org/logstash/ext/JrubyWrappedSynchronousQueueExt.java index 57c031d50..4962dffc6 100644 --- a/logstash-core/src/main/java/org/logstash/ext/JrubyWrappedSynchronousQueueExt.java +++ b/logstash-core/src/main/java/org/logstash/ext/JrubyWrappedSynchronousQueueExt.java @@ -1,3 +1,23 @@ +/* + * 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. + */ + + package org.logstash.ext; import java.util.concurrent.ArrayBlockingQueue; diff --git a/logstash-core/src/main/java/org/logstash/instrument/metrics/AbstractMetric.java b/logstash-core/src/main/java/org/logstash/instrument/metrics/AbstractMetric.java index 775b18ab4..8a3fe881d 100644 --- a/logstash-core/src/main/java/org/logstash/instrument/metrics/AbstractMetric.java +++ b/logstash-core/src/main/java/org/logstash/instrument/metrics/AbstractMetric.java @@ -1,3 +1,23 @@ +/* + * 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. + */ + + package org.logstash.instrument.metrics; diff --git a/logstash-core/src/main/java/org/logstash/instrument/metrics/AbstractMetricExt.java b/logstash-core/src/main/java/org/logstash/instrument/metrics/AbstractMetricExt.java index 2d5fe178d..ed4650a84 100644 --- a/logstash-core/src/main/java/org/logstash/instrument/metrics/AbstractMetricExt.java +++ b/logstash-core/src/main/java/org/logstash/instrument/metrics/AbstractMetricExt.java @@ -1,3 +1,23 @@ +/* + * 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. + */ + + package org.logstash.instrument.metrics; import org.jruby.Ruby; diff --git a/logstash-core/src/main/java/org/logstash/instrument/metrics/AbstractNamespacedMetricExt.java b/logstash-core/src/main/java/org/logstash/instrument/metrics/AbstractNamespacedMetricExt.java index 5d1051e82..df559b849 100644 --- a/logstash-core/src/main/java/org/logstash/instrument/metrics/AbstractNamespacedMetricExt.java +++ b/logstash-core/src/main/java/org/logstash/instrument/metrics/AbstractNamespacedMetricExt.java @@ -1,3 +1,23 @@ +/* + * 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. + */ + + package org.logstash.instrument.metrics; import org.jruby.Ruby; diff --git a/logstash-core/src/main/java/org/logstash/instrument/metrics/AbstractSimpleMetricExt.java b/logstash-core/src/main/java/org/logstash/instrument/metrics/AbstractSimpleMetricExt.java index 663f780a1..3df3a7558 100644 --- a/logstash-core/src/main/java/org/logstash/instrument/metrics/AbstractSimpleMetricExt.java +++ b/logstash-core/src/main/java/org/logstash/instrument/metrics/AbstractSimpleMetricExt.java @@ -1,3 +1,23 @@ +/* + * 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. + */ + + package org.logstash.instrument.metrics; import org.jruby.Ruby; diff --git a/logstash-core/src/main/java/org/logstash/instrument/metrics/Metric.java b/logstash-core/src/main/java/org/logstash/instrument/metrics/Metric.java index d51c015dc..d41e6acf1 100644 --- a/logstash-core/src/main/java/org/logstash/instrument/metrics/Metric.java +++ b/logstash-core/src/main/java/org/logstash/instrument/metrics/Metric.java @@ -1,3 +1,23 @@ +/* + * 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. + */ + + package org.logstash.instrument.metrics; /** diff --git a/logstash-core/src/main/java/org/logstash/instrument/metrics/MetricExt.java b/logstash-core/src/main/java/org/logstash/instrument/metrics/MetricExt.java index 9f28c1260..25d15239b 100644 --- a/logstash-core/src/main/java/org/logstash/instrument/metrics/MetricExt.java +++ b/logstash-core/src/main/java/org/logstash/instrument/metrics/MetricExt.java @@ -1,3 +1,23 @@ +/* + * 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. + */ + + package org.logstash.instrument.metrics; import java.util.concurrent.TimeUnit; diff --git a/logstash-core/src/main/java/org/logstash/instrument/metrics/MetricKeys.java b/logstash-core/src/main/java/org/logstash/instrument/metrics/MetricKeys.java index 501d94255..eb7b6fcc1 100644 --- a/logstash-core/src/main/java/org/logstash/instrument/metrics/MetricKeys.java +++ b/logstash-core/src/main/java/org/logstash/instrument/metrics/MetricKeys.java @@ -1,3 +1,23 @@ +/* + * 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. + */ + + package org.logstash.instrument.metrics; import org.jruby.RubySymbol; diff --git a/logstash-core/src/main/java/org/logstash/instrument/metrics/MetricType.java b/logstash-core/src/main/java/org/logstash/instrument/metrics/MetricType.java index 6a3e86cdc..b6fcf2c6b 100644 --- a/logstash-core/src/main/java/org/logstash/instrument/metrics/MetricType.java +++ b/logstash-core/src/main/java/org/logstash/instrument/metrics/MetricType.java @@ -1,3 +1,23 @@ +/* + * 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. + */ + + package org.logstash.instrument.metrics; diff --git a/logstash-core/src/main/java/org/logstash/instrument/metrics/NamespacedMetricExt.java b/logstash-core/src/main/java/org/logstash/instrument/metrics/NamespacedMetricExt.java index 6e2a00b36..66c24a93a 100644 --- a/logstash-core/src/main/java/org/logstash/instrument/metrics/NamespacedMetricExt.java +++ b/logstash-core/src/main/java/org/logstash/instrument/metrics/NamespacedMetricExt.java @@ -1,3 +1,23 @@ +/* + * 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. + */ + + package org.logstash.instrument.metrics; import org.jruby.Ruby; diff --git a/logstash-core/src/main/java/org/logstash/instrument/metrics/NullMetricExt.java b/logstash-core/src/main/java/org/logstash/instrument/metrics/NullMetricExt.java index 5a6c680f9..22f13a366 100644 --- a/logstash-core/src/main/java/org/logstash/instrument/metrics/NullMetricExt.java +++ b/logstash-core/src/main/java/org/logstash/instrument/metrics/NullMetricExt.java @@ -1,3 +1,23 @@ +/* + * 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. + */ + + package org.logstash.instrument.metrics; import org.jruby.Ruby; diff --git a/logstash-core/src/main/java/org/logstash/instrument/metrics/NullNamespacedMetricExt.java b/logstash-core/src/main/java/org/logstash/instrument/metrics/NullNamespacedMetricExt.java index 5f8ecb033..e6ecbe21d 100644 --- a/logstash-core/src/main/java/org/logstash/instrument/metrics/NullNamespacedMetricExt.java +++ b/logstash-core/src/main/java/org/logstash/instrument/metrics/NullNamespacedMetricExt.java @@ -1,3 +1,23 @@ +/* + * 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. + */ + + package org.logstash.instrument.metrics; import org.jruby.Ruby; diff --git a/logstash-core/src/main/java/org/logstash/instrument/metrics/SnapshotExt.java b/logstash-core/src/main/java/org/logstash/instrument/metrics/SnapshotExt.java index 187ae2339..72d6af6dc 100644 --- a/logstash-core/src/main/java/org/logstash/instrument/metrics/SnapshotExt.java +++ b/logstash-core/src/main/java/org/logstash/instrument/metrics/SnapshotExt.java @@ -1,3 +1,23 @@ +/* + * 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. + */ + + package org.logstash.instrument.metrics; import org.jruby.Ruby; diff --git a/logstash-core/src/main/java/org/logstash/instrument/metrics/counter/CounterMetric.java b/logstash-core/src/main/java/org/logstash/instrument/metrics/counter/CounterMetric.java index 1e0bc4a6d..ec792bb31 100644 --- a/logstash-core/src/main/java/org/logstash/instrument/metrics/counter/CounterMetric.java +++ b/logstash-core/src/main/java/org/logstash/instrument/metrics/counter/CounterMetric.java @@ -1,3 +1,23 @@ +/* + * 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. + */ + + package org.logstash.instrument.metrics.counter; import org.logstash.instrument.metrics.Metric; diff --git a/logstash-core/src/main/java/org/logstash/instrument/metrics/counter/LongCounter.java b/logstash-core/src/main/java/org/logstash/instrument/metrics/counter/LongCounter.java index 76814b768..49f4eb980 100644 --- a/logstash-core/src/main/java/org/logstash/instrument/metrics/counter/LongCounter.java +++ b/logstash-core/src/main/java/org/logstash/instrument/metrics/counter/LongCounter.java @@ -1,3 +1,23 @@ +/* + * 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. + */ + + package org.logstash.instrument.metrics.counter; import java.util.concurrent.atomic.LongAdder; diff --git a/logstash-core/src/main/java/org/logstash/instrument/metrics/gauge/AbstractGaugeMetric.java b/logstash-core/src/main/java/org/logstash/instrument/metrics/gauge/AbstractGaugeMetric.java index 3c37e9ae7..7a5280a6a 100644 --- a/logstash-core/src/main/java/org/logstash/instrument/metrics/gauge/AbstractGaugeMetric.java +++ b/logstash-core/src/main/java/org/logstash/instrument/metrics/gauge/AbstractGaugeMetric.java @@ -1,3 +1,23 @@ +/* + * 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. + */ + + package org.logstash.instrument.metrics.gauge; import org.logstash.instrument.metrics.AbstractMetric; diff --git a/logstash-core/src/main/java/org/logstash/instrument/metrics/gauge/BooleanGauge.java b/logstash-core/src/main/java/org/logstash/instrument/metrics/gauge/BooleanGauge.java index dc17ab205..bbf399dd4 100644 --- a/logstash-core/src/main/java/org/logstash/instrument/metrics/gauge/BooleanGauge.java +++ b/logstash-core/src/main/java/org/logstash/instrument/metrics/gauge/BooleanGauge.java @@ -1,3 +1,23 @@ +/* + * 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. + */ + + package org.logstash.instrument.metrics.gauge; import org.logstash.instrument.metrics.MetricType; diff --git a/logstash-core/src/main/java/org/logstash/instrument/metrics/gauge/GaugeMetric.java b/logstash-core/src/main/java/org/logstash/instrument/metrics/gauge/GaugeMetric.java index 2d7d39db9..d58c03416 100644 --- a/logstash-core/src/main/java/org/logstash/instrument/metrics/gauge/GaugeMetric.java +++ b/logstash-core/src/main/java/org/logstash/instrument/metrics/gauge/GaugeMetric.java @@ -1,3 +1,23 @@ +/* + * 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. + */ + + package org.logstash.instrument.metrics.gauge; diff --git a/logstash-core/src/main/java/org/logstash/instrument/metrics/gauge/LazyDelegatingGauge.java b/logstash-core/src/main/java/org/logstash/instrument/metrics/gauge/LazyDelegatingGauge.java index 843d2f5c1..bb4b736aa 100644 --- a/logstash-core/src/main/java/org/logstash/instrument/metrics/gauge/LazyDelegatingGauge.java +++ b/logstash-core/src/main/java/org/logstash/instrument/metrics/gauge/LazyDelegatingGauge.java @@ -1,3 +1,23 @@ +/* + * 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. + */ + + package org.logstash.instrument.metrics.gauge; import org.apache.logging.log4j.LogManager; diff --git a/logstash-core/src/main/java/org/logstash/instrument/metrics/gauge/NumberGauge.java b/logstash-core/src/main/java/org/logstash/instrument/metrics/gauge/NumberGauge.java index 143947f20..d5d455415 100644 --- a/logstash-core/src/main/java/org/logstash/instrument/metrics/gauge/NumberGauge.java +++ b/logstash-core/src/main/java/org/logstash/instrument/metrics/gauge/NumberGauge.java @@ -1,3 +1,23 @@ +/* + * 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. + */ + + package org.logstash.instrument.metrics.gauge; import org.logstash.instrument.metrics.MetricType; diff --git a/logstash-core/src/main/java/org/logstash/instrument/metrics/gauge/RubyHashGauge.java b/logstash-core/src/main/java/org/logstash/instrument/metrics/gauge/RubyHashGauge.java index a93260c0a..3c7e94637 100644 --- a/logstash-core/src/main/java/org/logstash/instrument/metrics/gauge/RubyHashGauge.java +++ b/logstash-core/src/main/java/org/logstash/instrument/metrics/gauge/RubyHashGauge.java @@ -1,3 +1,23 @@ +/* + * 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. + */ + + package org.logstash.instrument.metrics.gauge; import org.jruby.RubyHash; diff --git a/logstash-core/src/main/java/org/logstash/instrument/metrics/gauge/RubyTimeStampGauge.java b/logstash-core/src/main/java/org/logstash/instrument/metrics/gauge/RubyTimeStampGauge.java index 1a7ed83b8..c6cd0d3ee 100644 --- a/logstash-core/src/main/java/org/logstash/instrument/metrics/gauge/RubyTimeStampGauge.java +++ b/logstash-core/src/main/java/org/logstash/instrument/metrics/gauge/RubyTimeStampGauge.java @@ -1,3 +1,23 @@ +/* + * 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. + */ + + package org.logstash.instrument.metrics.gauge; import org.logstash.Timestamp; diff --git a/logstash-core/src/main/java/org/logstash/instrument/metrics/gauge/TextGauge.java b/logstash-core/src/main/java/org/logstash/instrument/metrics/gauge/TextGauge.java index 5fcfc7578..c1086f178 100644 --- a/logstash-core/src/main/java/org/logstash/instrument/metrics/gauge/TextGauge.java +++ b/logstash-core/src/main/java/org/logstash/instrument/metrics/gauge/TextGauge.java @@ -1,3 +1,23 @@ +/* + * 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. + */ + + package org.logstash.instrument.metrics.gauge; diff --git a/logstash-core/src/main/java/org/logstash/instrument/metrics/gauge/UnknownGauge.java b/logstash-core/src/main/java/org/logstash/instrument/metrics/gauge/UnknownGauge.java index 2f5f980c9..3b4a70627 100644 --- a/logstash-core/src/main/java/org/logstash/instrument/metrics/gauge/UnknownGauge.java +++ b/logstash-core/src/main/java/org/logstash/instrument/metrics/gauge/UnknownGauge.java @@ -1,3 +1,23 @@ +/* + * 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. + */ + + package org.logstash.instrument.metrics.gauge; import org.logstash.instrument.metrics.MetricType; diff --git a/logstash-core/src/main/java/org/logstash/instrument/monitors/HotThreadsMonitor.java b/logstash-core/src/main/java/org/logstash/instrument/monitors/HotThreadsMonitor.java index 3856ce3a6..0406d3195 100644 --- a/logstash-core/src/main/java/org/logstash/instrument/monitors/HotThreadsMonitor.java +++ b/logstash-core/src/main/java/org/logstash/instrument/monitors/HotThreadsMonitor.java @@ -1,3 +1,23 @@ +/* + * 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. + */ + + package org.logstash.instrument.monitors; import java.lang.management.ManagementFactory; diff --git a/logstash-core/src/main/java/org/logstash/instrument/monitors/MemoryMonitor.java b/logstash-core/src/main/java/org/logstash/instrument/monitors/MemoryMonitor.java index d44e56f8f..6629c6e6a 100644 --- a/logstash-core/src/main/java/org/logstash/instrument/monitors/MemoryMonitor.java +++ b/logstash-core/src/main/java/org/logstash/instrument/monitors/MemoryMonitor.java @@ -1,3 +1,23 @@ +/* + * 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. + */ + + package org.logstash.instrument.monitors; import java.lang.management.ManagementFactory; diff --git a/logstash-core/src/main/java/org/logstash/instrument/monitors/ProcessMonitor.java b/logstash-core/src/main/java/org/logstash/instrument/monitors/ProcessMonitor.java index e7de05f46..c63db2af4 100644 --- a/logstash-core/src/main/java/org/logstash/instrument/monitors/ProcessMonitor.java +++ b/logstash-core/src/main/java/org/logstash/instrument/monitors/ProcessMonitor.java @@ -1,3 +1,23 @@ +/* + * 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. + */ + + package org.logstash.instrument.monitors; import com.sun.management.UnixOperatingSystemMXBean; diff --git a/logstash-core/src/main/java/org/logstash/instrument/monitors/SystemMonitor.java b/logstash-core/src/main/java/org/logstash/instrument/monitors/SystemMonitor.java index 209e94de7..65f9ebac2 100644 --- a/logstash-core/src/main/java/org/logstash/instrument/monitors/SystemMonitor.java +++ b/logstash-core/src/main/java/org/logstash/instrument/monitors/SystemMonitor.java @@ -1,3 +1,23 @@ +/* + * 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. + */ + + package org.logstash.instrument.monitors; import java.lang.management.ManagementFactory; diff --git a/logstash-core/src/main/java/org/logstash/instrument/reports/MemoryReport.java b/logstash-core/src/main/java/org/logstash/instrument/reports/MemoryReport.java index fc267693c..83713a4d7 100644 --- a/logstash-core/src/main/java/org/logstash/instrument/reports/MemoryReport.java +++ b/logstash-core/src/main/java/org/logstash/instrument/reports/MemoryReport.java @@ -1,3 +1,23 @@ +/* + * 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. + */ + + package org.logstash.instrument.reports; import org.logstash.instrument.monitors.MemoryMonitor; @@ -28,4 +48,3 @@ public class MemoryReport { return MemoryMonitor.detect(type); } } - diff --git a/logstash-core/src/main/java/org/logstash/instrument/reports/ProcessReport.java b/logstash-core/src/main/java/org/logstash/instrument/reports/ProcessReport.java index 5b747adb0..9ea2917e9 100644 --- a/logstash-core/src/main/java/org/logstash/instrument/reports/ProcessReport.java +++ b/logstash-core/src/main/java/org/logstash/instrument/reports/ProcessReport.java @@ -1,3 +1,23 @@ +/* + * 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. + */ + + package org.logstash.instrument.reports; import org.logstash.instrument.monitors.ProcessMonitor; diff --git a/logstash-core/src/main/java/org/logstash/instrument/reports/ThreadsReport.java b/logstash-core/src/main/java/org/logstash/instrument/reports/ThreadsReport.java index b76222707..b570440fe 100644 --- a/logstash-core/src/main/java/org/logstash/instrument/reports/ThreadsReport.java +++ b/logstash-core/src/main/java/org/logstash/instrument/reports/ThreadsReport.java @@ -1,3 +1,23 @@ +/* + * 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. + */ + + package org.logstash.instrument.reports; import org.logstash.instrument.monitors.HotThreadsMonitor; @@ -39,4 +59,3 @@ public class ThreadsReport { return generate(options); } } - diff --git a/logstash-core/src/main/java/org/logstash/log/CustomLogEvent.java b/logstash-core/src/main/java/org/logstash/log/CustomLogEvent.java index 01a444542..bc6d0b10f 100644 --- a/logstash-core/src/main/java/org/logstash/log/CustomLogEvent.java +++ b/logstash-core/src/main/java/org/logstash/log/CustomLogEvent.java @@ -1,3 +1,23 @@ +/* + * 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. + */ + + /* * Licensed to Elasticsearch under one or more contributor * license agreements. See the NOTICE file distributed with diff --git a/logstash-core/src/main/java/org/logstash/log/CustomLogEventSerializer.java b/logstash-core/src/main/java/org/logstash/log/CustomLogEventSerializer.java index 6432394d9..a31d3c753 100644 --- a/logstash-core/src/main/java/org/logstash/log/CustomLogEventSerializer.java +++ b/logstash-core/src/main/java/org/logstash/log/CustomLogEventSerializer.java @@ -1,3 +1,23 @@ +/* + * 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. + */ + + package org.logstash.log; import com.fasterxml.jackson.core.JsonGenerator; diff --git a/logstash-core/src/main/java/org/logstash/log/DefaultDeprecationLogger.java b/logstash-core/src/main/java/org/logstash/log/DefaultDeprecationLogger.java index e0c018912..9564316a0 100644 --- a/logstash-core/src/main/java/org/logstash/log/DefaultDeprecationLogger.java +++ b/logstash-core/src/main/java/org/logstash/log/DefaultDeprecationLogger.java @@ -1,3 +1,23 @@ +/* + * 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. + */ + + package org.logstash.log; import co.elastic.logstash.api.DeprecationLogger; diff --git a/logstash-core/src/main/java/org/logstash/log/DeprecationLoggerExt.java b/logstash-core/src/main/java/org/logstash/log/DeprecationLoggerExt.java index 003df1ce4..a410e506a 100644 --- a/logstash-core/src/main/java/org/logstash/log/DeprecationLoggerExt.java +++ b/logstash-core/src/main/java/org/logstash/log/DeprecationLoggerExt.java @@ -1,3 +1,23 @@ +/* + * 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. + */ + + package org.logstash.log; import co.elastic.logstash.api.DeprecationLogger; diff --git a/logstash-core/src/main/java/org/logstash/log/LoggableExt.java b/logstash-core/src/main/java/org/logstash/log/LoggableExt.java index 20998599e..e5e119941 100644 --- a/logstash-core/src/main/java/org/logstash/log/LoggableExt.java +++ b/logstash-core/src/main/java/org/logstash/log/LoggableExt.java @@ -1,3 +1,23 @@ +/* + * 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. + */ + + package org.logstash.log; import org.jruby.RubyClass; diff --git a/logstash-core/src/main/java/org/logstash/log/LoggerExt.java b/logstash-core/src/main/java/org/logstash/log/LoggerExt.java index 6beeeca5d..946416b23 100644 --- a/logstash-core/src/main/java/org/logstash/log/LoggerExt.java +++ b/logstash-core/src/main/java/org/logstash/log/LoggerExt.java @@ -1,3 +1,23 @@ +/* + * 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. + */ + + package org.logstash.log; import org.apache.logging.log4j.Level; diff --git a/logstash-core/src/main/java/org/logstash/log/LogstashConfigurationFactory.java b/logstash-core/src/main/java/org/logstash/log/LogstashConfigurationFactory.java index 024c64e39..5fc50e328 100644 --- a/logstash-core/src/main/java/org/logstash/log/LogstashConfigurationFactory.java +++ b/logstash-core/src/main/java/org/logstash/log/LogstashConfigurationFactory.java @@ -1,3 +1,23 @@ +/* + * 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. + */ + + package org.logstash.log; import org.apache.logging.log4j.core.LoggerContext; diff --git a/logstash-core/src/main/java/org/logstash/log/LogstashLogEventFactory.java b/logstash-core/src/main/java/org/logstash/log/LogstashLogEventFactory.java index f13c264dd..6b253c9f9 100644 --- a/logstash-core/src/main/java/org/logstash/log/LogstashLogEventFactory.java +++ b/logstash-core/src/main/java/org/logstash/log/LogstashLogEventFactory.java @@ -1,3 +1,23 @@ +/* + * 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. + */ + + package org.logstash.log; import org.apache.logging.log4j.Level; diff --git a/logstash-core/src/main/java/org/logstash/log/LogstashLoggerContextFactory.java b/logstash-core/src/main/java/org/logstash/log/LogstashLoggerContextFactory.java index b232d5f31..f703c9165 100644 --- a/logstash-core/src/main/java/org/logstash/log/LogstashLoggerContextFactory.java +++ b/logstash-core/src/main/java/org/logstash/log/LogstashLoggerContextFactory.java @@ -1,3 +1,23 @@ +/* + * 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. + */ + + package org.logstash.log; import org.apache.logging.log4j.LogManager; diff --git a/logstash-core/src/main/java/org/logstash/log/LogstashMessageFactory.java b/logstash-core/src/main/java/org/logstash/log/LogstashMessageFactory.java index 7cadbbf03..609de6b4a 100644 --- a/logstash-core/src/main/java/org/logstash/log/LogstashMessageFactory.java +++ b/logstash-core/src/main/java/org/logstash/log/LogstashMessageFactory.java @@ -1,3 +1,23 @@ +/* + * 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. + */ + + package org.logstash.log; import org.apache.logging.log4j.message.Message; diff --git a/logstash-core/src/main/java/org/logstash/log/SlowLoggerExt.java b/logstash-core/src/main/java/org/logstash/log/SlowLoggerExt.java index 96b5a5223..8635d62f5 100644 --- a/logstash-core/src/main/java/org/logstash/log/SlowLoggerExt.java +++ b/logstash-core/src/main/java/org/logstash/log/SlowLoggerExt.java @@ -1,3 +1,23 @@ +/* + * 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. + */ + + package org.logstash.log; import org.apache.logging.log4j.LogManager; diff --git a/logstash-core/src/main/java/org/logstash/log/StructuredMessage.java b/logstash-core/src/main/java/org/logstash/log/StructuredMessage.java index ee6fa1bf3..44b6d3895 100644 --- a/logstash-core/src/main/java/org/logstash/log/StructuredMessage.java +++ b/logstash-core/src/main/java/org/logstash/log/StructuredMessage.java @@ -1,3 +1,23 @@ +/* + * 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. + */ + + package org.logstash.log; import com.fasterxml.jackson.databind.annotation.JsonSerialize; diff --git a/logstash-core/src/main/java/org/logstash/plugins/ConfigVariableExpander.java b/logstash-core/src/main/java/org/logstash/plugins/ConfigVariableExpander.java index c664717a4..3dd4d86d0 100644 --- a/logstash-core/src/main/java/org/logstash/plugins/ConfigVariableExpander.java +++ b/logstash-core/src/main/java/org/logstash/plugins/ConfigVariableExpander.java @@ -1,3 +1,23 @@ +/* + * 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. + */ + + package org.logstash.plugins; import org.logstash.common.EnvironmentVariableProvider; diff --git a/logstash-core/src/main/java/org/logstash/plugins/ConfigurationImpl.java b/logstash-core/src/main/java/org/logstash/plugins/ConfigurationImpl.java index 57e95302c..caf1a4d89 100644 --- a/logstash-core/src/main/java/org/logstash/plugins/ConfigurationImpl.java +++ b/logstash-core/src/main/java/org/logstash/plugins/ConfigurationImpl.java @@ -1,3 +1,23 @@ +/* + * 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. + */ + + package org.logstash.plugins; import co.elastic.logstash.api.Configuration; diff --git a/logstash-core/src/main/java/org/logstash/plugins/ContextImpl.java b/logstash-core/src/main/java/org/logstash/plugins/ContextImpl.java index a1b5be8ce..0fcbdc032 100644 --- a/logstash-core/src/main/java/org/logstash/plugins/ContextImpl.java +++ b/logstash-core/src/main/java/org/logstash/plugins/ContextImpl.java @@ -1,3 +1,23 @@ +/* + * 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. + */ + + package org.logstash.plugins; import co.elastic.logstash.api.*; diff --git a/logstash-core/src/main/java/org/logstash/plugins/CounterMetricImpl.java b/logstash-core/src/main/java/org/logstash/plugins/CounterMetricImpl.java index 095eb0264..87226ee17 100644 --- a/logstash-core/src/main/java/org/logstash/plugins/CounterMetricImpl.java +++ b/logstash-core/src/main/java/org/logstash/plugins/CounterMetricImpl.java @@ -1,3 +1,23 @@ +/* + * 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. + */ + + package org.logstash.plugins; import co.elastic.logstash.api.CounterMetric; diff --git a/logstash-core/src/main/java/org/logstash/plugins/HooksRegistryExt.java b/logstash-core/src/main/java/org/logstash/plugins/HooksRegistryExt.java index e3d2555d9..d2534ba06 100644 --- a/logstash-core/src/main/java/org/logstash/plugins/HooksRegistryExt.java +++ b/logstash-core/src/main/java/org/logstash/plugins/HooksRegistryExt.java @@ -1,3 +1,23 @@ +/* + * 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. + */ + + package org.logstash.plugins; import org.jruby.Ruby; diff --git a/logstash-core/src/main/java/org/logstash/plugins/NamespacedMetricImpl.java b/logstash-core/src/main/java/org/logstash/plugins/NamespacedMetricImpl.java index 912412b8a..5322bc80d 100644 --- a/logstash-core/src/main/java/org/logstash/plugins/NamespacedMetricImpl.java +++ b/logstash-core/src/main/java/org/logstash/plugins/NamespacedMetricImpl.java @@ -1,3 +1,23 @@ +/* + * 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. + */ + + package org.logstash.plugins; import co.elastic.logstash.api.CounterMetric; diff --git a/logstash-core/src/main/java/org/logstash/plugins/PluginClassLoader.java b/logstash-core/src/main/java/org/logstash/plugins/PluginClassLoader.java index f728f0876..25be0bce1 100644 --- a/logstash-core/src/main/java/org/logstash/plugins/PluginClassLoader.java +++ b/logstash-core/src/main/java/org/logstash/plugins/PluginClassLoader.java @@ -1,3 +1,23 @@ +/* + * 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. + */ + + package org.logstash.plugins; import java.io.File; diff --git a/logstash-core/src/main/java/org/logstash/plugins/PluginFactoryExt.java b/logstash-core/src/main/java/org/logstash/plugins/PluginFactoryExt.java index 0e487e616..fabe2150b 100644 --- a/logstash-core/src/main/java/org/logstash/plugins/PluginFactoryExt.java +++ b/logstash-core/src/main/java/org/logstash/plugins/PluginFactoryExt.java @@ -1,3 +1,23 @@ +/* + * 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. + */ + + package org.logstash.plugins; import co.elastic.logstash.api.Codec; diff --git a/logstash-core/src/main/java/org/logstash/plugins/PluginLookup.java b/logstash-core/src/main/java/org/logstash/plugins/PluginLookup.java index eaaba0fce..2b09e49b0 100644 --- a/logstash-core/src/main/java/org/logstash/plugins/PluginLookup.java +++ b/logstash-core/src/main/java/org/logstash/plugins/PluginLookup.java @@ -1,3 +1,23 @@ +/* + * 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. + */ + + package org.logstash.plugins; import co.elastic.logstash.api.Codec; diff --git a/logstash-core/src/main/java/org/logstash/plugins/PluginUtil.java b/logstash-core/src/main/java/org/logstash/plugins/PluginUtil.java index 23e450f85..7fa78650a 100644 --- a/logstash-core/src/main/java/org/logstash/plugins/PluginUtil.java +++ b/logstash-core/src/main/java/org/logstash/plugins/PluginUtil.java @@ -1,3 +1,23 @@ +/* + * 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. + */ + + package org.logstash.plugins; import co.elastic.logstash.api.Configuration; diff --git a/logstash-core/src/main/java/org/logstash/plugins/PluginValidator.java b/logstash-core/src/main/java/org/logstash/plugins/PluginValidator.java index 5011169a3..458d21fbf 100644 --- a/logstash-core/src/main/java/org/logstash/plugins/PluginValidator.java +++ b/logstash-core/src/main/java/org/logstash/plugins/PluginValidator.java @@ -1,3 +1,23 @@ +/* + * 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. + */ + + package org.logstash.plugins; import co.elastic.logstash.api.Codec; diff --git a/logstash-core/src/main/java/org/logstash/plugins/RootMetricImpl.java b/logstash-core/src/main/java/org/logstash/plugins/RootMetricImpl.java index da7b4271f..c4ea07f6f 100644 --- a/logstash-core/src/main/java/org/logstash/plugins/RootMetricImpl.java +++ b/logstash-core/src/main/java/org/logstash/plugins/RootMetricImpl.java @@ -1,3 +1,23 @@ +/* + * 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. + */ + + package org.logstash.plugins; import co.elastic.logstash.api.Metric; diff --git a/logstash-core/src/main/java/org/logstash/plugins/UniversalPluginExt.java b/logstash-core/src/main/java/org/logstash/plugins/UniversalPluginExt.java index a481ecfd1..cb00788a5 100644 --- a/logstash-core/src/main/java/org/logstash/plugins/UniversalPluginExt.java +++ b/logstash-core/src/main/java/org/logstash/plugins/UniversalPluginExt.java @@ -1,3 +1,23 @@ +/* + * 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. + */ + + package org.logstash.plugins; import org.jruby.Ruby; diff --git a/logstash-core/src/main/java/org/logstash/plugins/codecs/Dots.java b/logstash-core/src/main/java/org/logstash/plugins/codecs/Dots.java index 8430d9496..307944409 100644 --- a/logstash-core/src/main/java/org/logstash/plugins/codecs/Dots.java +++ b/logstash-core/src/main/java/org/logstash/plugins/codecs/Dots.java @@ -1,3 +1,23 @@ +/* + * 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. + */ + + package org.logstash.plugins.codecs; import co.elastic.logstash.api.Codec; diff --git a/logstash-core/src/main/java/org/logstash/plugins/codecs/Line.java b/logstash-core/src/main/java/org/logstash/plugins/codecs/Line.java index 5d52b2f09..d62981aaa 100644 --- a/logstash-core/src/main/java/org/logstash/plugins/codecs/Line.java +++ b/logstash-core/src/main/java/org/logstash/plugins/codecs/Line.java @@ -1,3 +1,23 @@ +/* + * 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. + */ + + package org.logstash.plugins.codecs; import co.elastic.logstash.api.Codec; diff --git a/logstash-core/src/main/java/org/logstash/plugins/codecs/Plain.java b/logstash-core/src/main/java/org/logstash/plugins/codecs/Plain.java index ef2108c62..026aba044 100644 --- a/logstash-core/src/main/java/org/logstash/plugins/codecs/Plain.java +++ b/logstash-core/src/main/java/org/logstash/plugins/codecs/Plain.java @@ -1,3 +1,23 @@ +/* + * 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. + */ + + package org.logstash.plugins.codecs; import co.elastic.logstash.api.Codec; diff --git a/logstash-core/src/main/java/org/logstash/plugins/discovery/PluginRegistry.java b/logstash-core/src/main/java/org/logstash/plugins/discovery/PluginRegistry.java index f779a317f..7b77283f1 100644 --- a/logstash-core/src/main/java/org/logstash/plugins/discovery/PluginRegistry.java +++ b/logstash-core/src/main/java/org/logstash/plugins/discovery/PluginRegistry.java @@ -1,3 +1,23 @@ +/* + * 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. + */ + + package org.logstash.plugins.discovery; import org.logstash.plugins.PluginLookup; diff --git a/logstash-core/src/main/java/org/logstash/plugins/filters/Uuid.java b/logstash-core/src/main/java/org/logstash/plugins/filters/Uuid.java index 2c8a23735..05e72823e 100644 --- a/logstash-core/src/main/java/org/logstash/plugins/filters/Uuid.java +++ b/logstash-core/src/main/java/org/logstash/plugins/filters/Uuid.java @@ -1,3 +1,23 @@ +/* + * 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. + */ + + package org.logstash.plugins.filters; import co.elastic.logstash.api.Configuration; diff --git a/logstash-core/src/main/java/org/logstash/plugins/inputs/Generator.java b/logstash-core/src/main/java/org/logstash/plugins/inputs/Generator.java index 25cd596d7..bd1949c8e 100644 --- a/logstash-core/src/main/java/org/logstash/plugins/inputs/Generator.java +++ b/logstash-core/src/main/java/org/logstash/plugins/inputs/Generator.java @@ -1,3 +1,23 @@ +/* + * 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. + */ + + package org.logstash.plugins.inputs; import co.elastic.logstash.api.Configuration; diff --git a/logstash-core/src/main/java/org/logstash/plugins/inputs/Stdin.java b/logstash-core/src/main/java/org/logstash/plugins/inputs/Stdin.java index 01af92072..6fd455156 100644 --- a/logstash-core/src/main/java/org/logstash/plugins/inputs/Stdin.java +++ b/logstash-core/src/main/java/org/logstash/plugins/inputs/Stdin.java @@ -1,3 +1,23 @@ +/* + * 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. + */ + + package org.logstash.plugins.inputs; import co.elastic.logstash.api.Codec; diff --git a/logstash-core/src/main/java/org/logstash/plugins/outputs/Sink.java b/logstash-core/src/main/java/org/logstash/plugins/outputs/Sink.java index 86fc67981..3a756abac 100644 --- a/logstash-core/src/main/java/org/logstash/plugins/outputs/Sink.java +++ b/logstash-core/src/main/java/org/logstash/plugins/outputs/Sink.java @@ -1,3 +1,23 @@ +/* + * 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. + */ + + package org.logstash.plugins.outputs; import co.elastic.logstash.api.Configuration; diff --git a/logstash-core/src/main/java/org/logstash/plugins/outputs/Stdout.java b/logstash-core/src/main/java/org/logstash/plugins/outputs/Stdout.java index 07e70ad99..f112f138f 100644 --- a/logstash-core/src/main/java/org/logstash/plugins/outputs/Stdout.java +++ b/logstash-core/src/main/java/org/logstash/plugins/outputs/Stdout.java @@ -1,3 +1,23 @@ +/* + * 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. + */ + + package org.logstash.plugins.outputs; import co.elastic.logstash.api.Codec; diff --git a/logstash-core/src/main/java/org/logstash/plugins/pipeline/AddressState.java b/logstash-core/src/main/java/org/logstash/plugins/pipeline/AddressState.java index 48d05c889..205282f9a 100644 --- a/logstash-core/src/main/java/org/logstash/plugins/pipeline/AddressState.java +++ b/logstash-core/src/main/java/org/logstash/plugins/pipeline/AddressState.java @@ -1,3 +1,23 @@ +/* + * 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. + */ + + package org.logstash.plugins.pipeline; import java.util.Set; diff --git a/logstash-core/src/main/java/org/logstash/plugins/pipeline/PipelineBus.java b/logstash-core/src/main/java/org/logstash/plugins/pipeline/PipelineBus.java index bae5b6f8c..906defd8e 100644 --- a/logstash-core/src/main/java/org/logstash/plugins/pipeline/PipelineBus.java +++ b/logstash-core/src/main/java/org/logstash/plugins/pipeline/PipelineBus.java @@ -1,3 +1,23 @@ +/* + * 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. + */ + + package org.logstash.plugins.pipeline; import com.google.common.annotations.VisibleForTesting; diff --git a/logstash-core/src/main/java/org/logstash/plugins/pipeline/PipelineInput.java b/logstash-core/src/main/java/org/logstash/plugins/pipeline/PipelineInput.java index 204958a8e..f29a24faa 100644 --- a/logstash-core/src/main/java/org/logstash/plugins/pipeline/PipelineInput.java +++ b/logstash-core/src/main/java/org/logstash/plugins/pipeline/PipelineInput.java @@ -1,3 +1,23 @@ +/* + * 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. + */ + + package org.logstash.plugins.pipeline; import org.logstash.ext.JrubyEventExtLibrary; diff --git a/logstash-core/src/main/java/org/logstash/plugins/pipeline/PipelineOutput.java b/logstash-core/src/main/java/org/logstash/plugins/pipeline/PipelineOutput.java index 0a110f379..a9247201c 100644 --- a/logstash-core/src/main/java/org/logstash/plugins/pipeline/PipelineOutput.java +++ b/logstash-core/src/main/java/org/logstash/plugins/pipeline/PipelineOutput.java @@ -1,3 +1,23 @@ +/* + * 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. + */ + + package org.logstash.plugins.pipeline; public interface PipelineOutput { diff --git a/logstash-core/src/main/java/org/logstash/secret/SecretIdentifier.java b/logstash-core/src/main/java/org/logstash/secret/SecretIdentifier.java index 8bf77141f..08f43abb1 100644 --- a/logstash-core/src/main/java/org/logstash/secret/SecretIdentifier.java +++ b/logstash-core/src/main/java/org/logstash/secret/SecretIdentifier.java @@ -1,3 +1,23 @@ +/* + * 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. + */ + + package org.logstash.secret; import java.util.Locale; diff --git a/logstash-core/src/main/java/org/logstash/secret/cli/SecretStoreCli.java b/logstash-core/src/main/java/org/logstash/secret/cli/SecretStoreCli.java index 143da1227..5967b7083 100644 --- a/logstash-core/src/main/java/org/logstash/secret/cli/SecretStoreCli.java +++ b/logstash-core/src/main/java/org/logstash/secret/cli/SecretStoreCli.java @@ -1,3 +1,23 @@ +/* + * 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. + */ + + package org.logstash.secret.cli; import org.logstash.secret.SecretIdentifier; diff --git a/logstash-core/src/main/java/org/logstash/secret/cli/Terminal.java b/logstash-core/src/main/java/org/logstash/secret/cli/Terminal.java index 6009ea17c..ff0b12b0a 100644 --- a/logstash-core/src/main/java/org/logstash/secret/cli/Terminal.java +++ b/logstash-core/src/main/java/org/logstash/secret/cli/Terminal.java @@ -1,3 +1,23 @@ +/* + * 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. + */ + + package org.logstash.secret.cli; import java.util.Scanner; diff --git a/logstash-core/src/main/java/org/logstash/secret/store/SecretStore.java b/logstash-core/src/main/java/org/logstash/secret/store/SecretStore.java index 44e3a1e72..27b9af906 100644 --- a/logstash-core/src/main/java/org/logstash/secret/store/SecretStore.java +++ b/logstash-core/src/main/java/org/logstash/secret/store/SecretStore.java @@ -1,3 +1,23 @@ +/* + * 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. + */ + + package org.logstash.secret.store; diff --git a/logstash-core/src/main/java/org/logstash/secret/store/SecretStoreException.java b/logstash-core/src/main/java/org/logstash/secret/store/SecretStoreException.java index b7270e2dd..ac1b3dc2c 100644 --- a/logstash-core/src/main/java/org/logstash/secret/store/SecretStoreException.java +++ b/logstash-core/src/main/java/org/logstash/secret/store/SecretStoreException.java @@ -1,3 +1,23 @@ +/* + * 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. + */ + + package org.logstash.secret.store; import org.logstash.secret.SecretIdentifier; diff --git a/logstash-core/src/main/java/org/logstash/secret/store/SecretStoreExt.java b/logstash-core/src/main/java/org/logstash/secret/store/SecretStoreExt.java index 827e5205a..1fa782f42 100644 --- a/logstash-core/src/main/java/org/logstash/secret/store/SecretStoreExt.java +++ b/logstash-core/src/main/java/org/logstash/secret/store/SecretStoreExt.java @@ -1,3 +1,23 @@ +/* + * 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. + */ + + package org.logstash.secret.store; import org.jruby.RubyHash; diff --git a/logstash-core/src/main/java/org/logstash/secret/store/SecretStoreFactory.java b/logstash-core/src/main/java/org/logstash/secret/store/SecretStoreFactory.java index 097ad6dec..5a5956ae9 100644 --- a/logstash-core/src/main/java/org/logstash/secret/store/SecretStoreFactory.java +++ b/logstash-core/src/main/java/org/logstash/secret/store/SecretStoreFactory.java @@ -1,3 +1,23 @@ +/* + * 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. + */ + + package org.logstash.secret.store; import org.apache.logging.log4j.LogManager; diff --git a/logstash-core/src/main/java/org/logstash/secret/store/SecretStoreUtil.java b/logstash-core/src/main/java/org/logstash/secret/store/SecretStoreUtil.java index 85639af0a..2a40da360 100644 --- a/logstash-core/src/main/java/org/logstash/secret/store/SecretStoreUtil.java +++ b/logstash-core/src/main/java/org/logstash/secret/store/SecretStoreUtil.java @@ -1,3 +1,23 @@ +/* + * 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. + */ + + package org.logstash.secret.store; import java.nio.ByteBuffer; diff --git a/logstash-core/src/main/java/org/logstash/secret/store/SecureConfig.java b/logstash-core/src/main/java/org/logstash/secret/store/SecureConfig.java index 07b70e90a..9d63cf89d 100644 --- a/logstash-core/src/main/java/org/logstash/secret/store/SecureConfig.java +++ b/logstash-core/src/main/java/org/logstash/secret/store/SecureConfig.java @@ -1,3 +1,23 @@ +/* + * 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. + */ + + package org.logstash.secret.store; import java.nio.CharBuffer; diff --git a/logstash-core/src/main/java/org/logstash/secret/store/backend/JavaKeyStore.java b/logstash-core/src/main/java/org/logstash/secret/store/backend/JavaKeyStore.java index b0424ff58..ab40eed61 100644 --- a/logstash-core/src/main/java/org/logstash/secret/store/backend/JavaKeyStore.java +++ b/logstash-core/src/main/java/org/logstash/secret/store/backend/JavaKeyStore.java @@ -1,3 +1,23 @@ +/* + * 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. + */ + + package org.logstash.secret.store.backend; import org.apache.logging.log4j.LogManager; @@ -408,4 +428,3 @@ public final class JavaKeyStore implements SecretStore { return !(chars == null || chars.length == 0); } } - diff --git a/logstash-core/src/main/java/org/logstash/util/UtilExt.java b/logstash-core/src/main/java/org/logstash/util/UtilExt.java index 57bf0a310..6e85dd20f 100644 --- a/logstash-core/src/main/java/org/logstash/util/UtilExt.java +++ b/logstash-core/src/main/java/org/logstash/util/UtilExt.java @@ -1,3 +1,23 @@ +/* + * 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. + */ + + package org.logstash.util; import org.jruby.RubyThread; diff --git a/logstash-core/src/test/java/org/logstash/AccessorsTest.java b/logstash-core/src/test/java/org/logstash/AccessorsTest.java index 34751a0b8..e731ba276 100644 --- a/logstash-core/src/test/java/org/logstash/AccessorsTest.java +++ b/logstash-core/src/test/java/org/logstash/AccessorsTest.java @@ -1,3 +1,23 @@ +/* + * 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. + */ + + package org.logstash; import java.io.Serializable; diff --git a/logstash-core/src/test/java/org/logstash/ClonerTest.java b/logstash-core/src/test/java/org/logstash/ClonerTest.java index 3db559182..0522b3567 100644 --- a/logstash-core/src/test/java/org/logstash/ClonerTest.java +++ b/logstash-core/src/test/java/org/logstash/ClonerTest.java @@ -1,3 +1,23 @@ +/* + * 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. + */ + + package org.logstash; import org.jruby.RubyString; diff --git a/logstash-core/src/test/java/org/logstash/ConvertedMapTest.java b/logstash-core/src/test/java/org/logstash/ConvertedMapTest.java index e9da6c394..14224ab12 100644 --- a/logstash-core/src/test/java/org/logstash/ConvertedMapTest.java +++ b/logstash-core/src/test/java/org/logstash/ConvertedMapTest.java @@ -1,3 +1,23 @@ +/* + * 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. + */ + + package org.logstash; import static org.junit.Assert.*; diff --git a/logstash-core/src/test/java/org/logstash/DLQEntryTest.java b/logstash-core/src/test/java/org/logstash/DLQEntryTest.java index f56dec1d7..f1d250f32 100644 --- a/logstash-core/src/test/java/org/logstash/DLQEntryTest.java +++ b/logstash-core/src/test/java/org/logstash/DLQEntryTest.java @@ -1,3 +1,23 @@ +/* + * 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. + */ + + /* * Licensed to Elasticsearch under one or more contributor * license agreements. See the NOTICE file distributed with diff --git a/logstash-core/src/test/java/org/logstash/EventTest.java b/logstash-core/src/test/java/org/logstash/EventTest.java index d974a31ec..5b9d34f7f 100644 --- a/logstash-core/src/test/java/org/logstash/EventTest.java +++ b/logstash-core/src/test/java/org/logstash/EventTest.java @@ -1,3 +1,23 @@ +/* + * 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. + */ + + package org.logstash; import java.io.IOException; diff --git a/logstash-core/src/test/java/org/logstash/FieldReferenceTest.java b/logstash-core/src/test/java/org/logstash/FieldReferenceTest.java index 687bb6f8e..9dc151270 100644 --- a/logstash-core/src/test/java/org/logstash/FieldReferenceTest.java +++ b/logstash-core/src/test/java/org/logstash/FieldReferenceTest.java @@ -1,3 +1,23 @@ +/* + * 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. + */ + + package org.logstash; import java.lang.reflect.Field; diff --git a/logstash-core/src/test/java/org/logstash/FileLockFactoryMain.java b/logstash-core/src/test/java/org/logstash/FileLockFactoryMain.java index 84aa5bc2e..97b3307a1 100644 --- a/logstash-core/src/test/java/org/logstash/FileLockFactoryMain.java +++ b/logstash-core/src/test/java/org/logstash/FileLockFactoryMain.java @@ -1,3 +1,23 @@ +/* + * 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. + */ + + package org.logstash; import java.io.IOException; diff --git a/logstash-core/src/test/java/org/logstash/FileLockFactoryTest.java b/logstash-core/src/test/java/org/logstash/FileLockFactoryTest.java index bf7e88a6e..a29276fd4 100644 --- a/logstash-core/src/test/java/org/logstash/FileLockFactoryTest.java +++ b/logstash-core/src/test/java/org/logstash/FileLockFactoryTest.java @@ -1,3 +1,23 @@ +/* + * 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. + */ + + package org.logstash; import java.nio.file.Path; diff --git a/logstash-core/src/test/java/org/logstash/JavafierTest.java b/logstash-core/src/test/java/org/logstash/JavafierTest.java index d93ee6b51..b33ae9ed3 100644 --- a/logstash-core/src/test/java/org/logstash/JavafierTest.java +++ b/logstash-core/src/test/java/org/logstash/JavafierTest.java @@ -1,3 +1,23 @@ +/* + * 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. + */ + + package org.logstash; import org.jruby.RubyBignum; diff --git a/logstash-core/src/test/java/org/logstash/KeyNodeTest.java b/logstash-core/src/test/java/org/logstash/KeyNodeTest.java index df9a0243c..c4b1a00e6 100644 --- a/logstash-core/src/test/java/org/logstash/KeyNodeTest.java +++ b/logstash-core/src/test/java/org/logstash/KeyNodeTest.java @@ -1,3 +1,23 @@ +/* + * 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. + */ + + package org.logstash; import org.junit.Test; diff --git a/logstash-core/src/test/java/org/logstash/RSpecTests.java b/logstash-core/src/test/java/org/logstash/RSpecTests.java index 835483651..eb728b132 100644 --- a/logstash-core/src/test/java/org/logstash/RSpecTests.java +++ b/logstash-core/src/test/java/org/logstash/RSpecTests.java @@ -1,3 +1,23 @@ +/* + * 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. + */ + + package org.logstash; import java.nio.charset.StandardCharsets; diff --git a/logstash-core/src/test/java/org/logstash/RubyfierTest.java b/logstash-core/src/test/java/org/logstash/RubyfierTest.java index 589b17dd0..43f8c4b1f 100644 --- a/logstash-core/src/test/java/org/logstash/RubyfierTest.java +++ b/logstash-core/src/test/java/org/logstash/RubyfierTest.java @@ -1,3 +1,23 @@ +/* + * 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. + */ + + package org.logstash; import org.jruby.RubyArray; diff --git a/logstash-core/src/test/java/org/logstash/StringInterpolationTest.java b/logstash-core/src/test/java/org/logstash/StringInterpolationTest.java index 1371a4952..536110c60 100644 --- a/logstash-core/src/test/java/org/logstash/StringInterpolationTest.java +++ b/logstash-core/src/test/java/org/logstash/StringInterpolationTest.java @@ -1,3 +1,23 @@ +/* + * 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. + */ + + package org.logstash; diff --git a/logstash-core/src/test/java/org/logstash/TimestampTest.java b/logstash-core/src/test/java/org/logstash/TimestampTest.java index 58959ab7f..2cf5889b8 100644 --- a/logstash-core/src/test/java/org/logstash/TimestampTest.java +++ b/logstash-core/src/test/java/org/logstash/TimestampTest.java @@ -1,3 +1,23 @@ +/* + * 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. + */ + + package org.logstash; import org.joda.time.DateTime; diff --git a/logstash-core/src/test/java/org/logstash/ValuefierTest.java b/logstash-core/src/test/java/org/logstash/ValuefierTest.java index 0e8838743..58982bca2 100644 --- a/logstash-core/src/test/java/org/logstash/ValuefierTest.java +++ b/logstash-core/src/test/java/org/logstash/ValuefierTest.java @@ -1,3 +1,23 @@ +/* + * 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. + */ + + package org.logstash; import java.util.ArrayList; diff --git a/logstash-core/src/test/java/org/logstash/ackedqueue/CheckpointTest.java b/logstash-core/src/test/java/org/logstash/ackedqueue/CheckpointTest.java index 83d1ac5aa..428f4ccef 100644 --- a/logstash-core/src/test/java/org/logstash/ackedqueue/CheckpointTest.java +++ b/logstash-core/src/test/java/org/logstash/ackedqueue/CheckpointTest.java @@ -1,3 +1,23 @@ +/* + * 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. + */ + + package org.logstash.ackedqueue; import org.junit.Test; diff --git a/logstash-core/src/test/java/org/logstash/ackedqueue/HeadPageTest.java b/logstash-core/src/test/java/org/logstash/ackedqueue/HeadPageTest.java index 30fb5b69b..810ad7f03 100644 --- a/logstash-core/src/test/java/org/logstash/ackedqueue/HeadPageTest.java +++ b/logstash-core/src/test/java/org/logstash/ackedqueue/HeadPageTest.java @@ -1,3 +1,23 @@ +/* + * 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. + */ + + package org.logstash.ackedqueue; import java.io.IOException; diff --git a/logstash-core/src/test/java/org/logstash/ackedqueue/PqRepairTest.java b/logstash-core/src/test/java/org/logstash/ackedqueue/PqRepairTest.java index 3d62f2f58..63272952e 100644 --- a/logstash-core/src/test/java/org/logstash/ackedqueue/PqRepairTest.java +++ b/logstash-core/src/test/java/org/logstash/ackedqueue/PqRepairTest.java @@ -1,3 +1,23 @@ +/* + * 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. + */ + + package org.logstash.ackedqueue; import java.io.IOException; diff --git a/logstash-core/src/test/java/org/logstash/ackedqueue/QueueTest.java b/logstash-core/src/test/java/org/logstash/ackedqueue/QueueTest.java index e0d44199a..8c7e0ed0f 100644 --- a/logstash-core/src/test/java/org/logstash/ackedqueue/QueueTest.java +++ b/logstash-core/src/test/java/org/logstash/ackedqueue/QueueTest.java @@ -1,3 +1,23 @@ +/* + * 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. + */ + + package org.logstash.ackedqueue; import java.io.FileOutputStream; diff --git a/logstash-core/src/test/java/org/logstash/ackedqueue/QueueTestHelpers.java b/logstash-core/src/test/java/org/logstash/ackedqueue/QueueTestHelpers.java index 1eded8f4e..b01680516 100644 --- a/logstash-core/src/test/java/org/logstash/ackedqueue/QueueTestHelpers.java +++ b/logstash-core/src/test/java/org/logstash/ackedqueue/QueueTestHelpers.java @@ -1,3 +1,23 @@ +/* + * 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. + */ + + package org.logstash.ackedqueue; import java.io.IOException; diff --git a/logstash-core/src/test/java/org/logstash/ackedqueue/StringElement.java b/logstash-core/src/test/java/org/logstash/ackedqueue/StringElement.java index 99092a908..d825b6837 100644 --- a/logstash-core/src/test/java/org/logstash/ackedqueue/StringElement.java +++ b/logstash-core/src/test/java/org/logstash/ackedqueue/StringElement.java @@ -1,3 +1,23 @@ +/* + * 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. + */ + + package org.logstash.ackedqueue; import java.nio.ByteBuffer; diff --git a/logstash-core/src/test/java/org/logstash/ackedqueue/TestSettings.java b/logstash-core/src/test/java/org/logstash/ackedqueue/TestSettings.java index c2fde02f7..bd7a8112e 100644 --- a/logstash-core/src/test/java/org/logstash/ackedqueue/TestSettings.java +++ b/logstash-core/src/test/java/org/logstash/ackedqueue/TestSettings.java @@ -1,3 +1,23 @@ +/* + * 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. + */ + + package org.logstash.ackedqueue; public class TestSettings { diff --git a/logstash-core/src/test/java/org/logstash/ackedqueue/io/FileCheckpointIOTest.java b/logstash-core/src/test/java/org/logstash/ackedqueue/io/FileCheckpointIOTest.java index 7ff54ef20..2ec024e55 100644 --- a/logstash-core/src/test/java/org/logstash/ackedqueue/io/FileCheckpointIOTest.java +++ b/logstash-core/src/test/java/org/logstash/ackedqueue/io/FileCheckpointIOTest.java @@ -1,3 +1,23 @@ +/* + * 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. + */ + + package org.logstash.ackedqueue.io; import org.junit.Before; diff --git a/logstash-core/src/test/java/org/logstash/ackedqueue/io/FileMmapIOTest.java b/logstash-core/src/test/java/org/logstash/ackedqueue/io/FileMmapIOTest.java index adf930ae7..e29e25a80 100644 --- a/logstash-core/src/test/java/org/logstash/ackedqueue/io/FileMmapIOTest.java +++ b/logstash-core/src/test/java/org/logstash/ackedqueue/io/FileMmapIOTest.java @@ -1,3 +1,23 @@ +/* + * 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. + */ + + package org.logstash.ackedqueue.io; import java.nio.file.Path; diff --git a/logstash-core/src/test/java/org/logstash/ackedqueue/io/IntVectorTest.java b/logstash-core/src/test/java/org/logstash/ackedqueue/io/IntVectorTest.java index 7bc9741d8..1db10e640 100644 --- a/logstash-core/src/test/java/org/logstash/ackedqueue/io/IntVectorTest.java +++ b/logstash-core/src/test/java/org/logstash/ackedqueue/io/IntVectorTest.java @@ -1,3 +1,23 @@ +/* + * 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. + */ + + package org.logstash.ackedqueue.io; import org.junit.Test; diff --git a/logstash-core/src/test/java/org/logstash/ackedqueue/io/LongVectorTest.java b/logstash-core/src/test/java/org/logstash/ackedqueue/io/LongVectorTest.java index 10c20ebcc..10a690be6 100644 --- a/logstash-core/src/test/java/org/logstash/ackedqueue/io/LongVectorTest.java +++ b/logstash-core/src/test/java/org/logstash/ackedqueue/io/LongVectorTest.java @@ -1,3 +1,23 @@ +/* + * 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. + */ + + package org.logstash.ackedqueue.io; import org.junit.Test; diff --git a/logstash-core/src/test/java/org/logstash/ackedqueue/io/MmapPageIOTest.java b/logstash-core/src/test/java/org/logstash/ackedqueue/io/MmapPageIOTest.java index 9a9266dc1..4ec2660d1 100644 --- a/logstash-core/src/test/java/org/logstash/ackedqueue/io/MmapPageIOTest.java +++ b/logstash-core/src/test/java/org/logstash/ackedqueue/io/MmapPageIOTest.java @@ -1,3 +1,23 @@ +/* + * 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. + */ + + package org.logstash.ackedqueue.io; import java.nio.file.Path; diff --git a/logstash-core/src/test/java/org/logstash/common/ConfigVariableExpanderTest.java b/logstash-core/src/test/java/org/logstash/common/ConfigVariableExpanderTest.java index d6b261373..31b8536f0 100644 --- a/logstash-core/src/test/java/org/logstash/common/ConfigVariableExpanderTest.java +++ b/logstash-core/src/test/java/org/logstash/common/ConfigVariableExpanderTest.java @@ -1,3 +1,23 @@ +/* + * 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. + */ + + package org.logstash.common; import org.junit.Assert; diff --git a/logstash-core/src/test/java/org/logstash/common/DeadLetterQueueFactoryTest.java b/logstash-core/src/test/java/org/logstash/common/DeadLetterQueueFactoryTest.java index bbd2f2490..9072b2de7 100644 --- a/logstash-core/src/test/java/org/logstash/common/DeadLetterQueueFactoryTest.java +++ b/logstash-core/src/test/java/org/logstash/common/DeadLetterQueueFactoryTest.java @@ -1,3 +1,23 @@ +/* + * 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. + */ + + /* * Licensed to Elasticsearch under one or more contributor * license agreements. See the NOTICE file distributed with diff --git a/logstash-core/src/test/java/org/logstash/common/FsUtilTest.java b/logstash-core/src/test/java/org/logstash/common/FsUtilTest.java index 013383837..39c0b2c85 100644 --- a/logstash-core/src/test/java/org/logstash/common/FsUtilTest.java +++ b/logstash-core/src/test/java/org/logstash/common/FsUtilTest.java @@ -1,3 +1,23 @@ +/* + * 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. + */ + + package org.logstash.common; import org.hamcrest.CoreMatchers; diff --git a/logstash-core/src/test/java/org/logstash/common/SourceWithMetadataTest.java b/logstash-core/src/test/java/org/logstash/common/SourceWithMetadataTest.java index ae87850cb..ee1b8c0bd 100644 --- a/logstash-core/src/test/java/org/logstash/common/SourceWithMetadataTest.java +++ b/logstash-core/src/test/java/org/logstash/common/SourceWithMetadataTest.java @@ -1,3 +1,23 @@ +/* + * 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. + */ + + package org.logstash.common; import org.junit.Test; diff --git a/logstash-core/src/test/java/org/logstash/common/io/DeadLetterQueueReaderTest.java b/logstash-core/src/test/java/org/logstash/common/io/DeadLetterQueueReaderTest.java index 55994aca1..2281e08d1 100644 --- a/logstash-core/src/test/java/org/logstash/common/io/DeadLetterQueueReaderTest.java +++ b/logstash-core/src/test/java/org/logstash/common/io/DeadLetterQueueReaderTest.java @@ -1,3 +1,23 @@ +/* + * 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. + */ + + /* * Licensed to Elasticsearch under one or more contributor * license agreements. See the NOTICE file distributed with diff --git a/logstash-core/src/test/java/org/logstash/common/io/DeadLetterQueueWriterTest.java b/logstash-core/src/test/java/org/logstash/common/io/DeadLetterQueueWriterTest.java index 61bd9a681..016919493 100644 --- a/logstash-core/src/test/java/org/logstash/common/io/DeadLetterQueueWriterTest.java +++ b/logstash-core/src/test/java/org/logstash/common/io/DeadLetterQueueWriterTest.java @@ -1,3 +1,23 @@ +/* + * 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. + */ + + /* * Licensed to Elasticsearch under one or more contributor * license agreements. See the NOTICE file distributed with diff --git a/logstash-core/src/test/java/org/logstash/common/io/RecordIOReaderTest.java b/logstash-core/src/test/java/org/logstash/common/io/RecordIOReaderTest.java index e8e46d50a..e8537c9f8 100644 --- a/logstash-core/src/test/java/org/logstash/common/io/RecordIOReaderTest.java +++ b/logstash-core/src/test/java/org/logstash/common/io/RecordIOReaderTest.java @@ -1,3 +1,23 @@ +/* + * 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. + */ + + package org.logstash.common.io; import org.junit.Before; diff --git a/logstash-core/src/test/java/org/logstash/common/io/RecordIOWriterTest.java b/logstash-core/src/test/java/org/logstash/common/io/RecordIOWriterTest.java index 2edb06893..9f2eeca65 100644 --- a/logstash-core/src/test/java/org/logstash/common/io/RecordIOWriterTest.java +++ b/logstash-core/src/test/java/org/logstash/common/io/RecordIOWriterTest.java @@ -1,3 +1,23 @@ +/* + * 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. + */ + + package org.logstash.common.io; import org.junit.Before; diff --git a/logstash-core/src/test/java/org/logstash/config/ir/CompiledPipelineTest.java b/logstash-core/src/test/java/org/logstash/config/ir/CompiledPipelineTest.java index 06af6f684..2764bd152 100644 --- a/logstash-core/src/test/java/org/logstash/config/ir/CompiledPipelineTest.java +++ b/logstash-core/src/test/java/org/logstash/config/ir/CompiledPipelineTest.java @@ -1,3 +1,23 @@ +/* + * 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. + */ + + package org.logstash.config.ir; import co.elastic.logstash.api.Codec; diff --git a/logstash-core/src/test/java/org/logstash/config/ir/ConfigCompilerTest.java b/logstash-core/src/test/java/org/logstash/config/ir/ConfigCompilerTest.java index aeae84e5c..e9f95ebd2 100644 --- a/logstash-core/src/test/java/org/logstash/config/ir/ConfigCompilerTest.java +++ b/logstash-core/src/test/java/org/logstash/config/ir/ConfigCompilerTest.java @@ -1,3 +1,23 @@ +/* + * 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. + */ + + package org.logstash.config.ir; import java.io.ByteArrayOutputStream; diff --git a/logstash-core/src/test/java/org/logstash/config/ir/EventConditionTest.java b/logstash-core/src/test/java/org/logstash/config/ir/EventConditionTest.java index 394fb0df9..4a56b5a98 100644 --- a/logstash-core/src/test/java/org/logstash/config/ir/EventConditionTest.java +++ b/logstash-core/src/test/java/org/logstash/config/ir/EventConditionTest.java @@ -1,3 +1,23 @@ +/* + * 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. + */ + + package org.logstash.config.ir; import org.jruby.RubyArray; diff --git a/logstash-core/src/test/java/org/logstash/config/ir/IRHelpers.java b/logstash-core/src/test/java/org/logstash/config/ir/IRHelpers.java index ec29b1a5f..0856d5eb1 100644 --- a/logstash-core/src/test/java/org/logstash/config/ir/IRHelpers.java +++ b/logstash-core/src/test/java/org/logstash/config/ir/IRHelpers.java @@ -1,3 +1,23 @@ +/* + * 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. + */ + + package org.logstash.config.ir; import org.hamcrest.MatcherAssert; diff --git a/logstash-core/src/test/java/org/logstash/config/ir/PipelineIRTest.java b/logstash-core/src/test/java/org/logstash/config/ir/PipelineIRTest.java index 653f4ccda..914a2fca0 100644 --- a/logstash-core/src/test/java/org/logstash/config/ir/PipelineIRTest.java +++ b/logstash-core/src/test/java/org/logstash/config/ir/PipelineIRTest.java @@ -1,3 +1,23 @@ +/* + * 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. + */ + + package org.logstash.config.ir; import org.junit.Test; diff --git a/logstash-core/src/test/java/org/logstash/config/ir/PipelineTestUtil.java b/logstash-core/src/test/java/org/logstash/config/ir/PipelineTestUtil.java index e5142ab1e..d647c8191 100644 --- a/logstash-core/src/test/java/org/logstash/config/ir/PipelineTestUtil.java +++ b/logstash-core/src/test/java/org/logstash/config/ir/PipelineTestUtil.java @@ -1,3 +1,23 @@ +/* + * 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. + */ + + package org.logstash.config.ir; import java.util.Collection; diff --git a/logstash-core/src/test/java/org/logstash/config/ir/PluginConfigNameMethodDouble.java b/logstash-core/src/test/java/org/logstash/config/ir/PluginConfigNameMethodDouble.java index 2e9b2590b..5bf4fb054 100644 --- a/logstash-core/src/test/java/org/logstash/config/ir/PluginConfigNameMethodDouble.java +++ b/logstash-core/src/test/java/org/logstash/config/ir/PluginConfigNameMethodDouble.java @@ -1,3 +1,23 @@ +/* + * 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. + */ + + package org.logstash.config.ir; import org.jruby.Ruby; diff --git a/logstash-core/src/test/java/org/logstash/config/ir/RubyEnvTestCase.java b/logstash-core/src/test/java/org/logstash/config/ir/RubyEnvTestCase.java index ed954bcc5..c29622d43 100644 --- a/logstash-core/src/test/java/org/logstash/config/ir/RubyEnvTestCase.java +++ b/logstash-core/src/test/java/org/logstash/config/ir/RubyEnvTestCase.java @@ -1,3 +1,23 @@ +/* + * 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. + */ + + package org.logstash.config.ir; import java.nio.file.Path; diff --git a/logstash-core/src/test/java/org/logstash/config/ir/compiler/CommonActionsTest.java b/logstash-core/src/test/java/org/logstash/config/ir/compiler/CommonActionsTest.java index 1b9fce899..e43234fac 100644 --- a/logstash-core/src/test/java/org/logstash/config/ir/compiler/CommonActionsTest.java +++ b/logstash-core/src/test/java/org/logstash/config/ir/compiler/CommonActionsTest.java @@ -1,3 +1,23 @@ +/* + * 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. + */ + + package org.logstash.config.ir.compiler; import org.junit.Assert; diff --git a/logstash-core/src/test/java/org/logstash/config/ir/compiler/DatasetCompilerTest.java b/logstash-core/src/test/java/org/logstash/config/ir/compiler/DatasetCompilerTest.java index 231245456..4881035a0 100644 --- a/logstash-core/src/test/java/org/logstash/config/ir/compiler/DatasetCompilerTest.java +++ b/logstash-core/src/test/java/org/logstash/config/ir/compiler/DatasetCompilerTest.java @@ -1,3 +1,23 @@ +/* + * 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. + */ + + package org.logstash.config.ir.compiler; import java.util.Collections; diff --git a/logstash-core/src/test/java/org/logstash/config/ir/compiler/FakeOutClass.java b/logstash-core/src/test/java/org/logstash/config/ir/compiler/FakeOutClass.java index 1d8e00f01..c076dc158 100644 --- a/logstash-core/src/test/java/org/logstash/config/ir/compiler/FakeOutClass.java +++ b/logstash-core/src/test/java/org/logstash/config/ir/compiler/FakeOutClass.java @@ -1,3 +1,23 @@ +/* + * 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. + */ + + package org.logstash.config.ir.compiler; import org.jruby.Ruby; diff --git a/logstash-core/src/test/java/org/logstash/config/ir/compiler/JavaCodecDelegatorTest.java b/logstash-core/src/test/java/org/logstash/config/ir/compiler/JavaCodecDelegatorTest.java index 7da86c699..4fb7d1770 100644 --- a/logstash-core/src/test/java/org/logstash/config/ir/compiler/JavaCodecDelegatorTest.java +++ b/logstash-core/src/test/java/org/logstash/config/ir/compiler/JavaCodecDelegatorTest.java @@ -1,3 +1,23 @@ +/* + * 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. + */ + + package org.logstash.config.ir.compiler; import co.elastic.logstash.api.Codec; diff --git a/logstash-core/src/test/java/org/logstash/config/ir/compiler/OutputDelegatorTest.java b/logstash-core/src/test/java/org/logstash/config/ir/compiler/OutputDelegatorTest.java index f2ecf3957..44d6b6159 100644 --- a/logstash-core/src/test/java/org/logstash/config/ir/compiler/OutputDelegatorTest.java +++ b/logstash-core/src/test/java/org/logstash/config/ir/compiler/OutputDelegatorTest.java @@ -1,3 +1,23 @@ +/* + * 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. + */ + + package org.logstash.config.ir.compiler; import javax.annotation.concurrent.NotThreadSafe; diff --git a/logstash-core/src/test/java/org/logstash/config/ir/compiler/PluginDelegatorTestCase.java b/logstash-core/src/test/java/org/logstash/config/ir/compiler/PluginDelegatorTestCase.java index d3d282ab6..0d2270f46 100644 --- a/logstash-core/src/test/java/org/logstash/config/ir/compiler/PluginDelegatorTestCase.java +++ b/logstash-core/src/test/java/org/logstash/config/ir/compiler/PluginDelegatorTestCase.java @@ -1,3 +1,23 @@ +/* + * 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. + */ + + package org.logstash.config.ir.compiler; import org.jruby.RubyArray; diff --git a/logstash-core/src/test/java/org/logstash/config/ir/compiler/PluginFactoryTest.java b/logstash-core/src/test/java/org/logstash/config/ir/compiler/PluginFactoryTest.java index 6264d3957..ebc399069 100644 --- a/logstash-core/src/test/java/org/logstash/config/ir/compiler/PluginFactoryTest.java +++ b/logstash-core/src/test/java/org/logstash/config/ir/compiler/PluginFactoryTest.java @@ -1,3 +1,23 @@ +/* + * 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. + */ + + package org.logstash.config.ir.compiler; import org.junit.Test; diff --git a/logstash-core/src/test/java/org/logstash/config/ir/graph/BooleanEdgeTest.java b/logstash-core/src/test/java/org/logstash/config/ir/graph/BooleanEdgeTest.java index 865412f4f..e6bd7e4e7 100644 --- a/logstash-core/src/test/java/org/logstash/config/ir/graph/BooleanEdgeTest.java +++ b/logstash-core/src/test/java/org/logstash/config/ir/graph/BooleanEdgeTest.java @@ -1,3 +1,23 @@ +/* + * 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. + */ + + package org.logstash.config.ir.graph; import org.junit.experimental.theories.DataPoint; diff --git a/logstash-core/src/test/java/org/logstash/config/ir/graph/EdgeTest.java b/logstash-core/src/test/java/org/logstash/config/ir/graph/EdgeTest.java index 2b55279f7..379a4db97 100644 --- a/logstash-core/src/test/java/org/logstash/config/ir/graph/EdgeTest.java +++ b/logstash-core/src/test/java/org/logstash/config/ir/graph/EdgeTest.java @@ -1,3 +1,23 @@ +/* + * 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. + */ + + package org.logstash.config.ir.graph; import org.junit.Test; diff --git a/logstash-core/src/test/java/org/logstash/config/ir/graph/GraphTest.java b/logstash-core/src/test/java/org/logstash/config/ir/graph/GraphTest.java index 26737b892..a6c222aa0 100644 --- a/logstash-core/src/test/java/org/logstash/config/ir/graph/GraphTest.java +++ b/logstash-core/src/test/java/org/logstash/config/ir/graph/GraphTest.java @@ -1,3 +1,23 @@ +/* + * 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. + */ + + package org.logstash.config.ir.graph; import org.junit.Test; diff --git a/logstash-core/src/test/java/org/logstash/config/ir/graph/IfVertexTest.java b/logstash-core/src/test/java/org/logstash/config/ir/graph/IfVertexTest.java index 9c9f77992..59e07f4dd 100644 --- a/logstash-core/src/test/java/org/logstash/config/ir/graph/IfVertexTest.java +++ b/logstash-core/src/test/java/org/logstash/config/ir/graph/IfVertexTest.java @@ -1,3 +1,23 @@ +/* + * 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. + */ + + package org.logstash.config.ir.graph; import org.junit.Test; diff --git a/logstash-core/src/test/java/org/logstash/config/ir/graph/PlainEdgeTest.java b/logstash-core/src/test/java/org/logstash/config/ir/graph/PlainEdgeTest.java index b84d16d6b..b5ed58bce 100644 --- a/logstash-core/src/test/java/org/logstash/config/ir/graph/PlainEdgeTest.java +++ b/logstash-core/src/test/java/org/logstash/config/ir/graph/PlainEdgeTest.java @@ -1,3 +1,23 @@ +/* + * 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. + */ + + package org.logstash.config.ir.graph; import org.junit.Test; diff --git a/logstash-core/src/test/java/org/logstash/config/ir/graph/PluginVertexTest.java b/logstash-core/src/test/java/org/logstash/config/ir/graph/PluginVertexTest.java index eb4a78a4e..3c4dab32e 100644 --- a/logstash-core/src/test/java/org/logstash/config/ir/graph/PluginVertexTest.java +++ b/logstash-core/src/test/java/org/logstash/config/ir/graph/PluginVertexTest.java @@ -1,3 +1,23 @@ +/* + * 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. + */ + + package org.logstash.config.ir.graph; import org.junit.Test; diff --git a/logstash-core/src/test/java/org/logstash/config/ir/graph/QueueVertexTest.java b/logstash-core/src/test/java/org/logstash/config/ir/graph/QueueVertexTest.java index ca8fdad0d..38a2d3517 100644 --- a/logstash-core/src/test/java/org/logstash/config/ir/graph/QueueVertexTest.java +++ b/logstash-core/src/test/java/org/logstash/config/ir/graph/QueueVertexTest.java @@ -1,3 +1,23 @@ +/* + * 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. + */ + + package org.logstash.config.ir.graph; import org.junit.Test; diff --git a/logstash-core/src/test/java/org/logstash/config/ir/graph/VertexTest.java b/logstash-core/src/test/java/org/logstash/config/ir/graph/VertexTest.java index 05e5f3bb8..16de35fb8 100644 --- a/logstash-core/src/test/java/org/logstash/config/ir/graph/VertexTest.java +++ b/logstash-core/src/test/java/org/logstash/config/ir/graph/VertexTest.java @@ -1,3 +1,23 @@ +/* + * 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. + */ + + package org.logstash.config.ir.graph; import org.junit.Test; diff --git a/logstash-core/src/test/java/org/logstash/config/ir/graph/algorithms/BreadthFirstTest.java b/logstash-core/src/test/java/org/logstash/config/ir/graph/algorithms/BreadthFirstTest.java index 3fa6dda6c..0a1613c4e 100644 --- a/logstash-core/src/test/java/org/logstash/config/ir/graph/algorithms/BreadthFirstTest.java +++ b/logstash-core/src/test/java/org/logstash/config/ir/graph/algorithms/BreadthFirstTest.java @@ -1,3 +1,23 @@ +/* + * 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. + */ + + package org.logstash.config.ir.graph.algorithms; import org.junit.Test; diff --git a/logstash-core/src/test/java/org/logstash/config/ir/graph/algorithms/DepthFirstTest.java b/logstash-core/src/test/java/org/logstash/config/ir/graph/algorithms/DepthFirstTest.java index 80cad6584..b2566031a 100644 --- a/logstash-core/src/test/java/org/logstash/config/ir/graph/algorithms/DepthFirstTest.java +++ b/logstash-core/src/test/java/org/logstash/config/ir/graph/algorithms/DepthFirstTest.java @@ -1,3 +1,23 @@ +/* + * 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. + */ + + package org.logstash.config.ir.graph.algorithms; import org.junit.Before; diff --git a/logstash-core/src/test/java/org/logstash/config/ir/graph/algorithms/GraphDiffTest.java b/logstash-core/src/test/java/org/logstash/config/ir/graph/algorithms/GraphDiffTest.java index 576e416dc..70427b37a 100644 --- a/logstash-core/src/test/java/org/logstash/config/ir/graph/algorithms/GraphDiffTest.java +++ b/logstash-core/src/test/java/org/logstash/config/ir/graph/algorithms/GraphDiffTest.java @@ -1,3 +1,23 @@ +/* + * 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. + */ + + package org.logstash.config.ir.graph.algorithms; import org.junit.Test; diff --git a/logstash-core/src/test/java/org/logstash/config/ir/graph/algorithms/TopologicalSortTest.java b/logstash-core/src/test/java/org/logstash/config/ir/graph/algorithms/TopologicalSortTest.java index c1d9bd396..23c50b350 100644 --- a/logstash-core/src/test/java/org/logstash/config/ir/graph/algorithms/TopologicalSortTest.java +++ b/logstash-core/src/test/java/org/logstash/config/ir/graph/algorithms/TopologicalSortTest.java @@ -1,3 +1,23 @@ +/* + * 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. + */ + + package org.logstash.config.ir.graph.algorithms; import org.junit.Test; diff --git a/logstash-core/src/test/java/org/logstash/config/ir/imperative/DSLTest.java b/logstash-core/src/test/java/org/logstash/config/ir/imperative/DSLTest.java index 5131c873f..71a6bfe2a 100644 --- a/logstash-core/src/test/java/org/logstash/config/ir/imperative/DSLTest.java +++ b/logstash-core/src/test/java/org/logstash/config/ir/imperative/DSLTest.java @@ -1,3 +1,23 @@ +/* + * 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. + */ + + package org.logstash.config.ir.imperative; import org.junit.Test; diff --git a/logstash-core/src/test/java/org/logstash/config/ir/imperative/IfStatementTest.java b/logstash-core/src/test/java/org/logstash/config/ir/imperative/IfStatementTest.java index 0275f8e6e..2f0631543 100644 --- a/logstash-core/src/test/java/org/logstash/config/ir/imperative/IfStatementTest.java +++ b/logstash-core/src/test/java/org/logstash/config/ir/imperative/IfStatementTest.java @@ -1,3 +1,23 @@ +/* + * 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. + */ + + package org.logstash.config.ir.imperative; import org.junit.Test; diff --git a/logstash-core/src/test/java/org/logstash/config/ir/imperative/ImperativeToGraphtest.java b/logstash-core/src/test/java/org/logstash/config/ir/imperative/ImperativeToGraphtest.java index 109e2b003..ea644531b 100644 --- a/logstash-core/src/test/java/org/logstash/config/ir/imperative/ImperativeToGraphtest.java +++ b/logstash-core/src/test/java/org/logstash/config/ir/imperative/ImperativeToGraphtest.java @@ -1,3 +1,23 @@ +/* + * 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. + */ + + package org.logstash.config.ir.imperative; import org.junit.Test; diff --git a/logstash-core/src/test/java/org/logstash/execution/ShutdownWatcherExtTest.java b/logstash-core/src/test/java/org/logstash/execution/ShutdownWatcherExtTest.java index 74233e556..a48c8a8cb 100644 --- a/logstash-core/src/test/java/org/logstash/execution/ShutdownWatcherExtTest.java +++ b/logstash-core/src/test/java/org/logstash/execution/ShutdownWatcherExtTest.java @@ -1,3 +1,23 @@ +/* + * 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. + */ + + package org.logstash.execution; import java.util.concurrent.ExecutionException; diff --git a/logstash-core/src/test/java/org/logstash/ext/JrubyEventExtLibraryTest.java b/logstash-core/src/test/java/org/logstash/ext/JrubyEventExtLibraryTest.java index 0fbd60663..533ab654a 100644 --- a/logstash-core/src/test/java/org/logstash/ext/JrubyEventExtLibraryTest.java +++ b/logstash-core/src/test/java/org/logstash/ext/JrubyEventExtLibraryTest.java @@ -1,3 +1,23 @@ +/* + * 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. + */ + + package org.logstash.ext; import java.io.IOException; diff --git a/logstash-core/src/test/java/org/logstash/ext/JrubyMemoryReadClientExtTest.java b/logstash-core/src/test/java/org/logstash/ext/JrubyMemoryReadClientExtTest.java index a458e805e..dfcde9c40 100644 --- a/logstash-core/src/test/java/org/logstash/ext/JrubyMemoryReadClientExtTest.java +++ b/logstash-core/src/test/java/org/logstash/ext/JrubyMemoryReadClientExtTest.java @@ -1,3 +1,23 @@ +/* + * 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. + */ + + package org.logstash.ext; import java.io.IOException; diff --git a/logstash-core/src/test/java/org/logstash/ext/JrubyTimestampExtLibraryTest.java b/logstash-core/src/test/java/org/logstash/ext/JrubyTimestampExtLibraryTest.java index c3fb68a4b..a4ccbf3d5 100644 --- a/logstash-core/src/test/java/org/logstash/ext/JrubyTimestampExtLibraryTest.java +++ b/logstash-core/src/test/java/org/logstash/ext/JrubyTimestampExtLibraryTest.java @@ -1,3 +1,23 @@ +/* + * 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. + */ + + package org.logstash.ext; import java.util.concurrent.TimeUnit; diff --git a/logstash-core/src/test/java/org/logstash/ext/TimestampTest.java b/logstash-core/src/test/java/org/logstash/ext/TimestampTest.java index ef35fde50..a85174d16 100644 --- a/logstash-core/src/test/java/org/logstash/ext/TimestampTest.java +++ b/logstash-core/src/test/java/org/logstash/ext/TimestampTest.java @@ -1,3 +1,23 @@ +/* + * 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. + */ + + package org.logstash.ext; import org.junit.Test; diff --git a/logstash-core/src/test/java/org/logstash/instrument/metrics/MetricTypeTest.java b/logstash-core/src/test/java/org/logstash/instrument/metrics/MetricTypeTest.java index 7a7bec6e1..bf7c2b17c 100644 --- a/logstash-core/src/test/java/org/logstash/instrument/metrics/MetricTypeTest.java +++ b/logstash-core/src/test/java/org/logstash/instrument/metrics/MetricTypeTest.java @@ -1,3 +1,23 @@ +/* + * 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. + */ + + package org.logstash.instrument.metrics; import org.junit.Test; diff --git a/logstash-core/src/test/java/org/logstash/instrument/metrics/counter/LongCounterTest.java b/logstash-core/src/test/java/org/logstash/instrument/metrics/counter/LongCounterTest.java index 0d1fd96fb..cd1453fd7 100644 --- a/logstash-core/src/test/java/org/logstash/instrument/metrics/counter/LongCounterTest.java +++ b/logstash-core/src/test/java/org/logstash/instrument/metrics/counter/LongCounterTest.java @@ -1,3 +1,23 @@ +/* + * 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. + */ + + package org.logstash.instrument.metrics.counter; import org.junit.Before; diff --git a/logstash-core/src/test/java/org/logstash/instrument/metrics/gauge/BooleanGaugeTest.java b/logstash-core/src/test/java/org/logstash/instrument/metrics/gauge/BooleanGaugeTest.java index b29a1f631..a0923c42d 100644 --- a/logstash-core/src/test/java/org/logstash/instrument/metrics/gauge/BooleanGaugeTest.java +++ b/logstash-core/src/test/java/org/logstash/instrument/metrics/gauge/BooleanGaugeTest.java @@ -1,3 +1,23 @@ +/* + * 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. + */ + + package org.logstash.instrument.metrics.gauge; import org.junit.Test; diff --git a/logstash-core/src/test/java/org/logstash/instrument/metrics/gauge/LazyDelegatingGaugeTest.java b/logstash-core/src/test/java/org/logstash/instrument/metrics/gauge/LazyDelegatingGaugeTest.java index 84b76d316..0a5617877 100644 --- a/logstash-core/src/test/java/org/logstash/instrument/metrics/gauge/LazyDelegatingGaugeTest.java +++ b/logstash-core/src/test/java/org/logstash/instrument/metrics/gauge/LazyDelegatingGaugeTest.java @@ -1,3 +1,23 @@ +/* + * 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. + */ + + package org.logstash.instrument.metrics.gauge; import java.net.URI; diff --git a/logstash-core/src/test/java/org/logstash/instrument/metrics/gauge/NumberGaugeTest.java b/logstash-core/src/test/java/org/logstash/instrument/metrics/gauge/NumberGaugeTest.java index 2b6f0c233..fde491913 100644 --- a/logstash-core/src/test/java/org/logstash/instrument/metrics/gauge/NumberGaugeTest.java +++ b/logstash-core/src/test/java/org/logstash/instrument/metrics/gauge/NumberGaugeTest.java @@ -1,3 +1,23 @@ +/* + * 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. + */ + + package org.logstash.instrument.metrics.gauge; import org.junit.Test; diff --git a/logstash-core/src/test/java/org/logstash/instrument/metrics/gauge/RubyHashGaugeTest.java b/logstash-core/src/test/java/org/logstash/instrument/metrics/gauge/RubyHashGaugeTest.java index 631fc4a79..bdc663228 100644 --- a/logstash-core/src/test/java/org/logstash/instrument/metrics/gauge/RubyHashGaugeTest.java +++ b/logstash-core/src/test/java/org/logstash/instrument/metrics/gauge/RubyHashGaugeTest.java @@ -1,3 +1,23 @@ +/* + * 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. + */ + + package org.logstash.instrument.metrics.gauge; import org.jruby.RubyHash; diff --git a/logstash-core/src/test/java/org/logstash/instrument/metrics/gauge/RubyTimeStampGaugeTest.java b/logstash-core/src/test/java/org/logstash/instrument/metrics/gauge/RubyTimeStampGaugeTest.java index 82b47c59f..accc385b5 100644 --- a/logstash-core/src/test/java/org/logstash/instrument/metrics/gauge/RubyTimeStampGaugeTest.java +++ b/logstash-core/src/test/java/org/logstash/instrument/metrics/gauge/RubyTimeStampGaugeTest.java @@ -1,3 +1,23 @@ +/* + * 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. + */ + + package org.logstash.instrument.metrics.gauge; import org.junit.Test; diff --git a/logstash-core/src/test/java/org/logstash/instrument/metrics/gauge/TextGaugeTest.java b/logstash-core/src/test/java/org/logstash/instrument/metrics/gauge/TextGaugeTest.java index 5b19b0c99..45d421857 100644 --- a/logstash-core/src/test/java/org/logstash/instrument/metrics/gauge/TextGaugeTest.java +++ b/logstash-core/src/test/java/org/logstash/instrument/metrics/gauge/TextGaugeTest.java @@ -1,3 +1,23 @@ +/* + * 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. + */ + + package org.logstash.instrument.metrics.gauge; import org.junit.Test; diff --git a/logstash-core/src/test/java/org/logstash/instrument/metrics/gauge/UnknownGaugeTest.java b/logstash-core/src/test/java/org/logstash/instrument/metrics/gauge/UnknownGaugeTest.java index 6b071e861..a8b010975 100644 --- a/logstash-core/src/test/java/org/logstash/instrument/metrics/gauge/UnknownGaugeTest.java +++ b/logstash-core/src/test/java/org/logstash/instrument/metrics/gauge/UnknownGaugeTest.java @@ -1,3 +1,23 @@ +/* + * 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. + */ + + package org.logstash.instrument.metrics.gauge; import org.junit.Test; diff --git a/logstash-core/src/test/java/org/logstash/instruments/monitors/HotThreadMonitorTest.java b/logstash-core/src/test/java/org/logstash/instruments/monitors/HotThreadMonitorTest.java index 3334269f4..ec6765fca 100644 --- a/logstash-core/src/test/java/org/logstash/instruments/monitors/HotThreadMonitorTest.java +++ b/logstash-core/src/test/java/org/logstash/instruments/monitors/HotThreadMonitorTest.java @@ -1,3 +1,23 @@ +/* + * 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. + */ + + package org.logstash.instruments.monitors; diff --git a/logstash-core/src/test/java/org/logstash/instruments/monitors/MemoryMonitorTest.java b/logstash-core/src/test/java/org/logstash/instruments/monitors/MemoryMonitorTest.java index bb03c99bf..67891879e 100644 --- a/logstash-core/src/test/java/org/logstash/instruments/monitors/MemoryMonitorTest.java +++ b/logstash-core/src/test/java/org/logstash/instruments/monitors/MemoryMonitorTest.java @@ -1,3 +1,23 @@ +/* + * 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. + */ + + package org.logstash.instruments.monitors; import org.junit.Test; diff --git a/logstash-core/src/test/java/org/logstash/instruments/monitors/ProcessMonitorTest.java b/logstash-core/src/test/java/org/logstash/instruments/monitors/ProcessMonitorTest.java index 4f474281d..95e3e7d8b 100644 --- a/logstash-core/src/test/java/org/logstash/instruments/monitors/ProcessMonitorTest.java +++ b/logstash-core/src/test/java/org/logstash/instruments/monitors/ProcessMonitorTest.java @@ -1,3 +1,23 @@ +/* + * 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. + */ + + package org.logstash.instruments.monitors; import org.junit.Test; diff --git a/logstash-core/src/test/java/org/logstash/instruments/monitors/SystemMonitorTest.java b/logstash-core/src/test/java/org/logstash/instruments/monitors/SystemMonitorTest.java index c3907bd09..92e51f689 100644 --- a/logstash-core/src/test/java/org/logstash/instruments/monitors/SystemMonitorTest.java +++ b/logstash-core/src/test/java/org/logstash/instruments/monitors/SystemMonitorTest.java @@ -1,3 +1,23 @@ +/* + * 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. + */ + + package org.logstash.instruments.monitors; import org.junit.Test; diff --git a/logstash-core/src/test/java/org/logstash/log/CustomLogEventTests.java b/logstash-core/src/test/java/org/logstash/log/CustomLogEventTests.java index 7fa89743e..a2af82ea4 100644 --- a/logstash-core/src/test/java/org/logstash/log/CustomLogEventTests.java +++ b/logstash-core/src/test/java/org/logstash/log/CustomLogEventTests.java @@ -1,3 +1,23 @@ +/* + * 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. + */ + + /* * Licensed to Elasticsearch under one or more contributor * license agreements. See the NOTICE file distributed with diff --git a/logstash-core/src/test/java/org/logstash/log/DefaultDeprecationLoggerTest.java b/logstash-core/src/test/java/org/logstash/log/DefaultDeprecationLoggerTest.java index 7353eac41..5cd47cac7 100644 --- a/logstash-core/src/test/java/org/logstash/log/DefaultDeprecationLoggerTest.java +++ b/logstash-core/src/test/java/org/logstash/log/DefaultDeprecationLoggerTest.java @@ -1,3 +1,23 @@ +/* + * 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. + */ + + package org.logstash.log; import org.apache.logging.log4j.LogManager; diff --git a/logstash-core/src/test/java/org/logstash/log/LogTestUtils.java b/logstash-core/src/test/java/org/logstash/log/LogTestUtils.java index 2ada1992b..9f4476433 100644 --- a/logstash-core/src/test/java/org/logstash/log/LogTestUtils.java +++ b/logstash-core/src/test/java/org/logstash/log/LogTestUtils.java @@ -1,3 +1,23 @@ +/* + * 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. + */ + + package org.logstash.log; import org.apache.logging.log4j.core.LoggerContext; diff --git a/logstash-core/src/test/java/org/logstash/log/LogstashConfigurationFactoryTest.java b/logstash-core/src/test/java/org/logstash/log/LogstashConfigurationFactoryTest.java index 3102335eb..0d1495df9 100644 --- a/logstash-core/src/test/java/org/logstash/log/LogstashConfigurationFactoryTest.java +++ b/logstash-core/src/test/java/org/logstash/log/LogstashConfigurationFactoryTest.java @@ -1,3 +1,23 @@ +/* + * 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. + */ + + package org.logstash.log; import org.apache.logging.log4j.LogManager; diff --git a/logstash-core/src/test/java/org/logstash/log/LogstashLoggerContextFactoryTest.java b/logstash-core/src/test/java/org/logstash/log/LogstashLoggerContextFactoryTest.java index a70feb30f..c51aff9c2 100644 --- a/logstash-core/src/test/java/org/logstash/log/LogstashLoggerContextFactoryTest.java +++ b/logstash-core/src/test/java/org/logstash/log/LogstashLoggerContextFactoryTest.java @@ -1,3 +1,23 @@ +/* + * 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. + */ + + package org.logstash.log; diff --git a/logstash-core/src/test/java/org/logstash/log/PluginDeprecationLoggerTest.java b/logstash-core/src/test/java/org/logstash/log/PluginDeprecationLoggerTest.java index 3d598355f..496e55d4a 100644 --- a/logstash-core/src/test/java/org/logstash/log/PluginDeprecationLoggerTest.java +++ b/logstash-core/src/test/java/org/logstash/log/PluginDeprecationLoggerTest.java @@ -1,3 +1,23 @@ +/* + * 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. + */ + + package org.logstash.log; import org.junit.*; diff --git a/logstash-core/src/test/java/org/logstash/log/SystemPropsSnapshotHelper.java b/logstash-core/src/test/java/org/logstash/log/SystemPropsSnapshotHelper.java index c39014020..2e996d3b4 100644 --- a/logstash-core/src/test/java/org/logstash/log/SystemPropsSnapshotHelper.java +++ b/logstash-core/src/test/java/org/logstash/log/SystemPropsSnapshotHelper.java @@ -1,3 +1,23 @@ +/* + * 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. + */ + + package org.logstash.log; import java.util.HashMap; diff --git a/logstash-core/src/test/java/org/logstash/log/TestingDeprecationPlugin.java b/logstash-core/src/test/java/org/logstash/log/TestingDeprecationPlugin.java index c4622e2eb..ee84b3b96 100644 --- a/logstash-core/src/test/java/org/logstash/log/TestingDeprecationPlugin.java +++ b/logstash-core/src/test/java/org/logstash/log/TestingDeprecationPlugin.java @@ -1,3 +1,23 @@ +/* + * 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. + */ + + package org.logstash.log; import co.elastic.logstash.api.*; diff --git a/logstash-core/src/test/java/org/logstash/plugins/ConfigurationImplTest.java b/logstash-core/src/test/java/org/logstash/plugins/ConfigurationImplTest.java index 02d543583..3493467e1 100644 --- a/logstash-core/src/test/java/org/logstash/plugins/ConfigurationImplTest.java +++ b/logstash-core/src/test/java/org/logstash/plugins/ConfigurationImplTest.java @@ -1,3 +1,23 @@ +/* + * 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. + */ + + package org.logstash.plugins; import co.elastic.logstash.api.Configuration; diff --git a/logstash-core/src/test/java/org/logstash/plugins/CounterMetricImplTest.java b/logstash-core/src/test/java/org/logstash/plugins/CounterMetricImplTest.java index 8f698c679..02be8c102 100644 --- a/logstash-core/src/test/java/org/logstash/plugins/CounterMetricImplTest.java +++ b/logstash-core/src/test/java/org/logstash/plugins/CounterMetricImplTest.java @@ -1,3 +1,23 @@ +/* + * 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. + */ + + package org.logstash.plugins; import co.elastic.logstash.api.CounterMetric; diff --git a/logstash-core/src/test/java/org/logstash/plugins/MetricTestCase.java b/logstash-core/src/test/java/org/logstash/plugins/MetricTestCase.java index 1fc79b73e..2aad692a4 100644 --- a/logstash-core/src/test/java/org/logstash/plugins/MetricTestCase.java +++ b/logstash-core/src/test/java/org/logstash/plugins/MetricTestCase.java @@ -1,3 +1,23 @@ +/* + * 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. + */ + + package org.logstash.plugins; import co.elastic.logstash.api.Metric; diff --git a/logstash-core/src/test/java/org/logstash/plugins/NamespacedMetricImplTest.java b/logstash-core/src/test/java/org/logstash/plugins/NamespacedMetricImplTest.java index c1b71b025..9f16d1524 100644 --- a/logstash-core/src/test/java/org/logstash/plugins/NamespacedMetricImplTest.java +++ b/logstash-core/src/test/java/org/logstash/plugins/NamespacedMetricImplTest.java @@ -1,3 +1,23 @@ +/* + * 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. + */ + + package org.logstash.plugins; import co.elastic.logstash.api.Metric; diff --git a/logstash-core/src/test/java/org/logstash/plugins/PluginFactoryExtTest.java b/logstash-core/src/test/java/org/logstash/plugins/PluginFactoryExtTest.java index a751bb392..aca712cdb 100644 --- a/logstash-core/src/test/java/org/logstash/plugins/PluginFactoryExtTest.java +++ b/logstash-core/src/test/java/org/logstash/plugins/PluginFactoryExtTest.java @@ -1,3 +1,23 @@ +/* + * 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. + */ + + package org.logstash.plugins; import co.elastic.logstash.api.*; diff --git a/logstash-core/src/test/java/org/logstash/plugins/PluginUtilValidateConfigTest.java b/logstash-core/src/test/java/org/logstash/plugins/PluginUtilValidateConfigTest.java index 01d27b8d1..c47de0e53 100644 --- a/logstash-core/src/test/java/org/logstash/plugins/PluginUtilValidateConfigTest.java +++ b/logstash-core/src/test/java/org/logstash/plugins/PluginUtilValidateConfigTest.java @@ -1,3 +1,23 @@ +/* + * 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. + */ + + package org.logstash.plugins; import co.elastic.logstash.api.Configuration; @@ -216,6 +236,3 @@ public class PluginUtilValidateConfigTest { } } } - - - diff --git a/logstash-core/src/test/java/org/logstash/plugins/PluginValidatorTest.java b/logstash-core/src/test/java/org/logstash/plugins/PluginValidatorTest.java index c3c756ce1..c4ddf47b3 100644 --- a/logstash-core/src/test/java/org/logstash/plugins/PluginValidatorTest.java +++ b/logstash-core/src/test/java/org/logstash/plugins/PluginValidatorTest.java @@ -1,3 +1,23 @@ +/* + * 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. + */ + + package org.logstash.plugins; import org.junit.Assert; diff --git a/logstash-core/src/test/java/org/logstash/plugins/TestContext.java b/logstash-core/src/test/java/org/logstash/plugins/TestContext.java index 4966fe956..4cfbeeb29 100644 --- a/logstash-core/src/test/java/org/logstash/plugins/TestContext.java +++ b/logstash-core/src/test/java/org/logstash/plugins/TestContext.java @@ -1,3 +1,23 @@ +/* + * 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. + */ + + package org.logstash.plugins; import co.elastic.logstash.api.*; diff --git a/logstash-core/src/test/java/org/logstash/plugins/TestPluginFactory.java b/logstash-core/src/test/java/org/logstash/plugins/TestPluginFactory.java index b5fd7bd6e..ca2c2f02c 100644 --- a/logstash-core/src/test/java/org/logstash/plugins/TestPluginFactory.java +++ b/logstash-core/src/test/java/org/logstash/plugins/TestPluginFactory.java @@ -1,3 +1,23 @@ +/* + * 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. + */ + + package org.logstash.plugins; import co.elastic.logstash.api.Codec; diff --git a/logstash-core/src/test/java/org/logstash/plugins/TestingPlugin.java b/logstash-core/src/test/java/org/logstash/plugins/TestingPlugin.java index b43be8ead..5cddf1db7 100644 --- a/logstash-core/src/test/java/org/logstash/plugins/TestingPlugin.java +++ b/logstash-core/src/test/java/org/logstash/plugins/TestingPlugin.java @@ -1,3 +1,23 @@ +/* + * 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. + */ + + package org.logstash.plugins; import co.elastic.logstash.api.LogstashPlugin; diff --git a/logstash-core/src/test/java/org/logstash/plugins/codecs/LineTest.java b/logstash-core/src/test/java/org/logstash/plugins/codecs/LineTest.java index 7873c050a..43ea6a639 100644 --- a/logstash-core/src/test/java/org/logstash/plugins/codecs/LineTest.java +++ b/logstash-core/src/test/java/org/logstash/plugins/codecs/LineTest.java @@ -1,3 +1,23 @@ +/* + * 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. + */ + + package org.logstash.plugins.codecs; import co.elastic.logstash.api.Codec; @@ -338,4 +358,3 @@ public class LineTest { } } - diff --git a/logstash-core/src/test/java/org/logstash/plugins/codecs/PlainTest.java b/logstash-core/src/test/java/org/logstash/plugins/codecs/PlainTest.java index 52639a82e..1c5fe8f68 100644 --- a/logstash-core/src/test/java/org/logstash/plugins/codecs/PlainTest.java +++ b/logstash-core/src/test/java/org/logstash/plugins/codecs/PlainTest.java @@ -1,3 +1,23 @@ +/* + * 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. + */ + + package org.logstash.plugins.codecs; import co.elastic.logstash.api.Codec; diff --git a/logstash-core/src/test/java/org/logstash/plugins/codecs/TestEventConsumer.java b/logstash-core/src/test/java/org/logstash/plugins/codecs/TestEventConsumer.java index 6e6aae1d3..bc5b3ad5a 100644 --- a/logstash-core/src/test/java/org/logstash/plugins/codecs/TestEventConsumer.java +++ b/logstash-core/src/test/java/org/logstash/plugins/codecs/TestEventConsumer.java @@ -1,3 +1,23 @@ +/* + * 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. + */ + + package org.logstash.plugins.codecs; import java.util.ArrayList; diff --git a/logstash-core/src/test/java/org/logstash/plugins/filters/UuidTest.java b/logstash-core/src/test/java/org/logstash/plugins/filters/UuidTest.java index d038daafc..d88b69a13 100644 --- a/logstash-core/src/test/java/org/logstash/plugins/filters/UuidTest.java +++ b/logstash-core/src/test/java/org/logstash/plugins/filters/UuidTest.java @@ -1,3 +1,23 @@ +/* + * 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. + */ + + package org.logstash.plugins.filters; import co.elastic.logstash.api.Configuration; diff --git a/logstash-core/src/test/java/org/logstash/plugins/inputs/StdinTest.java b/logstash-core/src/test/java/org/logstash/plugins/inputs/StdinTest.java index c36eeaafb..598ba583e 100644 --- a/logstash-core/src/test/java/org/logstash/plugins/inputs/StdinTest.java +++ b/logstash-core/src/test/java/org/logstash/plugins/inputs/StdinTest.java @@ -1,3 +1,23 @@ +/* + * 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. + */ + + package org.logstash.plugins.inputs; import org.junit.Test; diff --git a/logstash-core/src/test/java/org/logstash/plugins/outputs/StdoutTest.java b/logstash-core/src/test/java/org/logstash/plugins/outputs/StdoutTest.java index 9f243c474..1acd460b7 100644 --- a/logstash-core/src/test/java/org/logstash/plugins/outputs/StdoutTest.java +++ b/logstash-core/src/test/java/org/logstash/plugins/outputs/StdoutTest.java @@ -1,3 +1,23 @@ +/* + * 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. + */ + + package org.logstash.plugins.outputs; import co.elastic.logstash.api.Event; diff --git a/logstash-core/src/test/java/org/logstash/plugins/pipeline/PipelineBusTest.java b/logstash-core/src/test/java/org/logstash/plugins/pipeline/PipelineBusTest.java index 4f2dc9302..5de0b264b 100644 --- a/logstash-core/src/test/java/org/logstash/plugins/pipeline/PipelineBusTest.java +++ b/logstash-core/src/test/java/org/logstash/plugins/pipeline/PipelineBusTest.java @@ -1,3 +1,23 @@ +/* + * 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. + */ + + package org.logstash.plugins.pipeline; import org.junit.Before; diff --git a/logstash-core/src/test/java/org/logstash/secret/SecretIdentifierTest.java b/logstash-core/src/test/java/org/logstash/secret/SecretIdentifierTest.java index 1f537c518..75fe9e86e 100644 --- a/logstash-core/src/test/java/org/logstash/secret/SecretIdentifierTest.java +++ b/logstash-core/src/test/java/org/logstash/secret/SecretIdentifierTest.java @@ -1,3 +1,23 @@ +/* + * 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. + */ + + package org.logstash.secret; diff --git a/logstash-core/src/test/java/org/logstash/secret/cli/SecretStoreCliTest.java b/logstash-core/src/test/java/org/logstash/secret/cli/SecretStoreCliTest.java index 93dfe3b05..24d06ea2f 100644 --- a/logstash-core/src/test/java/org/logstash/secret/cli/SecretStoreCliTest.java +++ b/logstash-core/src/test/java/org/logstash/secret/cli/SecretStoreCliTest.java @@ -1,3 +1,23 @@ +/* + * 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. + */ + + package org.logstash.secret.cli; import org.junit.Before; diff --git a/logstash-core/src/test/java/org/logstash/secret/store/SecretStoreFactoryTest.java b/logstash-core/src/test/java/org/logstash/secret/store/SecretStoreFactoryTest.java index b391757cf..2d04364ed 100644 --- a/logstash-core/src/test/java/org/logstash/secret/store/SecretStoreFactoryTest.java +++ b/logstash-core/src/test/java/org/logstash/secret/store/SecretStoreFactoryTest.java @@ -1,3 +1,23 @@ +/* + * 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. + */ + + package org.logstash.secret.store; import org.junit.Rule; diff --git a/logstash-core/src/test/java/org/logstash/secret/store/SecretStoreUtilTest.java b/logstash-core/src/test/java/org/logstash/secret/store/SecretStoreUtilTest.java index 48a472f7c..f5e8ee3fa 100644 --- a/logstash-core/src/test/java/org/logstash/secret/store/SecretStoreUtilTest.java +++ b/logstash-core/src/test/java/org/logstash/secret/store/SecretStoreUtilTest.java @@ -1,3 +1,23 @@ +/* + * 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. + */ + + package org.logstash.secret.store; import org.junit.Before; diff --git a/logstash-core/src/test/java/org/logstash/secret/store/SecureConfigTest.java b/logstash-core/src/test/java/org/logstash/secret/store/SecureConfigTest.java index 5b83955b2..947b93f48 100644 --- a/logstash-core/src/test/java/org/logstash/secret/store/SecureConfigTest.java +++ b/logstash-core/src/test/java/org/logstash/secret/store/SecureConfigTest.java @@ -1,3 +1,23 @@ +/* + * 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. + */ + + package org.logstash.secret.store; import org.junit.Before; diff --git a/logstash-core/src/test/java/org/logstash/secret/store/backend/JavaKeyStoreTest.java b/logstash-core/src/test/java/org/logstash/secret/store/backend/JavaKeyStoreTest.java index ed2013cd9..6d5931aab 100644 --- a/logstash-core/src/test/java/org/logstash/secret/store/backend/JavaKeyStoreTest.java +++ b/logstash-core/src/test/java/org/logstash/secret/store/backend/JavaKeyStoreTest.java @@ -1,3 +1,23 @@ +/* + * 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. + */ + + package org.logstash.secret.store.backend; diff --git a/modules/fb_apache/configuration/logstash/fb_apache.conf.erb b/modules/fb_apache/configuration/logstash/fb_apache.conf.erb index 6f6ecb77a..f99616653 100644 --- a/modules/fb_apache/configuration/logstash/fb_apache.conf.erb +++ b/modules/fb_apache/configuration/logstash/fb_apache.conf.erb @@ -1,3 +1,20 @@ +# 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. + input { beats { port => <%= setting('var.input.beats.port', '5044') %> diff --git a/modules/fb_apache/lib/logstash_registry.rb b/modules/fb_apache/lib/logstash_registry.rb index 6eec19b91..53edefa05 100644 --- a/modules/fb_apache/lib/logstash_registry.rb +++ b/modules/fb_apache/lib/logstash_registry.rb @@ -1 +1,18 @@ +# 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. + LogStash::PLUGIN_REGISTRY.add(:modules, "fb_apache", LogStash::Modules::Scaffold.new("fb_apache", File.join(File.dirname(__FILE__), "..", "configuration"))) diff --git a/modules/netflow/configuration/logstash/netflow.conf.erb b/modules/netflow/configuration/logstash/netflow.conf.erb index 0af3c4f52..69772e7b1 100644 --- a/modules/netflow/configuration/logstash/netflow.conf.erb +++ b/modules/netflow/configuration/logstash/netflow.conf.erb @@ -1,3 +1,20 @@ +# 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. + input { udp { type => "netflow" diff --git a/modules/netflow/lib/logstash_registry.rb b/modules/netflow/lib/logstash_registry.rb index 94cd8da7c..c722e1120 100644 --- a/modules/netflow/lib/logstash_registry.rb +++ b/modules/netflow/lib/logstash_registry.rb @@ -1 +1,18 @@ +# 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. + LogStash::PLUGIN_REGISTRY.add(:modules, "netflow", LogStash::Modules::Scaffold.new("netflow", File.join(File.dirname(__FILE__), "..", "configuration"))) diff --git a/qa/Rakefile b/qa/Rakefile index b1e241732..ffdd10f48 100644 --- a/qa/Rakefile +++ b/qa/Rakefile @@ -1,3 +1,20 @@ +# 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 "rspec" require "rspec/core/runner" require "rspec/core/rake_task" diff --git a/qa/acceptance/spec/config_helper.rb b/qa/acceptance/spec/config_helper.rb index 3d9730c2d..6641d5c9e 100644 --- a/qa/acceptance/spec/config_helper.rb +++ b/qa/acceptance/spec/config_helper.rb @@ -1,4 +1,20 @@ -# encoding: utf-8 +# 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 "json" module SpecsHelper diff --git a/qa/acceptance/spec/lib/artifact_operation_spec.rb b/qa/acceptance/spec/lib/artifact_operation_spec.rb index f541f3a9f..82930e38a 100644 --- a/qa/acceptance/spec/lib/artifact_operation_spec.rb +++ b/qa/acceptance/spec/lib/artifact_operation_spec.rb @@ -1,4 +1,20 @@ -# encoding: utf-8 +# 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 '../spec_helper' require_relative '../shared_examples/installed' require_relative '../shared_examples/running' diff --git a/qa/acceptance/spec/lib/cli_operation_spec.rb b/qa/acceptance/spec/lib/cli_operation_spec.rb index 134a5a4d7..0b7bd0ecf 100644 --- a/qa/acceptance/spec/lib/cli_operation_spec.rb +++ b/qa/acceptance/spec/lib/cli_operation_spec.rb @@ -1,4 +1,20 @@ -# encoding: utf-8 +# 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 "../spec_helper" require_relative "../shared_examples/cli/logstash/version" require_relative "../shared_examples/cli/logstash-plugin/install" diff --git a/qa/acceptance/spec/shared_examples/cli/logstash-plugin/generate.rb b/qa/acceptance/spec/shared_examples/cli/logstash-plugin/generate.rb index 8c1968dff..f0d254aef 100644 --- a/qa/acceptance/spec/shared_examples/cli/logstash-plugin/generate.rb +++ b/qa/acceptance/spec/shared_examples/cli/logstash-plugin/generate.rb @@ -1,4 +1,20 @@ -# encoding: utf-8 +# 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 "../../../spec_helper" require "logstash/version" require "fileutils" diff --git a/qa/acceptance/spec/shared_examples/cli/logstash-plugin/install.rb b/qa/acceptance/spec/shared_examples/cli/logstash-plugin/install.rb index 1ef1e8aa9..fa06d90c5 100644 --- a/qa/acceptance/spec/shared_examples/cli/logstash-plugin/install.rb +++ b/qa/acceptance/spec/shared_examples/cli/logstash-plugin/install.rb @@ -1,4 +1,20 @@ -# encoding: utf-8 +# 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 "../../../spec_helper" require "logstash/version" require "fileutils" diff --git a/qa/acceptance/spec/shared_examples/cli/logstash-plugin/integration_plugin.rb b/qa/acceptance/spec/shared_examples/cli/logstash-plugin/integration_plugin.rb index bfec59cf5..427a19b3e 100644 --- a/qa/acceptance/spec/shared_examples/cli/logstash-plugin/integration_plugin.rb +++ b/qa/acceptance/spec/shared_examples/cli/logstash-plugin/integration_plugin.rb @@ -1,4 +1,20 @@ -# encoding: utf-8 +# 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 "../../../spec_helper" require "logstash/version" require "fileutils" diff --git a/qa/acceptance/spec/shared_examples/cli/logstash-plugin/list.rb b/qa/acceptance/spec/shared_examples/cli/logstash-plugin/list.rb index 1a04858e1..5598e9ab5 100644 --- a/qa/acceptance/spec/shared_examples/cli/logstash-plugin/list.rb +++ b/qa/acceptance/spec/shared_examples/cli/logstash-plugin/list.rb @@ -1,4 +1,20 @@ -# encoding: utf-8 +# 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 "../../../spec_helper" require "logstash/version" require "fileutils" diff --git a/qa/acceptance/spec/shared_examples/cli/logstash-plugin/remove.rb b/qa/acceptance/spec/shared_examples/cli/logstash-plugin/remove.rb index 2423ded08..105f711e8 100644 --- a/qa/acceptance/spec/shared_examples/cli/logstash-plugin/remove.rb +++ b/qa/acceptance/spec/shared_examples/cli/logstash-plugin/remove.rb @@ -1,4 +1,20 @@ -# encoding: utf-8 +# 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 "../../../spec_helper" require "logstash/version" require "fileutils" diff --git a/qa/acceptance/spec/shared_examples/cli/logstash-plugin/uninstall.rb b/qa/acceptance/spec/shared_examples/cli/logstash-plugin/uninstall.rb index 54ec8a6a7..6498040e0 100644 --- a/qa/acceptance/spec/shared_examples/cli/logstash-plugin/uninstall.rb +++ b/qa/acceptance/spec/shared_examples/cli/logstash-plugin/uninstall.rb @@ -1,4 +1,20 @@ -# encoding: utf-8 +# 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 "../../../spec_helper" require "logstash/version" require "fileutils" diff --git a/qa/acceptance/spec/shared_examples/cli/logstash-plugin/update.rb b/qa/acceptance/spec/shared_examples/cli/logstash-plugin/update.rb index 7b9f4880c..c7965031e 100644 --- a/qa/acceptance/spec/shared_examples/cli/logstash-plugin/update.rb +++ b/qa/acceptance/spec/shared_examples/cli/logstash-plugin/update.rb @@ -1,4 +1,20 @@ -# encoding: utf-8 +# 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 "../../../spec_helper" require "logstash/version" diff --git a/qa/acceptance/spec/shared_examples/cli/logstash/version.rb b/qa/acceptance/spec/shared_examples/cli/logstash/version.rb index ae6843313..c05869b2b 100644 --- a/qa/acceptance/spec/shared_examples/cli/logstash/version.rb +++ b/qa/acceptance/spec/shared_examples/cli/logstash/version.rb @@ -1,4 +1,20 @@ -# encoding: utf-8 +# 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 "../../../spec_helper" require "logstash/version" diff --git a/qa/acceptance/spec/shared_examples/installed.rb b/qa/acceptance/spec/shared_examples/installed.rb index 3d058134f..032dcf60f 100644 --- a/qa/acceptance/spec/shared_examples/installed.rb +++ b/qa/acceptance/spec/shared_examples/installed.rb @@ -1,3 +1,20 @@ +# 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 '../spec_helper' require 'logstash/version' diff --git a/qa/acceptance/spec/shared_examples/running.rb b/qa/acceptance/spec/shared_examples/running.rb index 55d18507c..2a04ca52b 100644 --- a/qa/acceptance/spec/shared_examples/running.rb +++ b/qa/acceptance/spec/shared_examples/running.rb @@ -1,3 +1,20 @@ +# 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 '../spec_helper' require 'logstash/version' diff --git a/qa/acceptance/spec/shared_examples/updated.rb b/qa/acceptance/spec/shared_examples/updated.rb index f6c9e8131..cae08700c 100644 --- a/qa/acceptance/spec/shared_examples/updated.rb +++ b/qa/acceptance/spec/shared_examples/updated.rb @@ -1,3 +1,20 @@ +# 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 '../spec_helper' require 'logstash/version' diff --git a/qa/acceptance/spec/spec_helper.rb b/qa/acceptance/spec/spec_helper.rb index 6f6b463b1..ec9b26f8a 100644 --- a/qa/acceptance/spec/spec_helper.rb +++ b/qa/acceptance/spec/spec_helper.rb @@ -1,4 +1,20 @@ -# encoding: utf-8 +# 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 'runner-tool' require_relative '../../rspec/helpers' require_relative '../../rspec/matchers' diff --git a/qa/integration/build.gradle b/qa/integration/build.gradle index dfc39b9b6..88518101b 100644 --- a/qa/integration/build.gradle +++ b/qa/integration/build.gradle @@ -1,3 +1,22 @@ +/* + * 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. + */ + description = """Logstash Integration Tests""" repositories { diff --git a/qa/integration/fixtures/logstash-dummy-pack/Rakefile b/qa/integration/fixtures/logstash-dummy-pack/Rakefile index bb55078e6..4c7570078 100644 --- a/qa/integration/fixtures/logstash-dummy-pack/Rakefile +++ b/qa/integration/fixtures/logstash-dummy-pack/Rakefile @@ -1,4 +1,20 @@ -# encoding: utf-8 +# 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 "paquet" TARGET_DIRECTORY = File.join(File.dirname(__FILE__), "dependencies") diff --git a/qa/integration/fixtures/logstash-dummy-pack/lib/logstash/outputs/secret.rb b/qa/integration/fixtures/logstash-dummy-pack/lib/logstash/outputs/secret.rb index 63b97c9cc..787d6c2a2 100644 --- a/qa/integration/fixtures/logstash-dummy-pack/lib/logstash/outputs/secret.rb +++ b/qa/integration/fixtures/logstash-dummy-pack/lib/logstash/outputs/secret.rb @@ -1,4 +1,20 @@ -# encoding: utf-8 +# 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 "logstash/outputs/base" # An secret output that does nothing. diff --git a/qa/integration/fixtures/logstash-dummy-pack/spec/outputs/secret_spec.rb b/qa/integration/fixtures/logstash-dummy-pack/spec/outputs/secret_spec.rb index 341b7a250..4151c7939 100644 --- a/qa/integration/fixtures/logstash-dummy-pack/spec/outputs/secret_spec.rb +++ b/qa/integration/fixtures/logstash-dummy-pack/spec/outputs/secret_spec.rb @@ -1,4 +1,20 @@ -# encoding: utf-8 +# 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 "logstash/devutils/rspec/spec_helper" require "logstash/outputs/secret" require "logstash/codecs/plain" diff --git a/qa/integration/framework/fixture.rb b/qa/integration/framework/fixture.rb index ba5120e3a..008bb9cbd 100644 --- a/qa/integration/framework/fixture.rb +++ b/qa/integration/framework/fixture.rb @@ -1,3 +1,20 @@ +# 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 "../services/service_locator" # A class that holds all fixtures for a given test file. This deals with diff --git a/qa/integration/framework/helpers.rb b/qa/integration/framework/helpers.rb index 51604f163..32ea1b514 100644 --- a/qa/integration/framework/helpers.rb +++ b/qa/integration/framework/helpers.rb @@ -1,4 +1,20 @@ -# encoding: utf-8 +# 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. + # Helper module for all tests require "flores/random" require "fileutils" diff --git a/qa/integration/framework/settings.rb b/qa/integration/framework/settings.rb index b5c567a04..74402e5be 100644 --- a/qa/integration/framework/settings.rb +++ b/qa/integration/framework/settings.rb @@ -1,3 +1,20 @@ +# 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 'yaml' # All settings for a test, global and per test diff --git a/qa/integration/patch/childprocess-modern-java.rb b/qa/integration/patch/childprocess-modern-java.rb index 7a2125d37..b15456f10 100644 --- a/qa/integration/patch/childprocess-modern-java.rb +++ b/qa/integration/patch/childprocess-modern-java.rb @@ -1,4 +1,19 @@ -# encoding: utf-8 +# 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. # Implementation of ChildProcess::JRuby::Process#pid depends heavily on # what Java SDK is being used; here, we look it up once at load, then @@ -20,4 +35,4 @@ if normalised_java_version_major >= 9 raise NotImplementedError, "pid is not supported on this platform: #{e.message}" end end -end \ No newline at end of file +end diff --git a/qa/integration/rspec.rb b/qa/integration/rspec.rb index e4f350c01..5f62af9e3 100644 --- a/qa/integration/rspec.rb +++ b/qa/integration/rspec.rb @@ -1,4 +1,19 @@ -# encoding: utf-8 +# 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 'rubygems' diff --git a/qa/integration/services/elasticsearch_service.rb b/qa/integration/services/elasticsearch_service.rb index 66963aca5..0b3380838 100644 --- a/qa/integration/services/elasticsearch_service.rb +++ b/qa/integration/services/elasticsearch_service.rb @@ -1,3 +1,20 @@ +# 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 'elasticsearch' class ElasticsearchService < Service diff --git a/qa/integration/services/filebeat_service.rb b/qa/integration/services/filebeat_service.rb index fab124076..f7d104473 100644 --- a/qa/integration/services/filebeat_service.rb +++ b/qa/integration/services/filebeat_service.rb @@ -1,4 +1,20 @@ -# encoding: utf-8 +# 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. + class FilebeatService < Service FILEBEAT_CMD = [File.join(File.dirname(__FILE__), "installed", "filebeat", "filebeat"), "-c"] diff --git a/qa/integration/services/http_proxy_service.rb b/qa/integration/services/http_proxy_service.rb index 66c51b248..10dfd615e 100644 --- a/qa/integration/services/http_proxy_service.rb +++ b/qa/integration/services/http_proxy_service.rb @@ -1,4 +1,20 @@ -# encoding: utf-8 +# 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. + class Http_proxyService < Service def initialize(settings) super("http_proxy", settings) diff --git a/qa/integration/services/kafka_service.rb b/qa/integration/services/kafka_service.rb index 71908f9ac..f2f1f58a9 100644 --- a/qa/integration/services/kafka_service.rb +++ b/qa/integration/services/kafka_service.rb @@ -1,3 +1,20 @@ +# 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 "service" class KafkaService < Service diff --git a/qa/integration/services/logstash_service.rb b/qa/integration/services/logstash_service.rb index a35c46b76..33539b7f3 100644 --- a/qa/integration/services/logstash_service.rb +++ b/qa/integration/services/logstash_service.rb @@ -1,3 +1,20 @@ +# 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 "monitoring_api" require "childprocess" diff --git a/qa/integration/services/monitoring_api.rb b/qa/integration/services/monitoring_api.rb index 99e64792d..5f15fc25a 100644 --- a/qa/integration/services/monitoring_api.rb +++ b/qa/integration/services/monitoring_api.rb @@ -1,3 +1,20 @@ +# 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 "manticore" require "json" diff --git a/qa/integration/services/service.rb b/qa/integration/services/service.rb index 8a11a81bf..11b5dbb99 100644 --- a/qa/integration/services/service.rb +++ b/qa/integration/services/service.rb @@ -1,3 +1,20 @@ +# 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 '../../../logstash-core/lib/logstash-core.rb' # Base class for a service like Kafka, ES, Logstash diff --git a/qa/integration/services/service_locator.rb b/qa/integration/services/service_locator.rb index ff537ebcd..035cbad4a 100644 --- a/qa/integration/services/service_locator.rb +++ b/qa/integration/services/service_locator.rb @@ -1,4 +1,20 @@ -# encoding: utf-8 +# 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 "service" # This is a registry used in Fixtures so a test can get back any service class diff --git a/qa/integration/specs/01_logstash_bin_smoke_spec.rb b/qa/integration/specs/01_logstash_bin_smoke_spec.rb index 5ac15b648..54f682147 100644 --- a/qa/integration/specs/01_logstash_bin_smoke_spec.rb +++ b/qa/integration/specs/01_logstash_bin_smoke_spec.rb @@ -1,3 +1,20 @@ +# 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' diff --git a/qa/integration/specs/beats_input_spec.rb b/qa/integration/specs/beats_input_spec.rb index 39a521a9e..b35956d61 100644 --- a/qa/integration/specs/beats_input_spec.rb +++ b/qa/integration/specs/beats_input_spec.rb @@ -1,3 +1,20 @@ +# 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 "stud/temporary" diff --git a/qa/integration/specs/cli/http_proxy_install_spec.rb b/qa/integration/specs/cli/http_proxy_install_spec.rb index 9ffcef5cd..37665234b 100644 --- a/qa/integration/specs/cli/http_proxy_install_spec.rb +++ b/qa/integration/specs/cli/http_proxy_install_spec.rb @@ -1,4 +1,20 @@ -# encoding: utf-8 +# 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" diff --git a/qa/integration/specs/cli/install_spec.rb b/qa/integration/specs/cli/install_spec.rb index d1c02037c..3e6e742bd 100644 --- a/qa/integration/specs/cli/install_spec.rb +++ b/qa/integration/specs/cli/install_spec.rb @@ -1,4 +1,20 @@ -# encoding: utf-8 +# 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" diff --git a/qa/integration/specs/cli/prepare_offline_pack_spec.rb b/qa/integration/specs/cli/prepare_offline_pack_spec.rb index e691903a6..560a59303 100644 --- a/qa/integration/specs/cli/prepare_offline_pack_spec.rb +++ b/qa/integration/specs/cli/prepare_offline_pack_spec.rb @@ -1,4 +1,20 @@ -# encoding: utf-8 +# 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" diff --git a/qa/integration/specs/cli/remove_spec.rb b/qa/integration/specs/cli/remove_spec.rb index 343b96849..5d6048874 100644 --- a/qa/integration/specs/cli/remove_spec.rb +++ b/qa/integration/specs/cli/remove_spec.rb @@ -1,4 +1,20 @@ -# encoding: utf-8 +# 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' diff --git a/qa/integration/specs/command_line_spec.rb b/qa/integration/specs/command_line_spec.rb index ae07e3024..b38f61346 100644 --- a/qa/integration/specs/command_line_spec.rb +++ b/qa/integration/specs/command_line_spec.rb @@ -1,4 +1,20 @@ -# encoding: utf-8 +# 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 "../framework/helpers" diff --git a/qa/integration/specs/deprecation_log_spec.rb b/qa/integration/specs/deprecation_log_spec.rb index d80ed0873..b80ae750d 100644 --- a/qa/integration/specs/deprecation_log_spec.rb +++ b/qa/integration/specs/deprecation_log_spec.rb @@ -1,3 +1,20 @@ +# 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' diff --git a/qa/integration/specs/dlq_spec.rb b/qa/integration/specs/dlq_spec.rb index d31691776..3145cb55f 100644 --- a/qa/integration/specs/dlq_spec.rb +++ b/qa/integration/specs/dlq_spec.rb @@ -1,3 +1,20 @@ +# 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' diff --git a/qa/integration/specs/env_variables_config_spec.rb b/qa/integration/specs/env_variables_config_spec.rb index d7594c901..248d8c352 100644 --- a/qa/integration/specs/env_variables_config_spec.rb +++ b/qa/integration/specs/env_variables_config_spec.rb @@ -1,3 +1,20 @@ +# 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' diff --git a/qa/integration/specs/es_output_how_spec.rb b/qa/integration/specs/es_output_how_spec.rb index b0f9d56ae..0272e8511 100644 --- a/qa/integration/specs/es_output_how_spec.rb +++ b/qa/integration/specs/es_output_how_spec.rb @@ -1,3 +1,20 @@ +# 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' diff --git a/qa/integration/specs/java_api_spec.rb b/qa/integration/specs/java_api_spec.rb index c27803043..ff21afccd 100644 --- a/qa/integration/specs/java_api_spec.rb +++ b/qa/integration/specs/java_api_spec.rb @@ -1,3 +1,20 @@ +# 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 '../framework/helpers' diff --git a/qa/integration/specs/kafka_input_spec.rb b/qa/integration/specs/kafka_input_spec.rb index bcd26fad0..6e9ac5a0f 100644 --- a/qa/integration/specs/kafka_input_spec.rb +++ b/qa/integration/specs/kafka_input_spec.rb @@ -1,3 +1,20 @@ +# 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' diff --git a/qa/integration/specs/monitoring_api_spec.rb b/qa/integration/specs/monitoring_api_spec.rb index 426263010..a821fdd28 100644 --- a/qa/integration/specs/monitoring_api_spec.rb +++ b/qa/integration/specs/monitoring_api_spec.rb @@ -1,3 +1,20 @@ +# 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' diff --git a/qa/integration/specs/multiple_pipeline_spec.rb b/qa/integration/specs/multiple_pipeline_spec.rb index 2eda19f12..7dba5947b 100644 --- a/qa/integration/specs/multiple_pipeline_spec.rb +++ b/qa/integration/specs/multiple_pipeline_spec.rb @@ -1,3 +1,20 @@ +# 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' diff --git a/qa/integration/specs/pipeline_log_spec.rb b/qa/integration/specs/pipeline_log_spec.rb index 37ee8424f..5a49b1cbe 100644 --- a/qa/integration/specs/pipeline_log_spec.rb +++ b/qa/integration/specs/pipeline_log_spec.rb @@ -1,3 +1,20 @@ +# 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' diff --git a/qa/integration/specs/plugin_name_log_spec.rb b/qa/integration/specs/plugin_name_log_spec.rb index 23e477bf3..68fd8f5d2 100644 --- a/qa/integration/specs/plugin_name_log_spec.rb +++ b/qa/integration/specs/plugin_name_log_spec.rb @@ -1,3 +1,20 @@ +# 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' diff --git a/qa/integration/specs/reload_config_spec.rb b/qa/integration/specs/reload_config_spec.rb index 3c88a5ee7..b4864e435 100644 --- a/qa/integration/specs/reload_config_spec.rb +++ b/qa/integration/specs/reload_config_spec.rb @@ -1,3 +1,20 @@ +# 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' diff --git a/qa/integration/specs/secret_store_spec.rb b/qa/integration/specs/secret_store_spec.rb index 111e6c687..c25aa3202 100644 --- a/qa/integration/specs/secret_store_spec.rb +++ b/qa/integration/specs/secret_store_spec.rb @@ -1,3 +1,20 @@ +# 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' diff --git a/qa/integration/specs/settings_spec.rb b/qa/integration/specs/settings_spec.rb index 238284cce..f1b1a9e01 100644 --- a/qa/integration/specs/settings_spec.rb +++ b/qa/integration/specs/settings_spec.rb @@ -1,3 +1,20 @@ +# 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' diff --git a/qa/integration/specs/slowlog_spec.rb b/qa/integration/specs/slowlog_spec.rb index 10c3f0466..a90cb5005 100644 --- a/qa/integration/specs/slowlog_spec.rb +++ b/qa/integration/specs/slowlog_spec.rb @@ -1,3 +1,20 @@ +# 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' diff --git a/qa/integration/specs/spec_helper.rb b/qa/integration/specs/spec_helper.rb index 138524561..a14e6463a 100644 --- a/qa/integration/specs/spec_helper.rb +++ b/qa/integration/specs/spec_helper.rb @@ -1,4 +1,20 @@ -# encoding: utf-8 +# 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. + RSpec.configure do |config| if RbConfig::CONFIG["host_os"] != "linux" exclude_tags = { :linux => true } diff --git a/qa/integration/src/test/java/org/logstash/integration/RSpecTests.java b/qa/integration/src/test/java/org/logstash/integration/RSpecTests.java index 2167abdf3..edc5f1602 100644 --- a/qa/integration/src/test/java/org/logstash/integration/RSpecTests.java +++ b/qa/integration/src/test/java/org/logstash/integration/RSpecTests.java @@ -1,3 +1,23 @@ +/* + * 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. + */ + + package org.logstash.integration; import java.nio.charset.StandardCharsets; diff --git a/qa/platform_config.rb b/qa/platform_config.rb index 097b7ef6a..3e7d5114a 100644 --- a/qa/platform_config.rb +++ b/qa/platform_config.rb @@ -1,4 +1,20 @@ -# encoding: utf-8 +# 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 "json" require "ostruct" diff --git a/qa/rspec/commands.rb b/qa/rspec/commands.rb index f90bc74cc..4b48fcd1c 100644 --- a/qa/rspec/commands.rb +++ b/qa/rspec/commands.rb @@ -1,4 +1,20 @@ -# encoding: utf-8 +# 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 "./commands/debian" require_relative "./commands/ubuntu" require_relative "./commands/redhat" diff --git a/qa/rspec/commands/base.rb b/qa/rspec/commands/base.rb index 3f06c2a02..52804c862 100644 --- a/qa/rspec/commands/base.rb +++ b/qa/rspec/commands/base.rb @@ -1,4 +1,20 @@ -# encoding: utf-8 +# 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 "../../vagrant/helpers" require_relative "system_helpers" diff --git a/qa/rspec/commands/centos/centos-6.rb b/qa/rspec/commands/centos/centos-6.rb index 371590490..011f89287 100644 --- a/qa/rspec/commands/centos/centos-6.rb +++ b/qa/rspec/commands/centos/centos-6.rb @@ -1,4 +1,20 @@ -# encoding: utf-8 +# 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 "../base" require_relative "../redhat" diff --git a/qa/rspec/commands/debian.rb b/qa/rspec/commands/debian.rb index 30fa8c8da..f4a6d490a 100644 --- a/qa/rspec/commands/debian.rb +++ b/qa/rspec/commands/debian.rb @@ -1,4 +1,20 @@ -# encoding: utf-8 +# 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 "base" module ServiceTester diff --git a/qa/rspec/commands/oel/oel-6.rb b/qa/rspec/commands/oel/oel-6.rb index ed92a8ce1..9033cd8b9 100644 --- a/qa/rspec/commands/oel/oel-6.rb +++ b/qa/rspec/commands/oel/oel-6.rb @@ -1,4 +1,20 @@ -# encoding: utf-8 +# 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 "../base" require_relative "../redhat" diff --git a/qa/rspec/commands/redhat.rb b/qa/rspec/commands/redhat.rb index b7dce8048..eaa6a1964 100644 --- a/qa/rspec/commands/redhat.rb +++ b/qa/rspec/commands/redhat.rb @@ -1,4 +1,20 @@ -# encoding: utf-8 +# 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 "base" module ServiceTester diff --git a/qa/rspec/commands/suse.rb b/qa/rspec/commands/suse.rb index 9b1e6eee9..733c0685a 100644 --- a/qa/rspec/commands/suse.rb +++ b/qa/rspec/commands/suse.rb @@ -1,4 +1,20 @@ -# encoding: utf-8 +# 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 "base" module ServiceTester diff --git a/qa/rspec/commands/suse/sles-11.rb b/qa/rspec/commands/suse/sles-11.rb index 80dd94dd7..7b3d792ec 100644 --- a/qa/rspec/commands/suse/sles-11.rb +++ b/qa/rspec/commands/suse/sles-11.rb @@ -1,4 +1,20 @@ -# encoding: utf-8 +# 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 "../base" require_relative "../suse" diff --git a/qa/rspec/commands/system_helpers.rb b/qa/rspec/commands/system_helpers.rb index 8cb892294..a720f7c84 100644 --- a/qa/rspec/commands/system_helpers.rb +++ b/qa/rspec/commands/system_helpers.rb @@ -1,3 +1,20 @@ +# 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 "base" module ServiceTester diff --git a/qa/rspec/commands/ubuntu.rb b/qa/rspec/commands/ubuntu.rb index 1d1ae75f9..00c9fe9d1 100644 --- a/qa/rspec/commands/ubuntu.rb +++ b/qa/rspec/commands/ubuntu.rb @@ -1,4 +1,20 @@ -# encoding: utf-8 +# 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 "debian" module ServiceTester diff --git a/qa/rspec/commands/ubuntu/ubuntu-1604.rb b/qa/rspec/commands/ubuntu/ubuntu-1604.rb index ae26bc09f..8765c15a1 100644 --- a/qa/rspec/commands/ubuntu/ubuntu-1604.rb +++ b/qa/rspec/commands/ubuntu/ubuntu-1604.rb @@ -1,4 +1,20 @@ -# encoding: utf-8 +# 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 "../base" require_relative "../ubuntu" diff --git a/qa/rspec/helpers.rb b/qa/rspec/helpers.rb index a939fa7df..3a457bc77 100644 --- a/qa/rspec/helpers.rb +++ b/qa/rspec/helpers.rb @@ -1,4 +1,20 @@ -# encoding: utf-8 +# 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 "commands" module ServiceTester diff --git a/qa/rspec/matchers.rb b/qa/rspec/matchers.rb index 4da583262..b5bd3c753 100644 --- a/qa/rspec/matchers.rb +++ b/qa/rspec/matchers.rb @@ -1,4 +1,20 @@ -# encoding: utf-8 +# 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 "./matchers/be_installed" require_relative "./matchers/be_running" require_relative "./matchers/cli_matchers" diff --git a/qa/rspec/matchers/be_installed.rb b/qa/rspec/matchers/be_installed.rb index 4de70ae21..ea2c9990c 100644 --- a/qa/rspec/matchers/be_installed.rb +++ b/qa/rspec/matchers/be_installed.rb @@ -1,4 +1,20 @@ -# encoding: utf-8 +# 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 'rspec/expectations' require_relative '../helpers' diff --git a/qa/rspec/matchers/be_running.rb b/qa/rspec/matchers/be_running.rb index dc687e1b1..c02777693 100644 --- a/qa/rspec/matchers/be_running.rb +++ b/qa/rspec/matchers/be_running.rb @@ -1,4 +1,20 @@ -# encoding: utf-8 +# 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 'rspec/expectations' require_relative '../helpers' diff --git a/qa/rspec/matchers/cli_matchers.rb b/qa/rspec/matchers/cli_matchers.rb index e31aa050a..9182080e2 100644 --- a/qa/rspec/matchers/cli_matchers.rb +++ b/qa/rspec/matchers/cli_matchers.rb @@ -1,4 +1,20 @@ -# encoding: utf-8 +# 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. + RSpec::Matchers.define :be_successful do match do |actual| actual.exit_status == 0 diff --git a/qa/vagrant/command.rb b/qa/vagrant/command.rb index a07b71f81..177df5821 100644 --- a/qa/vagrant/command.rb +++ b/qa/vagrant/command.rb @@ -1,4 +1,20 @@ -# encoding: utf-8 +# 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 "open3" require "bundler" diff --git a/qa/vagrant/helpers.rb b/qa/vagrant/helpers.rb index 9c65f714f..5125f6490 100644 --- a/qa/vagrant/helpers.rb +++ b/qa/vagrant/helpers.rb @@ -1,4 +1,20 @@ -# encoding: utf-8 +# 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 "open3" require "bundler" require_relative "command" diff --git a/rakelib/artifacts.rake b/rakelib/artifacts.rake index 46e32ad9c..f91b2fe67 100644 --- a/rakelib/artifacts.rake +++ b/rakelib/artifacts.rake @@ -1,3 +1,20 @@ +# 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. + namespace "artifact" do SNAPSHOT_BUILD = ENV["RELEASE"] != "1" diff --git a/rakelib/bootstrap.rake b/rakelib/bootstrap.rake index 7d9c2e688..23dfe93ff 100644 --- a/rakelib/bootstrap.rake +++ b/rakelib/bootstrap.rake @@ -1 +1,18 @@ +# 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. + task "bootstrap" => [ "vendor:all", "compile:all" ] diff --git a/rakelib/build.rake b/rakelib/build.rake index 45aec1f9b..79f412538 100644 --- a/rakelib/build.rake +++ b/rakelib/build.rake @@ -1,3 +1,20 @@ +# 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. + directory "build" do |task, args| mkdir_p task.name unless File.directory?(task.name) end diff --git a/rakelib/childprocess_patch.rb b/rakelib/childprocess_patch.rb index a62bdbc46..9ab057789 100644 --- a/rakelib/childprocess_patch.rb +++ b/rakelib/childprocess_patch.rb @@ -1,3 +1,20 @@ +# 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. + # This is a patch for childprocess and this is due to ruby-cabin/fpm interaction. # When we use the logger.pipe construct and the IO reach EOF we close the IO. # The problem Childprocess will try to flush to it and hit an IOError making the software crash in JRuby 9k. diff --git a/rakelib/compile.rake b/rakelib/compile.rake index 53c7f8c9a..f06833d31 100644 --- a/rakelib/compile.rake +++ b/rakelib/compile.rake @@ -1,3 +1,19 @@ +# 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. rule ".rb" => ".treetop" do |task, args| require "treetop" diff --git a/rakelib/default_plugins.rb b/rakelib/default_plugins.rb index 095cbe29a..8df255dd7 100644 --- a/rakelib/default_plugins.rb +++ b/rakelib/default_plugins.rb @@ -1,3 +1,20 @@ +# 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. + module LogStash module RakeLib diff --git a/rakelib/dependency.rake b/rakelib/dependency.rake index 717f7a421..3ca2ca54b 100644 --- a/rakelib/dependency.rake +++ b/rakelib/dependency.rake @@ -1,3 +1,20 @@ +# 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. + namespace "dependency" do task "bundler" do Rake::Task["gem:require"].invoke("bundler", "~> 1.17.3") diff --git a/rakelib/docs.rake b/rakelib/docs.rake index 6bd37d402..8971f30c2 100644 --- a/rakelib/docs.rake +++ b/rakelib/docs.rake @@ -1,4 +1,20 @@ -# encoding: utf-8 +# 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 "fileutils" DEFAULT_DOC_DIRECTORY = ::File.join(::File.dirname(__FILE__), "..", "build", "docs") diff --git a/rakelib/gems.rake b/rakelib/gems.rake index b5761f0db..c8e87cb18 100644 --- a/rakelib/gems.rake +++ b/rakelib/gems.rake @@ -1,3 +1,20 @@ +# 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 "rubygems/specification" require "rubygems/commands/install_command" diff --git a/rakelib/modules.rake b/rakelib/modules.rake index e90818524..fc09509d4 100644 --- a/rakelib/modules.rake +++ b/rakelib/modules.rake @@ -1,3 +1,20 @@ +# 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. + namespace "modules" do def unpacker(src_file, dest_dir) diff --git a/rakelib/plugin.rake b/rakelib/plugin.rake index e50994631..fc7f025b4 100644 --- a/rakelib/plugin.rake +++ b/rakelib/plugin.rake @@ -1,3 +1,20 @@ +# 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 "default_plugins" require 'rubygems' diff --git a/rakelib/plugins_docs_dependencies.rake b/rakelib/plugins_docs_dependencies.rake index 69e4d9f53..c01d1d27d 100644 --- a/rakelib/plugins_docs_dependencies.rake +++ b/rakelib/plugins_docs_dependencies.rake @@ -1,4 +1,20 @@ -# encoding: utf-8 +# 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 'json' class PluginVersionWorking diff --git a/rakelib/test.rake b/rakelib/test.rake index 81f131452..bc16097aa 100644 --- a/rakelib/test.rake +++ b/rakelib/test.rake @@ -1,3 +1,20 @@ +# 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. + # we need to call exit explicitly in order to set the proper exit code, otherwise # most common CI systems can not know whats up with this tests. diff --git a/rakelib/vendor.rake b/rakelib/vendor.rake index 01777a15e..73697038b 100644 --- a/rakelib/vendor.rake +++ b/rakelib/vendor.rake @@ -1,3 +1,20 @@ +# 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. + namespace "vendor" do def vendor(*args) return File.join("vendor", *args) diff --git a/rakelib/version.rake b/rakelib/version.rake index 6a5396d0f..144ba9b9c 100644 --- a/rakelib/version.rake +++ b/rakelib/version.rake @@ -1,3 +1,20 @@ +# 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 'yaml' VERSION_FILE = "versions.yml" diff --git a/rakelib/z_rubycheck.rake b/rakelib/z_rubycheck.rake index be782fde6..ab64deacd 100644 --- a/rakelib/z_rubycheck.rake +++ b/rakelib/z_rubycheck.rake @@ -1,3 +1,20 @@ +# 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. + if ENV['USE_RUBY'] != '1' if RUBY_ENGINE != "jruby" or Gem.ruby !~ /vendor\/jruby\/bin\/jruby/ puts "Restarting myself under Vendored JRuby (currently #{RUBY_ENGINE} #{RUBY_VERSION})" if ENV['DEBUG'] diff --git a/rubyUtils.gradle b/rubyUtils.gradle index 242419ded..db65c5434 100644 --- a/rubyUtils.gradle +++ b/rubyUtils.gradle @@ -1,3 +1,22 @@ +/* + * 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. + */ + buildscript { repositories { diff --git a/spec/bootstrap/environment_spec.rb b/spec/bootstrap/environment_spec.rb index f31cfcd38..95d432bc5 100644 --- a/spec/bootstrap/environment_spec.rb +++ b/spec/bootstrap/environment_spec.rb @@ -1,4 +1,20 @@ -# encoding: utf-8 +# 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 "spec_helper" require "bootstrap/environment" diff --git a/spec/compliance/license_spec.rb b/spec/compliance/license_spec.rb index d42b1cd44..7d32e9693 100644 --- a/spec/compliance/license_spec.rb +++ b/spec/compliance/license_spec.rb @@ -1,4 +1,19 @@ -# encoding: utf-8 +# 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 'spec_helper' require_relative '../../rakelib/default_plugins' diff --git a/spec/spec_helper.rb b/spec/spec_helper.rb index 674f7823b..8b13d49bf 100644 --- a/spec/spec_helper.rb +++ b/spec/spec_helper.rb @@ -1,4 +1,19 @@ -# encoding: utf-8 +# 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 "logstash/devutils/rspec/spec_helper" @@ -57,4 +72,3 @@ end def installed_plugins Gem::Specification.find_all.select { |spec| spec.metadata["logstash_plugin"] }.map { |plugin| plugin.name } end - diff --git a/spec/support/resource_dsl_methods.rb b/spec/support/resource_dsl_methods.rb index 3eb9ce8e4..ecff9b444 100644 --- a/spec/support/resource_dsl_methods.rb +++ b/spec/support/resource_dsl_methods.rb @@ -1,3 +1,20 @@ +# 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. + # Ruby doesn't have common class for boolean, # And to simplify the ResourceDSLMethods check it make sense to have it. module Boolean; end diff --git a/spec/unit/bootstrap/bundler_spec.rb b/spec/unit/bootstrap/bundler_spec.rb index 1216ddbe7..98a73cbe1 100644 --- a/spec/unit/bootstrap/bundler_spec.rb +++ b/spec/unit/bootstrap/bundler_spec.rb @@ -1,4 +1,20 @@ -# encoding: utf-8 +# 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 "spec_helper" require "bundler/cli" diff --git a/spec/unit/plugin_manager/gem_installer_spec.rb b/spec/unit/plugin_manager/gem_installer_spec.rb index ce593b4b3..cf57c9c4a 100644 --- a/spec/unit/plugin_manager/gem_installer_spec.rb +++ b/spec/unit/plugin_manager/gem_installer_spec.rb @@ -1,4 +1,20 @@ -# encoding: utf-8 +# 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 "pluginmanager/gem_installer" require "pluginmanager/ui" require "stud/temporary" diff --git a/spec/unit/plugin_manager/gemfile_spec.rb b/spec/unit/plugin_manager/gemfile_spec.rb index f4909c5bb..26e946be1 100644 --- a/spec/unit/plugin_manager/gemfile_spec.rb +++ b/spec/unit/plugin_manager/gemfile_spec.rb @@ -1,4 +1,20 @@ -# encoding: utf-8 +# 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 "spec_helper" require "pluginmanager/gemfile" diff --git a/spec/unit/plugin_manager/install_spec.rb b/spec/unit/plugin_manager/install_spec.rb index e6f44337b..efaa24ea4 100644 --- a/spec/unit/plugin_manager/install_spec.rb +++ b/spec/unit/plugin_manager/install_spec.rb @@ -1,4 +1,20 @@ -# encoding: utf-8 +# 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 'spec_helper' require 'pluginmanager/main' require "pluginmanager/pack_fetch_strategy/repository" diff --git a/spec/unit/plugin_manager/install_strategy_factory_spec.rb b/spec/unit/plugin_manager/install_strategy_factory_spec.rb index 00bdcd2b4..8e0969d8d 100644 --- a/spec/unit/plugin_manager/install_strategy_factory_spec.rb +++ b/spec/unit/plugin_manager/install_strategy_factory_spec.rb @@ -1,4 +1,20 @@ -# encoding: utf-8 +# 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 "pluginmanager/install_strategy_factory" describe LogStash::PluginManager::InstallStrategyFactory do diff --git a/spec/unit/plugin_manager/offline_plugin_packager_spec.rb b/spec/unit/plugin_manager/offline_plugin_packager_spec.rb index 367dece5d..c66e7d66d 100644 --- a/spec/unit/plugin_manager/offline_plugin_packager_spec.rb +++ b/spec/unit/plugin_manager/offline_plugin_packager_spec.rb @@ -1,4 +1,20 @@ -# encoding: utf-8 +# 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 "pluginmanager/offline_plugin_packager" require "stud/temporary" require "stud/try" diff --git a/spec/unit/plugin_manager/pack_fetch_strategy/repository_spec.rb b/spec/unit/plugin_manager/pack_fetch_strategy/repository_spec.rb index 4a6ad7b6f..a24adb4be 100644 --- a/spec/unit/plugin_manager/pack_fetch_strategy/repository_spec.rb +++ b/spec/unit/plugin_manager/pack_fetch_strategy/repository_spec.rb @@ -1,4 +1,20 @@ -# encoding: utf-8 +# 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 "pluginmanager/pack_fetch_strategy/repository" require "uri" require "webmock/rspec" diff --git a/spec/unit/plugin_manager/pack_fetch_strategy/uri_spec.rb b/spec/unit/plugin_manager/pack_fetch_strategy/uri_spec.rb index 210b32d5b..5aa1c19d9 100644 --- a/spec/unit/plugin_manager/pack_fetch_strategy/uri_spec.rb +++ b/spec/unit/plugin_manager/pack_fetch_strategy/uri_spec.rb @@ -1,4 +1,20 @@ -# encoding: utf-8 +# 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 "pluginmanager/pack_fetch_strategy/uri" require "stud/temporary" diff --git a/spec/unit/plugin_manager/pack_installer/local_spec.rb b/spec/unit/plugin_manager/pack_installer/local_spec.rb index ffc165bb2..c3077b832 100644 --- a/spec/unit/plugin_manager/pack_installer/local_spec.rb +++ b/spec/unit/plugin_manager/pack_installer/local_spec.rb @@ -1,4 +1,20 @@ -# encoding: utf-8 +# 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 "pluginmanager/pack_installer/local" require "stud/temporary" require "fileutils" diff --git a/spec/unit/plugin_manager/pack_installer/pack_spec.rb b/spec/unit/plugin_manager/pack_installer/pack_spec.rb index 845f4278f..617c0adc0 100644 --- a/spec/unit/plugin_manager/pack_installer/pack_spec.rb +++ b/spec/unit/plugin_manager/pack_installer/pack_spec.rb @@ -1,4 +1,20 @@ -# encoding: utf-8 +# 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 "pluginmanager/pack_installer/pack" require "stud/temporary" diff --git a/spec/unit/plugin_manager/pack_installer/remote_spec.rb b/spec/unit/plugin_manager/pack_installer/remote_spec.rb index c6daf9ba1..97463487b 100644 --- a/spec/unit/plugin_manager/pack_installer/remote_spec.rb +++ b/spec/unit/plugin_manager/pack_installer/remote_spec.rb @@ -1,4 +1,20 @@ -# encoding: utf-8 +# 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 "pluginmanager/pack_installer/remote" require "webmock/rspec" diff --git a/spec/unit/plugin_manager/prepare_offline_pack_spec.rb b/spec/unit/plugin_manager/prepare_offline_pack_spec.rb index 9c55457d0..2685d85e2 100644 --- a/spec/unit/plugin_manager/prepare_offline_pack_spec.rb +++ b/spec/unit/plugin_manager/prepare_offline_pack_spec.rb @@ -1,4 +1,20 @@ -# encoding: utf-8 +# 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 "spec_helper" require "pluginmanager/main" require "pluginmanager/prepare_offline_pack" diff --git a/spec/unit/plugin_manager/proxy_support_spec.rb b/spec/unit/plugin_manager/proxy_support_spec.rb index 4e7df213a..9c2beb995 100644 --- a/spec/unit/plugin_manager/proxy_support_spec.rb +++ b/spec/unit/plugin_manager/proxy_support_spec.rb @@ -1,4 +1,20 @@ -# encoding: utf-8 +# 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 "pluginmanager/proxy_support" require "rexml/document" require "fileutils" diff --git a/spec/unit/plugin_manager/ui_spec.rb b/spec/unit/plugin_manager/ui_spec.rb index faca7b3a6..c1f242576 100644 --- a/spec/unit/plugin_manager/ui_spec.rb +++ b/spec/unit/plugin_manager/ui_spec.rb @@ -1,4 +1,20 @@ -# encoding: utf-8 +# 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 "pluginmanager/ui" describe LogStash::PluginManager do it "set the a default ui" do diff --git a/spec/unit/plugin_manager/update_spec.rb b/spec/unit/plugin_manager/update_spec.rb index 3fc4d1d62..2bd719bbc 100644 --- a/spec/unit/plugin_manager/update_spec.rb +++ b/spec/unit/plugin_manager/update_spec.rb @@ -1,4 +1,20 @@ -# encoding: utf-8 +# 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 'spec_helper' require 'pluginmanager/main' diff --git a/spec/unit/plugin_manager/util_spec.rb b/spec/unit/plugin_manager/util_spec.rb index 669a18688..bdf9705d8 100644 --- a/spec/unit/plugin_manager/util_spec.rb +++ b/spec/unit/plugin_manager/util_spec.rb @@ -1,4 +1,20 @@ -#encoding: utf-8 +# 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 'spec_helper' require 'pluginmanager/util' require 'gems' diff --git a/spec/unit/plugin_manager/utils/downloader_spec.rb b/spec/unit/plugin_manager/utils/downloader_spec.rb index 2f7a105eb..aed0e07c0 100644 --- a/spec/unit/plugin_manager/utils/downloader_spec.rb +++ b/spec/unit/plugin_manager/utils/downloader_spec.rb @@ -1,4 +1,20 @@ -# encoding: utf-8 +# 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 "pluginmanager/utils/downloader" require "spec_helper" require "webmock/rspec" diff --git a/spec/unit/plugin_manager/utils/http_client_spec.rb b/spec/unit/plugin_manager/utils/http_client_spec.rb index e0d6510bd..d72aa16a7 100644 --- a/spec/unit/plugin_manager/utils/http_client_spec.rb +++ b/spec/unit/plugin_manager/utils/http_client_spec.rb @@ -1,4 +1,20 @@ -# encoding: utf-8 +# 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 "pluginmanager/utils/http_client" require "uri" diff --git a/spec/unit/util/compress_spec.rb b/spec/unit/util/compress_spec.rb index 33133c093..98b031037 100644 --- a/spec/unit/util/compress_spec.rb +++ b/spec/unit/util/compress_spec.rb @@ -1,4 +1,20 @@ -# encoding: utf-8 +# 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 "spec_helper" require 'ostruct' require "bootstrap/util/compress" diff --git a/tools/benchmark-cli/build.gradle b/tools/benchmark-cli/build.gradle index 9668d7ba2..7f63b350e 100644 --- a/tools/benchmark-cli/build.gradle +++ b/tools/benchmark-cli/build.gradle @@ -1,3 +1,22 @@ +/* + * 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. + */ + import org.yaml.snakeyaml.Yaml // fetch version from Logstash's master versions.yml file diff --git a/tools/benchmark-cli/src/main/java/org/logstash/benchmark/cli/BenchmarkMeta.java b/tools/benchmark-cli/src/main/java/org/logstash/benchmark/cli/BenchmarkMeta.java index 29538855e..fb00107ea 100644 --- a/tools/benchmark-cli/src/main/java/org/logstash/benchmark/cli/BenchmarkMeta.java +++ b/tools/benchmark-cli/src/main/java/org/logstash/benchmark/cli/BenchmarkMeta.java @@ -1,3 +1,23 @@ +/* + * 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. + */ + + package org.logstash.benchmark.cli; import java.net.InetAddress; diff --git a/tools/benchmark-cli/src/main/java/org/logstash/benchmark/cli/DataStore.java b/tools/benchmark-cli/src/main/java/org/logstash/benchmark/cli/DataStore.java index 872993fbf..04d463046 100644 --- a/tools/benchmark-cli/src/main/java/org/logstash/benchmark/cli/DataStore.java +++ b/tools/benchmark-cli/src/main/java/org/logstash/benchmark/cli/DataStore.java @@ -1,3 +1,23 @@ +/* + * 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. + */ + + package org.logstash.benchmark.cli; import java.io.Closeable; diff --git a/tools/benchmark-cli/src/main/java/org/logstash/benchmark/cli/JRubyInstallation.java b/tools/benchmark-cli/src/main/java/org/logstash/benchmark/cli/JRubyInstallation.java index 044dc312f..5d28cb8a0 100644 --- a/tools/benchmark-cli/src/main/java/org/logstash/benchmark/cli/JRubyInstallation.java +++ b/tools/benchmark-cli/src/main/java/org/logstash/benchmark/cli/JRubyInstallation.java @@ -1,3 +1,23 @@ +/* + * 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. + */ + + package org.logstash.benchmark.cli; import java.io.IOException; diff --git a/tools/benchmark-cli/src/main/java/org/logstash/benchmark/cli/LogstashInstallation.java b/tools/benchmark-cli/src/main/java/org/logstash/benchmark/cli/LogstashInstallation.java index 189faca0c..a509fdbd7 100644 --- a/tools/benchmark-cli/src/main/java/org/logstash/benchmark/cli/LogstashInstallation.java +++ b/tools/benchmark-cli/src/main/java/org/logstash/benchmark/cli/LogstashInstallation.java @@ -1,3 +1,23 @@ +/* + * 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. + */ + + package org.logstash.benchmark.cli; import java.io.File; diff --git a/tools/benchmark-cli/src/main/java/org/logstash/benchmark/cli/LsBenchSettings.java b/tools/benchmark-cli/src/main/java/org/logstash/benchmark/cli/LsBenchSettings.java index e793284d4..a80980456 100644 --- a/tools/benchmark-cli/src/main/java/org/logstash/benchmark/cli/LsBenchSettings.java +++ b/tools/benchmark-cli/src/main/java/org/logstash/benchmark/cli/LsBenchSettings.java @@ -1,3 +1,23 @@ +/* + * 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. + */ + + package org.logstash.benchmark.cli; /** diff --git a/tools/benchmark-cli/src/main/java/org/logstash/benchmark/cli/LsMetricsMonitor.java b/tools/benchmark-cli/src/main/java/org/logstash/benchmark/cli/LsMetricsMonitor.java index d482cf0bc..7e34fc6de 100644 --- a/tools/benchmark-cli/src/main/java/org/logstash/benchmark/cli/LsMetricsMonitor.java +++ b/tools/benchmark-cli/src/main/java/org/logstash/benchmark/cli/LsMetricsMonitor.java @@ -1,3 +1,23 @@ +/* + * 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. + */ + + package org.logstash.benchmark.cli; import java.io.ByteArrayOutputStream; diff --git a/tools/benchmark-cli/src/main/java/org/logstash/benchmark/cli/Main.java b/tools/benchmark-cli/src/main/java/org/logstash/benchmark/cli/Main.java index 725df18bc..a61085ae7 100644 --- a/tools/benchmark-cli/src/main/java/org/logstash/benchmark/cli/Main.java +++ b/tools/benchmark-cli/src/main/java/org/logstash/benchmark/cli/Main.java @@ -1,3 +1,23 @@ +/* + * 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. + */ + + package org.logstash.benchmark.cli; import java.io.File; diff --git a/tools/benchmark-cli/src/main/java/org/logstash/benchmark/cli/cases/ApacheLogsComplex.java b/tools/benchmark-cli/src/main/java/org/logstash/benchmark/cli/cases/ApacheLogsComplex.java index d10aad2aa..7247f37c2 100644 --- a/tools/benchmark-cli/src/main/java/org/logstash/benchmark/cli/cases/ApacheLogsComplex.java +++ b/tools/benchmark-cli/src/main/java/org/logstash/benchmark/cli/cases/ApacheLogsComplex.java @@ -1,3 +1,23 @@ +/* + * 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. + */ + + package org.logstash.benchmark.cli.cases; import java.io.ByteArrayOutputStream; diff --git a/tools/benchmark-cli/src/main/java/org/logstash/benchmark/cli/cases/Case.java b/tools/benchmark-cli/src/main/java/org/logstash/benchmark/cli/cases/Case.java index c88e3aca4..d5054580c 100644 --- a/tools/benchmark-cli/src/main/java/org/logstash/benchmark/cli/cases/Case.java +++ b/tools/benchmark-cli/src/main/java/org/logstash/benchmark/cli/cases/Case.java @@ -1,3 +1,23 @@ +/* + * 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. + */ + + package org.logstash.benchmark.cli.cases; import java.util.AbstractMap; diff --git a/tools/benchmark-cli/src/main/java/org/logstash/benchmark/cli/cases/CustomTestCase.java b/tools/benchmark-cli/src/main/java/org/logstash/benchmark/cli/cases/CustomTestCase.java index d06bfe0ee..12a53d237 100644 --- a/tools/benchmark-cli/src/main/java/org/logstash/benchmark/cli/cases/CustomTestCase.java +++ b/tools/benchmark-cli/src/main/java/org/logstash/benchmark/cli/cases/CustomTestCase.java @@ -1,3 +1,23 @@ +/* + * 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. + */ + + package org.logstash.benchmark.cli.cases; import org.apache.commons.io.IOUtils; diff --git a/tools/benchmark-cli/src/main/java/org/logstash/benchmark/cli/cases/GeneratorToStdout.java b/tools/benchmark-cli/src/main/java/org/logstash/benchmark/cli/cases/GeneratorToStdout.java index 18858fc78..6538ff73e 100644 --- a/tools/benchmark-cli/src/main/java/org/logstash/benchmark/cli/cases/GeneratorToStdout.java +++ b/tools/benchmark-cli/src/main/java/org/logstash/benchmark/cli/cases/GeneratorToStdout.java @@ -1,3 +1,23 @@ +/* + * 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. + */ + + package org.logstash.benchmark.cli.cases; import java.io.IOException; diff --git a/tools/benchmark-cli/src/main/java/org/logstash/benchmark/cli/ui/LsMetricStats.java b/tools/benchmark-cli/src/main/java/org/logstash/benchmark/cli/ui/LsMetricStats.java index 7a99b176a..86f560724 100644 --- a/tools/benchmark-cli/src/main/java/org/logstash/benchmark/cli/ui/LsMetricStats.java +++ b/tools/benchmark-cli/src/main/java/org/logstash/benchmark/cli/ui/LsMetricStats.java @@ -1,3 +1,23 @@ +/* + * 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. + */ + + package org.logstash.benchmark.cli.ui; /** diff --git a/tools/benchmark-cli/src/main/java/org/logstash/benchmark/cli/ui/LsVersionType.java b/tools/benchmark-cli/src/main/java/org/logstash/benchmark/cli/ui/LsVersionType.java index 1f0787663..b4da85f5a 100644 --- a/tools/benchmark-cli/src/main/java/org/logstash/benchmark/cli/ui/LsVersionType.java +++ b/tools/benchmark-cli/src/main/java/org/logstash/benchmark/cli/ui/LsVersionType.java @@ -1,3 +1,23 @@ +/* + * 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. + */ + + package org.logstash.benchmark.cli.ui; /** diff --git a/tools/benchmark-cli/src/main/java/org/logstash/benchmark/cli/ui/UserInput.java b/tools/benchmark-cli/src/main/java/org/logstash/benchmark/cli/ui/UserInput.java index d5c504474..7cecdcdc5 100644 --- a/tools/benchmark-cli/src/main/java/org/logstash/benchmark/cli/ui/UserInput.java +++ b/tools/benchmark-cli/src/main/java/org/logstash/benchmark/cli/ui/UserInput.java @@ -1,3 +1,23 @@ +/* + * 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. + */ + + package org.logstash.benchmark.cli.ui; import java.io.File; diff --git a/tools/benchmark-cli/src/main/java/org/logstash/benchmark/cli/ui/UserOutput.java b/tools/benchmark-cli/src/main/java/org/logstash/benchmark/cli/ui/UserOutput.java index 3b23c73c0..98bfa9301 100644 --- a/tools/benchmark-cli/src/main/java/org/logstash/benchmark/cli/ui/UserOutput.java +++ b/tools/benchmark-cli/src/main/java/org/logstash/benchmark/cli/ui/UserOutput.java @@ -1,3 +1,23 @@ +/* + * 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. + */ + + package org.logstash.benchmark.cli.ui; import java.io.PrintStream; diff --git a/tools/benchmark-cli/src/main/java/org/logstash/benchmark/cli/util/LsBenchCompressUtil.java b/tools/benchmark-cli/src/main/java/org/logstash/benchmark/cli/util/LsBenchCompressUtil.java index cfaeee4ab..4b59a6381 100644 --- a/tools/benchmark-cli/src/main/java/org/logstash/benchmark/cli/util/LsBenchCompressUtil.java +++ b/tools/benchmark-cli/src/main/java/org/logstash/benchmark/cli/util/LsBenchCompressUtil.java @@ -1,3 +1,23 @@ +/* + * 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. + */ + + package org.logstash.benchmark.cli.util; import java.io.BufferedInputStream; diff --git a/tools/benchmark-cli/src/main/java/org/logstash/benchmark/cli/util/LsBenchDownloader.java b/tools/benchmark-cli/src/main/java/org/logstash/benchmark/cli/util/LsBenchDownloader.java index 30feda67a..6a3e94002 100644 --- a/tools/benchmark-cli/src/main/java/org/logstash/benchmark/cli/util/LsBenchDownloader.java +++ b/tools/benchmark-cli/src/main/java/org/logstash/benchmark/cli/util/LsBenchDownloader.java @@ -1,3 +1,23 @@ +/* + * 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. + */ + + package org.logstash.benchmark.cli.util; import java.io.BufferedOutputStream; diff --git a/tools/benchmark-cli/src/main/java/org/logstash/benchmark/cli/util/LsBenchFileUtil.java b/tools/benchmark-cli/src/main/java/org/logstash/benchmark/cli/util/LsBenchFileUtil.java index 66e5696c1..a772af3dd 100644 --- a/tools/benchmark-cli/src/main/java/org/logstash/benchmark/cli/util/LsBenchFileUtil.java +++ b/tools/benchmark-cli/src/main/java/org/logstash/benchmark/cli/util/LsBenchFileUtil.java @@ -1,3 +1,23 @@ +/* + * 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. + */ + + package org.logstash.benchmark.cli.util; import java.io.File; diff --git a/tools/benchmark-cli/src/main/java/org/logstash/benchmark/cli/util/LsBenchJsonUtil.java b/tools/benchmark-cli/src/main/java/org/logstash/benchmark/cli/util/LsBenchJsonUtil.java index 6e4c34711..0f9fac079 100644 --- a/tools/benchmark-cli/src/main/java/org/logstash/benchmark/cli/util/LsBenchJsonUtil.java +++ b/tools/benchmark-cli/src/main/java/org/logstash/benchmark/cli/util/LsBenchJsonUtil.java @@ -1,3 +1,23 @@ +/* + * 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. + */ + + package org.logstash.benchmark.cli.util; import com.fasterxml.jackson.core.JsonProcessingException; diff --git a/tools/benchmark-cli/src/main/java/org/logstash/benchmark/cli/util/LsBenchLsSetup.java b/tools/benchmark-cli/src/main/java/org/logstash/benchmark/cli/util/LsBenchLsSetup.java index 3064f42d6..6688cc4bb 100644 --- a/tools/benchmark-cli/src/main/java/org/logstash/benchmark/cli/util/LsBenchLsSetup.java +++ b/tools/benchmark-cli/src/main/java/org/logstash/benchmark/cli/util/LsBenchLsSetup.java @@ -1,3 +1,23 @@ +/* + * 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. + */ + + package org.logstash.benchmark.cli.util; import java.io.File; diff --git a/tools/benchmark-cli/src/test/java/org/logstash/benchmark/cli/LsMetricsMonitorTest.java b/tools/benchmark-cli/src/test/java/org/logstash/benchmark/cli/LsMetricsMonitorTest.java index cd7b03808..d7af73e50 100644 --- a/tools/benchmark-cli/src/test/java/org/logstash/benchmark/cli/LsMetricsMonitorTest.java +++ b/tools/benchmark-cli/src/test/java/org/logstash/benchmark/cli/LsMetricsMonitorTest.java @@ -1,3 +1,23 @@ +/* + * 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. + */ + + package org.logstash.benchmark.cli; import com.github.tomakehurst.wiremock.client.WireMock; diff --git a/tools/benchmark-cli/src/test/java/org/logstash/benchmark/cli/MainEsStorageTest.java b/tools/benchmark-cli/src/test/java/org/logstash/benchmark/cli/MainEsStorageTest.java index 9b48a2c98..276cdb54d 100644 --- a/tools/benchmark-cli/src/test/java/org/logstash/benchmark/cli/MainEsStorageTest.java +++ b/tools/benchmark-cli/src/test/java/org/logstash/benchmark/cli/MainEsStorageTest.java @@ -1,3 +1,23 @@ +/* + * 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. + */ + + package org.logstash.benchmark.cli; import java.io.File; diff --git a/tools/benchmark-cli/src/test/java/org/logstash/benchmark/cli/MainTest.java b/tools/benchmark-cli/src/test/java/org/logstash/benchmark/cli/MainTest.java index dab08126a..6f4b1d40c 100644 --- a/tools/benchmark-cli/src/test/java/org/logstash/benchmark/cli/MainTest.java +++ b/tools/benchmark-cli/src/test/java/org/logstash/benchmark/cli/MainTest.java @@ -1,3 +1,23 @@ +/* + * 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. + */ + + package org.logstash.benchmark.cli; import java.io.File; diff --git a/tools/dependencies-report/build.gradle b/tools/dependencies-report/build.gradle index a75a33c66..cd32cf815 100644 --- a/tools/dependencies-report/build.gradle +++ b/tools/dependencies-report/build.gradle @@ -1,3 +1,22 @@ +/* + * 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. + */ + import org.yaml.snakeyaml.Yaml // fetch version from Logstash's master versions.yml file diff --git a/tools/dependencies-report/src/main/java/org/logstash/dependencies/Dependency.java b/tools/dependencies-report/src/main/java/org/logstash/dependencies/Dependency.java index 4f86329eb..5ba05a40c 100644 --- a/tools/dependencies-report/src/main/java/org/logstash/dependencies/Dependency.java +++ b/tools/dependencies-report/src/main/java/org/logstash/dependencies/Dependency.java @@ -1,3 +1,23 @@ +/* + * 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. + */ + + package org.logstash.dependencies; import org.apache.commons.csv.CSVFormat; diff --git a/tools/dependencies-report/src/main/java/org/logstash/dependencies/Main.java b/tools/dependencies-report/src/main/java/org/logstash/dependencies/Main.java index cb6f0f801..db60923f5 100644 --- a/tools/dependencies-report/src/main/java/org/logstash/dependencies/Main.java +++ b/tools/dependencies-report/src/main/java/org/logstash/dependencies/Main.java @@ -1,3 +1,23 @@ +/* + * 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. + */ + + package org.logstash.dependencies; import java.io.FileInputStream; diff --git a/tools/dependencies-report/src/main/java/org/logstash/dependencies/ReportGenerator.java b/tools/dependencies-report/src/main/java/org/logstash/dependencies/ReportGenerator.java index 4aa5a784f..6343706fb 100644 --- a/tools/dependencies-report/src/main/java/org/logstash/dependencies/ReportGenerator.java +++ b/tools/dependencies-report/src/main/java/org/logstash/dependencies/ReportGenerator.java @@ -1,3 +1,23 @@ +/* + * 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. + */ + + package org.logstash.dependencies; import org.apache.commons.csv.CSVFormat; diff --git a/tools/dependencies-report/src/test/java/org/logstash/dependencies/ReportGeneratorTest.java b/tools/dependencies-report/src/test/java/org/logstash/dependencies/ReportGeneratorTest.java index 48027e802..a7e53d57c 100644 --- a/tools/dependencies-report/src/test/java/org/logstash/dependencies/ReportGeneratorTest.java +++ b/tools/dependencies-report/src/test/java/org/logstash/dependencies/ReportGeneratorTest.java @@ -1,3 +1,23 @@ +/* + * 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. + */ + + package org.logstash.dependencies; import org.junit.Assert; @@ -177,4 +197,3 @@ public class ReportGeneratorTest { return s.replaceAll("\\r\\n", "\n"); } } - diff --git a/tools/ingest-converter/build.gradle b/tools/ingest-converter/build.gradle index 128b2573a..4a4684136 100644 --- a/tools/ingest-converter/build.gradle +++ b/tools/ingest-converter/build.gradle @@ -1,3 +1,22 @@ +/* + * 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. + */ + import org.yaml.snakeyaml.Yaml // fetch version from Logstash's master versions.yml file diff --git a/tools/ingest-converter/src/main/java/org/logstash/ingest/Append.java b/tools/ingest-converter/src/main/java/org/logstash/ingest/Append.java index 47126fb04..131805f22 100644 --- a/tools/ingest-converter/src/main/java/org/logstash/ingest/Append.java +++ b/tools/ingest-converter/src/main/java/org/logstash/ingest/Append.java @@ -1,3 +1,23 @@ +/* + * 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. + */ + + package org.logstash.ingest; import javax.script.ScriptException; diff --git a/tools/ingest-converter/src/main/java/org/logstash/ingest/Convert.java b/tools/ingest-converter/src/main/java/org/logstash/ingest/Convert.java index f4a0fe2e7..802eb4e39 100644 --- a/tools/ingest-converter/src/main/java/org/logstash/ingest/Convert.java +++ b/tools/ingest-converter/src/main/java/org/logstash/ingest/Convert.java @@ -1,3 +1,23 @@ +/* + * 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. + */ + + package org.logstash.ingest; import javax.script.ScriptException; diff --git a/tools/ingest-converter/src/main/java/org/logstash/ingest/Date.java b/tools/ingest-converter/src/main/java/org/logstash/ingest/Date.java index 8ad435a32..91237ff07 100644 --- a/tools/ingest-converter/src/main/java/org/logstash/ingest/Date.java +++ b/tools/ingest-converter/src/main/java/org/logstash/ingest/Date.java @@ -1,3 +1,23 @@ +/* + * 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. + */ + + package org.logstash.ingest; import javax.script.ScriptException; diff --git a/tools/ingest-converter/src/main/java/org/logstash/ingest/GeoIp.java b/tools/ingest-converter/src/main/java/org/logstash/ingest/GeoIp.java index 129fe1ed4..949ca243f 100644 --- a/tools/ingest-converter/src/main/java/org/logstash/ingest/GeoIp.java +++ b/tools/ingest-converter/src/main/java/org/logstash/ingest/GeoIp.java @@ -1,3 +1,23 @@ +/* + * 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. + */ + + package org.logstash.ingest; import javax.script.ScriptException; diff --git a/tools/ingest-converter/src/main/java/org/logstash/ingest/Grok.java b/tools/ingest-converter/src/main/java/org/logstash/ingest/Grok.java index 0d13ed9a5..44d9f1890 100644 --- a/tools/ingest-converter/src/main/java/org/logstash/ingest/Grok.java +++ b/tools/ingest-converter/src/main/java/org/logstash/ingest/Grok.java @@ -1,3 +1,23 @@ +/* + * 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. + */ + + package org.logstash.ingest; import javax.script.ScriptException; diff --git a/tools/ingest-converter/src/main/java/org/logstash/ingest/Gsub.java b/tools/ingest-converter/src/main/java/org/logstash/ingest/Gsub.java index ef57ae444..29ee3d01f 100644 --- a/tools/ingest-converter/src/main/java/org/logstash/ingest/Gsub.java +++ b/tools/ingest-converter/src/main/java/org/logstash/ingest/Gsub.java @@ -1,3 +1,23 @@ +/* + * 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. + */ + + package org.logstash.ingest; import javax.script.ScriptException; diff --git a/tools/ingest-converter/src/main/java/org/logstash/ingest/JsUtil.java b/tools/ingest-converter/src/main/java/org/logstash/ingest/JsUtil.java index 83c55b5c2..fd71da88a 100644 --- a/tools/ingest-converter/src/main/java/org/logstash/ingest/JsUtil.java +++ b/tools/ingest-converter/src/main/java/org/logstash/ingest/JsUtil.java @@ -1,3 +1,23 @@ +/* + * 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. + */ + + package org.logstash.ingest; import java.io.IOException; diff --git a/tools/ingest-converter/src/main/java/org/logstash/ingest/Json.java b/tools/ingest-converter/src/main/java/org/logstash/ingest/Json.java index 4b5e0a530..21b10d856 100644 --- a/tools/ingest-converter/src/main/java/org/logstash/ingest/Json.java +++ b/tools/ingest-converter/src/main/java/org/logstash/ingest/Json.java @@ -1,3 +1,23 @@ +/* + * 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. + */ + + package org.logstash.ingest; import javax.script.ScriptException; diff --git a/tools/ingest-converter/src/main/java/org/logstash/ingest/Lowercase.java b/tools/ingest-converter/src/main/java/org/logstash/ingest/Lowercase.java index 29fb397e4..77ccb8c64 100644 --- a/tools/ingest-converter/src/main/java/org/logstash/ingest/Lowercase.java +++ b/tools/ingest-converter/src/main/java/org/logstash/ingest/Lowercase.java @@ -1,3 +1,23 @@ +/* + * 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. + */ + + package org.logstash.ingest; import javax.script.ScriptException; diff --git a/tools/ingest-converter/src/main/java/org/logstash/ingest/Pipeline.java b/tools/ingest-converter/src/main/java/org/logstash/ingest/Pipeline.java index 102db9af6..e888852f7 100644 --- a/tools/ingest-converter/src/main/java/org/logstash/ingest/Pipeline.java +++ b/tools/ingest-converter/src/main/java/org/logstash/ingest/Pipeline.java @@ -1,3 +1,23 @@ +/* + * 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. + */ + + package org.logstash.ingest; import javax.script.ScriptException; diff --git a/tools/ingest-converter/src/main/java/org/logstash/ingest/Rename.java b/tools/ingest-converter/src/main/java/org/logstash/ingest/Rename.java index 5886537d4..dac5129a0 100644 --- a/tools/ingest-converter/src/main/java/org/logstash/ingest/Rename.java +++ b/tools/ingest-converter/src/main/java/org/logstash/ingest/Rename.java @@ -1,3 +1,23 @@ +/* + * 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. + */ + + package org.logstash.ingest; import javax.script.ScriptException; diff --git a/tools/ingest-converter/src/main/java/org/logstash/ingest/Set.java b/tools/ingest-converter/src/main/java/org/logstash/ingest/Set.java index 7e7f11d8d..587295869 100644 --- a/tools/ingest-converter/src/main/java/org/logstash/ingest/Set.java +++ b/tools/ingest-converter/src/main/java/org/logstash/ingest/Set.java @@ -1,3 +1,23 @@ +/* + * 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. + */ + + package org.logstash.ingest; import javax.script.ScriptException; diff --git a/tools/ingest-converter/src/test/java/org/logstash/ingest/AppendTest.java b/tools/ingest-converter/src/test/java/org/logstash/ingest/AppendTest.java index 89a23ed21..0fa5cd43d 100644 --- a/tools/ingest-converter/src/test/java/org/logstash/ingest/AppendTest.java +++ b/tools/ingest-converter/src/test/java/org/logstash/ingest/AppendTest.java @@ -1,3 +1,23 @@ +/* + * 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. + */ + + package org.logstash.ingest; import java.util.Arrays; diff --git a/tools/ingest-converter/src/test/java/org/logstash/ingest/ConvertTest.java b/tools/ingest-converter/src/test/java/org/logstash/ingest/ConvertTest.java index 0ba7f9a9a..e2197e116 100644 --- a/tools/ingest-converter/src/test/java/org/logstash/ingest/ConvertTest.java +++ b/tools/ingest-converter/src/test/java/org/logstash/ingest/ConvertTest.java @@ -1,3 +1,23 @@ +/* + * 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. + */ + + package org.logstash.ingest; import java.util.Arrays; diff --git a/tools/ingest-converter/src/test/java/org/logstash/ingest/DateTest.java b/tools/ingest-converter/src/test/java/org/logstash/ingest/DateTest.java index dd8a45542..49a475d2a 100644 --- a/tools/ingest-converter/src/test/java/org/logstash/ingest/DateTest.java +++ b/tools/ingest-converter/src/test/java/org/logstash/ingest/DateTest.java @@ -1,3 +1,23 @@ +/* + * 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. + */ + + package org.logstash.ingest; import java.util.Arrays; diff --git a/tools/ingest-converter/src/test/java/org/logstash/ingest/GeoIpTest.java b/tools/ingest-converter/src/test/java/org/logstash/ingest/GeoIpTest.java index 089747bc8..fb83ad3be 100644 --- a/tools/ingest-converter/src/test/java/org/logstash/ingest/GeoIpTest.java +++ b/tools/ingest-converter/src/test/java/org/logstash/ingest/GeoIpTest.java @@ -1,3 +1,23 @@ +/* + * 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. + */ + + package org.logstash.ingest; import java.util.Arrays; diff --git a/tools/ingest-converter/src/test/java/org/logstash/ingest/GrokTest.java b/tools/ingest-converter/src/test/java/org/logstash/ingest/GrokTest.java index 317618e0b..d423baf5f 100644 --- a/tools/ingest-converter/src/test/java/org/logstash/ingest/GrokTest.java +++ b/tools/ingest-converter/src/test/java/org/logstash/ingest/GrokTest.java @@ -1,3 +1,23 @@ +/* + * 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. + */ + + package org.logstash.ingest; import java.util.Arrays; diff --git a/tools/ingest-converter/src/test/java/org/logstash/ingest/GsubTest.java b/tools/ingest-converter/src/test/java/org/logstash/ingest/GsubTest.java index 6dc5b069b..26f422c13 100644 --- a/tools/ingest-converter/src/test/java/org/logstash/ingest/GsubTest.java +++ b/tools/ingest-converter/src/test/java/org/logstash/ingest/GsubTest.java @@ -1,3 +1,23 @@ +/* + * 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. + */ + + package org.logstash.ingest; import java.util.Collections; diff --git a/tools/ingest-converter/src/test/java/org/logstash/ingest/IngestTest.java b/tools/ingest-converter/src/test/java/org/logstash/ingest/IngestTest.java index 3117df7d4..d8983abe1 100644 --- a/tools/ingest-converter/src/test/java/org/logstash/ingest/IngestTest.java +++ b/tools/ingest-converter/src/test/java/org/logstash/ingest/IngestTest.java @@ -1,3 +1,23 @@ +/* + * 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. + */ + + package org.logstash.ingest; import java.io.ByteArrayOutputStream; diff --git a/tools/ingest-converter/src/test/java/org/logstash/ingest/JsonTest.java b/tools/ingest-converter/src/test/java/org/logstash/ingest/JsonTest.java index 685f1e3f5..cb7bf65b0 100644 --- a/tools/ingest-converter/src/test/java/org/logstash/ingest/JsonTest.java +++ b/tools/ingest-converter/src/test/java/org/logstash/ingest/JsonTest.java @@ -1,3 +1,23 @@ +/* + * 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. + */ + + package org.logstash.ingest; import java.util.Arrays; diff --git a/tools/ingest-converter/src/test/java/org/logstash/ingest/LowercaseTest.java b/tools/ingest-converter/src/test/java/org/logstash/ingest/LowercaseTest.java index ae188e24c..e6231dc60 100644 --- a/tools/ingest-converter/src/test/java/org/logstash/ingest/LowercaseTest.java +++ b/tools/ingest-converter/src/test/java/org/logstash/ingest/LowercaseTest.java @@ -1,3 +1,23 @@ +/* + * 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. + */ + + package org.logstash.ingest; import java.util.Arrays; diff --git a/tools/ingest-converter/src/test/java/org/logstash/ingest/PipelineTest.java b/tools/ingest-converter/src/test/java/org/logstash/ingest/PipelineTest.java index 41f58633c..830f5c466 100644 --- a/tools/ingest-converter/src/test/java/org/logstash/ingest/PipelineTest.java +++ b/tools/ingest-converter/src/test/java/org/logstash/ingest/PipelineTest.java @@ -1,3 +1,23 @@ +/* + * 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. + */ + + package org.logstash.ingest; import java.util.ArrayList; diff --git a/tools/ingest-converter/src/test/java/org/logstash/ingest/RenameTest.java b/tools/ingest-converter/src/test/java/org/logstash/ingest/RenameTest.java index 1734d119d..2ecd074eb 100644 --- a/tools/ingest-converter/src/test/java/org/logstash/ingest/RenameTest.java +++ b/tools/ingest-converter/src/test/java/org/logstash/ingest/RenameTest.java @@ -1,3 +1,23 @@ +/* + * 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. + */ + + package org.logstash.ingest; import java.util.Arrays; diff --git a/tools/ingest-converter/src/test/java/org/logstash/ingest/SetTest.java b/tools/ingest-converter/src/test/java/org/logstash/ingest/SetTest.java index 68af5e60c..8682b616c 100644 --- a/tools/ingest-converter/src/test/java/org/logstash/ingest/SetTest.java +++ b/tools/ingest-converter/src/test/java/org/logstash/ingest/SetTest.java @@ -1,3 +1,23 @@ +/* + * 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. + */ + + package org.logstash.ingest; import java.util.Arrays; diff --git a/tools/logstash-docgen/Rakefile b/tools/logstash-docgen/Rakefile index 43022f711..32c3c9cf8 100644 --- a/tools/logstash-docgen/Rakefile +++ b/tools/logstash-docgen/Rakefile @@ -1,2 +1,19 @@ +# 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 "bundler/gem_tasks" task :default => :spec diff --git a/tools/logstash-docgen/bin/extract_doc.rb b/tools/logstash-docgen/bin/extract_doc.rb index 34dbf9d6e..a66bcbd7f 100755 --- a/tools/logstash-docgen/bin/extract_doc.rb +++ b/tools/logstash-docgen/bin/extract_doc.rb @@ -1,4 +1,20 @@ -# encoding: utf-8 +# 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 "fileutils" # This scripts take the output result of the `logstash-docgen` and create the PR to the plugin repositoring diff --git a/tools/logstash-docgen/lib/logstash/docgen.rb b/tools/logstash-docgen/lib/logstash/docgen.rb index 7a70dce33..e5d565b4e 100644 --- a/tools/logstash-docgen/lib/logstash/docgen.rb +++ b/tools/logstash-docgen/lib/logstash/docgen.rb @@ -1,3 +1,20 @@ +# 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 "logstash/docgen/version" module LogStash diff --git a/tools/logstash-docgen/lib/logstash/docgen/asciidoc_format.rb b/tools/logstash-docgen/lib/logstash/docgen/asciidoc_format.rb index 3be292291..babeb778d 100644 --- a/tools/logstash-docgen/lib/logstash/docgen/asciidoc_format.rb +++ b/tools/logstash-docgen/lib/logstash/docgen/asciidoc_format.rb @@ -1,4 +1,20 @@ -# encoding: utf-8 +# 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 "asciidoctor" require "erb" diff --git a/tools/logstash-docgen/lib/logstash/docgen/dependency_lookup.rb b/tools/logstash-docgen/lib/logstash/docgen/dependency_lookup.rb index 227f04109..528cbf56d 100644 --- a/tools/logstash-docgen/lib/logstash/docgen/dependency_lookup.rb +++ b/tools/logstash-docgen/lib/logstash/docgen/dependency_lookup.rb @@ -1,4 +1,20 @@ -# encoding: utf-8 +# 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 "singleton" require "gems" diff --git a/tools/logstash-docgen/lib/logstash/docgen/dynamic_parser.rb b/tools/logstash-docgen/lib/logstash/docgen/dynamic_parser.rb index 486d71b7c..8ad098003 100644 --- a/tools/logstash-docgen/lib/logstash/docgen/dynamic_parser.rb +++ b/tools/logstash-docgen/lib/logstash/docgen/dynamic_parser.rb @@ -1,4 +1,20 @@ -# encoding: utf-8 +# 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. + # This is needed because some of the plugins have weird declaration in their header files # so I make sure the basic namespaces are correctly setup. module LogStash diff --git a/tools/logstash-docgen/lib/logstash/docgen/github_generator.rb b/tools/logstash-docgen/lib/logstash/docgen/github_generator.rb index 9604772c0..fd78a0f6e 100644 --- a/tools/logstash-docgen/lib/logstash/docgen/github_generator.rb +++ b/tools/logstash-docgen/lib/logstash/docgen/github_generator.rb @@ -1,4 +1,20 @@ -# encoding: utf-8 +# 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 "logstash/docgen/parser" require "logstash/docgen/task_runner" require "logstash/docgen/util" diff --git a/tools/logstash-docgen/lib/logstash/docgen/index.rb b/tools/logstash-docgen/lib/logstash/docgen/index.rb index 3568be8ea..1815de769 100644 --- a/tools/logstash-docgen/lib/logstash/docgen/index.rb +++ b/tools/logstash-docgen/lib/logstash/docgen/index.rb @@ -1,4 +1,20 @@ -# encoding: utf-8 +# 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 "erb" module LogStash module Docgen diff --git a/tools/logstash-docgen/lib/logstash/docgen/logstash_generator.rb b/tools/logstash-docgen/lib/logstash/docgen/logstash_generator.rb index 93ce1faff..7866555f7 100644 --- a/tools/logstash-docgen/lib/logstash/docgen/logstash_generator.rb +++ b/tools/logstash-docgen/lib/logstash/docgen/logstash_generator.rb @@ -1,4 +1,20 @@ -# encoding: utf-8 +# 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 "logstash/docgen/parser" require "logstash/docgen/index" require "logstash/docgen/util" diff --git a/tools/logstash-docgen/lib/logstash/docgen/parser.rb b/tools/logstash-docgen/lib/logstash/docgen/parser.rb index 2c2814b30..393f241b8 100644 --- a/tools/logstash-docgen/lib/logstash/docgen/parser.rb +++ b/tools/logstash-docgen/lib/logstash/docgen/parser.rb @@ -1,4 +1,20 @@ -# encoding: utf-8 +# 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 "logstash/docgen/dynamic_parser" require "logstash/docgen/static_parser" require "logstash/docgen/asciidoc_format" diff --git a/tools/logstash-docgen/lib/logstash/docgen/plugin_doc.rb b/tools/logstash-docgen/lib/logstash/docgen/plugin_doc.rb index 08fd52eff..71ac86a83 100644 --- a/tools/logstash-docgen/lib/logstash/docgen/plugin_doc.rb +++ b/tools/logstash-docgen/lib/logstash/docgen/plugin_doc.rb @@ -1,4 +1,20 @@ -# encoding: utf-8 +# 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 "logstash/docgen/parser" require "stud/temporary" diff --git a/tools/logstash-docgen/lib/logstash/docgen/runner.rb b/tools/logstash-docgen/lib/logstash/docgen/runner.rb index 0fd08321f..492f1b8d1 100644 --- a/tools/logstash-docgen/lib/logstash/docgen/runner.rb +++ b/tools/logstash-docgen/lib/logstash/docgen/runner.rb @@ -1,4 +1,20 @@ -# encoding: utf-8 +# 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 "logstash/docgen/github_generator" require "clamp" require "yaml" diff --git a/tools/logstash-docgen/lib/logstash/docgen/static_parser.rb b/tools/logstash-docgen/lib/logstash/docgen/static_parser.rb index de4d9953f..847a7c326 100644 --- a/tools/logstash-docgen/lib/logstash/docgen/static_parser.rb +++ b/tools/logstash-docgen/lib/logstash/docgen/static_parser.rb @@ -1,4 +1,20 @@ -# encoding: utf-8 +# 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. + module LogStash::Docgen # This class is parsing static content of the main class and # his ancestors, the result would be the description of the plugin and the diff --git a/tools/logstash-docgen/lib/logstash/docgen/task_runner.rb b/tools/logstash-docgen/lib/logstash/docgen/task_runner.rb index e74fee30a..34b85f5b4 100644 --- a/tools/logstash-docgen/lib/logstash/docgen/task_runner.rb +++ b/tools/logstash-docgen/lib/logstash/docgen/task_runner.rb @@ -1,4 +1,20 @@ -# encoding: utf-8 +# 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 "logstash/docgen/util" module LogStash module Docgen diff --git a/tools/logstash-docgen/lib/logstash/docgen/util.rb b/tools/logstash-docgen/lib/logstash/docgen/util.rb index 47286cc1c..609c3f987 100644 --- a/tools/logstash-docgen/lib/logstash/docgen/util.rb +++ b/tools/logstash-docgen/lib/logstash/docgen/util.rb @@ -1,4 +1,20 @@ -# encoding: utf-8 +# 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. + module LogStash module Docgen module Util def self.time_execution(&block) started_at = Time.now diff --git a/tools/logstash-docgen/lib/logstash/docgen/version.rb b/tools/logstash-docgen/lib/logstash/docgen/version.rb index b1940f52e..ee2cc7722 100644 --- a/tools/logstash-docgen/lib/logstash/docgen/version.rb +++ b/tools/logstash-docgen/lib/logstash/docgen/version.rb @@ -1,3 +1,20 @@ +# 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. + module Logstash module Docgen VERSION = "0.1.0" diff --git a/tools/logstash-docgen/spec/fixtures/plugins_source/base.rb b/tools/logstash-docgen/spec/fixtures/plugins_source/base.rb index 0f4a55469..325250f83 100644 --- a/tools/logstash-docgen/spec/fixtures/plugins_source/base.rb +++ b/tools/logstash-docgen/spec/fixtures/plugins_source/base.rb @@ -1,3 +1,20 @@ +# 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. + class LogStash::Inputs::Base # Parent configuration config :parent_config, :type => :string, :require => true diff --git a/tools/logstash-docgen/spec/fixtures/plugins_source/config_from_mixin.rb b/tools/logstash-docgen/spec/fixtures/plugins_source/config_from_mixin.rb index 9a9583fa3..96a6166a6 100644 --- a/tools/logstash-docgen/spec/fixtures/plugins_source/config_from_mixin.rb +++ b/tools/logstash-docgen/spec/fixtures/plugins_source/config_from_mixin.rb @@ -1,4 +1,19 @@ -# encoding: utf-8 +# 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. module ConfigFromMixin # Config mixing description diff --git a/tools/logstash-docgen/spec/fixtures/plugins_source/new_style_header.rb b/tools/logstash-docgen/spec/fixtures/plugins_source/new_style_header.rb index ec53055dd..013887f60 100644 --- a/tools/logstash-docgen/spec/fixtures/plugins_source/new_style_header.rb +++ b/tools/logstash-docgen/spec/fixtures/plugins_source/new_style_header.rb @@ -1,10 +1,24 @@ +# 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 "base" -# encoding: utf-8 -# # This is a new test plugins # with multiple line. - module LogStash module Inputs class Dummy < LogStash::Inputs::Base config_name "dummy" diff --git a/tools/logstash-docgen/spec/fixtures/plugins_source/old_style_header.rb b/tools/logstash-docgen/spec/fixtures/plugins_source/old_style_header.rb index 26852f43d..498c88b97 100644 --- a/tools/logstash-docgen/spec/fixtures/plugins_source/old_style_header.rb +++ b/tools/logstash-docgen/spec/fixtures/plugins_source/old_style_header.rb @@ -1,11 +1,25 @@ +# 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 "base" require_relative "config_from_mixin" -# encoding: utf-8 -# # This is a new test plugins # with multiple line. - class LogStash::Inputs::Dummy < LogStash::Inputs::Base config_name "dummy" diff --git a/tools/logstash-docgen/spec/logstash/docgen/dependency_lookup_spec.rb b/tools/logstash-docgen/spec/logstash/docgen/dependency_lookup_spec.rb index 516e1196d..9cde1d256 100644 --- a/tools/logstash-docgen/spec/logstash/docgen/dependency_lookup_spec.rb +++ b/tools/logstash-docgen/spec/logstash/docgen/dependency_lookup_spec.rb @@ -1,5 +1,20 @@ -# encoding: utf-8 +# 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 "logstash/docgen/dependency_lookup" require "spec_helper" diff --git a/tools/logstash-docgen/spec/logstash/docgen/task_runner_spec.rb b/tools/logstash-docgen/spec/logstash/docgen/task_runner_spec.rb index c28d71c7a..f14c28ac8 100644 --- a/tools/logstash-docgen/spec/logstash/docgen/task_runner_spec.rb +++ b/tools/logstash-docgen/spec/logstash/docgen/task_runner_spec.rb @@ -1,4 +1,20 @@ -# encoding: utf-8 +# 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 "logstash/docgen/task_runner" describe LogStash::Docgen::TaskRunner::Status do diff --git a/tools/logstash-docgen/spec/logstash/docgen/util_spec.rb b/tools/logstash-docgen/spec/logstash/docgen/util_spec.rb index b8164470f..5c3765fa3 100644 --- a/tools/logstash-docgen/spec/logstash/docgen/util_spec.rb +++ b/tools/logstash-docgen/spec/logstash/docgen/util_spec.rb @@ -1,4 +1,20 @@ -# encoding: utf-8 +# 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 "logstash/docgen/util" require "spec_helper" diff --git a/tools/logstash-docgen/spec/spec_helper.rb b/tools/logstash-docgen/spec/spec_helper.rb index 1856c339f..71980c650 100644 --- a/tools/logstash-docgen/spec/spec_helper.rb +++ b/tools/logstash-docgen/spec/spec_helper.rb @@ -1,5 +1,20 @@ -# encoding: utf-8 +# 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 "vcr" require "webmock" require_relative "support/helpers" diff --git a/tools/logstash-docgen/spec/support/helpers.rb b/tools/logstash-docgen/spec/support/helpers.rb index 30e2c33fc..373d800ca 100644 --- a/tools/logstash-docgen/spec/support/helpers.rb +++ b/tools/logstash-docgen/spec/support/helpers.rb @@ -1,5 +1,20 @@ -# encoding: utf-8 +# 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. + # This make the test suite non thread safe. def capture(&block) old_stdout = $stdout diff --git a/tools/logstash-docgen/templates/index-codecs.asciidoc.erb b/tools/logstash-docgen/templates/index-codecs.asciidoc.erb index af0659be0..44ef06915 100644 --- a/tools/logstash-docgen/templates/index-codecs.asciidoc.erb +++ b/tools/logstash-docgen/templates/index-codecs.asciidoc.erb @@ -1,3 +1,20 @@ +# 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. + [[codec-plugins]] == Codec plugins diff --git a/tools/logstash-docgen/templates/index-filters.asciidoc.erb b/tools/logstash-docgen/templates/index-filters.asciidoc.erb index 47340c5c2..abbb79372 100644 --- a/tools/logstash-docgen/templates/index-filters.asciidoc.erb +++ b/tools/logstash-docgen/templates/index-filters.asciidoc.erb @@ -1,3 +1,20 @@ +# 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. + [[filter-plugins]] == Filter plugins diff --git a/tools/logstash-docgen/templates/index-inputs.asciidoc.erb b/tools/logstash-docgen/templates/index-inputs.asciidoc.erb index ecc477537..59b27ed58 100644 --- a/tools/logstash-docgen/templates/index-inputs.asciidoc.erb +++ b/tools/logstash-docgen/templates/index-inputs.asciidoc.erb @@ -1,3 +1,20 @@ +# 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. + [[input-plugins]] == Input plugins diff --git a/tools/logstash-docgen/templates/index-outputs.asciidoc.erb b/tools/logstash-docgen/templates/index-outputs.asciidoc.erb index 6d6d241ba..0a097cdad 100644 --- a/tools/logstash-docgen/templates/index-outputs.asciidoc.erb +++ b/tools/logstash-docgen/templates/index-outputs.asciidoc.erb @@ -1,3 +1,20 @@ +# 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. + [[output-plugins]] == Output plugins diff --git a/tools/logstash-docgen/templates/plugin-doc.asciidoc.erb b/tools/logstash-docgen/templates/plugin-doc.asciidoc.erb index 7373bdceb..1d9a00815 100644 --- a/tools/logstash-docgen/templates/plugin-doc.asciidoc.erb +++ b/tools/logstash-docgen/templates/plugin-doc.asciidoc.erb @@ -1,3 +1,20 @@ +# 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. + :plugin: <%=name%> :type: <%=section%> diff --git a/tools/paquet/README.md b/tools/paquet/README.md index ac61e149a..87df4318c 100644 --- a/tools/paquet/README.md +++ b/tools/paquet/README.md @@ -23,7 +23,6 @@ And then execute: Define the dependencies in your Rakefile ```ruby -# encoding: utf-8 require "paquet" TARGET_DIRECTORY = File.join(File.dirname(__FILE__), "dependencies") diff --git a/tools/paquet/Rakefile b/tools/paquet/Rakefile index 43022f711..32c3c9cf8 100644 --- a/tools/paquet/Rakefile +++ b/tools/paquet/Rakefile @@ -1,2 +1,19 @@ +# 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 "bundler/gem_tasks" task :default => :spec diff --git a/tools/paquet/lib/paquet.rb b/tools/paquet/lib/paquet.rb index 0e19b6221..a754e3f82 100644 --- a/tools/paquet/lib/paquet.rb +++ b/tools/paquet/lib/paquet.rb @@ -1,4 +1,20 @@ -# encoding: utf-8 +# 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 "paquet/version" require "paquet/shell_ui" require "paquet/gem" diff --git a/tools/paquet/lib/paquet/dependency.rb b/tools/paquet/lib/paquet/dependency.rb index 08fc739cc..64aac5f6a 100644 --- a/tools/paquet/lib/paquet/dependency.rb +++ b/tools/paquet/lib/paquet/dependency.rb @@ -1,3 +1,20 @@ +# 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. + module Paquet class Dependency attr_reader :name, :version, :platform diff --git a/tools/paquet/lib/paquet/gem.rb b/tools/paquet/lib/paquet/gem.rb index 882196515..6c59f18e4 100644 --- a/tools/paquet/lib/paquet/gem.rb +++ b/tools/paquet/lib/paquet/gem.rb @@ -1,4 +1,20 @@ -# encoding: utf-8 +# 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 "paquet/dependency" require "paquet/shell_ui" require "paquet/utils" diff --git a/tools/paquet/lib/paquet/rspec/tasks.rb b/tools/paquet/lib/paquet/rspec/tasks.rb index de4aa9213..99726a0e9 100644 --- a/tools/paquet/lib/paquet/rspec/tasks.rb +++ b/tools/paquet/lib/paquet/rspec/tasks.rb @@ -1,4 +1,20 @@ -# encoding: utf-8 +# 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 "bundler" require "rake" require "rake/tasklib" diff --git a/tools/paquet/lib/paquet/shell_ui.rb b/tools/paquet/lib/paquet/shell_ui.rb index 331c37bef..e44290caa 100644 --- a/tools/paquet/lib/paquet/shell_ui.rb +++ b/tools/paquet/lib/paquet/shell_ui.rb @@ -1,4 +1,20 @@ -# encoding: utf-8 +# 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. + module Paquet class SilentUI class << self diff --git a/tools/paquet/lib/paquet/utils.rb b/tools/paquet/lib/paquet/utils.rb index b7800db2e..c932c06b4 100644 --- a/tools/paquet/lib/paquet/utils.rb +++ b/tools/paquet/lib/paquet/utils.rb @@ -1,4 +1,20 @@ -# encoding: utf-8 +# 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 "fileutils" require "uri" diff --git a/tools/paquet/lib/paquet/version.rb b/tools/paquet/lib/paquet/version.rb index 720bad35e..c5df561df 100644 --- a/tools/paquet/lib/paquet/version.rb +++ b/tools/paquet/lib/paquet/version.rb @@ -1,3 +1,20 @@ +# 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. + module Paquet VERSION = "0.2.1" end diff --git a/tools/paquet/spec/integration/paquet_spec.rb b/tools/paquet/spec/integration/paquet_spec.rb index b5b52f1ec..1988e7b1f 100644 --- a/tools/paquet/spec/integration/paquet_spec.rb +++ b/tools/paquet/spec/integration/paquet_spec.rb @@ -1,4 +1,20 @@ -# encoding: utf-8 +# 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 "bundler" require "fileutils" require "stud/temporary" diff --git a/tools/paquet/spec/paquet/dependency_spec.rb b/tools/paquet/spec/paquet/dependency_spec.rb index 0ed02f9fe..cb262d737 100644 --- a/tools/paquet/spec/paquet/dependency_spec.rb +++ b/tools/paquet/spec/paquet/dependency_spec.rb @@ -1,4 +1,20 @@ -# encoding: utf-8 +# 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 "paquet/dependency" describe Paquet::Dependency do diff --git a/tools/paquet/spec/paquet/gem_spec.rb b/tools/paquet/spec/paquet/gem_spec.rb index c7c807f4a..31b82e7c0 100644 --- a/tools/paquet/spec/paquet/gem_spec.rb +++ b/tools/paquet/spec/paquet/gem_spec.rb @@ -1,4 +1,20 @@ -# encoding: utf-8 +# 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 "paquet/gem" require "stud/temporary" require "fileutils" diff --git a/tools/paquet/spec/paquet/shell_ui_spec.rb b/tools/paquet/spec/paquet/shell_ui_spec.rb index 398274e94..b225aa5e0 100644 --- a/tools/paquet/spec/paquet/shell_ui_spec.rb +++ b/tools/paquet/spec/paquet/shell_ui_spec.rb @@ -1,4 +1,20 @@ -# encoding: utf-8 +# 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 "paquet/shell_ui" describe Paquet::ShellUi do diff --git a/tools/paquet/spec/paquet/utils_spec.rb b/tools/paquet/spec/paquet/utils_spec.rb index d2c0f2074..ef5c44aa6 100644 --- a/tools/paquet/spec/paquet/utils_spec.rb +++ b/tools/paquet/spec/paquet/utils_spec.rb @@ -1,4 +1,20 @@ -# encoding: utf-8 +# 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 "paquet/utils" require "stud/temporary" require "spec_helper" diff --git a/tools/paquet/spec/spec_helper.rb b/tools/paquet/spec/spec_helper.rb index a2d0aa45d..5ec3a3a42 100644 --- a/tools/paquet/spec/spec_helper.rb +++ b/tools/paquet/spec/spec_helper.rb @@ -1,2 +1,18 @@ -# encoding: utf-8 +# 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 "webmock/rspec" diff --git a/tools/paquet/spec/support/Rakefile b/tools/paquet/spec/support/Rakefile index 5e8040d85..dc2363d66 100644 --- a/tools/paquet/spec/support/Rakefile +++ b/tools/paquet/spec/support/Rakefile @@ -1,4 +1,20 @@ -# encoding: utf-8 +# 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 "paquet" TARGET_DIRECTORY = File.join(File.dirname(__FILE__), "dependencies") diff --git a/tools/release/bump_plugin_versions.rb b/tools/release/bump_plugin_versions.rb index 6f38a7c1f..06e28d5ef 100755 --- a/tools/release/bump_plugin_versions.rb +++ b/tools/release/bump_plugin_versions.rb @@ -1,5 +1,21 @@ #!/usr/bin/env ruby -# encoding: utf-8 +# 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 'net/http' require 'uri' require 'fileutils' diff --git a/tools/release/generate_release_notes.rb b/tools/release/generate_release_notes.rb index cf48e350f..fb259175e 100755 --- a/tools/release/generate_release_notes.rb +++ b/tools/release/generate_release_notes.rb @@ -1,8 +1,24 @@ #!/usr/bin/env ruby -# encoding: utf-8 +# 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. + # Example: # ruby generate_release_notes.rb 6.4 6.4.1 -# +# # This: # * compares the lock file of two commits # * for each plugin version bumped show CHANGELOG.md of the bumped version diff --git a/x-pack/build.gradle b/x-pack/build.gradle index b923cfd65..08954721c 100644 --- a/x-pack/build.gradle +++ b/x-pack/build.gradle @@ -1,3 +1,9 @@ +/* + * 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. + */ + description = """Logstash X-Pack""" repositories { diff --git a/x-pack/lib/monitoring/inputs/metrics/state_event_factory.rb b/x-pack/lib/monitoring/inputs/metrics/state_event_factory.rb index 175557b77..8556cc848 100644 --- a/x-pack/lib/monitoring/inputs/metrics/state_event_factory.rb +++ b/x-pack/lib/monitoring/inputs/metrics/state_event_factory.rb @@ -1,7 +1,7 @@ # 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. -# + module LogStash; module Inputs; class Metrics; class StateEventFactory require "logstash/config/lir_serializer" @@ -38,4 +38,3 @@ module LogStash; module Inputs; class Metrics; end end end; end; end - diff --git a/x-pack/lib/monitoring/inputs/metrics/stats_event_factory.rb b/x-pack/lib/monitoring/inputs/metrics/stats_event_factory.rb index a8d9a24b3..2d3ac6a2d 100644 --- a/x-pack/lib/monitoring/inputs/metrics/stats_event_factory.rb +++ b/x-pack/lib/monitoring/inputs/metrics/stats_event_factory.rb @@ -1,7 +1,7 @@ # 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. -# + module LogStash; module Inputs; class Metrics; class StatsEventFactory include ::LogStash::Util::Loggable diff --git a/x-pack/modules/arcsight/configuration/logstash/arcsight.conf.erb b/x-pack/modules/arcsight/configuration/logstash/arcsight.conf.erb index 483ae619a..57a24477f 100644 --- a/x-pack/modules/arcsight/configuration/logstash/arcsight.conf.erb +++ b/x-pack/modules/arcsight/configuration/logstash/arcsight.conf.erb @@ -1,7 +1,7 @@ # 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. -# + <% # Define the default inputs to use and a list of valid aliases defined_inputs = configured_inputs(["kafka"], {"eventbroker" => "kafka", "smartconnector" => "tcp"}) diff --git a/x-pack/modules/azure/lib/filters/azure_event.rb b/x-pack/modules/azure/lib/filters/azure_event.rb index 920b1f870..45588086a 100644 --- a/x-pack/modules/azure/lib/filters/azure_event.rb +++ b/x-pack/modules/azure/lib/filters/azure_event.rb @@ -244,4 +244,3 @@ module LogStash end end end - diff --git a/x-pack/qa/integration/spec_helper.rb b/x-pack/qa/integration/spec_helper.rb index 3c9bbc9b3..974092b02 100644 --- a/x-pack/qa/integration/spec_helper.rb +++ b/x-pack/qa/integration/spec_helper.rb @@ -9,4 +9,3 @@ require_relative "support/shared_examples" require_relative "support/elasticsearch/api/actions/update_password" require "json" require "json-schema" - diff --git a/x-pack/spec/modules/arcsight/arcsight_module_config_helper_spec.rb b/x-pack/spec/modules/arcsight/arcsight_module_config_helper_spec.rb index 854c25a71..4f84f97ac 100644 --- a/x-pack/spec/modules/arcsight/arcsight_module_config_helper_spec.rb +++ b/x-pack/spec/modules/arcsight/arcsight_module_config_helper_spec.rb @@ -1,11 +1,7 @@ -# encoding: utf-8 - # 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/devutils/rspec/spec_helper" - require 'x-pack/logstash_registry' require 'logstash-core' require 'logstash/settings' diff --git a/x-pack/src/test/java/org/logstash/xpack/test/RSpecIntegrationTests.java b/x-pack/src/test/java/org/logstash/xpack/test/RSpecIntegrationTests.java index 2524581ac..d11d143c3 100644 --- a/x-pack/src/test/java/org/logstash/xpack/test/RSpecIntegrationTests.java +++ b/x-pack/src/test/java/org/logstash/xpack/test/RSpecIntegrationTests.java @@ -1,3 +1,10 @@ +/* + * 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. + */ + + package org.logstash.xpack.test; import java.nio.charset.StandardCharsets; diff --git a/x-pack/src/test/java/org/logstash/xpack/test/RSpecTests.java b/x-pack/src/test/java/org/logstash/xpack/test/RSpecTests.java index 241c6590d..2e78e3cf5 100644 --- a/x-pack/src/test/java/org/logstash/xpack/test/RSpecTests.java +++ b/x-pack/src/test/java/org/logstash/xpack/test/RSpecTests.java @@ -1,3 +1,10 @@ +/* + * 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. + */ + + package org.logstash.xpack.test; import java.nio.charset.StandardCharsets; From 7549824fcba8fb417ed116ba0ea03333742d2065 Mon Sep 17 00:00:00 2001 From: Karen Metts Date: Mon, 27 Jan 2020 12:27:21 -0500 Subject: [PATCH 0381/1126] Add tips for troubleshooting a pipeline Fixes #11545 --- docs/static/troubleshooting.asciidoc | 27 +++++++++++++++++++++++++-- 1 file changed, 25 insertions(+), 2 deletions(-) diff --git a/docs/static/troubleshooting.asciidoc b/docs/static/troubleshooting.asciidoc index 6cabc7040..ec32e4782 100644 --- a/docs/static/troubleshooting.asciidoc +++ b/docs/static/troubleshooting.asciidoc @@ -8,8 +8,6 @@ have something to add, please: https://github.com/elastic/logstash/issues, or * create a pull request with your proposed changes at https://github.com/elastic/logstash. -// After merge, update PR link to link directly to this topic in GH - Also check out the https://discuss.elastic.co/c/logstash[Logstash discussion forum]. @@ -139,9 +137,34 @@ For general performance tuning tips and guidelines, see <>. +[float] +[[ts-pipeline]] +== Troubleshooting a pipeline + +Pipelines, by definition, are unique. Here are some guidelines to help you get +started. + +* Identify the offending pipeline. +* Start small. Create a minimum pipeline that manifests the problem. +For basic pipelines, this configuration could be enough to make the problem show itself. +[source,ruby] +----- +input {stdin{}} output {stdout{}} +----- + +For more complex pipelines, the problem could be caused by a series of plugins in +a specific order. Troubleshooting these pipelines usually requires trial and error. +Start by systematically removing input and output plugins until you're left with +the minimum set that manifest the issue. + +We want to expand this section to make it more helpful. If you have +troubleshooting tips to share, please: + +* create an issue at https://github.com/elastic/logstash/issues, or +* create a pull request with your proposed changes at https://github.com/elastic/logstash. [float] [[ts-kafka]] From d057e8bae01b5f8ce3f57732e49735a6bf277344 Mon Sep 17 00:00:00 2001 From: andsel Date: Tue, 28 Jan 2020 09:36:33 +0100 Subject: [PATCH 0382/1126] Minor, added suggestion to switch on the log per pipeline Fixes #11545 --- docs/static/troubleshooting.asciidoc | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/docs/static/troubleshooting.asciidoc b/docs/static/troubleshooting.asciidoc index ec32e4782..eb197018e 100644 --- a/docs/static/troubleshooting.asciidoc +++ b/docs/static/troubleshooting.asciidoc @@ -155,6 +155,10 @@ For basic pipelines, this configuration could be enough to make the problem show input {stdin{}} output {stdout{}} ----- +To better identify the offending pipeline, {ls} could separate its logs by pipeline. +To switch on the log per pipeline feature is sufficient to enable `pipeline.separate_logs` in your `logstash.yml` +or passing the `-Dls.pipeline.separate_logs=true` on command line. + For more complex pipelines, the problem could be caused by a series of plugins in a specific order. Troubleshooting these pipelines usually requires trial and error. Start by systematically removing input and output plugins until you're left with From 0a88578ef1e0354102584a96eafdc138bc130a4d Mon Sep 17 00:00:00 2001 From: andsel Date: Wed, 29 Jan 2020 09:13:21 +0100 Subject: [PATCH 0383/1126] Removed errored CLI flag description Fixes #11545 --- docs/static/troubleshooting.asciidoc | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/docs/static/troubleshooting.asciidoc b/docs/static/troubleshooting.asciidoc index eb197018e..017849f1b 100644 --- a/docs/static/troubleshooting.asciidoc +++ b/docs/static/troubleshooting.asciidoc @@ -156,8 +156,7 @@ input {stdin{}} output {stdout{}} ----- To better identify the offending pipeline, {ls} could separate its logs by pipeline. -To switch on the log per pipeline feature is sufficient to enable `pipeline.separate_logs` in your `logstash.yml` -or passing the `-Dls.pipeline.separate_logs=true` on command line. +Switch on the log per pipeline feature by enabling it, put `pipeline.separate_logs: true` in your `logstash.yml`. For more complex pipelines, the problem could be caused by a series of plugins in a specific order. Troubleshooting these pipelines usually requires trial and error. From 8c11a95f9f66d3ee01f13ec0e3d66dd7a7de2b2f Mon Sep 17 00:00:00 2001 From: Karen Metts <35154725+karenzone@users.noreply.github.com> Date: Wed, 12 Feb 2020 18:28:02 -0500 Subject: [PATCH 0384/1126] Update troubleshooting.asciidoc Fixes #11545 --- docs/static/troubleshooting.asciidoc | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/docs/static/troubleshooting.asciidoc b/docs/static/troubleshooting.asciidoc index 017849f1b..cb48217de 100644 --- a/docs/static/troubleshooting.asciidoc +++ b/docs/static/troubleshooting.asciidoc @@ -155,8 +155,8 @@ For basic pipelines, this configuration could be enough to make the problem show input {stdin{}} output {stdout{}} ----- -To better identify the offending pipeline, {ls} could separate its logs by pipeline. -Switch on the log per pipeline feature by enabling it, put `pipeline.separate_logs: true` in your `logstash.yml`. +{ls} can separate logs by pipeline. This feature can help you identify the offending pipeline. +Set `pipeline.separate_logs: true` in your `logstash.yml` to enable the log per pipeline feature. For more complex pipelines, the problem could be caused by a series of plugins in a specific order. Troubleshooting these pipelines usually requires trial and error. From d9016163730f7d679302bce4bfdfefe2d7c10a60 Mon Sep 17 00:00:00 2001 From: andsel Date: Mon, 27 Jan 2020 12:48:31 +0100 Subject: [PATCH 0385/1126] Adaptations to internal collector to send data directly to monitoring cluster Close 11573 Added check on HTTP server before asking for monitoring data in unit test Fixes #11541 Fixes #11641 --- config/logstash.yml | 38 ++-- docker/data/logstash/env2yaml/env2yaml.go | 10 + .../lib/logstash/api/commands/stats.rb | 2 +- .../lib/logstash/instrument/metric_store.rb | 2 +- x-pack/lib/helpers/elasticsearch_options.rb | 52 ++--- x-pack/lib/monitoring/inputs/metrics.rb | 47 ++++- .../inputs/metrics/state_event_factory.rb | 28 ++- .../inputs/metrics/stats_event_factory.rb | 28 ++- x-pack/lib/monitoring/monitoring.rb | 101 +++++++--- .../outputs/elasticsearch_monitoring.rb | 2 +- x-pack/lib/template.cfg.erb | 4 +- .../monitoring/direct_shipping_spec.rb | 37 ++++ .../es_documents_structure_validation_spec.rb | 123 ++++++++++++ x-pack/qa/integration/support/helpers.rb | 5 +- .../metrics/state_event_factory_spec.rb | 79 ++++++++ .../metrics/stats_event_factory_spec.rb | 81 ++++++++ x-pack/spec/monitoring/inputs/metrics_spec.rb | 2 +- .../monitoring/pipeline_register_hook_spec.rb | 49 +++++ .../monitoring_document_new_schema.json | 186 ++++++++++++++++++ .../schemas/states_document_new_schema.json | 94 +++++++++ 20 files changed, 882 insertions(+), 88 deletions(-) create mode 100644 x-pack/qa/integration/monitoring/direct_shipping_spec.rb create mode 100644 x-pack/qa/integration/monitoring/es_documents_structure_validation_spec.rb create mode 100644 x-pack/spec/monitoring/inputs/metrics/state_event_factory_spec.rb create mode 100644 x-pack/spec/monitoring/inputs/metrics/stats_event_factory_spec.rb create mode 100644 x-pack/spec/monitoring/pipeline_register_hook_spec.rb create mode 100644 x-pack/spec/monitoring/schemas/monitoring_document_new_schema.json create mode 100644 x-pack/spec/monitoring/schemas/states_document_new_schema.json diff --git a/config/logstash.yml b/config/logstash.yml index 3ec8577a0..4a713d32d 100644 --- a/config/logstash.yml +++ b/config/logstash.yml @@ -225,26 +225,28 @@ pipeline.ordered: auto # Default is false # pipeline.separate_logs: false # -# ------------ X-Pack Settings (not applicable for OSS build)-------------- +# ------------ Monitoring Settings (not applicable for OSS build)-------------- # -# X-Pack Monitoring -# https://www.elastic.co/guide/en/logstash/current/monitoring-logstash.html -#xpack.monitoring.enabled: false -#xpack.monitoring.elasticsearch.username: logstash_system -#xpack.monitoring.elasticsearch.password: password -#xpack.monitoring.elasticsearch.hosts: ["https://es1:9200", "https://es2:9200"] +# https://www.elastic.co/guide/en/logstash/current/monitoring-internal-collection.html +# Enable monitoring via internal collector to an Elasticsearch monitoring cluster +#monitoring.enabled: false +#monitoring.cluster_uuid: elasticsearch_cluster_uuid +#monitoring.elasticsearch.username: logstash_system +#monitoring.elasticsearch.password: password +#monitoring.elasticsearch.hosts: ["https://es1:9200", "https://es2:9200"] # an alternative to hosts + username/password settings is to use cloud_id/cloud_auth -#xpack.monitoring.elasticsearch.cloud_id: monitoring_cluster_id:xxxxxxxxxx -#xpack.monitoring.elasticsearch.cloud_auth: logstash_system:password -#xpack.monitoring.elasticsearch.ssl.certificate_authority: [ "/path/to/ca.crt" ] -#xpack.monitoring.elasticsearch.ssl.truststore.path: path/to/file -#xpack.monitoring.elasticsearch.ssl.truststore.password: password -#xpack.monitoring.elasticsearch.ssl.keystore.path: /path/to/file -#xpack.monitoring.elasticsearch.ssl.keystore.password: password -#xpack.monitoring.elasticsearch.ssl.verification_mode: certificate -#xpack.monitoring.elasticsearch.sniffing: false -#xpack.monitoring.collection.interval: 10s -#xpack.monitoring.collection.pipeline.details.enabled: true +#monitoring.elasticsearch.cloud_id: monitoring_cluster_id:xxxxxxxxxx +#monitoring.elasticsearch.cloud_auth: logstash_system:password +#monitoring.elasticsearch.ssl.certificate_authority: [ "/path/to/ca.crt" ] +#monitoring.elasticsearch.ssl.truststore.path: path/to/file +#monitoring.elasticsearch.ssl.truststore.password: password +#monitoring.elasticsearch.ssl.keystore.path: /path/to/file +#monitoring.elasticsearch.ssl.keystore.password: password +#monitoring.elasticsearch.ssl.verification_mode: certificate +#monitoring.elasticsearch.sniffing: false +#monitoring.collection.interval: 10s +#monitoring.collection.pipeline.details.enabled: true +# ------------ X-Pack Settings (not applicable for OSS build)-------------- # # X-Pack Management # https://www.elastic.co/guide/en/logstash/current/logstash-centralized-pipeline-management.html diff --git a/docker/data/logstash/env2yaml/env2yaml.go b/docker/data/logstash/env2yaml/env2yaml.go index e63390e8c..129ad09c0 100644 --- a/docker/data/logstash/env2yaml/env2yaml.go +++ b/docker/data/logstash/env2yaml/env2yaml.go @@ -84,6 +84,16 @@ func normalizeSetting(setting string) (string, error) { "modules", "path.logs", "path.plugins", + "monitoring.enabled", + "monitoring.collection.interval", + "monitoring.elasticsearch.hosts", + "monitoring.elasticsearch.username", + "monitoring.elasticsearch.password", + "monitoring.elasticsearch.ssl.certificate_authority", + "monitoring.elasticsearch.ssl.truststore.path", + "monitoring.elasticsearch.ssl.truststore.password", + "monitoring.elasticsearch.ssl.keystore.path", + "monitoring.elasticsearch.ssl.keystore.password", "xpack.monitoring.enabled", "xpack.monitoring.collection.interval", "xpack.monitoring.elasticsearch.hosts", diff --git a/logstash-core/lib/logstash/api/commands/stats.rb b/logstash-core/lib/logstash/api/commands/stats.rb index 9b3282f2e..69fe10395 100644 --- a/logstash-core/lib/logstash/api/commands/stats.rb +++ b/logstash-core/lib/logstash/api/commands/stats.rb @@ -185,7 +185,7 @@ module LogStash # @param vertex [Hash{String=>Object}] # @return [Hash{String=>Object}] def decorate_vertex(vertex) - plugin_id = vertex["id"]&.to_s + plugin_id = vertex[:id]&.to_s return vertex unless plugin_id && LogStash::PluginMetadata.exists?(plugin_id) plugin_metadata = LogStash::PluginMetadata.for_plugin(plugin_id) diff --git a/logstash-core/lib/logstash/instrument/metric_store.rb b/logstash-core/lib/logstash/instrument/metric_store.rb index 4cdbc9bcf..eaac28a9c 100644 --- a/logstash-core/lib/logstash/instrument/metric_store.rb +++ b/logstash-core/lib/logstash/instrument/metric_store.rb @@ -222,7 +222,7 @@ module LogStash module Instrument # This method take an array of keys and recursively search the metric store structure # and return a filtered hash of the structure. This method also take into consideration - # getting two different branchs. + # getting two different branches. # # # If one part of the `key_paths` contains a filter key with the following format. diff --git a/x-pack/lib/helpers/elasticsearch_options.rb b/x-pack/lib/helpers/elasticsearch_options.rb index 83fb37959..b24b575e5 100644 --- a/x-pack/lib/helpers/elasticsearch_options.rb +++ b/x-pack/lib/helpers/elasticsearch_options.rb @@ -26,38 +26,44 @@ module LogStash module Helpers # Populate the Elasticsearch options from LogStashSettings file, based on the feature that is being used. # @return Hash def es_options_from_settings(feature, settings) + prefix = if feature == "monitoring" && + LogStash::MonitoringExtension.use_direct_shipping?(settings) + "" + else + "xpack." + end opts = {} - if cloud_id = settings.get("xpack.#{feature}.elasticsearch.cloud_id") + if cloud_id = settings.get("#{prefix}#{feature}.elasticsearch.cloud_id") opts['cloud_id'] = cloud_id - check_cloud_id_configuration!(feature, settings) + check_cloud_id_configuration!(feature, settings, prefix) else - opts['hosts'] = settings.get("xpack.#{feature}.elasticsearch.hosts") + opts['hosts'] = settings.get("#{prefix}#{feature}.elasticsearch.hosts") end - if cloud_auth = settings.get("xpack.#{feature}.elasticsearch.cloud_auth") + if cloud_auth = settings.get("#{prefix}#{feature}.elasticsearch.cloud_auth") opts['cloud_auth'] = cloud_auth - check_cloud_auth_configuration!(feature, settings) + check_cloud_auth_configuration!(feature, settings, prefix) else - opts['user'] = settings.get("xpack.#{feature}.elasticsearch.username") - opts['password'] = settings.get("xpack.#{feature}.elasticsearch.password") + opts['user'] = settings.get("#{prefix}#{feature}.elasticsearch.username") + opts['password'] = settings.get("#{prefix}#{feature}.elasticsearch.password") end - opts['sniffing'] = settings.get("xpack.#{feature}.elasticsearch.sniffing") - opts['ssl_certificate_verification'] = settings.get("xpack.#{feature}.elasticsearch.ssl.verification_mode") == 'certificate' + opts['sniffing'] = settings.get("#{prefix}#{feature}.elasticsearch.sniffing") + opts['ssl_certificate_verification'] = settings.get("#{prefix}#{feature}.elasticsearch.ssl.verification_mode") == 'certificate' - if cacert = settings.get("xpack.#{feature}.elasticsearch.ssl.certificate_authority") + if cacert = settings.get("#{prefix}#{feature}.elasticsearch.ssl.certificate_authority") opts['cacert'] = cacert opts['ssl'] = true end - if truststore = settings.get("xpack.#{feature}.elasticsearch.ssl.truststore.path") + if truststore = settings.get("#{prefix}#{feature}.elasticsearch.ssl.truststore.path") opts['truststore'] = truststore - opts['truststore_password'] = settings.get("xpack.#{feature}.elasticsearch.ssl.truststore.password") + opts['truststore_password'] = settings.get("#{prefix}#{feature}.elasticsearch.ssl.truststore.password") opts['ssl'] = true end - if keystore = settings.get("xpack.#{feature}.elasticsearch.ssl.keystore.path") + if keystore = settings.get("#{prefix}#{feature}.elasticsearch.ssl.keystore.path") opts['keystore'] = keystore - opts['keystore_password']= settings.get("xpack.#{feature}.elasticsearch.ssl.keystore.password") + opts['keystore_password']= settings.get("#{prefix}#{feature}.elasticsearch.ssl.keystore.password") opts['ssl'] = true end opts @@ -135,19 +141,19 @@ module LogStash module Helpers private - def check_cloud_id_configuration!(feature, settings) - return if !settings.set?("xpack.#{feature}.elasticsearch.hosts") + def check_cloud_id_configuration!(feature, settings, prefix) + return if !settings.set?("#{prefix}#{feature}.elasticsearch.hosts") - raise ArgumentError.new("Both \"xpack.#{feature}.elasticsearch.cloud_id\" and " + - "\"xpack.#{feature}.elasticsearch.hosts\" specified, please only use one of those.") + raise ArgumentError.new("Both \"#{prefix}#{feature}.elasticsearch.cloud_id\" and " + + "\"#{prefix}#{feature}.elasticsearch.hosts\" specified, please only use one of those.") end - def check_cloud_auth_configuration!(feature, settings) - return if !settings.set?("xpack.#{feature}.elasticsearch.username") && - !settings.set?("xpack.#{feature}.elasticsearch.password") + def check_cloud_auth_configuration!(feature, settings, prefix) + return if !settings.set?("#{prefix}#{feature}.elasticsearch.username") && + !settings.set?("#{prefix}#{feature}.elasticsearch.password") - raise ArgumentError.new("Both \"xpack.#{feature}.elasticsearch.cloud_auth\" and " + - "\"xpack.#{feature}.elasticsearch.username\"/\"xpack.#{feature}.elasticsearch.password\" " + + raise ArgumentError.new("Both \"#{prefix}#{feature}.elasticsearch.cloud_auth\" and " + + "\"#{prefix}#{feature}.elasticsearch.username\"/\"#{prefix}#{feature}.elasticsearch.password\" " + "specified, please only use one of those.") end diff --git a/x-pack/lib/monitoring/inputs/metrics.rb b/x-pack/lib/monitoring/inputs/metrics.rb index 34c3a0952..cf5c0b19b 100644 --- a/x-pack/lib/monitoring/inputs/metrics.rb +++ b/x-pack/lib/monitoring/inputs/metrics.rb @@ -44,6 +44,7 @@ module LogStash module Inputs def register @global_stats = fetch_global_stats @agent = nil + @cluster_uuids = nil @settings = LogStash::SETTINGS.clone @last_updated_pipeline_hashes = [] @agent = execution_context.agent if execution_context @@ -105,15 +106,28 @@ module LogStash module Inputs end def update(snapshot) + if LogStash::MonitoringExtension.use_direct_shipping?(LogStash::SETTINGS) + @cluster_uuids ||= extract_cluster_uuids(snapshot.metric_store) + end update_stats(snapshot) update_states end def update_stats(snapshot) @logger.debug("Metrics input: received a new snapshot", :created_at => snapshot.created_at, :snapshot => snapshot) if @logger.debug? + if @cluster_uuids.nil? || @cluster_uuids.empty? + fire_stats_event(snapshot, nil) + else + @cluster_uuids.each do |cluster_uuid| + fire_stats_event(snapshot, cluster_uuid) + end + end + end + private + def fire_stats_event(snapshot, cluster_uuid) begin - event = StatsEventFactory.new(@global_stats, snapshot).make(agent, @extended_performance_collection) + event = StatsEventFactory.new(@global_stats, snapshot, cluster_uuid).make(agent, @extended_performance_collection, @collection_interval) rescue => e if @logger.debug? @logger.error("Failed to create monitoring event", :message => e.message, :error => e.class.name, :backtrace => e.backtrace) @@ -132,6 +146,7 @@ module LogStash module Inputs emit_event(event) end + public def update_states return unless @agent @@ -153,12 +168,19 @@ module LogStash module Inputs def update_pipeline_state(pipeline) return if pipeline.system? if @config_collection - emit_event(state_event_for(pipeline)) + events = state_event_for(pipeline) + events.each { |event| emit_event(event) } end end def state_event_for(pipeline) - StateEventFactory.new(pipeline).make() + if @cluster_uuids.nil? || @cluster_uuids.empty? + [StateEventFactory.new(pipeline, nil, @collection_interval).make()] + else + @cluster_uuids.map do |cluster_uuid| + StateEventFactory.new(pipeline, cluster_uuid, @collection_interval).make() + end + end end def emit_event(event) @@ -187,5 +209,24 @@ module LogStash module Inputs } } end + + def extract_cluster_uuids(stats) + result = stats.extract_metrics([:stats, :pipelines, :main, :config], :cluster_uuids) + if result && !result[:cluster_uuids].empty? + cluster_uuids = result[:cluster_uuids] + @logger.info("Found cluster_uuids from elasticsearch output plugins", :cluster_uuids => cluster_uuids) + if LogStash::SETTINGS.set?("monitoring.cluster_uuid") + @logger.warn("Found monitoring.cluster_uuid setting configured in logstash.yml while using the ones discovered from elasticsearch output plugins, ignoring setting monitoring.cluster_uuid") + end + cluster_uuids + else + if LogStash::SETTINGS.set?("monitoring.cluster_uuid") + [LogStash::SETTINGS.get("monitoring.cluster_uuid")] + else + @logger.warn("Can't find any cluster_uuid from elasticsearch output plugins nor monitoring.cluster_uuid in logstash.yml is defined") + [""] + end + end + end end end; end diff --git a/x-pack/lib/monitoring/inputs/metrics/state_event_factory.rb b/x-pack/lib/monitoring/inputs/metrics/state_event_factory.rb index 8556cc848..e60e44e18 100644 --- a/x-pack/lib/monitoring/inputs/metrics/state_event_factory.rb +++ b/x-pack/lib/monitoring/inputs/metrics/state_event_factory.rb @@ -5,16 +5,30 @@ module LogStash; module Inputs; class Metrics; class StateEventFactory require "logstash/config/lir_serializer" - def initialize(pipeline) + + def initialize(pipeline, cluster_uuid, collection_interval = 10) raise ArgumentError, "No pipeline passed in!" unless pipeline.is_a?(LogStash::Pipeline) || pipeline.is_a?(LogStash::JavaPipeline) - @event = LogStash::Event.new - @event.set("[@metadata]", { - "document_type" => "logstash_state", - "timestamp" => Time.now - }) + pipeline_doc = {"pipeline" => pipeline_data(pipeline)} - @event.set("[pipeline]", pipeline_data(pipeline)) + if (LogStash::MonitoringExtension.use_direct_shipping?(LogStash::SETTINGS)) + event_body = { + "type" => "logstash_state", + "logstash_state" => pipeline_doc, + "cluster_uuid" => cluster_uuid, + "interval_ms" => collection_interval * 1000, + "timestamp" => DateTime.now.strftime('%Y-%m-%dT%H:%M:%S.%L%z') + } + else + event_body = pipeline_doc + end + + @event = LogStash::Event.new( + {"@metadata" => { + "document_type" => "logstash_state", + "timestamp" => Time.now + }}.merge(event_body) + ) @event.remove("@timestamp") @event.remove("@version") diff --git a/x-pack/lib/monitoring/inputs/metrics/stats_event_factory.rb b/x-pack/lib/monitoring/inputs/metrics/stats_event_factory.rb index 2d3ac6a2d..17a7a3658 100644 --- a/x-pack/lib/monitoring/inputs/metrics/stats_event_factory.rb +++ b/x-pack/lib/monitoring/inputs/metrics/stats_event_factory.rb @@ -7,14 +7,15 @@ module LogStash; module Inputs; class Metrics; include ::LogStash::Util::Loggable require 'logstash/config/pipelines_info' - def initialize(global_stats, snapshot) + def initialize(global_stats, snapshot, cluster_uuid) @global_stats = global_stats @snapshot = snapshot @metric_store = @snapshot.metric_store + @cluster_uuid = cluster_uuid end - def make(agent, extended_performance_collection=true) - LogStash::Event.new( + def make(agent, extended_performance_collection=true, collection_interval=10) + metrics_doc = { "timestamp" => @snapshot.created_at, "logstash" => fetch_node_stats(agent, @metric_store), "events" => format_global_event_count(@metric_store), @@ -24,10 +25,25 @@ module LogStash; module Inputs; class Metrics; "jvm" => format_jvm_stats(@metric_store), "os" => format_os_stats(@metric_store), "queue" => format_queue_stats(agent, @metric_store), - "@metadata" => { + } + + if (LogStash::MonitoringExtension.use_direct_shipping?(LogStash::SETTINGS)) + event_body = { + "type" => "logstash_stats", + "logstash_stats" => metrics_doc, + "cluster_uuid" => @cluster_uuid, + "interval_ms" => collection_interval * 1000, + "timestamp" => DateTime.now.strftime('%Y-%m-%dT%H:%M:%S.%L%z') + } + else + event_body = metrics_doc + end + + LogStash::Event.new( + {"@metadata" => { "document_type" => "logstash_stats", "timestamp" => Time.now - } + }}.merge(event_body) ) end @@ -48,7 +64,7 @@ module LogStash; module Inputs; class Metrics; result["mem"] = { "heap_used_in_bytes" => heap_stats[:used_in_bytes], "heap_used_percent" => heap_stats[:used_percent], - "heap_max_in_bytes" => heap_stats[:max_in_bytes], + "heap_max_in_bytes" => heap_stats[:max_in_bytes], } result["gc"] = { diff --git a/x-pack/lib/monitoring/monitoring.rb b/x-pack/lib/monitoring/monitoring.rb index c24dfaa88..e9b9de997 100644 --- a/x-pack/lib/monitoring/monitoring.rb +++ b/x-pack/lib/monitoring/monitoring.rb @@ -88,6 +88,22 @@ module LogStash def get_binding binding end + + def monitoring_endpoint + if LogStash::MonitoringExtension.use_direct_shipping?(LogStash::SETTINGS) + "/_bulk/" + else + "/_monitoring/bulk?system_id=logstash&system_api_version=#{system_api_version}&interval=1s" + end + end + + def monitoring_index + if LogStash::MonitoringExtension.use_direct_shipping?(LogStash::SETTINGS) + ".monitoring-logstash-#{system_api_version}-" + Time.now.utc.to_date.strftime("%Y.%m.%d") + else + "" #let the ES xpack's reporter to create it + end + end end class PipelineRegisterHook @@ -124,6 +140,7 @@ module LogStash # To help keep passivity, assume that if "xpack.monitoring.elasticsearch.hosts" has been set that monitoring should be enabled. # return true if xpack.monitoring.enabled=true (explicitly) or xpack.monitoring.elasticsearch.hosts is configured def monitoring_enabled?(settings) + return settings.get_value("monitoring.enabled") if settings.set?("monitoring.enabled") return settings.get_value("xpack.monitoring.enabled") if settings.set?("xpack.monitoring.enabled") if settings.set?("xpack.monitoring.elasticsearch.hosts") || settings.set?("xpack.monitoring.elasticsearch.cloud_id") @@ -157,22 +174,51 @@ module LogStash end def generate_pipeline_config(settings) - collection_interval = settings.get("xpack.monitoring.collection.interval") - collection_timeout_interval = settings.get("xpack.monitoring.collection.timeout_interval") - extended_performance_collection = settings.get("xpack.monitoring.collection.pipeline.details.enabled") - config_collection = settings.get("xpack.monitoring.collection.config.enabled") + if settings.set?("xpack.monitoring.enabled") && settings.set?("monitoring.enabled") + raise ArgumentError.new("\"xpack.monitoring.enabled\" is configured while also \"monitoring.enabled\"") + end + + if any_set?(settings, /^xpack.monitoring/) && any_set?(settings, /^monitoring./) + raise ArgumentError.new("\"xpack.monitoring.*\" settings can't be configured while using \"monitoring.*\"") + end + + if MonitoringExtension.use_direct_shipping?(settings) + opt = retrieve_collection_settings(settings) + else + opt = retrieve_collection_settings(settings, "xpack.") + deprecation_logger.deprecated("xpack.monitoring.* settings are deprecated use the new monitoring.*. Please see https://www.elastic.co/guide/en/logstash/current/monitoring-internal-collection.html") + end es_settings = es_options_from_settings_or_modules('monitoring', settings) data = TemplateData.new(LogStash::SETTINGS.get("node.uuid"), API_VERSION, es_settings, - collection_interval, collection_timeout_interval, - extended_performance_collection, config_collection) + opt[:collection_interval], opt[:collection_timeout_interval], + opt[:extended_performance_collection], opt[:config_collection]) template_path = ::File.join(::File.dirname(__FILE__), "..", "template.cfg.erb") template = ::File.read(template_path) ERB.new(template, 3).result(data.get_binding) end + + private + def retrieve_collection_settings(settings, prefix="") + opt = {} + opt[:collection_interval] = settings.get("#{prefix}monitoring.collection.interval") + opt[:collection_timeout_interval] = settings.get("#{prefix}monitoring.collection.timeout_interval") + opt[:extended_performance_collection] = settings.get("#{prefix}monitoring.collection.pipeline.details.enabled") + opt[:config_collection] = settings.get("#{prefix}monitoring.collection.config.enabled") + opt + end + + def any_set?(settings, regexp) + !settings.get_subset(regexp).to_hash.keys.select { |k| settings.set?(k)}.empty? + end end + def self.use_direct_shipping?(settings) + settings.get("monitoring.enabled") + end + + public def initialize # nothing to do here end @@ -184,24 +230,10 @@ module LogStash def additionals_settings(settings) logger.trace("registering additionals_settings") - - settings.register(LogStash::Setting::Boolean.new("xpack.monitoring.enabled", false)) - settings.register(LogStash::Setting::ArrayCoercible.new("xpack.monitoring.elasticsearch.hosts", String, [ "http://localhost:9200" ] )) - settings.register(LogStash::Setting::TimeValue.new("xpack.monitoring.collection.interval", "10s")) - settings.register(LogStash::Setting::TimeValue.new("xpack.monitoring.collection.timeout_interval", "10m")) - settings.register(LogStash::Setting::NullableString.new("xpack.monitoring.elasticsearch.username", "logstash_system")) - settings.register(LogStash::Setting::NullableString.new("xpack.monitoring.elasticsearch.password")) - settings.register(LogStash::Setting::NullableString.new("xpack.monitoring.elasticsearch.cloud_id")) - settings.register(LogStash::Setting::NullableString.new("xpack.monitoring.elasticsearch.cloud_auth")) - settings.register(LogStash::Setting::NullableString.new("xpack.monitoring.elasticsearch.ssl.certificate_authority")) - settings.register(LogStash::Setting::NullableString.new("xpack.monitoring.elasticsearch.ssl.truststore.path")) - settings.register(LogStash::Setting::NullableString.new("xpack.monitoring.elasticsearch.ssl.truststore.password")) - settings.register(LogStash::Setting::NullableString.new("xpack.monitoring.elasticsearch.ssl.keystore.path")) - settings.register(LogStash::Setting::NullableString.new("xpack.monitoring.elasticsearch.ssl.keystore.password")) - settings.register(LogStash::Setting::String.new("xpack.monitoring.elasticsearch.ssl.verification_mode", "certificate", true, ["none", "certificate"])) - settings.register(LogStash::Setting::Boolean.new("xpack.monitoring.elasticsearch.sniffing", false)) - settings.register(LogStash::Setting::Boolean.new("xpack.monitoring.collection.pipeline.details.enabled", true)) - settings.register(LogStash::Setting::Boolean.new("xpack.monitoring.collection.config.enabled", true)) + # Deprecated settings from 7.7 + register_monitoring_settings(settings, "xpack.") + # Direct shipping settings + register_monitoring_settings(settings) # These Settings were renamed and deprecated in 6.x timeframe and removed for 7.0; provide guidance to ease transition. settings.register(LogStash::Setting::DeprecatedAndRenamed.new("xpack.monitoring.elasticsearch.url", "xpack.monitoring.elasticsearch.hosts")) @@ -213,5 +245,26 @@ module LogStash logger.error e.backtrace.to_s raise e end + + private + def register_monitoring_settings(settings, prefix = "") + settings.register(LogStash::Setting::Boolean.new("#{prefix}monitoring.enabled", false)) + settings.register(LogStash::Setting::ArrayCoercible.new("#{prefix}monitoring.elasticsearch.hosts", String, [ "http://localhost:9200" ] )) + settings.register(LogStash::Setting::TimeValue.new("#{prefix}monitoring.collection.interval", "10s")) + settings.register(LogStash::Setting::TimeValue.new("#{prefix}monitoring.collection.timeout_interval", "10m")) + settings.register(LogStash::Setting::NullableString.new("#{prefix}monitoring.elasticsearch.username", "logstash_system")) + settings.register(LogStash::Setting::NullableString.new("#{prefix}monitoring.elasticsearch.password")) + settings.register(LogStash::Setting::NullableString.new("#{prefix}monitoring.elasticsearch.cloud_id")) + settings.register(LogStash::Setting::NullableString.new("#{prefix}monitoring.elasticsearch.cloud_auth")) + settings.register(LogStash::Setting::NullableString.new("#{prefix}monitoring.elasticsearch.ssl.certificate_authority")) + settings.register(LogStash::Setting::NullableString.new("#{prefix}monitoring.elasticsearch.ssl.truststore.path")) + settings.register(LogStash::Setting::NullableString.new("#{prefix}monitoring.elasticsearch.ssl.truststore.password")) + settings.register(LogStash::Setting::NullableString.new("#{prefix}monitoring.elasticsearch.ssl.keystore.path")) + settings.register(LogStash::Setting::NullableString.new("#{prefix}monitoring.elasticsearch.ssl.keystore.password")) + settings.register(LogStash::Setting::String.new("#{prefix}monitoring.elasticsearch.ssl.verification_mode", "certificate", true, ["none", "certificate"])) + settings.register(LogStash::Setting::Boolean.new("#{prefix}monitoring.elasticsearch.sniffing", false)) + settings.register(LogStash::Setting::Boolean.new("#{prefix}monitoring.collection.pipeline.details.enabled", true)) + settings.register(LogStash::Setting::Boolean.new("#{prefix}monitoring.collection.config.enabled", true)) + end end end diff --git a/x-pack/lib/monitoring/outputs/elasticsearch_monitoring.rb b/x-pack/lib/monitoring/outputs/elasticsearch_monitoring.rb index a9b8e6084..84dadf8f5 100644 --- a/x-pack/lib/monitoring/outputs/elasticsearch_monitoring.rb +++ b/x-pack/lib/monitoring/outputs/elasticsearch_monitoring.rb @@ -10,7 +10,7 @@ module LogStash module Outputs config :document_type, :validate => :string def use_event_type?(client) - true + !LogStash::MonitoringExtension.use_direct_shipping?(LogStash::SETTINGS) end end end; end diff --git a/x-pack/lib/template.cfg.erb b/x-pack/lib/template.cfg.erb index 211bfbe5e..5bebfa0aa 100644 --- a/x-pack/lib/template.cfg.erb +++ b/x-pack/lib/template.cfg.erb @@ -20,10 +20,10 @@ output { <% else %> hosts => <%= es_hosts %> <% end %> - bulk_path => "/_monitoring/bulk?system_id=logstash&system_api_version=<%= system_api_version %>&interval=1s" + bulk_path => "<%= monitoring_endpoint %>" manage_template => false document_type => "%{[@metadata][document_type]}" - index => "" + index => "<%= monitoring_index %>" sniffing => <%= sniffing %> <% if auth? && !cloud_auth? %> user => "<%= user %>" diff --git a/x-pack/qa/integration/monitoring/direct_shipping_spec.rb b/x-pack/qa/integration/monitoring/direct_shipping_spec.rb new file mode 100644 index 000000000..054c13acb --- /dev/null +++ b/x-pack/qa/integration/monitoring/direct_shipping_spec.rb @@ -0,0 +1,37 @@ +# 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_relative "../spec_helper" + +describe "Direct shipping" do + + before :all do + @elasticsearch_service = elasticsearch + + cleanup_elasticsearch + + config = "input { generator { count => 100 } tcp { port => 6000 } } output { null {} }" + + @logstash_service = logstash_with_empty_default("bin/logstash -e '#{config}' -w 1", { + :settings => { + "monitoring.enabled" => true, + "monitoring.elasticsearch.hosts" => ["http://localhost:9200", "http://localhost:9200"], + "monitoring.collection.interval" => "1s", + "monitoring.elasticsearch.username" => "elastic", + "monitoring.elasticsearch.password" => elastic_password + }, # will be saved in the logstash.yml + :belzebuth => { + :wait_condition => /Pipelines running/, + :timeout => 5 * 60 # Fail safe, this mean something went wrong if we hit this before the wait_condition + } + }) + end + + include_examples "record monitoring data to es" + + after :all do + @logstash_service.stop unless @logstash_service.nil? + @elasticsearch_service.stop unless @elasticsearch_service.nil? + end +end diff --git a/x-pack/qa/integration/monitoring/es_documents_structure_validation_spec.rb b/x-pack/qa/integration/monitoring/es_documents_structure_validation_spec.rb new file mode 100644 index 000000000..5f2d7312e --- /dev/null +++ b/x-pack/qa/integration/monitoring/es_documents_structure_validation_spec.rb @@ -0,0 +1,123 @@ +# 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_relative "../spec_helper" + +describe "Monitoring internal collector documents" do + + before :all do + @elasticsearch_service = elasticsearch + + cleanup_elasticsearch + + # this is tcp input useful to keep main pipeline alive + @config = "input { tcp { port => 6000 } } output { null {} }" + end + + let(:max_retry) { 10 } + let(:schemas_path) { File.join(File.dirname(__FILE__), "..", "..", "..", "spec", "monitoring", "schemas") } + let(:retryable_errors) do + [NoMethodError, + RSpec::Expectations::ExpectationNotMetError, + Elasticsearch::Transport::Transport::Errors::ServiceUnavailable, + Elasticsearch::Transport::Transport::Errors::NotFound] + end + + describe "metrics" do + it "should be equal to with direct shipping" do + @logstash_service = start_monitoring_logstash(@config) + direct_shipping_document = retrieve_monitoring_document_from_es("logstash_stats") + + @logstash_service.stop unless @logstash_service.nil? + + cleanup_elasticsearch + + @logstash_service = start_monitoring_logstash(@config, "xpack") + es_reporter_shaped_document = retrieve_monitoring_document_from_es("logstash_stats") + + @logstash_service.stop unless @logstash_service.nil? + + verify_same_structure(es_reporter_shaped_document, direct_shipping_document) + end + end + + describe "state" do + it "should be equal to with direct shipping" do + @logstash_service = start_monitoring_logstash(@config) + direct_shipping_document = retrieve_monitoring_document_from_es("logstash_state") + @logstash_service.stop unless @logstash_service.nil? + + cleanup_elasticsearch + + @logstash_service = start_monitoring_logstash(@config, "xpack") + es_reporter_shaped_document = retrieve_monitoring_document_from_es("logstash_state") + + @logstash_service.stop unless @logstash_service.nil? + + verify_same_structure(es_reporter_shaped_document, direct_shipping_document) + end + end + + after :all do + @elasticsearch_service.stop unless @elasticsearch_service.nil? + end +end + +def retrieve_monitoring_document_from_es(document_type) + monitoring_document = nil + + Stud.try(max_retry.times, retryable_errors) do + elasticsearch_client.indices.refresh + api_response = elasticsearch_client.search :index => MONITORING_INDEXES, :body => {:query => {:term => {"type" => document_type}}} + expect(api_response["hits"]["total"]["value"]).to be > 0 + api_response["hits"]["hits"].each do |full_document| + monitoring_document = full_document["_source"] + end + end + monitoring_document +end + +def start_monitoring_logstash(config, prefix = "") + if !prefix.nil? && !prefix.empty? + mon_prefix = prefix + "." + else + mon_prefix = "" + end + logstash_with_empty_default("bin/logstash -e '#{config}' -w 1", { + :settings => { + "#{mon_prefix}monitoring.enabled" => true, + "#{mon_prefix}monitoring.elasticsearch.hosts" => ["http://localhost:9200", "http://localhost:9200"], + "#{mon_prefix}monitoring.collection.interval" => "1s", + "#{mon_prefix}monitoring.elasticsearch.username" => "elastic", + "#{mon_prefix}monitoring.elasticsearch.password" => elastic_password + }, # will be saved in the logstash.yml + :belzebuth => { + :wait_condition => /Pipelines running/, + :timeout => 5 * 60 # Fail safe, this mean something went wrong if we hit this before the wait_condition + } + }) +end + +def verify_same_structure(original, other, ignored_keys = /^source_node/) + orig_keys = filter_ignored_and_make_set(flatten_keys(original), ignored_keys) + other_keys = filter_ignored_and_make_set(flatten_keys(other), ignored_keys) + expect(other_keys - orig_keys).to eq([]) + expect(orig_keys - other_keys).to eq([]) +end + +def filter_ignored_and_make_set(keys_list, ignored_keys) + keys_list.sort.uniq.select { |k| !(k =~ ignored_keys) } +end + +def flatten_keys(hash, prefix = "") + flattened_keys = [] + hash.each do |k, v| + if v.is_a? Hash + flattened_keys += flatten_keys(v, k.to_s) + else + flattened_keys << (prefix + (prefix.empty? ? "" : ".") + k.to_s) + end + end + flattened_keys +end \ No newline at end of file diff --git a/x-pack/qa/integration/support/helpers.rb b/x-pack/qa/integration/support/helpers.rb index 62170bbaa..8b7e9dee4 100644 --- a/x-pack/qa/integration/support/helpers.rb +++ b/x-pack/qa/integration/support/helpers.rb @@ -114,6 +114,10 @@ def logstash_command_append(cmd, argument, value) end def logstash(cmd, options = {}) + logstash_with_empty_default(cmd, options, {"xpack.monitoring.enabled" => true}) +end + +def logstash_with_empty_default(cmd, options = {}, default_settings = {}) temporary_settings = Stud::Temporary.directory temporary_data = Stud::Temporary.directory @@ -121,7 +125,6 @@ def logstash(cmd, options = {}) cmd = logstash_command_append(cmd, "--path.data", temporary_data) logstash_yaml = File.join(temporary_settings, "logstash.yml") - default_settings = {"xpack.monitoring.enabled" => true} IO.write(logstash_yaml, YAML::dump(default_settings.merge(options.fetch(:settings, {})))) FileUtils.cp(File.join(get_logstash_path, "config", "log4j2.properties"), File.join(temporary_settings, "log4j2.properties") ) diff --git a/x-pack/spec/monitoring/inputs/metrics/state_event_factory_spec.rb b/x-pack/spec/monitoring/inputs/metrics/state_event_factory_spec.rb new file mode 100644 index 000000000..ad8498a68 --- /dev/null +++ b/x-pack/spec/monitoring/inputs/metrics/state_event_factory_spec.rb @@ -0,0 +1,79 @@ +# 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/agent" +require "logstash/runner" +require "spec_helper" +require "monitoring/inputs/metrics/state_event_factory" +require 'json' + +describe LogStash::Inputs::Metrics::StateEventFactory do + + let(:schemas_path) { File.join(File.dirname(__FILE__), "..", "..", "..", "..", "spec", "monitoring", "schemas") } + + let(:config) { + config_part = org.logstash.common.SourceWithMetadata.new("local", "...", 0, 0, "input { dummyblockinginput { } } output { null { } }") + LogStash::Config::PipelineConfig.new("DummySource", "fake_main", [config_part], LogStash::SETTINGS) + } + + let(:pipeline_settings) { LogStash::Runner::SYSTEM_SETTINGS.clone.merge({ + "pipeline.id" => "main", + "config.string" => config.config_parts.first.text, + }) } + + let(:agent) { LogStash::Agent.new(pipeline_settings) } + let(:metric) { agent.metric } + let(:collector) { metric.collector } + let(:agent_task) { start_agent(agent) } + + before :each do + agent + agent_task + + wait(60).for { agent.get_pipeline(:main) }.to_not be_nil + + # collector.snapshot_metric is timing dependant and if fired too fast will miss some metrics. + # after some tests a correct metric_store.size is 72 but when it is incomplete it is lower. + # I guess this 72 is dependant on the metrics we collect and there is probably a better + # way to make sure no metrics are missing without forcing a hard sleep but this is what is + # easily observable, feel free to refactor with a better "timing" test here. + wait(60).for { collector.snapshot_metric.metric_store.size }.to be >= 72 + end + + after :each do + agent.shutdown + agent_task.wait + LogStash::SETTINGS.set_value("monitoring.enabled", false) + end + + let(:pipeline) { LogStash::Pipeline.new(config) } + + subject(:sut) { described_class.new(pipeline, "funky_cluster_uuid") } + + context "with write direct flag enabled" do + let(:schema_file) { File.join(schemas_path, "states_document_new_schema.json") } + + it "should create a valid new event shape" do + LogStash::SETTINGS.set_value("monitoring.enabled", true) + + state_evt = sut.make + json = JSON.parse(state_evt.to_json) + expect(json['type']).to eq('logstash_state') + expect(json['logstash_state']).to be_truthy + expect(json['logstash_state']['pipeline']).to be_truthy + expect(JSON::Validator.fully_validate(schema_file, state_evt.to_json)).to be_empty + end + end + + context "with write direct flag disabled" do + let(:schema_file) { File.join(schemas_path, "states_document_schema.json") } + + it "should create a valid old event shape" do + LogStash::SETTINGS.set_value("monitoring.enabled", false) + + state_evt = sut.make + expect(JSON::Validator.fully_validate(schema_file, state_evt.to_json)).to be_empty + end + end +end \ No newline at end of file diff --git a/x-pack/spec/monitoring/inputs/metrics/stats_event_factory_spec.rb b/x-pack/spec/monitoring/inputs/metrics/stats_event_factory_spec.rb new file mode 100644 index 000000000..351323a20 --- /dev/null +++ b/x-pack/spec/monitoring/inputs/metrics/stats_event_factory_spec.rb @@ -0,0 +1,81 @@ +# 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 "monitoring/inputs/metrics/stats_event_factory" +require 'json' + +describe LogStash::Inputs::Metrics::StatsEventFactory do + let(:schemas_path) { File.join(File.dirname(__FILE__), "..", "..", "..", "..", "spec", "monitoring", "schemas") } + let(:queue) { Concurrent::Array.new } + + let(:config) { "input { dummyblockinginput { } } output { null { } }" } + + let(:pipeline_settings) { LogStash::Runner::SYSTEM_SETTINGS.clone.merge({ + "pipeline.id" => "main", + "config.string" => config, + }) } + + let(:agent) { LogStash::Agent.new(pipeline_settings) } + let(:metric) { agent.metric } + let(:collector) { metric.collector } + let(:agent_task) { start_agent(agent) } + + before :each do + agent + agent_task + + wait(60).for { agent.get_pipeline(:main) }.to_not be_nil + + # collector.snapshot_metric is timing dependant and if fired too fast will miss some metrics. + # after some tests a correct metric_store.size is 72 but when it is incomplete it is lower. + # I guess this 72 is dependant on the metrics we collect and there is probably a better + # way to make sure no metrics are missing without forcing a hard sleep but this is what is + # easily observable, feel free to refactor with a better "timing" test here. + wait(60).for { collector.snapshot_metric.metric_store.size }.to be >= 72 + + # Wait http server is up + wait(120).for { + begin + collector.snapshot_metric.metric_store.get_shallow(:http_address) + rescue LogStash::Instrument::MetricStore::MetricNotFound => e + nil + end + }.not_to be_nil + end + + after :each do + agent.shutdown + agent_task.wait + LogStash::SETTINGS.set_value("monitoring.enabled", false) + end + + context "new model" do + let(:schema_file) { File.join(schemas_path, "monitoring_document_new_schema.json") } + + it "should be valid" do + global_stats = {"uuid" => "00001" } + sut = described_class.new(global_stats, collector.snapshot_metric, "funky_cluster_uuid") + LogStash::SETTINGS.set_value("monitoring.enabled", true) + + monitoring_evt = sut.make(agent, true) + json = JSON.parse(monitoring_evt.to_json) + expect(json['type']).to eq('logstash_stats') + expect(JSON::Validator.fully_validate(schema_file, monitoring_evt.to_json)).to be_empty + end + end + + context "old model" do + let(:schema_file) { File.join(schemas_path, "monitoring_document_schema.json") } + + it "should be valid" do + global_stats = {"uuid" => "00001" } + sut = described_class.new(global_stats, collector.snapshot_metric, nil) + LogStash::SETTINGS.set_value("monitoring.enabled", false) + + monitoring_evt = sut.make(agent, true) + json = JSON.parse(monitoring_evt.to_json) + expect(JSON::Validator.fully_validate(schema_file, monitoring_evt.to_json)).to be_empty + end + end +end \ No newline at end of file diff --git a/x-pack/spec/monitoring/inputs/metrics_spec.rb b/x-pack/spec/monitoring/inputs/metrics_spec.rb index 873ca282f..3d8b99cb4 100644 --- a/x-pack/spec/monitoring/inputs/metrics_spec.rb +++ b/x-pack/spec/monitoring/inputs/metrics_spec.rb @@ -175,7 +175,7 @@ describe LogStash::Inputs::Metrics do describe "normal pipelines" do before(:each) do allow(pipeline).to receive(:system?).and_return(false) - allow(metrics_input).to receive(:state_event_for).with(pipeline).and_return(state_event) + allow(metrics_input).to receive(:state_event_for).with(pipeline).and_return([state_event]) allow(metrics_input).to receive(:emit_event) metrics_input.update_pipeline_state(pipeline) diff --git a/x-pack/spec/monitoring/pipeline_register_hook_spec.rb b/x-pack/spec/monitoring/pipeline_register_hook_spec.rb new file mode 100644 index 000000000..ac630bd4f --- /dev/null +++ b/x-pack/spec/monitoring/pipeline_register_hook_spec.rb @@ -0,0 +1,49 @@ +# 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 'monitoring/monitoring' + +describe LogStash::MonitoringExtension::PipelineRegisterHook do + + subject { described_class.new } + + before(:all) { + @extension = LogStash::MonitoringExtension.new + # used to register monitoring xpack's settings + @sys_settings = LogStash::Runner::SYSTEM_SETTINGS.clone + @extension.additionals_settings(@sys_settings) + } + + context 'validate monitoring settings' do + it "work without any monitoring settings" do + settings = @sys_settings.clone + settings.set_value("xpack.monitoring.enabled", true) + settings.set_value("xpack.monitoring.elasticsearch.hosts", "http://localhost:9200") + settings.set_value("xpack.monitoring.elasticsearch.username", "elastic") + settings.set_value("xpack.monitoring.elasticsearch.password", "changeme") + expect(subject.generate_pipeline_config(settings)).to be_truthy + end + + it "monitoring.enabled should conflict with xpack.monitoring.enabled" do + settings = @sys_settings.clone + settings.set_value("xpack.monitoring.enabled", true) + settings.set_value("monitoring.enabled", true) + + expect { + subject.generate_pipeline_config(settings) + }.to raise_error(ArgumentError) + end + + it "monitoring.* should conflict with any xpack.monitoring.*" do + settings = @sys_settings.clone + settings.set_value("xpack.monitoring.collection.interval", "10s") + settings.set_value("monitoring.enabled", true) + + expect { + subject.generate_pipeline_config(settings) + }.to raise_error(ArgumentError) + end + end + +end diff --git a/x-pack/spec/monitoring/schemas/monitoring_document_new_schema.json b/x-pack/spec/monitoring/schemas/monitoring_document_new_schema.json new file mode 100644 index 000000000..d8fd6855b --- /dev/null +++ b/x-pack/spec/monitoring/schemas/monitoring_document_new_schema.json @@ -0,0 +1,186 @@ +{ + "$schema": "http://json-schema.org/draft-04/schema#", + "definitions": { + "reloads": { + "type": "object", + "required": ["failures", "successes"], + "properties": { + "failures": { "type": "number" }, + "successes": { "type": "number" } + } + }, + "events": { + "type": "object", + "required": ["filtered", "in", "duration_in_millis", "out"], + "properties": { + "filtered": { "type": "number" }, + "in": { "type": "number" }, + "duration_in_millis": { "type": "number" }, + "out": { "type": "number" } + } + } + }, + "type": {"type": "string" }, + "cluster_uuid": {"type": "string" }, + "interval_ms": {"type": "integer" }, + "timestamp": {"type": "string" }, + "logstash_stats": { + "type": "object", + "required": ["jvm", "logstash", "process", "os", "events", "queue", "reloads", "pipelines"], + "properties": { + "jvm": { + "type": "object", + "required": ["mem", "uptime_in_millis", "gc"], + "properties": { + "mem": { + "type": "object", + "require": ["heap_used_in_bytes", "heap_max_in_bytes", "heap_used_percent"], + "properties": { + "heap_used_percent": { "type": "number" }, + "heap_max_in_bytes": { "type": "number" }, + "heap_used_in_bytes": { "type": "number" } + } + }, + "uptime_in_millis": { "type": "number" }, + "gc": { + "type": "object", + "required": ["collectors"], + "properties": { + "collectors": { + "type": "object", + "required": ["young", "old"], + "properties": { + "young": { + "type": "object", + "required": ["collection_count", "collection_time_in_millis"], + "properties": { + "collection_count": {"type": "number"}, + "collection_time_in_millis": {"type": "number"} + } + }, + "old": { + "type": "object", + "required": ["collection_count", "collection_time_in_millis"], + "properties": { + "collection_count": {"type": "number"}, + "collection_time_in_millis": {"type": "number"} + } + } + } + } + } + } + } + }, + "logstash": { + "type": "object", + "required": ["http_address", "uuid", "ephemeral_id"], + "properties": { + "http_address": { "type": "string" }, + "uuid": { "type": "string" }, + "ephemeral_id": { "type": "string" } + } + }, + "process": { + "type": "object", + "required": ["open_file_descriptors", "max_file_descriptors", "cpu"], + "properties": { + "open_file_descriptors": { "type": "number" }, + "max_file_descriptors": { "type": "number" }, + "cpu": { + "type": "object", + "required": ["percent"], + "properties": { "percent": { "type": "number"} } + } + } + }, + "os": { + "type": "object", + "required": ["cpu"], + "properties": { + "cpu": { + "type": "object", + "required": ["load_average"], + "properties": { + "load_average": { + "type": "object", + "required": ["1m"], + "properties": { + "1m": {"type": "number"}, + "5m": {"type": "number"}, + "15m": {"type": "number"} + } + } + } + } + } + }, + "events": {"$ref": "#/definitions/events"}, + "queue": { + "type": "object", + "required": ["events_count"], + "properties": { + "events_count": {"type": "number"} + } + }, + "reloads": {"$ref": "#/definitions/reloads"}, + "timestamp": {"type": "string"}, + "pipelines": { + "type": "array", + "minItems": 1, + "uniqueItems": true, + "items": { + "type": "object", + "required": ["id", "hash", "ephemeral_id", "events", "queue", "reloads", "vertices"], + "properties": { + "id": {"type": "string"}, + "hash": {"type": "string"}, + "ephemeral_id": {"type": "string"}, + "reloads": {"$ref": "#/definitions/reloads"}, + "queue": { + "type": "object", + "required": ["events_count", "type", "queue_size_in_bytes", "max_queue_size_in_bytes"], + "properties": { + "type": {"type": "string"}, + "events_count": {"type": "number"}, + "queue_size_in_bytes": {"type": "number"}, + "max_queue_size_in_bytes": {"type": "number"} + } + }, + "events": {"$ref": "#/definitions/events"}, + "vertices": { + "type": "array", + "minItems": 1, + "uniqueItems": true, + "items": { + "type": "object", + "patternProperties": { + "long_counters": { + "type": "array", + "items": { + "type": "object", + "properties": { + "name": {"type": "string"}, + "value": {"type": "number"} + } + } + }, + "double_gauges": { + "type": "array", + "items": { + "type": "object", + "properties": { + "name": {"type": "string"}, + "value": {"type": "string"} + } + } + } + } + } + } + } + } + } + } + } +} diff --git a/x-pack/spec/monitoring/schemas/states_document_new_schema.json b/x-pack/spec/monitoring/schemas/states_document_new_schema.json new file mode 100644 index 000000000..eb9e90f4f --- /dev/null +++ b/x-pack/spec/monitoring/schemas/states_document_new_schema.json @@ -0,0 +1,94 @@ +{ + "$schema": "http://json-schema.org/draft-04/schema#", + "definitions": { + "edge": { + "type": "object", + "properties": { + "from": {"type": "string"}, + "id": {"type": "string"}, + "to": {"type": "string"}, + "type": {"type": "string"} + } + }, + "vertex": { + "type": "object", + "properties": { + "id": {"type": "string"}, + "explicit_id": {"type": "boolean"}, + "type": {"type": "string"}, + "meta": { + "anyOf": [ + {"type": "null"}, + { + "type": "object", + "properties": { + "source": { + "type": "object", + "properties": { + "protocol": {"type": "string"}, + "id": {"type": "string"}, + "line": {"type": "number"}, + "column": {"type": "number"}, + "text": {"type": "string"} + } + } + } + } + ] + } + } + } + }, + "properties": { + "type": {"type": "string" }, + "cluster_uuid": {"type": "string" }, + "interval_ms": {"type": "integer" }, + "timestamp": {"type": "string" }, + "logstash_state": { + "type": "object", + "properties": { + "pipeline": { + "type": "object", + "properties": { + "batch_size": {"type": "integer"}, + "workers": {"type": "integer"}, + "hash": {"type": "string"}, + "ephemeral_id": {"type": "string"}, + "type": {"type": "string"}, + "name": {"type": "string"}, + "representation": { + "type": "object", + "properties": { + "hash": {"type": "string"}, + "version": {"type": "string"}, + "graph": { + "type": "object", + "properties": { + "edges": { + "type": "array", + "items": {"$ref": "#/definitions/edge"} + }, + "vertices": { + "type": "array", + "items": {"$ref": "#/definitions/vertex"} + } + } + }, + "plugins": { + "type": "array", + "items": { + "type": "object", + "properties": { + "name": {"type": "string"}, + "version": {"type": "string"} + } + } + } + } + } + } + } + } + } + } +} From b19db959af1743d6c68d5c355dc522012c2fa546 Mon Sep 17 00:00:00 2001 From: Joao Duarte Date: Thu, 12 Mar 2020 09:05:44 +0000 Subject: [PATCH 0386/1126] ensure mavencentral is always used before plugins.gradle.org Fixes #11682 --- build.gradle | 1 + 1 file changed, 1 insertion(+) diff --git a/build.gradle b/build.gradle index 8928e8abd..5a64f26d5 100644 --- a/build.gradle +++ b/build.gradle @@ -99,6 +99,7 @@ allprojects { subprojects { repositories { + mavenCentral() maven { url 'https://plugins.gradle.org/m2/' } From c731596c7c777944961edd8332e2714cf42f7157 Mon Sep 17 00:00:00 2001 From: Karen Metts Date: Fri, 6 Mar 2020 16:37:55 -0500 Subject: [PATCH 0387/1126] Change default threads for azure module Fixes #11664 --- docs/static/azure-module.asciidoc | 55 +++++++++++++++++++++++-------- 1 file changed, 41 insertions(+), 14 deletions(-) diff --git a/docs/static/azure-module.asciidoc b/docs/static/azure-module.asciidoc index 06c22d9e7..ed91fa8c1 100644 --- a/docs/static/azure-module.asciidoc +++ b/docs/static/azure-module.asciidoc @@ -220,32 +220,59 @@ https://portal.azure.com[Azure Portal]`-> Blob Storage account -> Access keys`. Here are some guidelines to help you achieve a successful deployment, and avoid data conflicts that can cause lost events. -* **Create a {ls} consumer group.** +* <> +* <> +* <> + +[[azure-bp-group]] +====== Create a {ls} consumer group + Create a new consumer group specifically for {ls}. Do not use the $default or any other consumer group that might already be in use. Reusing consumer groups among non-related consumers can cause unexpected behavior and possibly lost events. All {ls} instances should use the same consumer group so that they can work together for processing events. -* **Avoid overwriting offset with multiple Event Hubs.** + +[[azure-bp-multihub]] +====== Avoid overwriting offset with multiple Event Hubs + The offsets (position) of the Event Hubs are stored in the configured Azure Blob store. The Azure Blob store uses paths like a file system to store the offsets. If the paths between multiple Event Hubs overlap, then the offsets may be stored incorrectly. + To avoid duplicate file paths, use the advanced configuration model and make sure that at least one of these options is different per Event Hub: -** storage_connection -** storage_container (defaults to Event Hub name if not defined) -** consumer_group -* **Set number of threads correctly.** -The number of threads should equal the number of Event Hubs plus one (or more). -Each Event Hub needs at least one thread. An additional thread is needed to help -coordinate the other threads. The number of threads should not exceed the number of Event Hubs multiplied by the -number of partitions per Event Hub plus one. Threads are -currently available only as a global setting. -** Sample: Event Hubs = 4. Partitions on each Event Hub = 3. + +* storage_connection +* storage_container (defaults to Event Hub name if not defined) +* consumer_group + +[[azure-bp-threads]] +====== Set number of threads correctly + +By default, the number of threads used to service all event hubs is `16`. And +while this may be sufficient for most use cases, throughput may be improved by +refining this number. When servicing a large number of partitions across one or +more event hubs, setting a higher value may result in improved performance. The +maximum number of threads is not strictly bound by the total number of +partitions being serviced, but setting the value much higher than that may mean +that some threads are idle. + +NOTE: The number of threads *must* be greater than or equal to the number of Event +hubs plus one. + +NOTE: Threads are currently available only as a global setting across all event hubs +in a single `azure_event_hubs` input definition. However if your configuration +includes multiple `azure_event_hubs` inputs, the threads setting applies +independently to each. + +**Sample scenarios:** + +* Event Hubs = 4. Partitions on each Event Hub = 3. Minimum threads is 5 (4 Event Hubs plus one). Maximum threads is 13 (4 Event Hubs times 3 partitions plus one). -** If you're collecting activity logs from only one specified event hub instance, +* If you're collecting activity logs from only one specified event hub instance, then only 2 threads (1 Event Hub plus one) are required. [[azure-module-setup]] @@ -427,7 +454,7 @@ containers. ===== `threads` * Value type is <> * Minimum value is `2` -* Default value is `4` +* Default value is `16` Total number of threads used to process events. The value you set here applies to all Event Hubs. Even with advanced configuration, this value is a global From d90616fdee79d7bdad4c1f3267e873dd2e25b197 Mon Sep 17 00:00:00 2001 From: andsel Date: Tue, 21 Jan 2020 09:40:00 +0100 Subject: [PATCH 0388/1126] Added clarification that configuration force reload doesn't work on WinOS Fixes #11520 --- docs/static/reloading-config.asciidoc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/static/reloading-config.asciidoc b/docs/static/reloading-config.asciidoc index fee08bc8e..5fe784f2c 100644 --- a/docs/static/reloading-config.asciidoc +++ b/docs/static/reloading-config.asciidoc @@ -21,7 +21,7 @@ checks the config files for changes (in seconds). If Logstash is already running without auto-reload enabled, you can force Logstash to reload the config file and restart the pipeline by sending a SIGHUP (signal hangup) to the -process running Logstash. For example: +process running Logstash, but it's not supported on Windows OS. For example: [source,shell] ---------------------------------- From 7116d39b9f1dbf0cac3d34116797a93c9f6ccb0f Mon Sep 17 00:00:00 2001 From: Andrea Selva Date: Fri, 13 Mar 2020 16:16:24 +0100 Subject: [PATCH 0389/1126] Adaptations to internal collector to send data directly to monitoring cluster Close 11573 (#11641) Added check on HTTP server before asking for monitoring data in unit test Fixes #11541 From 89aaebb61b2fb2122dd5fe83784b6add8dbbd6fa Mon Sep 17 00:00:00 2001 From: Andres Rodriguez Date: Fri, 13 Mar 2020 12:07:45 -0400 Subject: [PATCH 0390/1126] Revert "Adaptations to internal collector to send data directly to monitoring cluster Close 11573 (#11641)" (#11687) This reverts commit 7116d39b9f1dbf0cac3d34116797a93c9f6ccb0f. From ff471bbb97338bfe258c1ee5e16ac659805f2db7 Mon Sep 17 00:00:00 2001 From: j-yama <38563686+j-yama@users.noreply.github.com> Date: Fri, 13 Mar 2020 15:00:25 +0900 Subject: [PATCH 0391/1126] Add `sudo` into the rpm import of GPG-KEY Fixes #11684 --- docs/static/getting-started-with-logstash.asciidoc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/static/getting-started-with-logstash.asciidoc b/docs/static/getting-started-with-logstash.asciidoc index de39968f3..8f22500d8 100644 --- a/docs/static/getting-started-with-logstash.asciidoc +++ b/docs/static/getting-started-with-logstash.asciidoc @@ -179,7 +179,7 @@ Download and install the public signing key: [source,sh] -------------------------------------------------- -rpm --import https://artifacts.elastic.co/GPG-KEY-elasticsearch +sudo rpm --import https://artifacts.elastic.co/GPG-KEY-elasticsearch -------------------------------------------------- Add the following in your `/etc/yum.repos.d/` directory From 81a96546d3149764cbcac7271f3854ca53b63764 Mon Sep 17 00:00:00 2001 From: Mark Ramotowski Date: Sat, 14 Mar 2020 18:05:33 +0000 Subject: [PATCH 0392/1126] Fixed typo in guage metric of unknown type log. Fixes #11689 --- .../logstash/instrument/metrics/gauge/LazyDelegatingGauge.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/logstash-core/src/main/java/org/logstash/instrument/metrics/gauge/LazyDelegatingGauge.java b/logstash-core/src/main/java/org/logstash/instrument/metrics/gauge/LazyDelegatingGauge.java index bb4b736aa..1e1d995a2 100644 --- a/logstash-core/src/main/java/org/logstash/instrument/metrics/gauge/LazyDelegatingGauge.java +++ b/logstash-core/src/main/java/org/logstash/instrument/metrics/gauge/LazyDelegatingGauge.java @@ -111,7 +111,7 @@ public class LazyDelegatingGauge extends AbstractMetric implements Gauge } else if (value instanceof RubyTimestamp) { lazyMetric = new RubyTimeStampGauge(key, (RubyTimestamp) value); } else { - LOGGER.warn("A gauge metric of an unknown type ({}) has been create for key: {}. This may result in invalid serialization. It is recommended to " + + LOGGER.warn("A gauge metric of an unknown type ({}) has been created for key: {}. This may result in invalid serialization. It is recommended to " + "log an issue to the responsible developer/development team.", value.getClass().getCanonicalName(), key); lazyMetric = new UnknownGauge(key, value); } From ae3002d7d42687641f4f6a2367a0bd93dc68cf76 Mon Sep 17 00:00:00 2001 From: andsel Date: Mon, 16 Mar 2020 16:00:52 +0100 Subject: [PATCH 0393/1126] minor, used the correct placeholder Fixes #11691 --- docs/static/include/pluginbody.asciidoc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/static/include/pluginbody.asciidoc b/docs/static/include/pluginbody.asciidoc index 892e9b8c9..507822e2f 100644 --- a/docs/static/include/pluginbody.asciidoc +++ b/docs/static/include/pluginbody.asciidoc @@ -43,7 +43,7 @@ Alternatively, you can use the examples repo we host on github.com *** alternately, via ssh: `git clone git@github.com:GITUSERNAME/logstash`+-pass:attributes[{plugintype}]-MYPLUGINNAME.git+ ** +cd logstash-pass:attributes[{plugintype}]-MYPLUGINNAME+ -. **Clone the {inputtype} plugin example and copy it to your plugin branch.** +. **Clone the {plugintype} plugin example and copy it to your plugin branch.** + You don't want to include the example .git directory or its contents, so delete it before you copy the example. From 758bc5c6203b078c3606ec13e9d4454dd32913de Mon Sep 17 00:00:00 2001 From: Colin Surprenant Date: Mon, 16 Mar 2020 16:58:56 -0400 Subject: [PATCH 0394/1126] support quoted plugin option key (#11693) 7.7 clean backport of #11688 --- logstash-core/lib/logstash/compiler/lscl.rb | 2 +- .../spec/logstash/compiler/compiler_spec.rb | 15 +++++++++++++++ 2 files changed, 16 insertions(+), 1 deletion(-) diff --git a/logstash-core/lib/logstash/compiler/lscl.rb b/logstash-core/lib/logstash/compiler/lscl.rb index 6b5d8f5b0..7c792a9a8 100644 --- a/logstash-core/lib/logstash/compiler/lscl.rb +++ b/logstash-core/lib/logstash/compiler/lscl.rb @@ -147,7 +147,7 @@ module LogStashCompilerLSCLGrammar; module LogStash; module Compiler; module LSC class Attribute < Node def expr - [name.text_value, value.expr] + [name.is_a?(AST::String) ? name.text_value[1...-1] : name.text_value, value.expr] end end diff --git a/logstash-core/spec/logstash/compiler/compiler_spec.rb b/logstash-core/spec/logstash/compiler/compiler_spec.rb index 35f4b48fb..95b2b34d7 100644 --- a/logstash-core/spec/logstash/compiler/compiler_spec.rb +++ b/logstash-core/spec/logstash/compiler/compiler_spec.rb @@ -243,6 +243,21 @@ describe LogStash::Compiler do end end + describe "a plugin with quoted parameter keys" do + let(:plugin_source) { "generator { notquoted => 1 'singlequoted' => 2 \"doublequoted\" => 3}" } + let(:expected_plugin_args) do + { + "notquoted" => 1, + "singlequoted" => 2, + "doublequoted" => 3, + } + end + + it "should contain the plugin" do + expect(c_plugin).to ir_eql(j.iPlugin(rand_meta, INPUT, "generator", expected_plugin_args)) + end + end + describe "a plugin with multiple array parameter types" do let(:plugin_source) { "generator { aarg => [1] aarg => [2] aarg => [3]}" } let(:expected_plugin_args) do From 1c964a27a53944515a8bbbac490cdfcc9054bdde Mon Sep 17 00:00:00 2001 From: Karen Metts Date: Tue, 17 Mar 2020 17:18:52 -0400 Subject: [PATCH 0395/1126] Expand section on force reloading config Fixes #11699 --- docs/static/reloading-config.asciidoc | 17 +++++++++++------ 1 file changed, 11 insertions(+), 6 deletions(-) diff --git a/docs/static/reloading-config.asciidoc b/docs/static/reloading-config.asciidoc index 5fe784f2c..019610e0d 100644 --- a/docs/static/reloading-config.asciidoc +++ b/docs/static/reloading-config.asciidoc @@ -1,8 +1,7 @@ [[reloading-config]] === Reloading the Config File -Starting with Logstash 2.3, you can set Logstash to detect and reload configuration -changes automatically. +You can set Logstash to detect and reload configuration changes automatically. To enable automatic config reloading, start Logstash with the `--config.reload.automatic` (or `-r`) command-line option specified. For example: @@ -19,9 +18,13 @@ By default, Logstash checks for configuration changes every 3 seconds. To change use the `--config.reload.interval ` option, where `interval` specifies how often Logstash checks the config files for changes (in seconds). -If Logstash is already running without auto-reload enabled, you can force Logstash to -reload the config file and restart the pipeline by sending a SIGHUP (signal hangup) to the -process running Logstash, but it's not supported on Windows OS. For example: +[[force-reload]] +==== Force reloading the config file + +If Logstash is already running without auto-reload enabled, you can force +Logstash to reload the config file and restart the pipeline. Do this by sending +a SIGHUP (signal hangup) to the process running Logstash. +For example: [source,shell] ---------------------------------- @@ -30,7 +33,9 @@ kill -SIGHUP 14175 Where 14175 is the ID of the process running Logstash. -==== How Automatic Config Reloading Works +NOTE: This functionality is not supported on Windows OS. + +==== How automatic config reloading works When Logstash detects a change in a config file, it stops the current pipeline by stopping all inputs, and it attempts to create a new pipeline that uses the updated configuration. From e77a2985c309db98c69364ba59ab34fa11e7db5e Mon Sep 17 00:00:00 2001 From: andsel Date: Wed, 25 Mar 2020 13:06:33 +0100 Subject: [PATCH 0396/1126] Start dev cycle for 7.8.0 Fixes #11719 --- README.md | 16 ++++++++-------- versions.yml | 4 ++-- 2 files changed, 10 insertions(+), 10 deletions(-) diff --git a/README.md b/README.md index 98dfd88ec..d5996bd78 100644 --- a/README.md +++ b/README.md @@ -28,14 +28,14 @@ These builds are created nightly and have undergone no formal QA, so they should | [deb-complete][] | [deb-oss][] | | [rpm-complete][] | [rpm-oss][] | -[tar-complete]: https://snapshots.elastic.co/downloads/logstash/logstash-7.7.0-SNAPSHOT.tar.gz -[zip-complete]: https://snapshots.elastic.co/downloads/logstash/logstash-7.7.0-SNAPSHOT.zip -[deb-complete]: https://snapshots.elastic.co/downloads/logstash/logstash-7.7.0-SNAPSHOT.deb -[rpm-complete]: https://snapshots.elastic.co/downloads/logstash/logstash-7.7.0-SNAPSHOT.rpm -[tar-oss]: https://snapshots.elastic.co/downloads/logstash/logstash-oss-7.7.0-SNAPSHOT.tar.gz -[zip-oss]: https://snapshots.elastic.co/downloads/logstash/logstash-oss-7.7.0-SNAPSHOT.zip -[deb-oss]: https://snapshots.elastic.co/downloads/logstash/logstash-oss-7.7.0-SNAPSHOT.deb -[rpm-oss]: https://snapshots.elastic.co/downloads/logstash/logstash-oss-7.7.0-SNAPSHOT.rpm +[tar-complete]: https://snapshots.elastic.co/downloads/logstash/logstash-7.8.0-SNAPSHOT.tar.gz +[zip-complete]: https://snapshots.elastic.co/downloads/logstash/logstash-7.8.0-SNAPSHOT.zip +[deb-complete]: https://snapshots.elastic.co/downloads/logstash/logstash-7.8.0-SNAPSHOT.deb +[rpm-complete]: https://snapshots.elastic.co/downloads/logstash/logstash-7.8.0-SNAPSHOT.rpm +[tar-oss]: https://snapshots.elastic.co/downloads/logstash/logstash-oss-7.8.0-SNAPSHOT.tar.gz +[zip-oss]: https://snapshots.elastic.co/downloads/logstash/logstash-oss-7.8.0-SNAPSHOT.zip +[deb-oss]: https://snapshots.elastic.co/downloads/logstash/logstash-oss-7.8.0-SNAPSHOT.deb +[rpm-oss]: https://snapshots.elastic.co/downloads/logstash/logstash-oss-7.8.0-SNAPSHOT.rpm ## Need Help? diff --git a/versions.yml b/versions.yml index 6ac7f2132..47b589b38 100644 --- a/versions.yml +++ b/versions.yml @@ -1,7 +1,7 @@ --- # alpha and beta qualifiers are now added via VERSION_QUALIFIER environment var -logstash: 7.7.0 -logstash-core: 7.7.0 +logstash: 7.8.0 +logstash-core: 7.8.0 logstash-core-plugin-api: 2.1.16 # jruby must reference a *released* version of jruby which can be downloaded from the official download url From baf60a98407bee86dc4a8f28c87e66b869a06515 Mon Sep 17 00:00:00 2001 From: Karol Bucek Date: Thu, 26 Mar 2020 11:47:41 +0100 Subject: [PATCH 0397/1126] Updated: JRuby to 9.2.11.1 Fixes #11723 --- rubyUtils.gradle | 2 +- versions.yml | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/rubyUtils.gradle b/rubyUtils.gradle index db65c5434..a4cfa2013 100644 --- a/rubyUtils.gradle +++ b/rubyUtils.gradle @@ -25,7 +25,7 @@ buildscript { dependencies { classpath 'org.yaml:snakeyaml:1.23' classpath "de.undercouch:gradle-download-task:3.2.0" - classpath "org.jruby:jruby-complete:9.2.11.0" + classpath "org.jruby:jruby-complete:9.2.11.1" } } diff --git a/versions.yml b/versions.yml index 47b589b38..284de3f1c 100644 --- a/versions.yml +++ b/versions.yml @@ -7,8 +7,8 @@ logstash-core-plugin-api: 2.1.16 # jruby must reference a *released* version of jruby which can be downloaded from the official download url # *and* for which jars artifacts are published for compile-time jruby: - version: 9.2.11.0 - sha1: c92bf2e52132b4d6d120f8dfbae15b36ab20d9d4 + version: 9.2.11.1 + sha1: cceb81635fe3cd39f895c7632428e94b503e8e3d # jruby-runtime-override, if specified, will override the jruby version installed in vendor/jruby for logstash runtime only, # not for the compile-time jars From 0aae62ace2740356034d98eede799f8a3ec17bee Mon Sep 17 00:00:00 2001 From: Colin Surprenant Date: Mon, 30 Mar 2020 10:49:22 -0400 Subject: [PATCH 0398/1126] separate filter & output execution, rebatch after filter when ordered (#11726) 7.8 clean backport of #11710 --- .../lib/logstash/config/lir_serializer.rb | 8 + .../logstash/ackedqueue/AckedReadBatch.java | 36 ++-- .../logstash/config/ir/CompiledPipeline.java | 157 ++++++++++++++---- .../org/logstash/config/ir/PipelineIR.java | 6 + .../config/ir/compiler/DatasetCompiler.java | 137 ++++++++++----- .../org/logstash/config/ir/graph/Graph.java | 2 +- .../config/ir/graph/SeparatorVertex.java | 64 +++++++ .../logstash/execution/MemoryReadBatch.java | 29 ++-- .../org/logstash/execution/QueueBatch.java | 8 +- .../org/logstash/execution/WorkerLoop.java | 27 +-- 10 files changed, 353 insertions(+), 121 deletions(-) create mode 100644 logstash-core/src/main/java/org/logstash/config/ir/graph/SeparatorVertex.java diff --git a/logstash-core/lib/logstash/config/lir_serializer.rb b/logstash-core/lib/logstash/config/lir_serializer.rb index e19049eef..9826d3217 100644 --- a/logstash-core/lib/logstash/config/lir_serializer.rb +++ b/logstash-core/lib/logstash/config/lir_serializer.rb @@ -63,6 +63,8 @@ module LogStash; if_vertex(v) when :queue queue_vertex(v) + when :separator + separator_vertex(v) end decorate_vertex(v, hashified_vertex) @@ -75,6 +77,8 @@ module LogStash; :if elsif v.java_kind_of?(org.logstash.config.ir.graph.QueueVertex) :queue + elsif v.java_kind_of?(org.logstash.config.ir.graph.SeparatorVertex) + :separator else raise "Unexpected vertex type! #{v}" end @@ -106,6 +110,10 @@ module LogStash; {} end + def separator_vertex(v) + {} + end + def edge(e) e_json = { "from" => e.from.id, diff --git a/logstash-core/src/main/java/org/logstash/ackedqueue/AckedReadBatch.java b/logstash-core/src/main/java/org/logstash/ackedqueue/AckedReadBatch.java index dbc8c686a..74a2dafec 100644 --- a/logstash-core/src/main/java/org/logstash/ackedqueue/AckedReadBatch.java +++ b/logstash-core/src/main/java/org/logstash/ackedqueue/AckedReadBatch.java @@ -22,12 +22,10 @@ package org.logstash.ackedqueue; import org.jruby.RubyArray; import org.jruby.RubyHash; -import org.jruby.runtime.ThreadContext; -import org.jruby.runtime.builtin.IRubyObject; import org.logstash.ackedqueue.ext.JRubyAckedQueueExt; import org.logstash.execution.MemoryReadBatch; import org.logstash.execution.QueueBatch; -import org.logstash.ext.JrubyEventExtLibrary; +import org.logstash.ext.JrubyEventExtLibrary.RubyEvent; import java.io.IOException; import java.util.Collection; @@ -42,12 +40,19 @@ public final class AckedReadBatch implements QueueBatch { private RubyHash generated; - public static AckedReadBatch create(final JRubyAckedQueueExt queue, final int size, - final long timeout) { + public static AckedReadBatch create( + final JRubyAckedQueueExt queue, + final int size, + final long timeout) + { return new AckedReadBatch(queue, size, timeout); } - private AckedReadBatch(final JRubyAckedQueueExt queue, final int size, final long timeout) { + private AckedReadBatch( + final JRubyAckedQueueExt queue, + final int size, + final long timeout) + { AckedBatch batch; try { batch = queue.readBatch(size, timeout); @@ -65,7 +70,7 @@ public final class AckedReadBatch implements QueueBatch { } @Override - public void merge(final IRubyObject event) { + public void merge(final RubyEvent event) { if (!event.isNil() && !originals.containsKey(event)) { generated.put(event, RUBY.getTrue()); } @@ -75,14 +80,12 @@ public final class AckedReadBatch implements QueueBatch { @Override public RubyArray to_a() { final RubyArray result = RUBY.newArray(filteredSize()); - for (final JrubyEventExtLibrary.RubyEvent event - : (Collection) originals.keys()) { + for (final RubyEvent event : (Collection) originals.keys()) { if (!MemoryReadBatch.isCancelled(event)) { result.append(event); } } - for (final JrubyEventExtLibrary.RubyEvent event - : (Collection) generated.keys()) { + for (final RubyEvent event : (Collection) generated.keys()) { if (!MemoryReadBatch.isCancelled(event)) { result.append(event); } @@ -90,6 +93,17 @@ public final class AckedReadBatch implements QueueBatch { return result; } + @SuppressWarnings({"unchecked"}) + @Override + public Collection collection() { + // This only returns the originals and does not filter cancelled one + // because it is only used in the WorkerLoop where only originals + // non-cancelled exists. We should revisit this AckedReadBatch + // implementation and get rid of this dual original/generated idea. + // The MemoryReadBatch does not use such a strategy. + return originals.directKeySet(); + } + public void close() throws IOException { if (ackedBatch != null) { ackedBatch.close(); diff --git a/logstash-core/src/main/java/org/logstash/config/ir/CompiledPipeline.java b/logstash-core/src/main/java/org/logstash/config/ir/CompiledPipeline.java index 872fbbb6c..ef4287089 100644 --- a/logstash-core/src/main/java/org/logstash/config/ir/CompiledPipeline.java +++ b/logstash-core/src/main/java/org/logstash/config/ir/CompiledPipeline.java @@ -17,12 +17,12 @@ * under the License. */ - package org.logstash.config.ir; import co.elastic.logstash.api.Codec; import org.apache.logging.log4j.LogManager; import org.apache.logging.log4j.Logger; +import org.jruby.RubyArray; import org.jruby.RubyHash; import org.jruby.javasupport.JavaUtil; import org.jruby.runtime.builtin.IRubyObject; @@ -38,11 +38,13 @@ import org.logstash.config.ir.compiler.DatasetCompiler; import org.logstash.config.ir.compiler.EventCondition; import org.logstash.config.ir.compiler.RubyIntegration; import org.logstash.config.ir.compiler.SplitDataset; +import org.logstash.config.ir.graph.SeparatorVertex; import org.logstash.config.ir.graph.IfVertex; import org.logstash.config.ir.graph.PluginVertex; import org.logstash.config.ir.graph.Vertex; import org.logstash.config.ir.imperative.PluginStatement; -import org.logstash.ext.JrubyEventExtLibrary; +import org.logstash.execution.QueueBatch; +import org.logstash.ext.JrubyEventExtLibrary.RubyEvent; import org.logstash.plugins.ConfigVariableExpander; import org.logstash.secret.store.SecretStore; @@ -57,6 +59,8 @@ import java.util.Objects; import java.util.stream.Collectors; import java.util.stream.Stream; +import static org.logstash.config.ir.compiler.Utils.copyNonCancelledEvents; + /** *

Compiled Logstash Pipeline Configuration.

* This class represents an executable pipeline, compiled from the configured topology that is @@ -136,14 +140,27 @@ public final class CompiledPipeline { } /** - * This method contains the actual compilation of the {@link Dataset} representing the - * underlying pipeline from the Queue to the outputs. - * @return Compiled {@link Dataset} representation of the underlying {@link PipelineIR} topology + * Perform the actual compilation of the {@link Dataset} representing the + * underlying pipeline from the Queue to the outputs using the + * unordered execution model. + * @return CompiledPipeline.CompiledExecution the compiled pipeline */ - public Dataset buildExecution() { - return new CompiledPipeline.CompiledExecution().toDataset(); + public CompiledPipeline.CompiledExecution buildExecution() { + return buildExecution(false); } + /** + * Perform the actual compilation of the {@link Dataset} representing the + * underlying pipeline from the Queue to the outputs using the ordered or + * unordered execution model. + * @param orderedExecution determines whether to build an execution that enforces order or not + * @return CompiledPipeline.CompiledExecution the compiled pipeline + */ + public CompiledPipeline.CompiledExecution buildExecution(boolean orderedExecution) { + return orderedExecution + ? new CompiledPipeline.CompiledOrderedExecution() + : new CompiledPipeline.CompiledUnorderedExecution(); + } /** * Sets up all outputs learned from {@link PipelineIR}. @@ -294,12 +311,58 @@ public final class CompiledPipeline { return outputs.containsKey(vertex.getId()); } + public final class CompiledOrderedExecution extends CompiledExecution { + + @Override + public void compute(final QueueBatch batch, final boolean flush, final boolean shutdown) { + compute(batch.collection(), flush, shutdown); + } + + @SuppressWarnings({"rawtypes", "unchecked"}) + @Override + public void compute(final RubyArray batch, final boolean flush, final boolean shutdown) { + compute((Collection) batch, flush, shutdown); + } + + @SuppressWarnings({"rawtypes", "unchecked"}) + private void compute(final Collection batch, final boolean flush, final boolean shutdown) { + final RubyArray outputBatch = RubyUtil.RUBY.newArray(); + // send batch one-by-one as single-element batches down the filters + final RubyArray filterBatch = RubyUtil.RUBY.newArray(1); + for (final RubyEvent e : batch) { + filterBatch.set(0, e); + final Collection result = compiledFilters.compute(filterBatch, flush, shutdown); + copyNonCancelledEvents(result, outputBatch); + compiledFilters.clear(); + } + compiledOutputs.compute(outputBatch, flush, shutdown); + } + } + + public final class CompiledUnorderedExecution extends CompiledExecution { + + @Override + public void compute(final QueueBatch batch, final boolean flush, final boolean shutdown) { + compute(batch.to_a(), flush, shutdown); + } + + @SuppressWarnings({"rawtypes", "unchecked"}) + @Override + public void compute(final RubyArray batch, final boolean flush, final boolean shutdown) { + final RubyArray outputBatch = RubyUtil.RUBY.newArray(); + final Collection result = compiledFilters.compute(batch, flush, shutdown); + copyNonCancelledEvents(result, outputBatch); + compiledFilters.clear(); + compiledOutputs.compute(outputBatch, flush, shutdown); + } + } + /** * Instances of this class represent a fully compiled pipeline execution. Note that this class * has a separate lifecycle from {@link CompiledPipeline} because it holds per (worker-thread) * state and thus needs to be instantiated once per thread. */ - private final class CompiledExecution { + public abstract class CompiledExecution { /** * Compiled {@link IfVertex, indexed by their ID as returned by {@link Vertex#getId()}. @@ -312,35 +375,51 @@ public final class CompiledPipeline { */ private final Map plugins = new HashMap<>(50); - private final Dataset compiled; + protected final Dataset compiledFilters; + protected final Dataset compiledOutputs; CompiledExecution() { - compiled = compile(); + compiledFilters = compileFilters(); + compiledOutputs = compileOutputs(); } - Dataset toDataset() { - return compiled; + public abstract void compute(final QueueBatch batch, final boolean flush, final boolean shutdown); + + @SuppressWarnings({"rawtypes"}) + public abstract void compute(final RubyArray batch, final boolean flush, final boolean shutdown); + + /** + * Instantiates the graph of compiled filter section {@link Dataset}. + * @return Compiled {@link Dataset} representing the filter section of the pipeline. + */ + private Dataset compileFilters() { + final Vertex separator = pipelineIR.getGraph() + .vertices() + .filter(v -> v instanceof SeparatorVertex) + .findFirst() + .orElseThrow(() -> new IllegalStateException("Missing Filter End Vertex")); + return DatasetCompiler.terminalFilterDataset(flatten(Collections.emptyList(), separator)); } /** - * Instantiates the graph of compiled {@link Dataset}. - * @return Compiled {@link Dataset} representing the pipeline. + * Instantiates the graph of compiled output section {@link Dataset}. + * @return Compiled {@link Dataset} representing the output section of the pipeline. */ - private Dataset compile() { + private Dataset compileOutputs() { final Collection outputNodes = pipelineIR.getGraph() .allLeaves().filter(CompiledPipeline.this::isOutput) .collect(Collectors.toList()); if (outputNodes.isEmpty()) { return Dataset.IDENTITY; } else { - return DatasetCompiler.terminalDataset(outputNodes.stream().map( - leaf -> outputDataset(leaf, flatten(Collections.emptyList(), leaf)) - ).collect(Collectors.toList())); + return DatasetCompiler.terminalOutputDataset(outputNodes.stream() + .map(leaf -> outputDataset(leaf, flatten(Collections.emptyList(), leaf))) + .collect(Collectors.toList())); } } /** - * Build a {@link Dataset} representing the {@link JrubyEventExtLibrary.RubyEvent}s after + * Build a {@link Dataset} representing the {@link RubyEvent}s after * the application of the given filter. * @param vertex Vertex of the filter to create this {@link Dataset} for * @param datasets All the datasets that have children passing into this filter @@ -353,7 +432,8 @@ public final class CompiledPipeline { final ComputeStepSyntaxElement prepared = DatasetCompiler.filterDataset( flatten(datasets, vertex), - filters.get(vertexId)); + filters.get(vertexId) + ); LOGGER.debug("Compiled filter\n {} \n into \n {}", vertex, prepared); plugins.put(vertexId, prepared.instantiate()); @@ -363,7 +443,7 @@ public final class CompiledPipeline { } /** - * Build a {@link Dataset} representing the {@link JrubyEventExtLibrary.RubyEvent}s after + * Build a {@link Dataset} representing the {@link RubyEvent}s after * the application of the given output. * @param vertex Vertex of the output to create this {@link Dataset} for * @param datasets All the datasets that have children passing into this output @@ -377,7 +457,8 @@ public final class CompiledPipeline { DatasetCompiler.outputDataset( flatten(datasets, vertex), outputs.get(vertexId), - outputs.size() == 1); + outputs.size() == 1 + ); LOGGER.debug("Compiled output\n {} \n into \n {}", vertex, prepared); plugins.put(vertexId, prepared.instantiate()); @@ -388,14 +469,17 @@ public final class CompiledPipeline { /** * Split the given {@link Dataset}s and return the dataset half of their elements that contains - * the {@link JrubyEventExtLibrary.RubyEvent} that fulfil the given {@link EventCondition}. + * the {@link RubyEvent} that fulfil the given {@link EventCondition}. * @param datasets Datasets that are the parents of the datasets to split * @param condition Condition that must be fulfilled * @param vertex Vertex id to cache the resulting {@link Dataset} under * @return The half of the datasets contents that fulfils the condition */ - private SplitDataset split(final Collection datasets, - final EventCondition condition, final Vertex vertex) { + private SplitDataset split( + final Collection datasets, + final EventCondition condition, + final Vertex vertex) + { final String vertexId = vertex.getId(); SplitDataset conditional = iffs.get(vertexId); if (conditional == null) { @@ -425,9 +509,13 @@ public final class CompiledPipeline { * @param start Vertex to compile children for * @return Datasets originating from given {@link Vertex} */ - private Collection flatten(final Collection datasets, - final Vertex start) { - final Collection result = compileDependencies(start, datasets, + private Collection flatten( + final Collection datasets, + final Vertex start) + { + final Collection result = compileDependencies( + start, + datasets, start.incomingVertices().filter(v -> isFilter(v) || isOutput(v) || v instanceof IfVertex) ); return result.isEmpty() ? datasets : result; @@ -440,8 +528,11 @@ public final class CompiledPipeline { * @param dependencies Dependencies of {@code start} * @return Datasets compiled from vertex children */ - private Collection compileDependencies(final Vertex start, - final Collection datasets, final Stream dependencies) { + private Collection compileDependencies( + final Vertex start, + final Collection datasets, + final Stream dependencies) + { return dependencies.map( dependency -> { if (isFilter(dependency)) { @@ -460,13 +551,15 @@ public final class CompiledPipeline { // It is important that we double check that we are actually dealing with the // positive/left branch of the if condition if (ifvert.outgoingBooleanEdgesByType(true) - .anyMatch(edge -> Objects.equals(edge.getTo(), start))) { + .anyMatch(edge -> Objects.equals(edge.getTo(), start))) + { return ifDataset; } else { return ifDataset.right(); } } - }).collect(Collectors.toList()); + } + ).collect(Collectors.toList()); } } } diff --git a/logstash-core/src/main/java/org/logstash/config/ir/PipelineIR.java b/logstash-core/src/main/java/org/logstash/config/ir/PipelineIR.java index f7b89aad0..0c0b15ef2 100644 --- a/logstash-core/src/main/java/org/logstash/config/ir/PipelineIR.java +++ b/logstash-core/src/main/java/org/logstash/config/ir/PipelineIR.java @@ -28,6 +28,7 @@ import org.logstash.config.ir.graph.Graph; import org.logstash.config.ir.graph.PluginVertex; import org.logstash.config.ir.graph.QueueVertex; import org.logstash.config.ir.graph.Vertex; +import org.logstash.config.ir.graph.SeparatorVertex; public final class PipelineIR implements Hashable { @@ -42,7 +43,9 @@ public final class PipelineIR implements Hashable { } private final Graph graph; + private final QueueVertex queue; + // Temporary until we have LIR execution // Then we will no longer need this property here private final String originalSource; @@ -63,6 +66,9 @@ public final class PipelineIR implements Hashable { // Now we connect the queue to the root of the filter section tempGraph = tempGraph.chain(filterSection); + // Connect the filter section to the filter end vertex to separate from the output section + tempGraph = tempGraph.chain(new SeparatorVertex("filter_to_output")); + // Finally, connect the filter out node to all the outputs this.graph = tempGraph.chain(outputSection); diff --git a/logstash-core/src/main/java/org/logstash/config/ir/compiler/DatasetCompiler.java b/logstash-core/src/main/java/org/logstash/config/ir/compiler/DatasetCompiler.java index 74bd7eb46..2e30d678c 100644 --- a/logstash-core/src/main/java/org/logstash/config/ir/compiler/DatasetCompiler.java +++ b/logstash-core/src/main/java/org/logstash/config/ir/compiler/DatasetCompiler.java @@ -53,8 +53,10 @@ public final class DatasetCompiler { // Utility Class } - public static ComputeStepSyntaxElement splitDataset(final Collection parents, - final EventCondition condition) { + public static ComputeStepSyntaxElement splitDataset( + final Collection parents, + final EventCondition condition) + { final ClassFields fields = new ClassFields(); final ValueSyntaxElement ifData = fields.add(new ArrayList<>()); final ValueSyntaxElement elseData = fields.add(new ArrayList<>()); @@ -104,8 +106,10 @@ public final class DatasetCompiler { * @param plugin Filter Plugin * @return Dataset representing the filter plugin */ - public static ComputeStepSyntaxElement filterDataset(final Collection parents, - final AbstractFilterDelegatorExt plugin) { + public static ComputeStepSyntaxElement filterDataset( + final Collection parents, + final AbstractFilterDelegatorExt plugin) + { final ClassFields fields = new ClassFields(); final ValueSyntaxElement outputBuffer = fields.add(new ArrayList<>()); final Closure clear = Closure.wrap(); @@ -113,10 +117,12 @@ public final class DatasetCompiler { if (parents.isEmpty()) { compute = filterBody(outputBuffer, BATCH_ARG, fields, plugin); } else { - final Collection parentFields = - parents.stream().map(fields::add).collect(Collectors.toList()); - @SuppressWarnings("rawtypes") - final RubyArray inputBuffer = RubyUtil.RUBY.newArray(); + final Collection parentFields = parents + .stream() + .map(fields::add) + .collect(Collectors.toList() + ); + @SuppressWarnings("rawtypes") final RubyArray inputBuffer = RubyUtil.RUBY.newArray(); clear.add(clearSyntax(parentFields)); final ValueSyntaxElement inputBufferField = fields.add(inputBuffer); compute = withInputBuffering( @@ -128,7 +134,49 @@ public final class DatasetCompiler { } /** - *

Builds a terminal {@link Dataset} from the given parent {@link Dataset}s.

+ *

Builds a terminal {@link Dataset} for the filters from the given parent {@link Dataset}s.

+ *

If the given set of parent {@link Dataset} is empty the sum is defined as the + * trivial dataset that does not invoke any computation whatsoever.

+ * {@link Dataset#compute(RubyArray, boolean, boolean)} is always + * {@link Collections#emptyList()}. + * @param parents Parent {@link Dataset} to sum + * @return Dataset representing the sum of given parent {@link Dataset} + */ + public static Dataset terminalFilterDataset(final Collection parents) { + if (parents.isEmpty()) { + return Dataset.IDENTITY; + } + + final int count = parents.size(); + if (count == 1) { + // No need for a terminal dataset here, if there is only a single parent node we can + // call it directly. + return parents.iterator().next(); + } + + final ClassFields fields = new ClassFields(); + final Collection parentFields = parents + .stream() + .map(fields::add) + .collect(Collectors.toList()); + @SuppressWarnings("rawtypes") final RubyArray inputBuffer = RubyUtil.RUBY.newArray(); + final ValueSyntaxElement inputBufferField = fields.add(inputBuffer); + final ValueSyntaxElement outputBufferField = fields.add(new ArrayList<>()); + final Closure clear = Closure.wrap().add(clearSyntax(parentFields)); + final Closure compute = withInputBuffering( + Closure.wrap( + // pass thru filter + buffer(outputBufferField, inputBufferField) + ), + parentFields, + inputBufferField + ); + + return prepare(withOutputBuffering(compute, clear, outputBufferField, fields)).instantiate(); + } + + /** + *

Builds a terminal {@link Dataset} for the outputs from the given parent {@link Dataset}s.

*

If the given set of parent {@link Dataset} is empty the sum is defined as the * trivial dataset that does not invoke any computation whatsoever.

* {@link Dataset#compute(RubyArray, boolean, boolean)} is always @@ -136,29 +184,32 @@ public final class DatasetCompiler { * @param parents Parent {@link Dataset} to sum and terminate * @return Dataset representing the sum of given parent {@link Dataset} */ - public static Dataset terminalDataset(final Collection parents) { - final int count = parents.size(); - final Dataset result; - if (count > 1) { - final ClassFields fields = new ClassFields(); - final Collection parentFields = - parents.stream().map(fields::add).collect(Collectors.toList()); - result = compileOutput( - Closure.wrap( - parentFields.stream().map(DatasetCompiler::computeDataset) - .toArray(MethodLevelSyntaxElement[]::new) - ).add(clearSyntax(parentFields)), Closure.EMPTY, fields - ).instantiate(); - } else if (count == 1) { - // No need for a terminal dataset here, if there is only a single parent node we can - // call it directly. - result = parents.iterator().next(); - } else { + public static Dataset terminalOutputDataset(final Collection parents) { + if (parents.isEmpty()) { throw new IllegalArgumentException( - "Cannot create Terminal Dataset for an empty number of parent datasets" + "Cannot create terminal output dataset for an empty number of parent datasets" ); } - return result; + + final int count = parents.size(); + if (count == 1) { + // No need for a terminal dataset here, if there is only a single parent node we can + // call it directly. + return parents.iterator().next(); + } + + final ClassFields fields = new ClassFields(); + final Collection parentFields = parents + .stream() + .map(fields::add) + .collect(Collectors.toList()); + final Closure compute = Closure.wrap(parentFields + .stream() + .map(DatasetCompiler::computeDataset) + .toArray(MethodLevelSyntaxElement[]::new) + ).add(clearSyntax(parentFields)); + + return compileOutput(compute, Closure.EMPTY, fields).instantiate(); } /** @@ -177,8 +228,11 @@ public final class DatasetCompiler { * @param terminal Set to true if this output is the only output in the pipeline * @return Output Dataset */ - public static ComputeStepSyntaxElement outputDataset(final Collection parents, - final AbstractOutputDelegatorExt output, final boolean terminal) { + public static ComputeStepSyntaxElement outputDataset( + final Collection parents, + final AbstractOutputDelegatorExt output, + final boolean terminal) + { final ClassFields fields = new ClassFields(); final Closure clearSyntax; final Closure computeSyntax; @@ -215,14 +269,19 @@ public final class DatasetCompiler { return compileOutput(computeSyntax, clearSyntax, fields); } - private static ValueSyntaxElement invokeOutput(final ValueSyntaxElement output, - final MethodLevelSyntaxElement events) { + private static ValueSyntaxElement invokeOutput( + final ValueSyntaxElement output, + final MethodLevelSyntaxElement events) + { return output.call("multiReceive", events); } - private static Closure filterBody(final ValueSyntaxElement outputBuffer, - final ValueSyntaxElement inputBuffer, final ClassFields fields, - final AbstractFilterDelegatorExt plugin) { + private static Closure filterBody( + final ValueSyntaxElement outputBuffer, + final ValueSyntaxElement inputBuffer, + final ClassFields fields, + final AbstractFilterDelegatorExt plugin) + { final ValueSyntaxElement filterField = fields.add(plugin); final Closure body = Closure.wrap( setPluginIdForLog4j(plugin), @@ -372,8 +431,10 @@ public final class DatasetCompiler { ); } - private static MethodLevelSyntaxElement buffer(final ValueSyntaxElement resultBuffer, - final ValueSyntaxElement argument) { + private static MethodLevelSyntaxElement buffer( + final ValueSyntaxElement resultBuffer, + final ValueSyntaxElement argument) + { return resultBuffer.call("addAll", argument); } diff --git a/logstash-core/src/main/java/org/logstash/config/ir/graph/Graph.java b/logstash-core/src/main/java/org/logstash/config/ir/graph/Graph.java index f41558ad7..e94aa1e3a 100644 --- a/logstash-core/src/main/java/org/logstash/config/ir/graph/Graph.java +++ b/logstash-core/src/main/java/org/logstash/config/ir/graph/Graph.java @@ -432,7 +432,7 @@ public final class Graph implements SourceComponent, Hashable { public String uniqueHash() { return Util.digest(this.vertices(). - filter(v -> !(v instanceof QueueVertex)). // has no metadata + filter(v -> !(v instanceof QueueVertex) && !(v instanceof SeparatorVertex)). // has no metadata map(Vertex::getSourceWithMetadata). map(SourceWithMetadata::uniqueHash). sorted(). diff --git a/logstash-core/src/main/java/org/logstash/config/ir/graph/SeparatorVertex.java b/logstash-core/src/main/java/org/logstash/config/ir/graph/SeparatorVertex.java new file mode 100644 index 000000000..cb9a753dd --- /dev/null +++ b/logstash-core/src/main/java/org/logstash/config/ir/graph/SeparatorVertex.java @@ -0,0 +1,64 @@ +/* + * 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. + */ + + +package org.logstash.config.ir.graph; + +import org.logstash.common.IncompleteSourceWithMetadataException; +import org.logstash.common.Util; +import org.logstash.config.ir.SourceComponent; +import org.logstash.common.SourceWithMetadata; + +public final class SeparatorVertex extends Vertex { + + public SeparatorVertex(String id) throws IncompleteSourceWithMetadataException { + super(new SourceWithMetadata("internal", id, 0,0,"separator"), id); + } + + @Override + public String toString() { + return this.getId(); + } + + @Override + public SeparatorVertex copy() { + try { + return new SeparatorVertex(this.getId()); + } catch (IncompleteSourceWithMetadataException e) { + // Never happens + throw new RuntimeException(e); + } + } + + @Override + public boolean sourceComponentEquals(SourceComponent other) { + return other instanceof SeparatorVertex && ((SeparatorVertex)other).getId() == this.getId(); + } + + // Special vertices really have no metadata + @Override + public SourceWithMetadata getSourceWithMetadata() { + return null; + } + + @Override + public String uniqueHash() { + return Util.digest("SEPARATOR_" + this.getId()); + } +} diff --git a/logstash-core/src/main/java/org/logstash/execution/MemoryReadBatch.java b/logstash-core/src/main/java/org/logstash/execution/MemoryReadBatch.java index 7764fd4af..d7713a119 100644 --- a/logstash-core/src/main/java/org/logstash/execution/MemoryReadBatch.java +++ b/logstash-core/src/main/java/org/logstash/execution/MemoryReadBatch.java @@ -17,30 +17,27 @@ * under the License. */ - package org.logstash.execution; import org.jruby.RubyArray; -import org.jruby.runtime.builtin.IRubyObject; -import org.logstash.ext.JrubyEventExtLibrary; - +import org.logstash.ext.JrubyEventExtLibrary.RubyEvent; +import java.util.Collection; import java.util.LinkedHashSet; - import static org.logstash.RubyUtil.RUBY; public final class MemoryReadBatch implements QueueBatch { - private final LinkedHashSet events; + private final LinkedHashSet events; - public MemoryReadBatch(final LinkedHashSet events) { + public MemoryReadBatch(final LinkedHashSet events) { this.events = events; } - public static boolean isCancelled(final IRubyObject event) { - return ((JrubyEventExtLibrary.RubyEvent) event).getEvent().isCancelled(); + public static boolean isCancelled(final RubyEvent event) { + return event.getEvent().isCancelled(); } - public static MemoryReadBatch create(LinkedHashSet events) { + public static MemoryReadBatch create(LinkedHashSet events) { return new MemoryReadBatch(events); } @@ -52,7 +49,7 @@ public final class MemoryReadBatch implements QueueBatch { @SuppressWarnings({"rawtypes"}) public RubyArray to_a() { final RubyArray result = RUBY.newArray(events.size()); - for (final IRubyObject event : events) { + for (final RubyEvent event : events) { if (!isCancelled(event)) { result.append(event); } @@ -61,7 +58,15 @@ public final class MemoryReadBatch implements QueueBatch { } @Override - public void merge(final IRubyObject event) { + public Collection collection() { + // This does not filter cancelled events because it is + // only used in the WorkerLoop where there are no cancelled + // events yet. + return events; + } + + @Override + public void merge(final RubyEvent event) { events.add(event); } diff --git a/logstash-core/src/main/java/org/logstash/execution/QueueBatch.java b/logstash-core/src/main/java/org/logstash/execution/QueueBatch.java index 1ae819029..d303ff404 100644 --- a/logstash-core/src/main/java/org/logstash/execution/QueueBatch.java +++ b/logstash-core/src/main/java/org/logstash/execution/QueueBatch.java @@ -17,17 +17,17 @@ * under the License. */ - package org.logstash.execution; import org.jruby.RubyArray; -import org.jruby.runtime.builtin.IRubyObject; - +import org.logstash.ext.JrubyEventExtLibrary.RubyEvent; import java.io.IOException; +import java.util.Collection; public interface QueueBatch { int filteredSize(); @SuppressWarnings({"rawtypes"}) RubyArray to_a(); - void merge(IRubyObject event); + Collection collection(); + void merge(RubyEvent event); void close() throws IOException; } diff --git a/logstash-core/src/main/java/org/logstash/execution/WorkerLoop.java b/logstash-core/src/main/java/org/logstash/execution/WorkerLoop.java index 5c1266e3a..16dd457d8 100644 --- a/logstash-core/src/main/java/org/logstash/execution/WorkerLoop.java +++ b/logstash-core/src/main/java/org/logstash/execution/WorkerLoop.java @@ -17,24 +17,19 @@ * under the License. */ - package org.logstash.execution; import java.util.concurrent.atomic.AtomicBoolean; import java.util.concurrent.atomic.LongAdder; import org.apache.logging.log4j.LogManager; import org.apache.logging.log4j.Logger; -import org.jruby.RubyArray; -import org.jruby.runtime.ThreadContext; -import org.logstash.RubyUtil; import org.logstash.config.ir.CompiledPipeline; -import org.logstash.config.ir.compiler.Dataset; public final class WorkerLoop implements Runnable { private static final Logger LOGGER = LogManager.getLogger(WorkerLoop.class); - private final Dataset execution; + private final CompiledPipeline.CompiledExecution execution; private final QueueReadClient readClient; @@ -65,7 +60,7 @@ public final class WorkerLoop implements Runnable { { this.consumedCounter = consumedCounter; this.filteredCounter = filteredCounter; - this.execution = pipeline.buildExecution(); + this.execution = pipeline.buildExecution(preserveEventOrder); this.drainQueue = drainQueue; this.readClient = readClient; this.flushRequested = flushRequested; @@ -84,7 +79,7 @@ public final class WorkerLoop implements Runnable { consumedCounter.add(batch.filteredSize()); final boolean isFlush = flushRequested.compareAndSet(true, false); readClient.startMetrics(batch); - compute(batch, isFlush, false); + execution.compute(batch, isFlush, false); int filteredCount = batch.filteredSize(); filteredCounter.add(filteredCount); readClient.addOutputMetrics(filteredCount); @@ -98,7 +93,7 @@ public final class WorkerLoop implements Runnable { //for this we need to create a new empty batch to contain the final flushed events final QueueBatch batch = readClient.newBatch(); readClient.startMetrics(batch); - compute(batch, true, true); + execution.compute(batch, true, true); readClient.closeBatch(batch); } catch (final Exception ex) { LOGGER.error( @@ -109,20 +104,6 @@ public final class WorkerLoop implements Runnable { } } - @SuppressWarnings("unchecked") - private void compute(final QueueBatch batch, final boolean flush, final boolean shutdown) { - if (preserveEventOrder) { - // send batch events one-by-one as single-element batches - @SuppressWarnings({"rawtypes"}) final RubyArray singleElementBatch = RubyUtil.RUBY.newArray(1); - batch.to_a().forEach((e) -> { - singleElementBatch.set(0, e); - execution.compute(singleElementBatch, flush, shutdown); - }); - } else { - execution.compute(batch.to_a(), flush, shutdown); - } - } - private boolean isDraining() { return drainQueue && !readClient.isEmpty(); } From 448c9c65336ca36a38d1dee84d76d6a8ca466348 Mon Sep 17 00:00:00 2001 From: Rob Bavey Date: Wed, 18 Mar 2020 11:12:35 -0400 Subject: [PATCH 0399/1126] 7.6.2 Release notes Fixes #11705 --- docs/static/releasenotes.asciidoc | 62 ++++++++++++++++++++++++++++++- 1 file changed, 61 insertions(+), 1 deletion(-) diff --git a/docs/static/releasenotes.asciidoc b/docs/static/releasenotes.asciidoc index 4f5dadcca..c0284c6b9 100644 --- a/docs/static/releasenotes.asciidoc +++ b/docs/static/releasenotes.asciidoc @@ -3,6 +3,7 @@ This section summarizes the changes in the following releases: +* <> * <> * <> * <> @@ -26,6 +27,65 @@ This section summarizes the changes in the following releases: * <> * <> + +[[logstash-7-6-2]] +=== Logstash 7.6.2 Release Notes + + +* Fixed: Support for quoted plugin option key. The Java execution engine had a regression where adding quotes +around plugin configuration keys would stop the pipeline from starting. https://github.com/elastic/logstash/pull/11694[#11694] +* Fixed: Issue where users were not able to start pipeline when a configuration file was completely commented out. https://github.com/elastic/logstash/pull/11615[#11615] +* Fixed: Typo in gauge metric of unknown type log. https://github.com/elastic/logstash/pull/11689[#11689] +* Fixed: Issue where using command line `--help` option was showing wrong information. https://github.com/elastic/logstash/pull/11634[#11634] +* [Doc] Backport more references to contributing issues guidelines. https://github.com/elastic/logstash/pull/11666[#11666] +* [Doc] Add tips for troubleshooting a pipeline. https://github.com/elastic/logstash/pull/11545[#11545] +* [Doc] Update to include verification mode switch. https://github.com/elastic/logstash/pull/11284[#11284] +* [Doc] Updates security API examples https://github.com/elastic/logstash/pull/10752[#10752] +* [Doc] Update logging.asciidoc to emphasize that logging to console is included in out-of-the-box settings. https://github.com/elastic/logstash/pull/10717[#10717] +* [Doc] Update offline-plugins.asciidoc to use correct command syntax. https://github.com/elastic/logstash/pull/10912[#10912] +* Bump puma to 4.3.3. https://github.com/elastic/logstash/pull/11651[#11651] + + +==== Plugins + +*Beats Input* + +* Fixed issue where calling `java_import` on `org.logstash.netty.SslContextBuilder` was causing the TCP input to pick up the wrong SslContextBuilder class + potentially causing pipeline creation to fail https://github.com/logstash-plugins/logstash-input-beats/pull/388[#388] + +*Http Input* + +* Refactor: scope (and avoid unused) java imports https://github.com/logstash-plugins/logstash-input-http/pull/124[#124] + +*Redis Input* + +* [DOC] Reordered config option to alpha order https://github.com/logstash-plugins/logstash-input-redis/issues/79[#79] + +*Snmp Input* + +* Refactor: scope and review java_imports https://github.com/logstash-plugins/logstash-input-snmp/pull/72[#72] + +*Tcp Input* + +* Refactor: scope java_import to avoid polluting https://github.com/logstash-plugins/logstash-input-tcp/pull/152[#152] + +*Kafka Integration* + +* Fix links in changelog pointing to stand-alone plugin changelogs. https://github.com/logstash-plugins/logstash-integration-kafka/pull/18[#18] +* Refactor: scope java_import to plugin class https://github.com/logstash-plugins/logstash-integration-kafka/pull/18[#18] + +*Rabbitmq Integration* + +* Refactor: scope (and remove unused) java imports https://github.com/logstash-plugins/logstash-integration-rabbitmq/pull/29[#29] + +*Elasticsearch Output* + +* [DOC] Replaced link to Elastic Cloud trial with attribute, and fixed a comma splice https://github.com/logstash-plugins/logstash-output-elasticsearch/pull/926[#926] +* [DOC] Replaced setting name with correct value https://github.com/logstash-plugins/logstash-output-elasticsearch/pull/919[#919] +* Fixed integration tests for Elasticsearch 7.6+ https://github.com/logstash-plugins/logstash-output-elasticsearch/pull/922[#922] +* Fixed integration tests for Elasticsearch API `7.5.0` https://github.com/logstash-plugins/logstash-output-elasticsearch/pull/923[#923] + + [[logstash-7-6-1]] === Logstash 7.6.1 Release Notes @@ -1115,4 +1175,4 @@ Here are the plugin changes. - Tweaked logging statements to reduce verbosity - Fixed numerous issues relating to builds on Travis https://github.com/logstash-plugins/logstash-output-elasticsearch/pull/799[#799] * logstash-output-s3 - - Fixed issue where on restart, 0 byte files could erroneously be uploaded to s3 https://github.com/logstash-plugins/logstash-output-s3/issues/195[#195] + - Fixed issue where on restart, 0 byte files could erroneously be uploaded to s3 https://github.com/logstash-plugins/logstash-output-s3/issues/195[#195] \ No newline at end of file From 85f0f87a31ac991f3d73de30c13cfec45abb94eb Mon Sep 17 00:00:00 2001 From: Rob Bavey Date: Wed, 18 Mar 2020 15:51:09 -0400 Subject: [PATCH 0400/1126] Update to release notes based on review Fixes #11705 --- docs/static/releasenotes.asciidoc | 1 - 1 file changed, 1 deletion(-) diff --git a/docs/static/releasenotes.asciidoc b/docs/static/releasenotes.asciidoc index c0284c6b9..effd6bd70 100644 --- a/docs/static/releasenotes.asciidoc +++ b/docs/static/releasenotes.asciidoc @@ -40,7 +40,6 @@ around plugin configuration keys would stop the pipeline from starting. https:// * [Doc] Backport more references to contributing issues guidelines. https://github.com/elastic/logstash/pull/11666[#11666] * [Doc] Add tips for troubleshooting a pipeline. https://github.com/elastic/logstash/pull/11545[#11545] * [Doc] Update to include verification mode switch. https://github.com/elastic/logstash/pull/11284[#11284] -* [Doc] Updates security API examples https://github.com/elastic/logstash/pull/10752[#10752] * [Doc] Update logging.asciidoc to emphasize that logging to console is included in out-of-the-box settings. https://github.com/elastic/logstash/pull/10717[#10717] * [Doc] Update offline-plugins.asciidoc to use correct command syntax. https://github.com/elastic/logstash/pull/10912[#10912] * Bump puma to 4.3.3. https://github.com/elastic/logstash/pull/11651[#11651] From d56a0739dc03e09cb421c8bfb71880463a14dfa2 Mon Sep 17 00:00:00 2001 From: Karol Bucek Date: Tue, 31 Mar 2020 09:48:41 +0200 Subject: [PATCH 0401/1126] Refactor: avoid array in case of single event while also making the array case cleaner & effective (JRuby uses specialized array holder for 1 / 2 values) + Refactor: minor - use true/false constants directly + Refactor: do not allocate empty array Fixes #11732 --- .../src/main/java/org/logstash/Event.java | 4 +++- .../logstash/ext/JrubyEventExtLibrary.java | 20 +++++++++---------- 2 files changed, 12 insertions(+), 12 deletions(-) diff --git a/logstash-core/src/main/java/org/logstash/Event.java b/logstash-core/src/main/java/org/logstash/Event.java index c5cb31f6d..8b037c55e 100644 --- a/logstash-core/src/main/java/org/logstash/Event.java +++ b/logstash-core/src/main/java/org/logstash/Event.java @@ -247,13 +247,15 @@ public final class Event implements Cloneable, Queueable, co.elastic.logstash.ap return JSON_MAPPER.writeValueAsString(this.data); } + private static final Event[] NULL_ARRAY = new Event[0]; + @SuppressWarnings("unchecked") public static Event[] fromJson(String json) throws IOException { // empty/blank json string does not generate an event if (json == null || json.trim().isEmpty()) { - return new Event[]{ }; + return NULL_ARRAY; } Event[] result; diff --git a/logstash-core/src/main/java/org/logstash/ext/JrubyEventExtLibrary.java b/logstash-core/src/main/java/org/logstash/ext/JrubyEventExtLibrary.java index 515ce55c4..d69c7e64b 100644 --- a/logstash-core/src/main/java/org/logstash/ext/JrubyEventExtLibrary.java +++ b/logstash-core/src/main/java/org/logstash/ext/JrubyEventExtLibrary.java @@ -127,14 +127,14 @@ public final class JrubyEventExtLibrary { public IRubyObject ruby_cancel(ThreadContext context) { this.event.cancel(); - return context.runtime.getTrue(); + return context.tru; } @JRubyMethod(name = "uncancel") public IRubyObject ruby_uncancel(ThreadContext context) { this.event.uncancel(); - return context.runtime.getFalse(); + return context.fals; } @JRubyMethod(name = "cancelled?") @@ -251,18 +251,16 @@ public final class JrubyEventExtLibrary { throw RaiseException.from(context.runtime, RubyUtil.PARSER_ERROR, e.getMessage()); } - @SuppressWarnings("rawtypes") - RubyArray result = RubyArray.newArray(context.runtime, events.length); - if (events.length == 1) { // micro optimization for the 1 event more common use-case. - result.set(0, RubyEvent.newRubyEvent(context.runtime, events[0])); - } else { - for (int i = 0; i < events.length; i++) { - result.set(i, RubyEvent.newRubyEvent(context.runtime, events[i])); - } + return context.runtime.newArray(RubyEvent.newRubyEvent(context.runtime, events[0])); } - return result; + + IRubyObject[] rubyEvents = new IRubyObject[events.length]; + for (int i = 0; i < events.length; i++) { + rubyEvents[i] = RubyEvent.newRubyEvent(context.runtime, events[i]); + } + return context.runtime.newArrayNoCopy(rubyEvents); } @JRubyMethod(name = "validate_value", required = 1, meta = true) From 9d789292f3dc721c92b7fb3a0763a0618393b529 Mon Sep 17 00:00:00 2001 From: Luca Belluccini Date: Fri, 13 Mar 2020 11:43:04 +0100 Subject: [PATCH 0402/1126] Clarify behavior in case of PQ full & isolator pattern Fixes #11685 --- docs/static/pipeline-pipeline-config.asciidoc | 2 ++ 1 file changed, 2 insertions(+) diff --git a/docs/static/pipeline-pipeline-config.asciidoc b/docs/static/pipeline-pipeline-config.asciidoc index 5b73a030f..1ced2a175 100644 --- a/docs/static/pipeline-pipeline-config.asciidoc +++ b/docs/static/pipeline-pipeline-config.asciidoc @@ -152,6 +152,8 @@ Here is an example of this scenario using the output isolator pattern. In this architecture, each stage has its own queue with its own tuning and settings. Note that this approach uses up to three times as much disk space and incurs three times as much serialization/deserialization cost as a single pipeline. +If one or both persistent queues of the downstream pipelines (in the example above, `buffered-es` and `buffered-http`) are full, then the upstream pipeline (in the example above, `intake`) will receive backpressure. Once the persistent queue of the upstream pipeline becomes full, both outputs will stop. + [[forked-path-pattern]] ===== The forked path pattern From bd7d5b9b0fe2dfcde7b169f6a1e947b98f09165f Mon Sep 17 00:00:00 2001 From: Luca Belluccini Date: Fri, 13 Mar 2020 12:01:13 +0100 Subject: [PATCH 0403/1126] Better wording thanks to Andrea Selva Fixes #11685 --- docs/static/pipeline-pipeline-config.asciidoc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/static/pipeline-pipeline-config.asciidoc b/docs/static/pipeline-pipeline-config.asciidoc index 1ced2a175..c946cb1ae 100644 --- a/docs/static/pipeline-pipeline-config.asciidoc +++ b/docs/static/pipeline-pipeline-config.asciidoc @@ -152,7 +152,7 @@ Here is an example of this scenario using the output isolator pattern. In this architecture, each stage has its own queue with its own tuning and settings. Note that this approach uses up to three times as much disk space and incurs three times as much serialization/deserialization cost as a single pipeline. -If one or both persistent queues of the downstream pipelines (in the example above, `buffered-es` and `buffered-http`) are full, then the upstream pipeline (in the example above, `intake`) will receive backpressure. Once the persistent queue of the upstream pipeline becomes full, both outputs will stop. +If any of the persistent queues of the downstream pipelines (in the example above, `buffered-es` and `buffered-http`) become full, both outputs will stop. [[forked-path-pattern]] ===== The forked path pattern From f4b934914521035b79cf23cabca8c4b60f6bca4e Mon Sep 17 00:00:00 2001 From: Colin Surprenant Date: Thu, 2 Apr 2020 16:29:37 -0400 Subject: [PATCH 0404/1126] simplify batch classes, do not compute JE empty batches, refactor RE worker loop (#11746) 7.x clean backport or #11737 cleanup RubyArray "rawtypes" remove all LinkedHashSet from batch and queue classes avoid processing empty batches in Java worker loop cleanup AckedReadBatch and MemoryReadBatch refactor Ruby worker loop similar to Java Execution to not use batch merge remove QueueBatch merge and replace LinkedHashSet with ArrayList --- logstash-core/lib/logstash/pipeline.rb | 52 ++++++------ .../spec/logstash/pipeline_pq_file_spec.rb | 60 ++++++++++---- .../util/wrapped_synchronous_queue_spec.rb | 5 +- .../org/logstash/ackedqueue/AckedBatch.java | 22 +++-- .../logstash/ackedqueue/AckedReadBatch.java | 80 +++++++------------ .../org/logstash/common/LsQueueUtils.java | 39 +++++---- .../logstash/config/ir/CompiledPipeline.java | 36 +++------ .../logstash/execution/MemoryReadBatch.java | 35 ++++---- .../org/logstash/execution/QueueBatch.java | 5 +- .../org/logstash/execution/WorkerLoop.java | 22 ++--- .../logstash/ext/JrubyAckedReadClientExt.java | 5 +- .../ext/JrubyMemoryReadClientExt.java | 3 +- .../config/ir/CompiledPipelineTest.java | 10 +++ .../config/ir/EventConditionTest.java | 3 +- x-pack/spec/monitoring/inputs/metrics_spec.rb | 2 +- 15 files changed, 193 insertions(+), 186 deletions(-) diff --git a/logstash-core/lib/logstash/pipeline.rb b/logstash-core/lib/logstash/pipeline.rb index b60c0b9f4..766d1be49 100644 --- a/logstash-core/lib/logstash/pipeline.rb +++ b/logstash-core/lib/logstash/pipeline.rb @@ -363,13 +363,17 @@ module LogStash; class Pipeline < BasePipeline batch = filter_queue_client.read_batch.to_java # metrics are started in read_batch batch_size = batch.filteredSize + events = batch.to_a if batch_size > 0 @events_consumed.add(batch_size) - filter_batch(batch) + events = filter_batch(events) end - flush_filters_to_batch(batch, :final => false) if signal.flush? - if batch.filteredSize > 0 - output_batch(batch, output_events_map) + + if signal.flush? + events = flush_filters_to_batch(events, :final => false) + end + if events.size > 0 + output_batch(events, output_events_map) filter_queue_client.close_batch(batch) end # keep break at end of loop, after the read_batch operation, some pipeline specs rely on this "final read_batch" before shutdown. @@ -380,18 +384,17 @@ module LogStash; class Pipeline < BasePipeline # for this we need to create a new empty batch to contain the final flushed events batch = filter_queue_client.to_java.newBatch filter_queue_client.start_metrics(batch) # explicitly call start_metrics since we dont do a read_batch here - flush_filters_to_batch(batch, :final => true) - output_batch(batch, output_events_map) + events = batch.to_a + events = flush_filters_to_batch(events, :final => true) + output_batch(events, output_events_map) filter_queue_client.close_batch(batch) end - def filter_batch(batch) - filter_func(batch.to_a).each do |e| - #these are both original and generated events - batch.merge(e) unless e.cancelled? - end - filter_queue_client.add_filtered_metrics(batch.filtered_size) - @events_filtered.add(batch.filteredSize) + def filter_batch(events) + result = filter_func(events) + filter_queue_client.add_filtered_metrics(result.size) + @events_filtered.add(result.size) + result rescue Exception => e # Plugins authors should manage their own exceptions in the plugin code # but if an exception is raised up to the worker thread they are considered @@ -406,13 +409,15 @@ module LogStash; class Pipeline < BasePipeline end # Take an array of events and send them to the correct output - def output_batch(batch, output_events_map) + def output_batch(events, output_events_map) # Build a mapping of { output_plugin => [events...]} - batch.to_a.each do |event| - # We ask the AST to tell us which outputs to send each event to - # Then, we stick it in the correct bin - output_func(event).each do |output| - output_events_map[output].push(event) + events.each do |event| + unless event.cancelled? + # We ask the AST to tell us which outputs to send each event to + # Then, we stick it in the correct bin + output_func(event).each do |output| + output_events_map[output].push(event) + end end end # Now that we have our output to event mapping we can just invoke each output @@ -422,7 +427,7 @@ module LogStash; class Pipeline < BasePipeline events.clear end - filter_queue_client.add_output_metrics(batch.filtered_size) + filter_queue_client.add_output_metrics(events.size) end def resolve_cluster_uuids @@ -600,15 +605,16 @@ module LogStash; class Pipeline < BasePipeline # # @param batch [ReadClient::ReadBatch] # @param options [Hash] - def flush_filters_to_batch(batch, options = {}) + def flush_filters_to_batch(events, options = {}) + result = events flush_filters(options) do |event| unless event.cancelled? @logger.debug? and @logger.debug("Pushing flushed events", default_logging_keys(:event => event)) - batch.merge(event) + result << event end end - @flushing.set(false) + result end # flush_filters_to_batch def plugin_threads_info diff --git a/logstash-core/spec/logstash/pipeline_pq_file_spec.rb b/logstash-core/spec/logstash/pipeline_pq_file_spec.rb index 50c33a46c..3c18176cc 100644 --- a/logstash-core/spec/logstash/pipeline_pq_file_spec.rb +++ b/logstash-core/spec/logstash/pipeline_pq_file_spec.rb @@ -80,10 +80,13 @@ describe LogStash::Pipeline do EOS end - let(:pipeline_settings) { { "queue.type" => queue_type, "pipeline.workers" => worker_thread_count, "pipeline.id" => pipeline_id} } + let(:pipeline_settings) {{ + "queue.type" => queue_type, + "pipeline.workers" => worker_thread_count, + "pipeline.id" => pipeline_id + }} let(:pipeline_config) { mock_pipeline_config(pipeline_id, config, pipeline_settings_obj) } - subject { described_class.new(pipeline_config, metric) } let(:counting_output) { PipelinePqFileOutput.new({ "id" => output_id }) } let(:metric_store) { subject.metric.collector.snapshot_metric.metric_store } @@ -95,7 +98,6 @@ describe LogStash::Pipeline do let(:number_of_events) { 100_000 } let(:page_capacity) { 1 * 1024 * 512 } # 1 128 let(:max_bytes) { 1024 * 1024 * 1024 } # 1 gb - let(:queue_type) { "persisted" } # "memory" "memory_acked" let(:times) { [] } let(:pipeline_thread) do @@ -105,6 +107,8 @@ describe LogStash::Pipeline do Thread.new { s.run } end + let(:collected_metric) { metric_store.get_with_path("stats/pipelines/") } + before :each do FileUtils.mkdir_p(this_queue_folder) @@ -139,19 +143,43 @@ describe LogStash::Pipeline do # Dir.rm_rf(this_queue_folder) end - let(:collected_metric) { metric_store.get_with_path("stats/pipelines/") } + shared_examples "a well behaved pipeline" do + it "populates the core metrics" do + _metric = collected_metric[:stats][:pipelines][:main][:events] + expect(_metric[:duration_in_millis].value).not_to be_nil + expect(_metric[:in].value).to eq(number_of_events) + expect(_metric[:filtered].value).to eq(number_of_events) + expect(_metric[:out].value).to eq(number_of_events) + STDOUT.puts " pipeline: #{subject.class}" + STDOUT.puts " queue.type: #{pipeline_settings_obj.get("queue.type")}" + STDOUT.puts " queue.page_capacity: #{pipeline_settings_obj.get("queue.page_capacity") / 1024}KB" + STDOUT.puts " queue.max_bytes: #{pipeline_settings_obj.get("queue.max_bytes") / 1024}KB" + STDOUT.puts " workers: #{worker_thread_count}" + STDOUT.puts " events: #{number_of_events}" + STDOUT.puts " took: #{times.first}s" + end + end - it "populates the pipelines core metrics" do - _metric = collected_metric[:stats][:pipelines][:main][:events] - expect(_metric[:duration_in_millis].value).not_to be_nil - expect(_metric[:in].value).to eq(number_of_events) - expect(_metric[:filtered].value).to eq(number_of_events) - expect(_metric[:out].value).to eq(number_of_events) - STDOUT.puts " queue.type: #{pipeline_settings_obj.get("queue.type")}" - STDOUT.puts " queue.page_capacity: #{pipeline_settings_obj.get("queue.page_capacity") / 1024}KB" - STDOUT.puts " queue.max_bytes: #{pipeline_settings_obj.get("queue.max_bytes") / 1024}KB" - STDOUT.puts " workers: #{worker_thread_count}" - STDOUT.puts " events: #{number_of_events}" - STDOUT.puts " took: #{times.first}s" + context "using PQ" do + let(:queue_type) { "persisted" } # "memory", "persisted" + context "with Ruby execution" do + subject { LogStash::Pipeline.new(pipeline_config, metric) } + it_behaves_like "a well behaved pipeline" + end + context "with Java execution" do + subject { LogStash::JavaPipeline.new(pipeline_config, metric) } + it_behaves_like "a well behaved pipeline" + end + end + context "using MQ" do + let(:queue_type) { "memory" } # "memory", "persisted" + context "with Ruby execution" do + subject { LogStash::Pipeline.new(pipeline_config, metric) } + it_behaves_like "a well behaved pipeline" + end + context "with Java execution" do + subject { LogStash::JavaPipeline.new(pipeline_config, metric) } + it_behaves_like "a well behaved pipeline" + end end end diff --git a/logstash-core/spec/logstash/util/wrapped_synchronous_queue_spec.rb b/logstash-core/spec/logstash/util/wrapped_synchronous_queue_spec.rb index 0e7c0bae8..10cac5093 100644 --- a/logstash-core/spec/logstash/util/wrapped_synchronous_queue_spec.rb +++ b/logstash-core/spec/logstash/util/wrapped_synchronous_queue_spec.rb @@ -119,19 +119,16 @@ describe LogStash::WrappedSynchronousQueue do message = data.get("message") expect(messages).to include(message) messages.delete(message) - # read_batch.cancel("value-#{i}") if i > 2 # TODO: disabled for https://github.com/elastic/logstash/issues/6055 - will have to properly refactor if message.match /value-[3-4]/ data.cancel - read_batch.merge(LogStash::Event.new({ "message" => message.gsub(/value/, 'generated') })) end end - # expect(read_batch.cancelled_size).to eq(2) # disabled for https://github.com/elastic/logstash/issues/6055 received = [] read_batch.to_a.each do |data| received << data.get("message") end + expect(received.size).to eq(3) (0..2).each {|i| expect(received).to include("value-#{i}")} - (3..4).each {|i| expect(received).to include("generated-#{i}")} end it "handles Java proxied read-batch object" do diff --git a/logstash-core/src/main/java/org/logstash/ackedqueue/AckedBatch.java b/logstash-core/src/main/java/org/logstash/ackedqueue/AckedBatch.java index 8daceb2b4..cde1cab7e 100644 --- a/logstash-core/src/main/java/org/logstash/ackedqueue/AckedBatch.java +++ b/logstash-core/src/main/java/org/logstash/ackedqueue/AckedBatch.java @@ -21,11 +21,12 @@ package org.logstash.ackedqueue; import java.io.IOException; -import org.jruby.Ruby; -import org.jruby.RubyBoolean; -import org.jruby.RubyHash; +import java.util.ArrayList; +import java.util.Collection; import org.logstash.Event; -import org.logstash.ext.JrubyEventExtLibrary; +import org.logstash.ext.JrubyEventExtLibrary.RubyEvent; + +import static org.logstash.RubyUtil.RUBY; public final class AckedBatch { private Batch batch; @@ -36,14 +37,11 @@ public final class AckedBatch { return ackedBatch; } - public RubyHash toRubyHash(final Ruby runtime) { - final RubyBoolean trueValue = runtime.getTrue(); - final RubyHash result = RubyHash.newHash(runtime); - this.batch.getElements().forEach(e -> result.fastASet( - JrubyEventExtLibrary.RubyEvent.newRubyEvent(runtime, (Event) e), - trueValue - ) - ); + public Collection events() { + final ArrayList result = new ArrayList<>(this.batch.size()); + for (final Queueable e : batch.getElements()) { + result.add(RubyEvent.newRubyEvent(RUBY, (Event) e)); + } return result; } diff --git a/logstash-core/src/main/java/org/logstash/ackedqueue/AckedReadBatch.java b/logstash-core/src/main/java/org/logstash/ackedqueue/AckedReadBatch.java index 74a2dafec..cec53c340 100644 --- a/logstash-core/src/main/java/org/logstash/ackedqueue/AckedReadBatch.java +++ b/logstash-core/src/main/java/org/logstash/ackedqueue/AckedReadBatch.java @@ -21,13 +21,12 @@ package org.logstash.ackedqueue; import org.jruby.RubyArray; -import org.jruby.RubyHash; import org.logstash.ackedqueue.ext.JRubyAckedQueueExt; import org.logstash.execution.MemoryReadBatch; import org.logstash.execution.QueueBatch; import org.logstash.ext.JrubyEventExtLibrary.RubyEvent; - import java.io.IOException; +import java.util.ArrayList; import java.util.Collection; import static org.logstash.RubyUtil.RUBY; @@ -36,74 +35,55 @@ public final class AckedReadBatch implements QueueBatch { private AckedBatch ackedBatch; - private RubyHash originals; - - private RubyHash generated; + private Collection events; public static AckedReadBatch create( final JRubyAckedQueueExt queue, final int size, final long timeout) { - return new AckedReadBatch(queue, size, timeout); - } - - private AckedReadBatch( - final JRubyAckedQueueExt queue, - final int size, - final long timeout) - { - AckedBatch batch; try { - batch = queue.readBatch(size, timeout); + final AckedBatch batch = queue.readBatch(size, timeout); + return (batch == null) ? new AckedReadBatch() : new AckedReadBatch(batch); } catch (IOException e) { throw new IllegalStateException(e); } - if (batch == null) { - originals = RubyHash.newHash(RUBY); - ackedBatch = null; - } else { - ackedBatch = batch; - originals = ackedBatch.toRubyHash(RUBY); - } - generated = RubyHash.newHash(RUBY); + } + + public static AckedReadBatch create() { + return new AckedReadBatch(); + } + + private AckedReadBatch() { + ackedBatch = null; + events = new ArrayList<>(); + } + + private AckedReadBatch(AckedBatch batch) { + ackedBatch = batch; + events = batch.events(); } @Override - public void merge(final RubyEvent event) { - if (!event.isNil() && !originals.containsKey(event)) { - generated.put(event, RUBY.getTrue()); - } - } - - @SuppressWarnings({"unchecked", "rawtypes"}) - @Override - public RubyArray to_a() { - final RubyArray result = RUBY.newArray(filteredSize()); - for (final RubyEvent event : (Collection) originals.keys()) { - if (!MemoryReadBatch.isCancelled(event)) { - result.append(event); - } - } - for (final RubyEvent event : (Collection) generated.keys()) { - if (!MemoryReadBatch.isCancelled(event)) { - result.append(event); + public RubyArray to_a() { + @SuppressWarnings({"unchecked"}) final RubyArray result = RUBY.newArray(events.size()); + for (final RubyEvent e : events) { + if (!MemoryReadBatch.isCancelled(e)) { + result.append(e); } } return result; } - @SuppressWarnings({"unchecked"}) @Override - public Collection collection() { - // This only returns the originals and does not filter cancelled one - // because it is only used in the WorkerLoop where only originals - // non-cancelled exists. We should revisit this AckedReadBatch - // implementation and get rid of this dual original/generated idea. - // The MemoryReadBatch does not use such a strategy. - return originals.directKeySet(); + public Collection events() { + // This does not filter cancelled events because it is + // only used in the WorkerLoop where there are no cancelled + // events yet. + return events; } + @Override public void close() throws IOException { if (ackedBatch != null) { ackedBatch.close(); @@ -112,6 +92,6 @@ public final class AckedReadBatch implements QueueBatch { @Override public int filteredSize() { - return originals.size() + generated.size(); + return events.size(); } } diff --git a/logstash-core/src/main/java/org/logstash/common/LsQueueUtils.java b/logstash-core/src/main/java/org/logstash/common/LsQueueUtils.java index 938b8c60b..acb809376 100644 --- a/logstash-core/src/main/java/org/logstash/common/LsQueueUtils.java +++ b/logstash-core/src/main/java/org/logstash/common/LsQueueUtils.java @@ -20,11 +20,11 @@ package org.logstash.common; +import java.util.ArrayList; import java.util.Collection; -import java.util.LinkedHashSet; import java.util.concurrent.BlockingQueue; import java.util.concurrent.TimeUnit; -import org.logstash.ext.JrubyEventExtLibrary; +import org.logstash.ext.JrubyEventExtLibrary.RubyEvent; /** * Utilities around {@link BlockingQueue}. @@ -42,9 +42,12 @@ public final class LsQueueUtils { * @param events Events to add to Queue * @throws InterruptedException On interrupt during blocking queue add */ - public static void addAll(final BlockingQueue queue, - final Collection events) throws InterruptedException { - for (final JrubyEventExtLibrary.RubyEvent event : events) { + public static void addAll( + final BlockingQueue queue, + final Collection events) + throws InterruptedException + { + for (final RubyEvent event : events) { queue.put(event); } } @@ -65,13 +68,14 @@ public final class LsQueueUtils { * @throws InterruptedException On Interrupt during {@link BlockingQueue#poll()} or * {@link BlockingQueue#drainTo(Collection)} */ - public static LinkedHashSet drain( - final BlockingQueue queue, final int count, final long nanos - ) throws InterruptedException { + public static Collection drain( + final BlockingQueue queue, + final int count, + final long nanos) + throws InterruptedException + { int left = count; - //todo: make this an ArrayList once we remove the Ruby pipeline/execution - final LinkedHashSet collection = - new LinkedHashSet<>(4 * count / 3 + 1); + final ArrayList collection = new ArrayList<>(4 * count / 3 + 1); do { final int drained = drain(queue, collection, left, nanos); if (drained == 0) { @@ -95,15 +99,18 @@ public final class LsQueueUtils { * @throws InterruptedException On Interrupt during {@link BlockingQueue#poll()} or * {@link BlockingQueue#drainTo(Collection)} */ - private static int drain(final BlockingQueue queue, - final Collection collection, final int count, - final long nanos) throws InterruptedException { + private static int drain( + final BlockingQueue queue, + final Collection collection, + final int count, + final long nanos) + throws InterruptedException + { int added = 0; do { added += queue.drainTo(collection, count - added); if (added < count) { - final JrubyEventExtLibrary.RubyEvent event = - queue.poll(nanos, TimeUnit.NANOSECONDS); + final RubyEvent event = queue.poll(nanos, TimeUnit.NANOSECONDS); if (event == null) { break; } diff --git a/logstash-core/src/main/java/org/logstash/config/ir/CompiledPipeline.java b/logstash-core/src/main/java/org/logstash/config/ir/CompiledPipeline.java index ef4287089..3ed4ad9c4 100644 --- a/logstash-core/src/main/java/org/logstash/config/ir/CompiledPipeline.java +++ b/logstash-core/src/main/java/org/logstash/config/ir/CompiledPipeline.java @@ -48,14 +48,7 @@ import org.logstash.ext.JrubyEventExtLibrary.RubyEvent; import org.logstash.plugins.ConfigVariableExpander; import org.logstash.secret.store.SecretStore; -import java.util.ArrayList; -import java.util.Collection; -import java.util.Collections; -import java.util.HashMap; -import java.util.HashSet; -import java.util.List; -import java.util.Map; -import java.util.Objects; +import java.util.*; import java.util.stream.Collectors; import java.util.stream.Stream; @@ -315,20 +308,14 @@ public final class CompiledPipeline { @Override public void compute(final QueueBatch batch, final boolean flush, final boolean shutdown) { - compute(batch.collection(), flush, shutdown); + compute(batch.events(), flush, shutdown); } - @SuppressWarnings({"rawtypes", "unchecked"}) @Override - public void compute(final RubyArray batch, final boolean flush, final boolean shutdown) { - compute((Collection) batch, flush, shutdown); - } - - @SuppressWarnings({"rawtypes", "unchecked"}) - private void compute(final Collection batch, final boolean flush, final boolean shutdown) { - final RubyArray outputBatch = RubyUtil.RUBY.newArray(); + public void compute(final Collection batch, final boolean flush, final boolean shutdown) { + @SuppressWarnings({"unchecked"}) final RubyArray outputBatch = RubyUtil.RUBY.newArray(); // send batch one-by-one as single-element batches down the filters - final RubyArray filterBatch = RubyUtil.RUBY.newArray(1); + @SuppressWarnings({"unchecked"}) final RubyArray filterBatch = RubyUtil.RUBY.newArray(1); for (final RubyEvent e : batch) { filterBatch.set(0, e); final Collection result = compiledFilters.compute(filterBatch, flush, shutdown); @@ -343,14 +330,14 @@ public final class CompiledPipeline { @Override public void compute(final QueueBatch batch, final boolean flush, final boolean shutdown) { - compute(batch.to_a(), flush, shutdown); + compute(batch.events(), flush, shutdown); } - @SuppressWarnings({"rawtypes", "unchecked"}) @Override - public void compute(final RubyArray batch, final boolean flush, final boolean shutdown) { - final RubyArray outputBatch = RubyUtil.RUBY.newArray(); - final Collection result = compiledFilters.compute(batch, flush, shutdown); + public void compute(final Collection batch, final boolean flush, final boolean shutdown) { + // we know for now this comes from batch.collection() which returns a LinkedHashSet + final Collection result = compiledFilters.compute(RubyArray.newArray(RubyUtil.RUBY, batch), flush, shutdown); + @SuppressWarnings({"unchecked"}) final RubyArray outputBatch = RubyUtil.RUBY.newArray(result.size()); copyNonCancelledEvents(result, outputBatch); compiledFilters.clear(); compiledOutputs.compute(outputBatch, flush, shutdown); @@ -385,8 +372,7 @@ public final class CompiledPipeline { public abstract void compute(final QueueBatch batch, final boolean flush, final boolean shutdown); - @SuppressWarnings({"rawtypes"}) - public abstract void compute(final RubyArray batch, final boolean flush, final boolean shutdown); + public abstract void compute(final Collection batch, final boolean flush, final boolean shutdown); /** * Instantiates the graph of compiled filter section {@link Dataset}. diff --git a/logstash-core/src/main/java/org/logstash/execution/MemoryReadBatch.java b/logstash-core/src/main/java/org/logstash/execution/MemoryReadBatch.java index d7713a119..5108d0a3d 100644 --- a/logstash-core/src/main/java/org/logstash/execution/MemoryReadBatch.java +++ b/logstash-core/src/main/java/org/logstash/execution/MemoryReadBatch.java @@ -21,55 +21,50 @@ package org.logstash.execution; import org.jruby.RubyArray; import org.logstash.ext.JrubyEventExtLibrary.RubyEvent; +import java.util.ArrayList; import java.util.Collection; -import java.util.LinkedHashSet; + import static org.logstash.RubyUtil.RUBY; public final class MemoryReadBatch implements QueueBatch { - private final LinkedHashSet events; - - public MemoryReadBatch(final LinkedHashSet events) { - this.events = events; - } + private final Collection events; public static boolean isCancelled(final RubyEvent event) { return event.getEvent().isCancelled(); } - public static MemoryReadBatch create(LinkedHashSet events) { + public static MemoryReadBatch create(Collection events) { return new MemoryReadBatch(events); } public static MemoryReadBatch create() { - return create(new LinkedHashSet<>()); + return new MemoryReadBatch(new ArrayList<>()); + } + + private MemoryReadBatch(final Collection events) { + this.events = events; } @Override - @SuppressWarnings({"rawtypes"}) - public RubyArray to_a() { - final RubyArray result = RUBY.newArray(events.size()); - for (final RubyEvent event : events) { - if (!isCancelled(event)) { - result.append(event); + public RubyArray to_a() { + @SuppressWarnings({"unchecked"}) final RubyArray result = RUBY.newArray(events.size()); + for (final RubyEvent e : events) { + if (!isCancelled(e)) { + result.append(e); } } return result; } @Override - public Collection collection() { + public Collection events() { // This does not filter cancelled events because it is // only used in the WorkerLoop where there are no cancelled // events yet. return events; } - @Override - public void merge(final RubyEvent event) { - events.add(event); - } - @Override public int filteredSize() { return events.size(); diff --git a/logstash-core/src/main/java/org/logstash/execution/QueueBatch.java b/logstash-core/src/main/java/org/logstash/execution/QueueBatch.java index d303ff404..7da54d6f5 100644 --- a/logstash-core/src/main/java/org/logstash/execution/QueueBatch.java +++ b/logstash-core/src/main/java/org/logstash/execution/QueueBatch.java @@ -26,8 +26,7 @@ import java.util.Collection; public interface QueueBatch { int filteredSize(); - @SuppressWarnings({"rawtypes"}) RubyArray to_a(); - Collection collection(); - void merge(RubyEvent event); + RubyArray to_a(); + Collection events(); void close() throws IOException; } diff --git a/logstash-core/src/main/java/org/logstash/execution/WorkerLoop.java b/logstash-core/src/main/java/org/logstash/execution/WorkerLoop.java index 16dd457d8..843f67fe7 100644 --- a/logstash-core/src/main/java/org/logstash/execution/WorkerLoop.java +++ b/logstash-core/src/main/java/org/logstash/execution/WorkerLoop.java @@ -76,17 +76,19 @@ public final class WorkerLoop implements Runnable { do { isShutdown = isShutdown || shutdownRequested.get(); final QueueBatch batch = readClient.readBatch(); - consumedCounter.add(batch.filteredSize()); final boolean isFlush = flushRequested.compareAndSet(true, false); - readClient.startMetrics(batch); - execution.compute(batch, isFlush, false); - int filteredCount = batch.filteredSize(); - filteredCounter.add(filteredCount); - readClient.addOutputMetrics(filteredCount); - readClient.addFilteredMetrics(filteredCount); - readClient.closeBatch(batch); - if (isFlush) { - flushing.set(false); + if (batch.filteredSize() > 0 || isFlush) { + consumedCounter.add(batch.filteredSize()); + readClient.startMetrics(batch); + execution.compute(batch, isFlush, false); + int filteredCount = batch.filteredSize(); + filteredCounter.add(filteredCount); + readClient.addOutputMetrics(filteredCount); + readClient.addFilteredMetrics(filteredCount); + readClient.closeBatch(batch); + if (isFlush) { + flushing.set(false); + } } } while (!isShutdown || isDraining()); //we are shutting down, queue is drained if it was required, now perform a final flush. diff --git a/logstash-core/src/main/java/org/logstash/ext/JrubyAckedReadClientExt.java b/logstash-core/src/main/java/org/logstash/ext/JrubyAckedReadClientExt.java index 3ddec0bcb..3807ed688 100644 --- a/logstash-core/src/main/java/org/logstash/ext/JrubyAckedReadClientExt.java +++ b/logstash-core/src/main/java/org/logstash/ext/JrubyAckedReadClientExt.java @@ -76,13 +76,12 @@ public final class JrubyAckedReadClientExt extends QueueReadClientBase implement @Override public QueueBatch newBatch() { - return AckedReadBatch.create(queue, 0, 0); + return AckedReadBatch.create(); } @Override public QueueBatch readBatch() { - AckedReadBatch batch = - AckedReadBatch.create(queue, batchSize, waitForMillis); + final AckedReadBatch batch = AckedReadBatch.create(queue, batchSize, waitForMillis); startMetrics(batch); return batch; } diff --git a/logstash-core/src/main/java/org/logstash/ext/JrubyMemoryReadClientExt.java b/logstash-core/src/main/java/org/logstash/ext/JrubyMemoryReadClientExt.java index 9d7df1699..95e173b6a 100644 --- a/logstash-core/src/main/java/org/logstash/ext/JrubyMemoryReadClientExt.java +++ b/logstash-core/src/main/java/org/logstash/ext/JrubyMemoryReadClientExt.java @@ -77,8 +77,7 @@ public final class JrubyMemoryReadClientExt extends QueueReadClientBase { @Override @SuppressWarnings("unchecked") public QueueBatch readBatch() throws InterruptedException { - MemoryReadBatch batch = MemoryReadBatch.create( - LsQueueUtils.drain(queue, batchSize, waitForNanos)); + final MemoryReadBatch batch = MemoryReadBatch.create(LsQueueUtils.drain(queue, batchSize, waitForNanos)); startMetrics(batch); return batch; } diff --git a/logstash-core/src/test/java/org/logstash/config/ir/CompiledPipelineTest.java b/logstash-core/src/test/java/org/logstash/config/ir/CompiledPipelineTest.java index 2764bd152..638c0cc98 100644 --- a/logstash-core/src/test/java/org/logstash/config/ir/CompiledPipelineTest.java +++ b/logstash-core/src/test/java/org/logstash/config/ir/CompiledPipelineTest.java @@ -34,6 +34,7 @@ import java.util.function.Consumer; import java.util.function.Supplier; import org.hamcrest.CoreMatchers; import org.hamcrest.MatcherAssert; +import org.jruby.RubyArray; import org.jruby.RubyObject; import org.jruby.RubyString; import org.jruby.runtime.builtin.IRubyObject; @@ -115,6 +116,7 @@ public final class CompiledPipelineTest extends RubyEnvTestCase { EVENT_SINKS.remove(runId); } + @SuppressWarnings({"unchecked"}) @Test public void buildsTrivialPipeline() throws Exception { final PipelineIR pipelineIR = ConfigCompiler.configToPipelineIR( @@ -134,6 +136,7 @@ public final class CompiledPipelineTest extends RubyEnvTestCase { MatcherAssert.assertThat(outputEvents.contains(testEvent), CoreMatchers.is(true)); } + @SuppressWarnings({"unchecked"}) @Test public void buildsStraightPipeline() throws Exception { final PipelineIR pipelineIR = ConfigCompiler.configToPipelineIR( @@ -155,6 +158,7 @@ public final class CompiledPipelineTest extends RubyEnvTestCase { MatcherAssert.assertThat(outputEvents.contains(testEvent), CoreMatchers.is(true)); } + @SuppressWarnings({"unchecked"}) @Test public void buildsForkedPipeline() throws Exception { final PipelineIR pipelineIR = ConfigCompiler.configToPipelineIR(IRHelpers.toSourceWithMetadata( @@ -280,6 +284,7 @@ public final class CompiledPipelineTest extends RubyEnvTestCase { verifyRegex("!~", 0); } + @SuppressWarnings({"unchecked"}) private void verifyRegex(String operator, int expectedEvents) throws IncompleteSourceWithMetadataException { final Event event = new Event(); @@ -307,6 +312,7 @@ public final class CompiledPipelineTest extends RubyEnvTestCase { outputEvents.clear(); } + @SuppressWarnings({"unchecked"}) @Test public void equalityCheckOnCompositeField() throws Exception { final PipelineIR pipelineIR = ConfigCompiler.configToPipelineIR( @@ -338,6 +344,7 @@ public final class CompiledPipelineTest extends RubyEnvTestCase { MatcherAssert.assertThat(testEvent.getEvent().getField("foo"), CoreMatchers.nullValue()); } + @SuppressWarnings({"unchecked"}) @Test public void conditionalWithNullField() throws Exception { final PipelineIR pipelineIR = ConfigCompiler.configToPipelineIR( @@ -362,6 +369,7 @@ public final class CompiledPipelineTest extends RubyEnvTestCase { MatcherAssert.assertThat(testEvent.getEvent().getField("foo"), CoreMatchers.is("bar")); } + @SuppressWarnings({"unchecked"}) @Test public void conditionalNestedMetaFieldPipeline() throws Exception { final PipelineIR pipelineIR = ConfigCompiler.configToPipelineIR( @@ -387,6 +395,7 @@ public final class CompiledPipelineTest extends RubyEnvTestCase { MatcherAssert.assertThat(testEvent.getEvent().getField("foo"), CoreMatchers.nullValue()); } + @SuppressWarnings({"unchecked"}) @Test public void moreThan255Parents() throws Exception { final PipelineIR pipelineIR = ConfigCompiler.configToPipelineIR( @@ -440,6 +449,7 @@ public final class CompiledPipelineTest extends RubyEnvTestCase { verifyComparison(expected, String.format("[brr] %s [baz]", op), event); } + @SuppressWarnings({"unchecked"}) private void verifyComparison(final boolean expected, final String conditional, final Event event) throws IncompleteSourceWithMetadataException { final JrubyEventExtLibrary.RubyEvent testEvent = diff --git a/logstash-core/src/test/java/org/logstash/config/ir/EventConditionTest.java b/logstash-core/src/test/java/org/logstash/config/ir/EventConditionTest.java index 4a56b5a98..d65b52652 100644 --- a/logstash-core/src/test/java/org/logstash/config/ir/EventConditionTest.java +++ b/logstash-core/src/test/java/org/logstash/config/ir/EventConditionTest.java @@ -72,7 +72,7 @@ public final class EventConditionTest extends RubyEnvTestCase { } @Test - @SuppressWarnings("rawtypes") + @SuppressWarnings({"rawtypes", "unchecked"}) public void testInclusionWithFieldInField() throws Exception { final PipelineIR pipelineIR = ConfigCompiler.configToPipelineIR( IRHelpers.toSourceWithMetadata("input {mockinput{}} filter { " + @@ -154,6 +154,7 @@ public final class EventConditionTest extends RubyEnvTestCase { testConditionWithConstantValue("\"\"", 0); } + @SuppressWarnings({"unchecked"}) private void testConditionWithConstantValue(String condition, int expectedMatches) throws Exception { final PipelineIR pipelineIR = ConfigCompiler.configToPipelineIR( IRHelpers.toSourceWithMetadata("input {mockinput{}} filter { " + diff --git a/x-pack/spec/monitoring/inputs/metrics_spec.rb b/x-pack/spec/monitoring/inputs/metrics_spec.rb index 3d8b99cb4..47e1db9c3 100644 --- a/x-pack/spec/monitoring/inputs/metrics_spec.rb +++ b/x-pack/spec/monitoring/inputs/metrics_spec.rb @@ -2,11 +2,11 @@ # or more contributor license agreements. Licensed under the Elastic License; # you may not use this file except in compliance with the Elastic License. +require 'spec_helper' require "logstash-core" require "logstash/agent" require "monitoring/inputs/metrics" require "rspec/wait" -require 'spec_helper' require "json" require "json-schema" require 'monitoring/monitoring' From 0a4aa8b49182e21a141a65d2696f36b1005e937f Mon Sep 17 00:00:00 2001 From: Karen Metts Date: Tue, 24 Mar 2020 18:19:17 -0400 Subject: [PATCH 0405/1126] Add guidelines for setting jvm heap size Fixes #11716 --- docs/index.asciidoc | 3 +++ docs/static/best-practice.asciidoc | 1 - docs/static/config-details.asciidoc | 29 +++++++++++++++++++++++++++++ 3 files changed, 32 insertions(+), 1 deletion(-) create mode 100644 docs/static/config-details.asciidoc diff --git a/docs/index.asciidoc b/docs/index.asciidoc index cddbf5e56..ff4c0bf63 100644 --- a/docs/index.asciidoc +++ b/docs/index.asciidoc @@ -214,6 +214,9 @@ include::{plugins-repo-dir}/plugins/codecs.asciidoc[] :edit_url!: include::static/best-practice.asciidoc[] +:edit_url!: +include::static/config-details.asciidoc[] + :edit_url!: include::static/troubleshooting.asciidoc[] diff --git a/docs/static/best-practice.asciidoc b/docs/static/best-practice.asciidoc index 2be607b14..adb40c1a6 100644 --- a/docs/static/best-practice.asciidoc +++ b/docs/static/best-practice.asciidoc @@ -109,4 +109,3 @@ reached the PQ can be committed. - diff --git a/docs/static/config-details.asciidoc b/docs/static/config-details.asciidoc new file mode 100644 index 000000000..e528a0eae --- /dev/null +++ b/docs/static/config-details.asciidoc @@ -0,0 +1,29 @@ +[[heap-size]] +=== Setting the heap size + +NOTE: Heap size should be no less than 4GB and no more than 8GB. + +Here are some additional tips for adjusting the JVM heap size: + +* CPU utilization can increase unnecessarily if the heap size is too low, +resulting in the JVM constantly garbage collecting. You can check for this issue +by doubling the heap size to see if performance improves. + +* Do not increase the heap size past the amount of physical +memory. Leave at least 1GB free for the OS and other processes. + +* Set the minimum (Xms) and maximum (Xmx) heap allocation size to the same +value to prevent the heap from resizing at runtime, which is a very costly +process. + +* You can make more accurate measurements of the JVM heap by using either the +`jmap` command line utility distributed with Java or by using VisualVM. For more +info, see <>. + + + + + + + + From 9b732a2cbee0362cf2468be924ce861677699a10 Mon Sep 17 00:00:00 2001 From: Karen Metts Date: Wed, 1 Apr 2020 16:18:51 -0400 Subject: [PATCH 0406/1126] Incorporate review comments Fixes #11716 --- docs/static/config-details.asciidoc | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/docs/static/config-details.asciidoc b/docs/static/config-details.asciidoc index e528a0eae..81cdb3e1b 100644 --- a/docs/static/config-details.asciidoc +++ b/docs/static/config-details.asciidoc @@ -1,7 +1,11 @@ [[heap-size]] === Setting the heap size -NOTE: Heap size should be no less than 4GB and no more than 8GB. +Set the jvm heap size in the `jvm.options` <>. + +NOTE: The recommended heap size for typical ingestion scenarios should be no +less than 4GB and no more than 8GB. Here are some additional tips for adjusting the JVM heap size: @@ -27,3 +31,5 @@ info, see <>. + + From 0eb2f54de249a2e45d23bf4cce560de9fe970784 Mon Sep 17 00:00:00 2001 From: Rob Bavey Date: Wed, 8 Apr 2020 09:00:34 -0400 Subject: [PATCH 0407/1126] Update gradle version to 6.3 (#11742) (#11761) * Backport of #11742. Not a clean backport as 7.x had not previously been upgraded to 5.6.4 as master had been. * Update gradle version to 6.3 Gradle versions prior to 6.3 cannot run under JDK14. This commit upgrades the version of Gradle to 6.3, and removes all deprecation warnings that can currently be removed. Changes include: * Increase gradle memory to 2g * Increase gradle memory in the license check job to 2g * Replace use of `testCompile` * Replace `runtime` with `runtimeOnly` * Remove`compile` depedencies from gradle files * Replace deprecated archive methods * Fix dependencies report build * Make jruby dependencies 'api', fix archiveVersion * Set `duplicatesStrategy` for all tasks of type Copy * Use `configureEach` for global 'withType' calls ** Use the recommended Tasks API calls (https://blog.gradle.org/preview-avoiding-task-configuration-time) * Run `./gradlew wrapper` earlier to improve caching * Use copy with chown for resources that need to be run during `./gradlew wrapper` --- Dockerfile | 16 +++++--- build.gradle | 14 ++++--- ci/license_check.sh | 2 +- ci/unit_tests.sh | 4 +- gradle.properties | 1 + gradle/wrapper/gradle-wrapper.properties | 3 +- gradlew | 2 +- gradlew.bat | 2 +- logstash-core/benchmarks/build.gradle | 28 ++++++------- logstash-core/build.gradle | 51 ++++++++++++------------ qa/integration/build.gradle | 6 +-- rubyUtils.gradle | 3 +- tools/benchmark-cli/build.gradle | 30 +++++++------- tools/dependencies-report/build.gradle | 20 +++++----- tools/ingest-converter/build.gradle | 14 +++---- x-pack/build.gradle | 6 +-- 16 files changed, 106 insertions(+), 96 deletions(-) diff --git a/Dockerfile b/Dockerfile index 1925810b9..a62f16d99 100644 --- a/Dockerfile +++ b/Dockerfile @@ -20,9 +20,15 @@ WORKDIR /home/logstash # used by the purge policy LABEL retention="keep" -ADD gradlew /opt/logstash/gradlew -ADD gradle/wrapper /opt/logstash/gradle/wrapper -RUN /opt/logstash/gradlew wrapper +# Setup gradle wrapper. When running any `gradle` command, a `settings.gradle` is expected (and will soon be required). +# This section adds the gradle wrapper, `settings.gradle` and sets the permissions (setting the user to root for `chown` +# and working directory to allow this and then reverts back to the previous working directory and user. +COPY --chown=logstash:logstash gradlew /opt/logstash/gradlew +COPY --chown=logstash:logstash gradle/wrapper /opt/logstash/gradle/wrapper +COPY --chown=logstash:logstash settings.gradle /opt/logstash/settings.gradle +WORKDIR /opt/logstash +RUN ./gradlew wrapper --warning-mode all +WORKDIR /home/logstash ADD versions.yml /opt/logstash/versions.yml ADD LICENSE.txt /opt/logstash/LICENSE.txt @@ -46,7 +52,6 @@ ADD bin /opt/logstash/bin ADD modules /opt/logstash/modules ADD x-pack /opt/logstash/x-pack ADD ci /opt/logstash/ci -ADD settings.gradle /opt/logstash/settings.gradle USER root RUN rm -rf build && \ @@ -55,5 +60,4 @@ RUN rm -rf build && \ USER logstash WORKDIR /opt/logstash -LABEL retention="prune" - +LABEL retention="prune" \ No newline at end of file diff --git a/build.gradle b/build.gradle index 5a64f26d5..2f6fefb6c 100644 --- a/build.gradle +++ b/build.gradle @@ -30,7 +30,7 @@ buildscript { } plugins { - id "de.undercouch.download" version "3.2.0" + id "de.undercouch.download" version "4.0.4" } apply plugin: 'de.undercouch.download' @@ -45,23 +45,28 @@ allprojects { apply plugin: 'java' apply plugin: 'idea' + apply plugin: 'java-library' project.sourceCompatibility = JavaVersion.VERSION_1_8 project.targetCompatibility = JavaVersion.VERSION_1_8 - tasks.withType(JavaCompile).all { + tasks.withType(JavaCompile).configureEach { options.compilerArgs.add("-Xlint:all") options.compilerArgs.add("-Xlint:-processing") options.compilerArgs.add("-Werror") } - tasks.withType(Javadoc) { + tasks.withType(Javadoc).configureEach { options.addStringOption("Xwerror", "-quiet") if (JavaVersion.current().compareTo(JavaVersion.VERSION_1_9) > 0) { options.addBooleanOption("html5", true) } } + tasks.withType(Copy).configureEach { + duplicatesStrategy = DuplicatesStrategy.EXCLUDE + } + clean { delete "${projectDir}/out/" } @@ -105,7 +110,7 @@ subprojects { } } dependencies { - compile "gradle.plugin.com.github.jk1:gradle-license-report:0.7.1" + implementation "gradle.plugin.com.github.jk1:gradle-license-report:0.7.1" } apply plugin: 'com.github.jk1.dependency-license-report' @@ -427,7 +432,6 @@ task deleteLocalEs(type: Delete) { task copyEs(type: Copy, dependsOn: [downloadEs, deleteLocalEs]) { from tarTree(resources.gzip(project.ext.elasticsearchDownloadLocation)) into "./build/" - doLast { file("./build/${project.ext.unpackedElasticsearchName}").renameTo('./build/elasticsearch') System.out.println "Unzipped ${project.ext.elasticsearchDownloadLocation} to ./build/elasticsearch" diff --git a/ci/license_check.sh b/ci/license_check.sh index 3bb9396ee..c552d797b 100755 --- a/ci/license_check.sh +++ b/ci/license_check.sh @@ -1,5 +1,5 @@ #!/bin/bash -i -export GRADLE_OPTS="-Dorg.gradle.daemon=false -Dorg.gradle.logging.level=info -Dfile.encoding=UTF-8" +export GRADLE_OPTS="-Xmx2g -Dorg.gradle.daemon=false -Dorg.gradle.logging.level=info -Dfile.encoding=UTF-8" ./gradlew installDefaultGems bin/dependencies-report --csv report.csv diff --git a/ci/unit_tests.sh b/ci/unit_tests.sh index ae0ad5921..113d544d6 100755 --- a/ci/unit_tests.sh +++ b/ci/unit_tests.sh @@ -16,10 +16,10 @@ SELECTED_TEST_SUITE=$1 if [[ $SELECTED_TEST_SUITE == $"java" ]]; then echo "Running Java Tests" - ./gradlew javaTests --console=plain + ./gradlew javaTests --console=plain --warning-mode all elif [[ $SELECTED_TEST_SUITE == $"ruby" ]]; then echo "Running Ruby unit tests" - ./gradlew rubyTests --console=plain + ./gradlew rubyTests --console=plain --warning-mode all else echo "Running Java and Ruby unit tests" ./gradlew test --console=plain diff --git a/gradle.properties b/gradle.properties index 6b1823d86..5e0fa8494 100644 --- a/gradle.properties +++ b/gradle.properties @@ -1 +1,2 @@ +org.gradle.jvmargs=-Xmx2g -Dfile.encoding=UTF-8 org.gradle.daemon=false diff --git a/gradle/wrapper/gradle-wrapper.properties b/gradle/wrapper/gradle-wrapper.properties index 115e6ac0a..4579c909b 100644 --- a/gradle/wrapper/gradle-wrapper.properties +++ b/gradle/wrapper/gradle-wrapper.properties @@ -1,5 +1,6 @@ +#Thu Apr 02 09:48:49 EDT 2020 distributionBase=GRADLE_USER_HOME distributionPath=wrapper/dists -distributionUrl=https\://services.gradle.org/distributions/gradle-4.10-bin.zip +distributionUrl=https\://services.gradle.org/distributions/gradle-6.3-bin.zip zipStoreBase=GRADLE_USER_HOME zipStorePath=wrapper/dists diff --git a/gradlew b/gradlew index cccdd3d51..3e84efe61 100755 --- a/gradlew +++ b/gradlew @@ -28,7 +28,7 @@ APP_NAME="Gradle" APP_BASE_NAME=`basename "$0"` # Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. -DEFAULT_JVM_OPTS="" +DEFAULT_JVM_OPTS='"-Xmx64m" "-Xms64m"' # Use the maximum available, or set MAX_FD != -1 to use that value. MAX_FD="maximum" diff --git a/gradlew.bat b/gradlew.bat index e95643d6a..1688408e8 100644 --- a/gradlew.bat +++ b/gradlew.bat @@ -14,7 +14,7 @@ set APP_BASE_NAME=%~n0 set APP_HOME=%DIRNAME% @rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. -set DEFAULT_JVM_OPTS= +set DEFAULT_JVM_OPTS="-Xmx64m" "-Xms64m" @rem Find java.exe if defined JAVA_HOME goto findJavaFromJavaHome diff --git a/logstash-core/benchmarks/build.gradle b/logstash-core/benchmarks/build.gradle index 00b6e4f8c..f9093f9da 100644 --- a/logstash-core/benchmarks/build.gradle +++ b/logstash-core/benchmarks/build.gradle @@ -38,7 +38,7 @@ buildscript { } dependencies { classpath 'org.yaml:snakeyaml:1.17' - classpath 'com.github.jengelman.gradle.plugins:shadow:1.2.4' + classpath 'com.github.jengelman.gradle.plugins:shadow:4.0.4' } } @@ -51,19 +51,17 @@ jar { } ext { - jmh = 1.18 + jmh = 1.22 } dependencies { - compile project(':logstash-core') - compile "org.openjdk.jmh:jmh-core:$jmh" - compile "org.openjdk.jmh:jmh-generator-annprocess:$jmh" - compile "org.openjdk.jmh:jmh-core-benchmarks:$jmh" - compile 'net.sf.jopt-simple:jopt-simple:5.0.3' - compile 'com.google.guava:guava:21.0' - compile 'commons-io:commons-io:2.5' - runtime 'joda-time:joda-time:2.8.2' - compile "org.jruby:jruby-core:$jrubyVersion" + implementation project(':logstash-core') + implementation "org.openjdk.jmh:jmh-core:$jmh" + annotationProcessor "org.openjdk.jmh:jmh-generator-annprocess:$jmh" + implementation 'com.google.guava:guava:21.0' + implementation 'commons-io:commons-io:2.5' + runtimeOnly 'joda-time:joda-time:2.8.2' + api "org.jruby:jruby-core:$jrubyVersion" } javadoc { @@ -73,9 +71,9 @@ javadoc { apply plugin: 'com.github.johnrengelman.shadow' shadowJar { - baseName = 'logstash-core-benchmarks-all' - classifier = null - version = null + archiveBaseName = 'logstash-core-benchmarks-all' + archiveClassifier = null + archiveVersion = '' } task jmh(type: JavaExec, dependsOn: [':logstash-core-benchmarks:clean', ':logstash-core-benchmarks:shadowJar']) { @@ -87,7 +85,7 @@ task jmh(type: JavaExec, dependsOn: [':logstash-core-benchmarks:clean', ':logsta doFirst { args = [ "-Djava.io.tmpdir=${buildDir.absolutePath}", - "-XX:+UseParNewGC", "-XX:+UseConcMarkSweepGC", "-XX:CMSInitiatingOccupancyFraction=75", + "-XX:+UseConcMarkSweepGC", "-XX:CMSInitiatingOccupancyFraction=75", "-XX:+UseCMSInitiatingOccupancyOnly", "-XX:+DisableExplicitGC", "-XX:+HeapDumpOnOutOfMemoryError", "-Xms2g", "-Xmx2g", shadowJar.archivePath, diff --git a/logstash-core/build.gradle b/logstash-core/build.gradle index 14ee22de0..c16dda7fd 100644 --- a/logstash-core/build.gradle +++ b/logstash-core/build.gradle @@ -45,19 +45,19 @@ buildscript { task sourcesJar(type: Jar, dependsOn: classes) { from sourceSets.main.allSource - classifier 'sources' - extension 'jar' + archiveClassifier = 'sources' + archiveExtension = 'jar' } task javadocJar(type: Jar, dependsOn: javadoc) { from javadoc.destinationDir - classifier 'javadoc' - extension 'jar' + archiveClassifier = 'javadoc' + archiveExtension = 'jar' } task copyRuntimeLibs(type: Copy) { into project.file('lib/jars/') - from configurations.compile, configurations.runtime + from configurations.compileClasspath, configurations.runtimeClasspath } // copy jar file into the gem lib dir but without the version number in filename @@ -148,35 +148,36 @@ def customJRubyDir = project.hasProperty("custom.jruby.path") ? project.property def customJRubyVersion = customJRubyDir == "" ? "" : Files.readAllLines(Paths.get(customJRubyDir, "VERSION")).get(0).trim() dependencies { - compile 'org.apache.logging.log4j:log4j-api:2.12.1' - compile 'org.apache.logging.log4j:log4j-core:2.12.1' - runtime 'org.apache.logging.log4j:log4j-slf4j-impl:2.12.1' - compile('org.reflections:reflections:0.9.11') { + implementation 'org.apache.logging.log4j:log4j-api:2.12.1' + annotationProcessor 'org.apache.logging.log4j:log4j-core:2.12.1' + api 'org.apache.logging.log4j:log4j-core:2.12.1' + runtimeOnly 'org.apache.logging.log4j:log4j-slf4j-impl:2.12.1' + implementation('org.reflections:reflections:0.9.11') { exclude group: 'com.google.guava', module: 'guava' } - compile 'commons-codec:commons-codec:1.13' + implementation 'commons-codec:commons-codec:1.13' // Jackson version moved to versions.yml in the project root (the JrJackson version is there too) - compile "com.fasterxml.jackson.core:jackson-core:${jacksonVersion}" - compile "com.fasterxml.jackson.core:jackson-databind:${jacksonDatabindVersion}" - compile "com.fasterxml.jackson.core:jackson-annotations:${jacksonVersion}" - compile 'org.codehaus.janino:janino:3.1.0' - compile "com.fasterxml.jackson.dataformat:jackson-dataformat-cbor:${jacksonVersion}" + implementation "com.fasterxml.jackson.core:jackson-core:${jacksonVersion}" + api "com.fasterxml.jackson.core:jackson-databind:${jacksonDatabindVersion}" + api "com.fasterxml.jackson.core:jackson-annotations:${jacksonVersion}" + implementation 'org.codehaus.janino:janino:3.1.0' + implementation "com.fasterxml.jackson.dataformat:jackson-dataformat-cbor:${jacksonVersion}" if (customJRubyDir == "") { - compile "org.jruby:jruby-complete:${jrubyVersion}" + api "org.jruby:jruby-complete:${jrubyVersion}" } else { - compile files(customJRubyDir + "/maven/jruby-complete/target/jruby-complete-${customJRubyVersion}.jar") + api files(customJRubyDir + "/maven/jruby-complete/target/jruby-complete-${customJRubyVersion}.jar") } - compile group: 'com.google.guava', name: 'guava', version: '22.0' + implementation group: 'com.google.guava', name: 'guava', version: '22.0' // WARNING: DO NOT UPGRADE "google-java-format" // later versions require GPL licensed code in javac-shaded that is // Apache2 incompatible - compile('com.google.googlejavaformat:google-java-format:1.1') { + implementation('com.google.googlejavaformat:google-java-format:1.1') { exclude group: 'com.google.guava', module: 'guava' } - compile 'org.javassist:javassist:3.26.0-GA' - testCompile 'org.apache.logging.log4j:log4j-core:2.12.1:tests' - testCompile 'junit:junit:4.12' - testCompile 'net.javacrumbs.json-unit:json-unit:2.3.0' - testCompile 'org.elasticsearch:securemock:1.2' - testCompile 'org.assertj:assertj-core:3.11.1' + implementation 'org.javassist:javassist:3.26.0-GA' + testImplementation 'org.apache.logging.log4j:log4j-core:2.12.1:tests' + testImplementation 'junit:junit:4.12' + testImplementation 'net.javacrumbs.json-unit:json-unit:2.3.0' + testImplementation 'org.elasticsearch:securemock:1.2' + testImplementation 'org.assertj:assertj-core:3.11.1' } diff --git a/qa/integration/build.gradle b/qa/integration/build.gradle index 88518101b..451d11983 100644 --- a/qa/integration/build.gradle +++ b/qa/integration/build.gradle @@ -30,9 +30,9 @@ buildscript { } dependencies { - testCompile project(':logstash-core') - testCompile 'org.assertj:assertj-core:3.8.0' - testCompile 'junit:junit:4.12' + testImplementation project(':logstash-core') + testImplementation 'org.assertj:assertj-core:3.8.0' + testImplementation 'junit:junit:4.12' } test { diff --git a/rubyUtils.gradle b/rubyUtils.gradle index a4cfa2013..8d00fc2cd 100644 --- a/rubyUtils.gradle +++ b/rubyUtils.gradle @@ -24,7 +24,7 @@ buildscript { } dependencies { classpath 'org.yaml:snakeyaml:1.23' - classpath "de.undercouch:gradle-download-task:3.2.0" + classpath "de.undercouch:gradle-download-task:4.0.4" classpath "org.jruby:jruby-complete:9.2.11.1" } } @@ -42,6 +42,7 @@ import java.lang.annotation.Annotation import java.nio.file.Files import java.nio.file.Paths + ext { bundle = this.&bundle bundleWithEnv = this.&bundleWithEnv diff --git a/tools/benchmark-cli/build.gradle b/tools/benchmark-cli/build.gradle index 7f63b350e..c08ca9d5b 100644 --- a/tools/benchmark-cli/build.gradle +++ b/tools/benchmark-cli/build.gradle @@ -37,7 +37,7 @@ buildscript { } dependencies { classpath 'org.yaml:snakeyaml:1.17' - classpath 'com.github.jengelman.gradle.plugins:shadow:1.2.4' + classpath 'com.github.jengelman.gradle.plugins:shadow:4.0.4' } } @@ -47,17 +47,17 @@ ext { } dependencies { - compile 'net.sf.jopt-simple:jopt-simple:5.0.3' - compile group: 'org.apache.httpcomponents', name: 'httpclient', version: '4.5.3' - compile group: 'org.apache.commons', name: 'commons-compress', version: '1.14' - compile group: 'org.apache.commons', name: 'commons-lang3', version: '3.6' - compile group: 'commons-io', name: 'commons-io', version: '2.5' - compile 'com.fasterxml.jackson.core:jackson-core:2.7.4' - compile 'com.fasterxml.jackson.core:jackson-databind:2.7.4' - compile group: 'org.elasticsearch.client', name: 'rest', version: elasticsearch - compile "org.openjdk.jmh:jmh-core:$jmh" - testCompile group: 'com.github.tomakehurst', name: 'wiremock-standalone', version: '2.6.0' - testCompile "junit:junit:4.12" + implementation 'net.sf.jopt-simple:jopt-simple:5.0.3' + implementation group: 'org.apache.httpcomponents', name: 'httpclient', version: '4.5.3' + implementation group: 'org.apache.commons', name: 'commons-compress', version: '1.14' + implementation group: 'org.apache.commons', name: 'commons-lang3', version: '3.6' + implementation group: 'commons-io', name: 'commons-io', version: '2.5' + implementation 'com.fasterxml.jackson.core:jackson-core:2.7.4' + implementation 'com.fasterxml.jackson.core:jackson-databind:2.7.4' + implementation group: 'org.elasticsearch.client', name: 'rest', version: elasticsearch + implementation "org.openjdk.jmh:jmh-core:$jmh" + testImplementation group: 'com.github.tomakehurst', name: 'wiremock-standalone', version: '2.6.0' + testImplementation "junit:junit:4.12" } javadoc { @@ -75,9 +75,9 @@ test { apply plugin: 'com.github.johnrengelman.shadow' shadowJar { - baseName = 'benchmark-cli' - classifier = null - version = null + archiveBaseName = 'benchmark-cli' + archiveClassifier = null + archiveVersion = '' } assemble.dependsOn shadowJar diff --git a/tools/dependencies-report/build.gradle b/tools/dependencies-report/build.gradle index cd32cf815..621b8bc17 100644 --- a/tools/dependencies-report/build.gradle +++ b/tools/dependencies-report/build.gradle @@ -38,17 +38,17 @@ buildscript { } dependencies { classpath 'org.yaml:snakeyaml:1.17' - classpath 'com.github.jengelman.gradle.plugins:shadow:1.2.4' + classpath 'com.github.jengelman.gradle.plugins:shadow:4.0.4' } } dependencies { - compile 'commons-io:commons-io:2.6' - compile 'org.apache.commons:commons-csv:1.5' - compile "com.fasterxml.jackson.core:jackson-core:${jacksonVersion}" - compile "com.fasterxml.jackson.core:jackson-databind:${jacksonVersion}" - compile "com.fasterxml.jackson.core:jackson-annotations:${jacksonVersion}" - testCompile 'junit:junit:4.12' + implementation 'commons-io:commons-io:2.6' + implementation 'org.apache.commons:commons-csv:1.5' + implementation "com.fasterxml.jackson.core:jackson-core:${jacksonVersion}" + implementation "com.fasterxml.jackson.core:jackson-databind:${jacksonVersion}" + implementation "com.fasterxml.jackson.core:jackson-annotations:${jacksonVersion}" + testImplementation 'junit:junit:4.12' } javadoc { @@ -64,9 +64,9 @@ test { apply plugin: 'com.github.johnrengelman.shadow' shadowJar { - baseName = 'dependencies-report' - classifier = null - version = null + archiveBaseName = 'dependencies-report' + archiveClassifier = null + archiveVersion = '' } assemble.dependsOn shadowJar diff --git a/tools/ingest-converter/build.gradle b/tools/ingest-converter/build.gradle index 4a4684136..b30a0e7c5 100644 --- a/tools/ingest-converter/build.gradle +++ b/tools/ingest-converter/build.gradle @@ -37,14 +37,14 @@ buildscript { } dependencies { classpath 'org.yaml:snakeyaml:1.17' - classpath 'com.github.jengelman.gradle.plugins:shadow:1.2.4' + classpath 'com.github.jengelman.gradle.plugins:shadow:4.0.4' } } dependencies { - compile 'net.sf.jopt-simple:jopt-simple:5.0.3' - testCompile "junit:junit:4.12" - testCompile 'commons-io:commons-io:2.5' + implementation 'net.sf.jopt-simple:jopt-simple:4.6' + testImplementation "junit:junit:4.12" + testImplementation 'commons-io:commons-io:2.5' } javadoc { @@ -54,9 +54,9 @@ javadoc { apply plugin: 'com.github.johnrengelman.shadow' shadowJar { - baseName = 'ingest-converter' - classifier = null - version = null + archiveBaseName = 'ingest-converter' + archiveClassifier = null + archiveVersion = '' } assemble.dependsOn shadowJar diff --git a/x-pack/build.gradle b/x-pack/build.gradle index 08954721c..61fcf0170 100644 --- a/x-pack/build.gradle +++ b/x-pack/build.gradle @@ -17,9 +17,9 @@ buildscript { } dependencies { - testCompile project(':logstash-core') - testCompile 'org.assertj:assertj-core:3.8.0' - testCompile 'junit:junit:4.12' + testImplementation project(':logstash-core') + testImplementation 'org.assertj:assertj-core:3.8.0' + testImplementation 'junit:junit:4.12' } test { From deeede98249bc280a5cc53d1bb9e0e62f7c15b0d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jo=C3=A3o=20Duarte?= Date: Wed, 8 Apr 2020 14:55:17 +0100 Subject: [PATCH 0408/1126] update benchmark cli dependencies (#11766) also use jackson version in benchmark-cli from versions.yml --- tools/benchmark-cli/build.gradle | 16 +++++++++------- 1 file changed, 9 insertions(+), 7 deletions(-) diff --git a/tools/benchmark-cli/build.gradle b/tools/benchmark-cli/build.gradle index c08ca9d5b..e1338e425 100644 --- a/tools/benchmark-cli/build.gradle +++ b/tools/benchmark-cli/build.gradle @@ -24,6 +24,8 @@ def versionMap = (Map) (new Yaml()).load(new File("$projectDir/../../versions.ym description = """Logstash End to End Benchmarking Utility""" version = versionMap['logstash-core'] +String jacksonVersion = versionMap['jackson'] +String jacksonDatabindVersion = versionMap['jackson-databind'] repositories { mavenCentral() @@ -42,18 +44,18 @@ buildscript { } ext { - jmh = '1.18' - elasticsearch = '5.5.0' + jmh = '1.23' + elasticsearch = '5.5.3' } dependencies { implementation 'net.sf.jopt-simple:jopt-simple:5.0.3' implementation group: 'org.apache.httpcomponents', name: 'httpclient', version: '4.5.3' - implementation group: 'org.apache.commons', name: 'commons-compress', version: '1.14' - implementation group: 'org.apache.commons', name: 'commons-lang3', version: '3.6' - implementation group: 'commons-io', name: 'commons-io', version: '2.5' - implementation 'com.fasterxml.jackson.core:jackson-core:2.7.4' - implementation 'com.fasterxml.jackson.core:jackson-databind:2.7.4' + implementation group: 'org.apache.commons', name: 'commons-compress', version: '1.20' + implementation group: 'org.apache.commons', name: 'commons-lang3', version: '3.10' + implementation group: 'commons-io', name: 'commons-io', version: '2.6' + implementation "com.fasterxml.jackson.core:jackson-core:${jacksonVersion}" + api "com.fasterxml.jackson.core:jackson-databind:${jacksonDatabindVersion}" implementation group: 'org.elasticsearch.client', name: 'rest', version: elasticsearch implementation "org.openjdk.jmh:jmh-core:$jmh" testImplementation group: 'com.github.tomakehurst', name: 'wiremock-standalone', version: '2.6.0' From 085868595f21e73ba9e3ef8fa6ca80f2d6011b47 Mon Sep 17 00:00:00 2001 From: Joao Duarte Date: Thu, 9 Apr 2020 10:05:40 +0100 Subject: [PATCH 0409/1126] release notes script add version in plugin entries Fixes #11769 --- tools/release/generate_release_notes.rb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tools/release/generate_release_notes.rb b/tools/release/generate_release_notes.rb index fb259175e..141783e7f 100755 --- a/tools/release/generate_release_notes.rb +++ b/tools/release/generate_release_notes.rb @@ -87,7 +87,7 @@ report << "==== Plugins\n" plugin_changes.each do |plugin, versions| _, type, name = plugin.split("-") - header = "*#{name.capitalize} #{type.capitalize}*" + header = "*#{name.capitalize} #{type.capitalize} - #{versions.last}*" start_changelog_file = Tempfile.new(plugin + 'start') end_changelog_file = Tempfile.new(plugin + 'end') changelog = `curl https://raw.githubusercontent.com/logstash-plugins/#{plugin}/v#{versions.last}/CHANGELOG.md`.split("\n") From f2701dc7038f58cfbc0fc024d4be9837c351ce1b Mon Sep 17 00:00:00 2001 From: Ry Biesemeyer Date: Fri, 17 May 2019 21:06:14 +0000 Subject: [PATCH 0410/1126] performance: share a single secret store Loading a Java Keystore can take anywhere from ~0.3s to upwards of 3s, so the pattern of loading one per variable we need to replace adds a significant amount of overhead on pipelines that use these variables, whether or not they are provided by the keystore. By providing a private, constant, lazy singleton, we ensure that we don't incur the cost of repeatedly building the keystore. Fixes #10794 --- .../lib/logstash/util/lazy_singleton.rb | 33 +++++++++++++++++++ .../logstash/util/substitution_variables.rb | 23 ++++++++++++- logstash-core/spec/logstash/settings_spec.rb | 10 ++++++ 3 files changed, 65 insertions(+), 1 deletion(-) create mode 100644 logstash-core/lib/logstash/util/lazy_singleton.rb diff --git a/logstash-core/lib/logstash/util/lazy_singleton.rb b/logstash-core/lib/logstash/util/lazy_singleton.rb new file mode 100644 index 000000000..5e876da28 --- /dev/null +++ b/logstash-core/lib/logstash/util/lazy_singleton.rb @@ -0,0 +1,33 @@ +require 'thread' # Mutex + +# A [LazySingleton] wraps the result of the provided block, +# which is guaranteed to be called at-most-once, even if the +# block's return value is nil. +class ::LogStash::Util::LazySingleton + + def initialize(&block) + @mutex = Mutex.new + @block = block + @instantiated = false + end + + def instance + unless @instantiated + @mutex.synchronize do + unless @instantiated + @instance = @block.call + @instantiated = true + end + end + end + + return @instance + end + + def reset! + @mutex.synchronize do + @instantiated = false + @instance = nil + end + end +end diff --git a/logstash-core/lib/logstash/util/substitution_variables.rb b/logstash-core/lib/logstash/util/substitution_variables.rb index e21bdfc82..ea1954c28 100644 --- a/logstash-core/lib/logstash/util/substitution_variables.rb +++ b/logstash-core/lib/logstash/util/substitution_variables.rb @@ -17,12 +17,17 @@ java_import "org.logstash.secret.store.SecretStoreExt" +require_relative 'lazy_singleton' + module ::LogStash::Util::SubstitutionVariables include LogStash::Util::Loggable SUBSTITUTION_PLACEHOLDER_REGEX = /\${(?[a-zA-Z_.][a-zA-Z0-9_.]*)(:(?[^}]*))?}/ + SECRET_STORE = ::LogStash::Util::LazySingleton.new { load_secret_store } + private_constant :SECRET_STORE + # Recursive method to replace substitution variable references in parameters def deep_replace(value) if value.is_a?(Hash) @@ -57,7 +62,7 @@ module ::LogStash::Util::SubstitutionVariables logger.debug("Replacing `#{placeholder}` with actual value") #check the secret store if it exists - secret_store = SecretStoreExt.getIfExists(LogStash::SETTINGS.get_setting("keystore.file").value, LogStash::SETTINGS.get_setting("keystore.classname").value) + secret_store = SECRET_STORE.instance replacement = secret_store.nil? ? nil : secret_store.retrieveSecret(SecretStoreExt.getStoreId(name)) #check the environment replacement = ENV.fetch(name, default) if replacement.nil? @@ -69,4 +74,20 @@ module ::LogStash::Util::SubstitutionVariables end end # def replace_placeholders + class << self + private + + # loads a secret_store from disk if available, or returns nil + # + # @api private + # @return [SecretStoreExt,nil] + def load_secret_store + SecretStoreExt.getIfExists(LogStash::SETTINGS.get_setting("keystore.file").value, LogStash::SETTINGS.get_setting("keystore.classname").value) + end + + # @api test + def reset_secret_store + SECRET_STORE.reset! + end + end end diff --git a/logstash-core/spec/logstash/settings_spec.rb b/logstash-core/spec/logstash/settings_spec.rb index 88047834e..dc10b02d3 100644 --- a/logstash-core/spec/logstash/settings_spec.rb +++ b/logstash-core/spec/logstash/settings_spec.rb @@ -174,6 +174,11 @@ describe LogStash::Settings do before :each do LogStash::SETTINGS.set("keystore.file", File.join(File.dirname(__FILE__), "../../src/test/resources/logstash.keystore.with.default.pass")) + LogStash::Util::SubstitutionVariables.send(:reset_secret_store) + end + + after(:each) do + LogStash::Util::SubstitutionVariables.send(:reset_secret_store) end context "placeholders in flat logstash.yml" do @@ -227,6 +232,7 @@ describe LogStash::Settings do before :each do LogStash::SETTINGS.set("keystore.file", File.join(File.dirname(__FILE__), "../../src/test/resources/logstash.keystore.with.default.pass")) + LogStash::Util::SubstitutionVariables.send(:reset_secret_store) end before do @@ -241,6 +247,10 @@ describe LogStash::Settings do ENV.delete('a') end + after(:each) do + LogStash::Util::SubstitutionVariables.send(:reset_secret_store) + end + subject do settings = described_class.new settings.register(LogStash::Setting::ArrayCoercible.new("host", String, [])) From a6c92efef442633c1d3987eea2c25ccf609c7215 Mon Sep 17 00:00:00 2001 From: Joao Duarte Date: Tue, 25 Feb 2020 10:39:31 +0000 Subject: [PATCH 0411/1126] remove :cluster_uuids gauge Fixes #11628 --- logstash-core/lib/logstash/java_pipeline.rb | 1 - 1 file changed, 1 deletion(-) diff --git a/logstash-core/lib/logstash/java_pipeline.rb b/logstash-core/lib/logstash/java_pipeline.rb index 1ae774e0a..67733058e 100644 --- a/logstash-core/lib/logstash/java_pipeline.rb +++ b/logstash-core/lib/logstash/java_pipeline.rb @@ -245,7 +245,6 @@ module LogStash; class JavaPipeline < JavaBasePipeline config_metric.gauge(:ephemeral_id, ephemeral_id) config_metric.gauge(:hash, lir.unique_hash) config_metric.gauge(:graph, ::LogStash::Config::LIRSerializer.serialize(lir)) - config_metric.gauge(:cluster_uuids, resolve_cluster_uuids) pipeline_log_params = default_logging_keys( "pipeline.workers" => pipeline_workers, From d33195750e435a81d16ce3633f097f4583c24fbb Mon Sep 17 00:00:00 2001 From: Rob Bavey Date: Sun, 12 Apr 2020 21:14:29 -0400 Subject: [PATCH 0412/1126] Fix hard coded constraint on pipeline name for metrics Fixes #11777 --- x-pack/lib/monitoring/inputs/metrics.rb | 15 ++++++++++++--- x-pack/lib/monitoring/inputs/timer_task_logger.rb | 2 +- .../monitoring/direct_shipping_spec.rb | 3 ++- 3 files changed, 15 insertions(+), 5 deletions(-) diff --git a/x-pack/lib/monitoring/inputs/metrics.rb b/x-pack/lib/monitoring/inputs/metrics.rb index cf5c0b19b..011d077b2 100644 --- a/x-pack/lib/monitoring/inputs/metrics.rb +++ b/x-pack/lib/monitoring/inputs/metrics.rb @@ -211,9 +211,18 @@ module LogStash module Inputs end def extract_cluster_uuids(stats) - result = stats.extract_metrics([:stats, :pipelines, :main, :config], :cluster_uuids) - if result && !result[:cluster_uuids].empty? - cluster_uuids = result[:cluster_uuids] + cluster_uuids = [] + agent.running_pipelines.each do |pipeline_id, _| + unless pipeline_id.to_sym == :".monitoring-logstash" + path = [:stats, :pipelines, pipeline_id.to_sym, :config] + found_cluster_uuids = stats.extract_metrics(path, :cluster_uuids) + if found_cluster_uuids && !found_cluster_uuids[:cluster_uuids].empty? + cluster_uuids |= found_cluster_uuids[:cluster_uuids] + end + end + end + + unless cluster_uuids.empty? @logger.info("Found cluster_uuids from elasticsearch output plugins", :cluster_uuids => cluster_uuids) if LogStash::SETTINGS.set?("monitoring.cluster_uuid") @logger.warn("Found monitoring.cluster_uuid setting configured in logstash.yml while using the ones discovered from elasticsearch output plugins, ignoring setting monitoring.cluster_uuid") diff --git a/x-pack/lib/monitoring/inputs/timer_task_logger.rb b/x-pack/lib/monitoring/inputs/timer_task_logger.rb index be3edac77..2471b26b8 100644 --- a/x-pack/lib/monitoring/inputs/timer_task_logger.rb +++ b/x-pack/lib/monitoring/inputs/timer_task_logger.rb @@ -14,7 +14,7 @@ module LogStash module Inputs if exception.is_a?(Concurrent::TimeoutError) logger.debug("metric shipper took too much time to complete", :exception => exception.class, :message => exception.message) else - logger.error("metric shipper exception", :exception => exception.class, :message => exception.message) + logger.error("metric shipper exception", :exception => exception.class, :message => exception.message, :backtrace => exception.backtrace) end end end diff --git a/x-pack/qa/integration/monitoring/direct_shipping_spec.rb b/x-pack/qa/integration/monitoring/direct_shipping_spec.rb index 054c13acb..336592423 100644 --- a/x-pack/qa/integration/monitoring/direct_shipping_spec.rb +++ b/x-pack/qa/integration/monitoring/direct_shipping_spec.rb @@ -3,6 +3,7 @@ # you may not use this file except in compliance with the Elastic License. require_relative "../spec_helper" +require 'securerandom' describe "Direct shipping" do @@ -13,7 +14,7 @@ describe "Direct shipping" do config = "input { generator { count => 100 } tcp { port => 6000 } } output { null {} }" - @logstash_service = logstash_with_empty_default("bin/logstash -e '#{config}' -w 1", { + @logstash_service = logstash_with_empty_default("bin/logstash -e '#{config}' -w 1 --pipeline.id #{SecureRandom.hex(8)}", { :settings => { "monitoring.enabled" => true, "monitoring.elasticsearch.hosts" => ["http://localhost:9200", "http://localhost:9200"], From c00c3da95a960cdd49b0e9b7c523f74a586da4e2 Mon Sep 17 00:00:00 2001 From: Rob Bavey Date: Mon, 13 Apr 2020 09:07:23 -0400 Subject: [PATCH 0413/1126] Incorporate review comments Fixes #11777 --- x-pack/lib/monitoring/inputs/metrics.rb | 16 +++++----------- 1 file changed, 5 insertions(+), 11 deletions(-) diff --git a/x-pack/lib/monitoring/inputs/metrics.rb b/x-pack/lib/monitoring/inputs/metrics.rb index 011d077b2..8379c396f 100644 --- a/x-pack/lib/monitoring/inputs/metrics.rb +++ b/x-pack/lib/monitoring/inputs/metrics.rb @@ -211,18 +211,12 @@ module LogStash module Inputs end def extract_cluster_uuids(stats) - cluster_uuids = [] - agent.running_pipelines.each do |pipeline_id, _| - unless pipeline_id.to_sym == :".monitoring-logstash" - path = [:stats, :pipelines, pipeline_id.to_sym, :config] - found_cluster_uuids = stats.extract_metrics(path, :cluster_uuids) - if found_cluster_uuids && !found_cluster_uuids[:cluster_uuids].empty? - cluster_uuids |= found_cluster_uuids[:cluster_uuids] - end - end - end + cluster_uuids = agent.running_pipelines.flat_map do |_, pipeline| + next if pipeline.system? + pipeline.resolve_cluster_uuids + end.compact.uniq - unless cluster_uuids.empty? + if cluster_uuids.any? @logger.info("Found cluster_uuids from elasticsearch output plugins", :cluster_uuids => cluster_uuids) if LogStash::SETTINGS.set?("monitoring.cluster_uuid") @logger.warn("Found monitoring.cluster_uuid setting configured in logstash.yml while using the ones discovered from elasticsearch output plugins, ignoring setting monitoring.cluster_uuid") From 3b4dd6c5ac59ab713ac48f8c6d35c7f16177d9bc Mon Sep 17 00:00:00 2001 From: Karen Metts Date: Thu, 9 Apr 2020 12:53:00 -0400 Subject: [PATCH 0414/1126] Note that unit qualifier is required for config.reload.interval Fixes #11771 --- docs/static/breaking-changes.asciidoc | 1 + docs/static/reloading-config.asciidoc | 4 +++- docs/static/running-logstash-command-line.asciidoc | 1 + docs/static/settings-file.asciidoc | 2 +- 4 files changed, 6 insertions(+), 2 deletions(-) diff --git a/docs/static/breaking-changes.asciidoc b/docs/static/breaking-changes.asciidoc index 8fc007239..e93490c23 100644 --- a/docs/static/breaking-changes.asciidoc +++ b/docs/static/breaking-changes.asciidoc @@ -249,6 +249,7 @@ Changes to Logstash Core are plugin agnostic. * The setting `config.reload.interval` has been changed to use time value strings such as `5m`, `10s` etc. Previously, users had to convert this to a millisecond time value themselves. + Note that the unit qualifier (`s`) is required. [float] ===== RPM/Deb package changes diff --git a/docs/static/reloading-config.asciidoc b/docs/static/reloading-config.asciidoc index 019610e0d..fdf2003c2 100644 --- a/docs/static/reloading-config.asciidoc +++ b/docs/static/reloading-config.asciidoc @@ -16,7 +16,9 @@ in configuration settings from the command-line. By default, Logstash checks for configuration changes every 3 seconds. To change this interval, use the `--config.reload.interval ` option, where `interval` specifies how often Logstash -checks the config files for changes (in seconds). +checks the config files for changes (in seconds). + +Note that the unit qualifier (`s`) is required. [[force-reload]] ==== Force reloading the config file diff --git a/docs/static/running-logstash-command-line.asciidoc b/docs/static/running-logstash-command-line.asciidoc index 3da475eea..51657380a 100644 --- a/docs/static/running-logstash-command-line.asciidoc +++ b/docs/static/running-logstash-command-line.asciidoc @@ -209,6 +209,7 @@ With this command, Logstash concatenates three config files, `/tmp/one`, `/tmp/t *`--config.reload.interval RELOAD_INTERVAL`*:: How frequently to poll the configuration location for changes. The default value is "3s". + Note that the unit qualifier (`s`) is required. *`--http.host HTTP_HOST`*:: Web API binding host. This option specifies the bind address for the metrics REST endpoint. The default is "127.0.0.1". diff --git a/docs/static/settings-file.asciidoc b/docs/static/settings-file.asciidoc index 776e6b6b1..57379e04c 100644 --- a/docs/static/settings-file.asciidoc +++ b/docs/static/settings-file.asciidoc @@ -157,7 +157,7 @@ guaranteed, but you save the processing cost of preserving order. | `false` | `config.reload.interval` -| How often in seconds Logstash checks the config files for changes. +| How often in seconds Logstash checks the config files for changes. Note that the unit qualifier (`s`) is required. | `3s` | `config.debug` From 73a8808b1992b2eca9e542d2b067342453ed2669 Mon Sep 17 00:00:00 2001 From: Karen Metts Date: Thu, 9 Apr 2020 15:24:44 -0400 Subject: [PATCH 0415/1126] Update description in logstash.yml Fixes #11771 --- config/logstash.yml | 3 +++ 1 file changed, 3 insertions(+) diff --git a/config/logstash.yml b/config/logstash.yml index 4a713d32d..1f0a7c884 100644 --- a/config/logstash.yml +++ b/config/logstash.yml @@ -86,6 +86,9 @@ pipeline.ordered: auto # config.reload.automatic: false # # How often to check if the pipeline configuration has changed (in seconds) +# Note that the unit value (s) is required. Values without a qualifier (e.g. 60) +# are treated as nanoseconds. +# Setting the interval this way is not recommended and might change in later versions. # # config.reload.interval: 3s # From a8fca3c07f38501c74e4ac2767a49f1623929ffd Mon Sep 17 00:00:00 2001 From: Andres Rodriguez Date: Mon, 13 Apr 2020 15:27:23 -0400 Subject: [PATCH 0416/1126] Change plugin name from java_sink to sink In the docs templating, the plugin name is used to autogenerate a code example of how to configure specific plugin. As such, if a plugin name is different from how you configure it, this results in an example of how to configure this plugin with an incorrect name. This changes the java_sink plugin name to sink to correctly autogenerate the example. Fixes: #11675, Fixes: #11214 Fixes #11782 --- docs/static/core-plugins/outputs/java_sink.asciidoc | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/docs/static/core-plugins/outputs/java_sink.asciidoc b/docs/static/core-plugins/outputs/java_sink.asciidoc index cfec6dbb9..5f340f5b0 100644 --- a/docs/static/core-plugins/outputs/java_sink.asciidoc +++ b/docs/static/core-plugins/outputs/java_sink.asciidoc @@ -1,4 +1,4 @@ -:plugin: java_sink +:plugin: sink :type: output :default_codec!: @@ -12,7 +12,7 @@ END - REPLACES GENERATED VARIABLES [id="plugins-{type}s-{plugin}"] -=== Java_sink output plugin +=== Sink output plugin include::{include_path}/plugin_header-core.asciidoc[] @@ -22,7 +22,7 @@ An event sink that discards any events received. Generally useful for testing th and filters. [id="plugins-{type}s-{plugin}-options"] -==== Java_sink Output Configuration Options +==== Sink Output Configuration Options There are no special configuration options for this plugin, but it does support the <>. @@ -30,4 +30,4 @@ but it does support the <>. [id="plugins-{type}s-{plugin}-common-options"] include::{include_path}/{type}.asciidoc[] -:default_codec!: \ No newline at end of file +:default_codec!: From 2e545c75e47cf13a693bca8c44bb6be2a9f63bc9 Mon Sep 17 00:00:00 2001 From: Rob Bavey Date: Mon, 13 Apr 2020 14:44:42 -0400 Subject: [PATCH 0417/1126] Remove separator vertices and associated edges from serialized output The separator vertices are an implementation detail of the serialized output of the LIR, and are not meaningful to the pipeline viewer. This commit removes the separator vertices, and reworks the edges to account for this. Fixes #11779 --- .../lib/logstash/config/lir_serializer.rb | 28 +++++++++++++++---- 1 file changed, 23 insertions(+), 5 deletions(-) diff --git a/logstash-core/lib/logstash/config/lir_serializer.rb b/logstash-core/lib/logstash/config/lir_serializer.rb index 9826d3217..506f9c57d 100644 --- a/logstash-core/lib/logstash/config/lir_serializer.rb +++ b/logstash-core/lib/logstash/config/lir_serializer.rb @@ -26,7 +26,7 @@ module LogStash; def self.serialize(lir_pipeline) self.new(lir_pipeline).serialize end - + def initialize(lir_pipeline) @lir_pipeline = lir_pipeline end @@ -44,11 +44,11 @@ module LogStash; end def vertices - graph.getVertices.map {|v| vertex(v) } + graph.getVertices.map {|v| vertex(v) }.compact end def edges - graph.getEdges.map {|e| edge(e) } + remove_separators_from_edges(graph.getEdges) end def graph @@ -64,10 +64,10 @@ module LogStash; when :queue queue_vertex(v) when :separator - separator_vertex(v) + nil end - decorate_vertex(v, hashified_vertex) + decorate_vertex(v, hashified_vertex) unless hashified_vertex.nil? end def vertex_type(v) @@ -114,6 +114,24 @@ module LogStash; {} end + # For separators, create new edges going between the incoming and all of the outgoing edges, and remove + # the separator vertices from the serialized output. + def remove_separators_from_edges(edges) + edges_with_separators_removed = [] + edges.each do |e| + if vertex_type(e.to) == :separator + e.to.getOutgoingEdges.each do |outgoing| + edges_with_separators_removed << edge(org.logstash.config.ir.graph.PlainEdge.new(e.from, outgoing.to)) + end + elsif vertex_type(e.from) == :separator + # Skip the edges coming from the 'from' separator + else + edges_with_separators_removed << edge(e) + end + end + edges_with_separators_removed + end + def edge(e) e_json = { "from" => e.from.id, From ba7fd0cedc0739cc88f53e881b2b7274b872fdd2 Mon Sep 17 00:00:00 2001 From: Rob Bavey Date: Mon, 13 Apr 2020 15:29:52 -0400 Subject: [PATCH 0418/1126] Handle Boolean Edges Fixes #11779 --- logstash-core/lib/logstash/config/lir_serializer.rb | 6 +++++- .../inputs/metrics/state_event/lir_serializer_spec.rb | 2 +- 2 files changed, 6 insertions(+), 2 deletions(-) diff --git a/logstash-core/lib/logstash/config/lir_serializer.rb b/logstash-core/lib/logstash/config/lir_serializer.rb index 506f9c57d..6740ae70e 100644 --- a/logstash-core/lib/logstash/config/lir_serializer.rb +++ b/logstash-core/lib/logstash/config/lir_serializer.rb @@ -121,7 +121,11 @@ module LogStash; edges.each do |e| if vertex_type(e.to) == :separator e.to.getOutgoingEdges.each do |outgoing| - edges_with_separators_removed << edge(org.logstash.config.ir.graph.PlainEdge.new(e.from, outgoing.to)) + if e.java_kind_of?(org.logstash.config.ir.graph.BooleanEdge) + edges_with_separators_removed << edge(org.logstash.config.ir.graph.BooleanEdge.new(e.edgeType, e.from, outgoing.to)) + else + edges_with_separators_removed << edge(org.logstash.config.ir.graph.PlainEdge.factory.make(e.from, outgoing.to)) + end end elsif vertex_type(e.from) == :separator # Skip the edges coming from the 'from' separator diff --git a/x-pack/spec/monitoring/inputs/metrics/state_event/lir_serializer_spec.rb b/x-pack/spec/monitoring/inputs/metrics/state_event/lir_serializer_spec.rb index b4c2c64dd..1c4b1b994 100644 --- a/x-pack/spec/monitoring/inputs/metrics/state_event/lir_serializer_spec.rb +++ b/x-pack/spec/monitoring/inputs/metrics/state_event/lir_serializer_spec.rb @@ -10,7 +10,7 @@ describe ::LogStash::Config::LIRSerializer do <<-EOC input { fake_input {} } filter { - if ([foo] > 2) { + if ([foo] < 2) { fake_filter {} } } From dfe5cc5ee77043445838ffb10455811963683a89 Mon Sep 17 00:00:00 2001 From: Karen Metts <35154725+karenzone@users.noreply.github.com> Date: Tue, 14 Apr 2020 15:47:56 -0400 Subject: [PATCH 0419/1126] Restructure monitoring docs to support new and legacy internal collectors (#11714) * [Doc] added description of xpack.monitoring.collection.write_direct.enabled setting * Added page to mark as deprecated the legacy internal collector and fixed all the `xpack.monitoring.*` references * Included legacy collector file into monitoring overview * Restructure monitoring docs * Incorporate review comments Co-authored-by: andsel Fixes #11787 --- docs/index.asciidoc | 7 +- docs/static/docker.asciidoc | 6 +- .../monitoring/collectors-legacy.asciidoc | 49 ++++++ docs/static/monitoring/collectors.asciidoc | 12 +- .../monitoring-internal-legacy.asciidoc | 155 ++++++++++++++++++ .../monitoring/monitoring-internal.asciidoc | 123 +++++++------- docs/static/monitoring/monitoring-mb.asciidoc | 13 +- .../monitoring-output-legacy.asciidoc | 47 ++++++ .../monitoring/monitoring-output.asciidoc | 21 ++- .../monitoring/monitoring-overview.asciidoc | 25 ++- docs/static/monitoring/monitoring.asciidoc | 2 +- .../monitoring/troubleshooting.asciidoc | 2 +- docs/static/security/logstash.asciidoc | 4 +- .../monitoring-settings-legacy.asciidoc | 106 ++++++++++++ .../settings/monitoring-settings.asciidoc | 69 ++++---- docs/static/upgrading.asciidoc | 2 +- 16 files changed, 507 insertions(+), 136 deletions(-) create mode 100644 docs/static/monitoring/collectors-legacy.asciidoc create mode 100644 docs/static/monitoring/monitoring-internal-legacy.asciidoc create mode 100644 docs/static/monitoring/monitoring-output-legacy.asciidoc create mode 100644 docs/static/settings/monitoring-settings-legacy.asciidoc diff --git a/docs/index.asciidoc b/docs/index.asciidoc index ff4c0bf63..45abb59c7 100644 --- a/docs/index.asciidoc +++ b/docs/index.asciidoc @@ -187,14 +187,13 @@ include::static/deploying.asciidoc[] :edit_url: https://github.com/elastic/logstash/edit/{branch}/docs/static/performance-checklist.asciidoc include::static/performance-checklist.asciidoc[] -// Monitoring -:edit_url!: -include::static/monitoring/monitoring.asciidoc[] - // X-Pack Monitoring :edit_url!: include::static/monitoring/monitoring-overview.asciidoc[] +// Monitoring +:edit_url!: +include::static/monitoring/monitoring.asciidoc[] // Working with Plugins diff --git a/docs/static/docker.asciidoc b/docs/static/docker.asciidoc index a05f947a6..366902632 100644 --- a/docs/static/docker.asciidoc +++ b/docs/static/docker.asciidoc @@ -153,7 +153,7 @@ Some example translations are shown here: **Environment Variable**:: **Logstash Setting** `PIPELINE_WORKERS`:: `pipeline.workers` `LOG_LEVEL`:: `log.level` -`XPACK_MONITORING_ENABLED`:: `xpack.monitoring.enabled` +`MONITORING_ENABLED`:: `monitoring.enabled` In general, any setting listed in the <> can be configured with this technique. @@ -170,9 +170,9 @@ images: [horizontal] `http.host`:: `0.0.0.0` -`xpack.monitoring.elasticsearch.hosts`:: `http://elasticsearch:9200` +`monitoring.elasticsearch.hosts`:: `http://elasticsearch:9200` -NOTE: The setting `xpack.monitoring.elasticsearch.hosts` is not +NOTE: The setting `monitoring.elasticsearch.hosts` is not defined in the `-oss` image. These settings are defined in the default `logstash.yml`. They can be overridden diff --git a/docs/static/monitoring/collectors-legacy.asciidoc b/docs/static/monitoring/collectors-legacy.asciidoc new file mode 100644 index 000000000..1feb8baa4 --- /dev/null +++ b/docs/static/monitoring/collectors-legacy.asciidoc @@ -0,0 +1,49 @@ +[float] +[role="xpack"] +[[logstash-monitoring-collectors-legacy]] +===== Collectors + +Collectors, as their name implies, collect things. In monitoring for Logstash, +collectors are just <> in the same way that ordinary Logstash +configurations provide inputs. + +Like monitoring for {es}, each collector can create zero or more monitoring +documents. As it is currently implemented, each Logstash node runs two types of +collectors: one for node stats and one for pipeline stats. + +[options="header"] +|======================= +| Collector | Data Types | Description +| Node Stats | `logstash_stats` +| Gathers details about the running node, such as memory utilization and CPU +usage (for example, `GET /_stats`). + +This runs on every Logstash node with monitoring enabled. One common +failure is that Logstash directories are copied with their `path.data` directory +included (`./data` by default), which copies the persistent UUID of the Logstash +node along with it. As a result, it generally appears that one or more Logstash +nodes are failing to collect monitoring data, when in fact they are all really +misreporting as the _same_ Logstash node. Re-use `path.data` directories only +when upgrading Logstash, such that upgraded nodes replace the previous versions. +| Pipeline Stats | `logstash_state` +| Gathers details about the node's running pipelines, which powers the +Monitoring Pipeline UI. +|======================= + +Per collection interval, which defaults to 10 seconds (`10s`), each collector is +run. The failure of an individual collector does not impact any other collector. +Each collector, as an ordinary Logstash input, creates a separate Logstash event +in its isolated monitoring pipeline. The Logstash output then sends the data. + +The collection interval can be configured dynamically and you can also disable +data collection. For more information about the configuration options for the +collectors, see <>. + +WARNING: Unlike {es} and {kib} monitoring, there is no +`xpack.monitoring.collection.enabled` setting on Logstash. You must use the +`xpack.monitoring.enabled` setting to enable and disable data collection. + +If gaps exist in the monitoring charts in {kib}, it is typically because either +a collector failed or the monitoring cluster did not receive the data (for +example, it was being restarted). In the event that a collector fails, a logged +error should exist on the node that attempted to perform the collection. diff --git a/docs/static/monitoring/collectors.asciidoc b/docs/static/monitoring/collectors.asciidoc index 30a373f24..8b09cf6a0 100644 --- a/docs/static/monitoring/collectors.asciidoc +++ b/docs/static/monitoring/collectors.asciidoc @@ -3,11 +3,11 @@ [[logstash-monitoring-collectors]] ===== Collectors -Collectors, as their name implies, collect things. In {monitoring} for Logstash, +Collectors, as their name implies, collect things. In monitoring for Logstash, collectors are just <> in the same way that ordinary Logstash configurations provide inputs. -Like {monitoring} for {es}, each collector can create zero or more monitoring +Like monitoring for {es}, each collector can create zero or more monitoring documents. As it is currently implemented, each Logstash node runs two types of collectors: one for node stats and one for pipeline stats. @@ -18,7 +18,7 @@ collectors: one for node stats and one for pipeline stats. | Gathers details about the running node, such as memory utilization and CPU usage (for example, `GET /_stats`). -This runs on every Logstash node with {monitoring} enabled. One common +This runs on every Logstash node with monitoring enabled. One common failure is that Logstash directories are copied with their `path.data` directory included (`./data` by default), which copies the persistent UUID of the Logstash node along with it. As a result, it generally appears that one or more Logstash @@ -39,9 +39,9 @@ The collection interval can be configured dynamically and you can also disable data collection. For more information about the configuration options for the collectors, see <>. -WARNING: Unlike {monitoring} for {es} and {kib}, there is no -`xpack.monitoring.collection.enabled` setting on Logstash. You must use the -`xpack.monitoring.enabled` setting to enable and disable data collection. +WARNING: Unlike for {es} and {kib} monitoring, there is no +`monitoring.collection.enabled` setting on Logstash. You must use the +`monitoring.enabled` setting to enable and disable data collection. If gaps exist in the monitoring charts in {kib}, it is typically because either a collector failed or the monitoring cluster did not receive the data (for diff --git a/docs/static/monitoring/monitoring-internal-legacy.asciidoc b/docs/static/monitoring/monitoring-internal-legacy.asciidoc new file mode 100644 index 000000000..a86f81501 --- /dev/null +++ b/docs/static/monitoring/monitoring-internal-legacy.asciidoc @@ -0,0 +1,155 @@ +[role="xpack"] +[[monitoring-internal-collection-legacy]] +=== Collect {ls} monitoring data using legacy internal collectors +++++ +Legacy internal collection +++++ + +IMPORTANT: Use <> or +<> instead of legacy +internal collection. If you are currently using legacy internal collection, you +should migrate to either Metricbeat collection or internal collection. + +==== Migrating from legacy internal collection to new internal collection + +Migrating from legacy internal collection to new +<> is straightforward. + +** Drop the `xpack.` prefix from your configuration settings. +For example, `xpack.monitoring.enabled` is now `monitoring.enabled`. See +<> for the full list. +** Change the hosts settings and configuration options to point to the monitoring +cluster instead of the production cluster. +** If you don’t have an Elasticsearch output plugin configured in the pipelines, +add the <> setting to your +logstash.yml. + +==== Components for legacy internal collection + +Monitoring {ls} with legacy internal collection uses these components: + +* <> +* <> + +These pieces live outside of the default Logstash pipeline in a dedicated monitoring +pipeline. This configuration ensures that all data and processing has a minimal +impact on ordinary Logstash processing. Existing Logstash features, such as the +<>, can be reused to +benefit from its retry policies. + +NOTE: The `elasticsearch` output that is used for monitoring {ls} is +configured exclusively through settings found in `logstash.yml`. It is not +configured by using anything from the Logstash configurations that might also be +using their own separate `elasticsearch` outputs. + + +The production {es} cluster should be configured to receive {ls} monitoring +data. This configuration enables the production {es} cluster to add metadata +(for example, its cluster UUID) to the Logstash monitoring data and then route +it to the monitoring clusters. For more information about typical monitoring +architectures, see {ref}/how-monitoring-works.html[How monitoring works] in the +{ref}[Elasticsearch Reference]. + + +include::collectors-legacy.asciidoc[] +include::monitoring-output-legacy.asciidoc[] + + +[[configure-internal-collectors-legacy]] +==== Configure {ls} monitoring with internal collectors +++++ +Configure internal collection +++++ + +To monitor Logstash nodes: + +. Specify where to send monitoring data. This cluster is often referred to as +the _production cluster_. For examples of typical monitoring architectures, see +{ref}/how-monitoring-works.html[How monitoring works]. ++ +-- +IMPORTANT: To visualize Logstash as part of the Elastic Stack (as shown in Step +6), send metrics to your _production_ cluster. Sending metrics to a dedicated +monitoring cluster will show the Logstash metrics under the _monitoring_ cluster. + +-- + +. Verify that the `xpack.monitoring.collection.enabled` setting is `true` on the +production cluster. If that setting is `false`, the collection of monitoring data +is disabled in {es} and data is ignored from all other sources. + +. Configure your Logstash nodes to send metrics by setting the +`xpack.monitoring.elasticsearch.hosts` in `logstash.yml`. If {security-features} +are enabled, you also need to specify the credentials for the +{ref}/built-in-users.html[built-in `logstash_system` user]. For more information +about these settings, see <>. ++ +-- +[source,yaml] +-------------------------------------------------- +xpack.monitoring.elasticsearch.hosts: ["http://es-prod-node-1:9200", "http://es-prod-node-2:9200"] <1> +xpack.monitoring.elasticsearch.username: "logstash_system" +xpack.monitoring.elasticsearch.password: "changeme" +-------------------------------------------------- + +<1> If SSL/TLS is enabled on the production cluster, you must +connect through HTTPS. As of v5.2.1, you can specify multiple +Elasticsearch hosts as an array as well as specifying a single +host as a string. If multiple URLs are specified, Logstash +can round-robin requests to these production nodes. +-- + +. If SSL/TLS is enabled on the production {es} cluster, specify the trusted +CA certificates that will be used to verify the identity of the nodes +in the cluster. ++ +-- +To add a CA certificate to a Logstash node's trusted certificates, you +can specify the location of the PEM encoded certificate with the +`certificate_authority` setting: + +[source,yaml] +-------------------------------------------------- +xpack.monitoring.elasticsearch.ssl.certificate_authority: /path/to/ca.crt +-------------------------------------------------- + +Alternatively, you can configure trusted certificates using a truststore +(a Java Keystore file that contains the certificates): + +[source,yaml] +-------------------------------------------------- +xpack.monitoring.elasticsearch.ssl.truststore.path: /path/to/file +xpack.monitoring.elasticsearch.ssl.truststore.password: password +-------------------------------------------------- + +Also, optionally, you can set up client certificate using a keystore +(a Java Keystore file that contains the certificate): + +[source,yaml] +-------------------------------------------------- +xpack.monitoring.elasticsearch.ssl.keystore.path: /path/to/file +xpack.monitoring.elasticsearch.ssl.keystore.password: password +-------------------------------------------------- + +Set sniffing to `true` to enable discovery of other nodes of the {es} cluster. +It defaults to `false`. + +[source,yaml] +-------------------------------------------------- +xpack.monitoring.elasticsearch.sniffing: false +-------------------------------------------------- + +-- + +. Restart your Logstash nodes. + +. To verify your monitoring configuration, point your web browser at your {kib} +host, and select **Monitoring** from the side navigation. Metrics reported from +your Logstash nodes should be visible in the Logstash section. When security is +enabled, to view the monitoring dashboards you must log in to {kib} as a user +who has the `kibana_user` and `monitoring_user` roles. ++ +image::images/monitoring-ui.png["Monitoring",link="monitoring/images/monitoring-ui.png"] + +include::../settings/monitoring-settings-legacy.asciidoc[] + diff --git a/docs/static/monitoring/monitoring-internal.asciidoc b/docs/static/monitoring/monitoring-internal.asciidoc index f9eb3a8f8..dd23d16bb 100644 --- a/docs/static/monitoring/monitoring-internal.asciidoc +++ b/docs/static/monitoring/monitoring-internal.asciidoc @@ -1,36 +1,15 @@ [role="xpack"] [[monitoring-internal-collection]] -=== Collect {ls} monitoring data using internal collectors +=== Use internal collectors to send monitoring data ++++ Internal collection ++++ -Using internal collectors for {ls} {monitoring} these components: - -* <> -* <> - -These pieces live outside of the default Logstash pipeline in a dedicated monitoring -pipeline. This configuration ensures that all data and processing has a minimal -impact on ordinary Logstash processing. Existing Logstash features, such as the -<>, can be reused to -benefit from its retry policies. - -NOTE: The `elasticsearch` output that is used by {monitoring} for Logstash is -configured exclusively via settings found in `logstash.yml`. It is not -configured by using anything from the Logstash configurations that might also be -using their own separate `elasticsearch` outputs. - -The {es} cluster that is configured for use with {monitoring} for Logstash is -expected to be the production cluster. This configuration enables the production -{es} cluster to add metadata (for example, its cluster UUID) to the Logstash -monitoring data then route it to the monitoring clusters. For more information -about typical monitoring architectures, see -{ref}/how-monitoring-works.html[How monitoring works] in the {ref}[Elasticsearch Reference]. - -include::collectors.asciidoc[] -include::monitoring-output.asciidoc[] +Internal collectors send {ls} monitoring data directly to your _monitoring_ cluster. +The benefit of internal collection is that you have fewer pieces of software to +install and maintain. +<> is available as an alternative. [[configure-internal-collectors]] ==== Configure {ls} monitoring with internal collectors @@ -40,23 +19,16 @@ include::monitoring-output.asciidoc[] To monitor Logstash nodes: -. Specify where to send monitoring data. This cluster is often referred to as -the _production cluster_. For examples of typical monitoring architectures, see -{ref}/how-monitoring-works.html[How monitoring works]. -+ --- -IMPORTANT: To visualize Logstash as part of the Elastic Stack (as shown in Step -6), send metrics to your _production_ cluster. Sending metrics to a dedicated -monitoring cluster will show the Logstash metrics under the _monitoring_ cluster. +. Specify the location of the _monitoring cluster_. For examples of typical +monitoring architectures, see {ref}/how-monitoring-works.html[How monitoring +works] in the {ref}[Elasticsearch Reference]. --- - -. Verify that the `xpack.monitoring.collection.enabled` setting is `true` on the -production cluster. If that setting is `false`, the collection of monitoring data -is disabled in {es} and data is ignored from all other sources. +. Verify that the `monitoring.collection.enabled` setting is `true` on the +monitoring cluster. If that setting is `false`, the collection of monitoring data +is disabled in {es}, and data is ignored from all other sources. . Configure your Logstash nodes to send metrics by setting the -`xpack.monitoring.elasticsearch.hosts` in `logstash.yml`. If {security-features} +`monitoring.elasticsearch.hosts` in `logstash.yml`. If {security-features} are enabled, you also need to specify the credentials for the {ref}/built-in-users.html[built-in `logstash_system` user]. For more information about these settings, see <>. @@ -64,21 +36,18 @@ information about these settings, see <>. -- [source,yaml] -------------------------------------------------- -xpack.monitoring.elasticsearch.hosts: ["http://es-prod-node-1:9200", "http://es-prod-node-2:9200"] <1> -xpack.monitoring.elasticsearch.username: "logstash_system" <2> -xpack.monitoring.elasticsearch.password: "changeme" +monitoring.elasticsearch.hosts: ["http://es-prod-node-1:9200", "http://es-prod-node-2:9200"] +monitoring.elasticsearch.username: "logstash_system" +monitoring.elasticsearch.password: "changeme" -------------------------------------------------- -<1> If SSL/TLS is enabled on the production cluster, you must -connect through HTTPS. As of v5.2.1, you can specify multiple -Elasticsearch hosts as an array as well as specifying a single -host as a string. If multiple URLs are specified, Logstash -can round-robin requests to these production nodes. -<2> If {security-features} are disabled on the production cluster, you can omit -these `username` and `password` settings. +If SSL/TLS is enabled on the monitoring cluster, you must connect through HTTPS. +You can specify a single host as a string, or multiple Elasticsearch hosts as an +array. If multiple URLs are specified, Logstash can round-robin requests to +these monitoring nodes. -- -. If SSL/TLS is enabled on the production {es} cluster, specify the trusted +. If SSL/TLS is enabled on the monitoring {es} cluster, specify the trusted CA certificates that will be used to verify the identity of the nodes in the cluster. + @@ -89,7 +58,7 @@ can specify the location of the PEM encoded certificate with the [source,yaml] -------------------------------------------------- -xpack.monitoring.elasticsearch.ssl.certificate_authority: /path/to/ca.crt +monitoring.elasticsearch.ssl.certificate_authority: /path/to/ca.crt -------------------------------------------------- Alternatively, you can configure trusted certificates using a truststore @@ -97,8 +66,8 @@ Alternatively, you can configure trusted certificates using a truststore [source,yaml] -------------------------------------------------- -xpack.monitoring.elasticsearch.ssl.truststore.path: /path/to/file -xpack.monitoring.elasticsearch.ssl.truststore.password: password +monitoring.elasticsearch.ssl.truststore.path: /path/to/file +monitoring.elasticsearch.ssl.truststore.password: password -------------------------------------------------- Also, optionally, you can set up client certificate using a keystore @@ -106,8 +75,8 @@ Also, optionally, you can set up client certificate using a keystore [source,yaml] -------------------------------------------------- -xpack.monitoring.elasticsearch.ssl.keystore.path: /path/to/file -xpack.monitoring.elasticsearch.ssl.keystore.password: password +monitoring.elasticsearch.ssl.keystore.path: /path/to/file +monitoring.elasticsearch.ssl.keystore.password: password -------------------------------------------------- Set sniffing to `true` to enable discovery of other nodes of the {es} cluster. @@ -115,28 +84,46 @@ It defaults to `false`. [source,yaml] -------------------------------------------------- -xpack.monitoring.elasticsearch.sniffing: false +monitoring.elasticsearch.sniffing: false -------------------------------------------------- -- . Restart your Logstash nodes. -. To verify your {monitoring} configuration, point your web browser at your {kib} +. To verify your monitoring configuration, point your web browser at your {kib} host, and select **Monitoring** from the side navigation. Metrics reported from your Logstash nodes should be visible in the Logstash section. When security is -enabled, to view the monitoring dashboards you must log in to {kib} as a user -who has the `kibana_user` and `monitoring_user` roles. +enabled, you must log in to {kib} as a user who has the `kibana_user` and +`monitoring_user` roles. + image::images/monitoring-ui.png["Monitoring",link="monitoring/images/monitoring-ui.png"] -[float] -[[monitoring-upgraded-logstash]] -===== Re-enabling Logstash Monitoring After Upgrading - -When upgrading from older versions of {xpack}, the built-in `logstash_system` -user is disabled for security reasons. To resume monitoring, -change the password and re-enable the logstash_system user. - include::../settings/monitoring-settings.asciidoc[] + +[[internal-collector-components]] +==== How {ls} monitoring with internal collectors works + +Monitoring {ls} with internal collectors uses these components: + +* <> +* <> + +These pieces live outside of the default Logstash pipeline in a dedicated +monitoring pipeline. This configuration ensures that all data and processing has +a minimal impact on ordinary Logstash processing. Existing Logstash features, +such as the <>, can be +reused to benefit from its retry policies. + +NOTE: The `elasticsearch` output for Logstash monitoring is configured +exclusively through settings in `logstash.yml`. + +The monitoring {es} cluster should be configured to receive {ls} monitoring +data directly from {ls}. For more information about typical monitoring +architectures, see {ref}/how-monitoring-works.html[How monitoring works] in the +{ref}[Elasticsearch Reference]. + + +include::collectors.asciidoc[] +include::monitoring-output.asciidoc[] diff --git a/docs/static/monitoring/monitoring-mb.asciidoc b/docs/static/monitoring/monitoring-mb.asciidoc index ba54c04ad..dec7f6925 100644 --- a/docs/static/monitoring/monitoring-mb.asciidoc +++ b/docs/static/monitoring/monitoring-mb.asciidoc @@ -6,16 +6,19 @@ {metricbeat} collection ++++ -You can use {metricbeat} to collect data about {ls} -and ship it to the monitoring cluster, rather than routing it through the -production cluster as described in <>. +You can use {metricbeat} to collect data about {ls} and ship it to the +monitoring cluster. The benefit of Metricbeat collection is that the monitoring +agent remains active even if the {ls} instance does not. + +<> is available as an +alternative. //NOTE: The tagged regions are re-used in the Stack Overview. To collect and ship monitoring data: . <> -. <> +. <> . <> [float] @@ -29,7 +32,7 @@ commented out: [source,yaml] ---------------------------------- -xpack.monitoring.enabled: false +monitoring.enabled: false ---------------------------------- Remove the `#` at the beginning of the line to enable the setting. diff --git a/docs/static/monitoring/monitoring-output-legacy.asciidoc b/docs/static/monitoring/monitoring-output-legacy.asciidoc new file mode 100644 index 000000000..349308f62 --- /dev/null +++ b/docs/static/monitoring/monitoring-output-legacy.asciidoc @@ -0,0 +1,47 @@ +[float] +[role="xpack"] +[[logstash-monitoring-output-legacy]] +==== Output + +Like all Logstash pipelines, the purpose of the dedicated monitoring pipeline is +to send events to outputs. In the case of monitoring for Logstash, the output +is always an `elasticsearch` output. However, unlike ordinary Logstash pipelines, +the output is configured within the `logstash.yml` settings file via the +`xpack.monitoring.elasticsearch.*` settings. + +Other than its unique manner of configuration, this `elasticsearch` output +behaves like all `elasticsearch` outputs, including its ability to pause data +collection when issues exist with the output. + +IMPORTANT: It is critical that all Logstash nodes share the same setup. +Otherwise, monitoring data might be routed in different ways or to different places. + +[float] +[[logstash-monitoring-default-legacy]] +===== Default Configuration + +If a Logstash node does not explicitly define a monitoring output setting, +the following default configuration is used: + +[source,yaml] +--------------------------------------------------- +xpack.monitoring.elasticsearch.hosts: [ "http://localhost:9200" ] +--------------------------------------------------- + +All data produced by monitoring for Logstash is indexed in the monitoring +cluster by using the `.monitoring-logstash` template, which is managed by the +{ref}/es-monitoring-exporters.html[exporters] within {es}. + +If you are working with a cluster that has {security} enabled, extra steps are +necessary to properly configure Logstash. For more information, see +<>. + +IMPORTANT: When discussing security relative to the `elasticsearch` output, it +is critical to remember that all users are managed on the production cluster, +which is identified in the `xpack.monitoring.elasticsearch.hosts` setting. +This is particularly important to remember when you move from development +environments to production environments, where you often have dedicated +monitoring clusters. + +For more information about the configuration options for the output, see +<>. \ No newline at end of file diff --git a/docs/static/monitoring/monitoring-output.asciidoc b/docs/static/monitoring/monitoring-output.asciidoc index 16ba44ec9..18a226351 100644 --- a/docs/static/monitoring/monitoring-output.asciidoc +++ b/docs/static/monitoring/monitoring-output.asciidoc @@ -4,10 +4,10 @@ ==== Output Like all Logstash pipelines, the purpose of the dedicated monitoring pipeline is -to send events to outputs. In the case of {monitoring} for Logstash, the output +to send events to outputs. In the case of Logstash monitoring, the output is always an `elasticsearch` output. However, unlike ordinary Logstash pipelines, the output is configured within the `logstash.yml` settings file via the -`xpack.monitoring.elasticsearch.*` settings. +`monitoring.elasticsearch.*` settings. Other than its unique manner of configuration, this `elasticsearch` output behaves like all `elasticsearch` outputs, including its ability to pause data @@ -20,15 +20,15 @@ Otherwise, monitoring data might be routed in different ways or to different pla [[logstash-monitoring-default]] ===== Default Configuration -If a Logstash node does not explicitly define an {monitoring} output setting, +If a Logstash node does not explicitly define a monitoring output setting, the following default configuration is used: [source,yaml] --------------------------------------------------- -xpack.monitoring.elasticsearch.hosts: [ "http://localhost:9200" ] +monitoring.elasticsearch.hosts: [ "http://localhost:9200" ] --------------------------------------------------- -All data produced by {monitoring} for Logstash is indexed in the monitoring +All data produced by Logstash monitoring is indexed in the monitoring cluster by using the `.monitoring-logstash` template, which is managed by the {ref}/es-monitoring-exporters.html[exporters] within {es}. @@ -36,12 +36,11 @@ If you are working with a cluster that has {security-features} enabled, extra steps are necessary to properly configure Logstash. For more information, see <>. -IMPORTANT: When discussing security relative to the `elasticsearch` output, it -is critical to remember that all users are managed on the production cluster, -which is identified in the `xpack.monitoring.elasticsearch.hosts` setting. -This is particularly important to remember when you move from development -environments to production environments, where you often have dedicated -monitoring clusters. +IMPORTANT: When discussing security relative to the `elasticsearch` output, +remember that all users are managed on the production cluster, which is +identified in the `monitoring.elasticsearch.hosts` setting. This is particularly +important when you move from development environments to production +environments, where you often have dedicated monitoring clusters. For more information about the configuration options for the output, see <>. \ No newline at end of file diff --git a/docs/static/monitoring/monitoring-overview.asciidoc b/docs/static/monitoring/monitoring-overview.asciidoc index 1c6ff5b9b..5e6e994ee 100644 --- a/docs/static/monitoring/monitoring-overview.asciidoc +++ b/docs/static/monitoring/monitoring-overview.asciidoc @@ -1,27 +1,40 @@ [role="xpack"] [[configuring-logstash]] -== Monitoring {ls} with {xpack} +== Monitoring {ls} Use the {stack} {monitor-features} to gain insight into the health of {ls} instances running in your environment. For an introduction to monitoring your Elastic stack, see -{ref}/monitor-elasticsearch-cluster.html[Monitoring a cluster]. - +{ref}/monitor-elasticsearch-cluster.html[Monitoring a cluster] in the +{ref}[Elasticsearch Reference]. [float] [[configuring-logstash-xpack]] -=== Configuring {xpack} monitoring for {ls} +=== Configuring monitoring for {ls} Make sure monitoring is enabled on your {es} cluster. Then configure *one* of these methods to collect {ls} metrics: -* <> -* <> +* <>. Metricbeat collects +monitoring data from your {ls} instance and sends it directly to your monitoring +cluster. The benefit of Metricbeat collection is that the monitoring +agent remains active even if the {ls} instance does not. + +* <>. Internal collectors send +monitoring data directly to your monitoring cluster. The benefit of internal +collection is that you have fewer pieces of software to install and maintain. + +* <>. Legacy +internal collectors send monitoring data to your production cluster. +This is no longer a preferred approach. Use +<> or +<> instead. include::monitoring-mb.asciidoc[] include::monitoring-internal.asciidoc[] +include::monitoring-internal-legacy.asciidoc[] include::monitoring-ui.asciidoc[] include::pipeline-viewer.asciidoc[] include::troubleshooting.asciidoc[] diff --git a/docs/static/monitoring/monitoring.asciidoc b/docs/static/monitoring/monitoring.asciidoc index 6b85a7830..11c1a4c66 100644 --- a/docs/static/monitoring/monitoring.asciidoc +++ b/docs/static/monitoring/monitoring.asciidoc @@ -19,7 +19,7 @@ requiring any extra configuration. Alternatively, you can <> to send data to a monitoring cluster. -NOTE: {monitoring} is a feature under the Basic License and is therefore +NOTE: Monitoring is a feature under the Basic License and is therefore *free to use*. diff --git a/docs/static/monitoring/troubleshooting.asciidoc b/docs/static/monitoring/troubleshooting.asciidoc index d4ae09a20..aeb3f01f5 100644 --- a/docs/static/monitoring/troubleshooting.asciidoc +++ b/docs/static/monitoring/troubleshooting.asciidoc @@ -1,6 +1,6 @@ [role="xpack"] [[monitoring-troubleshooting]] -=== Troubleshooting {monitoring} in Logstash +=== Troubleshooting monitoring in Logstash ++++ Troubleshooting ++++ diff --git a/docs/static/security/logstash.asciidoc b/docs/static/security/logstash.asciidoc index e97032d22..8418774d7 100644 --- a/docs/static/security/logstash.asciidoc +++ b/docs/static/security/logstash.asciidoc @@ -217,8 +217,8 @@ Then configure the user and password in the `logstash.yml` configuration file: [source,yaml] ---------------------------------------------------------- -xpack.monitoring.elasticsearch.username: logstash_system -xpack.monitoring.elasticsearch.password: t0p.s3cr3t +monitoring.elasticsearch.username: logstash_system +monitoring.elasticsearch.password: t0p.s3cr3t ---------------------------------------------------------- If you initially installed an older version of {xpack} and then upgraded, the diff --git a/docs/static/settings/monitoring-settings-legacy.asciidoc b/docs/static/settings/monitoring-settings-legacy.asciidoc new file mode 100644 index 000000000..686c237bd --- /dev/null +++ b/docs/static/settings/monitoring-settings-legacy.asciidoc @@ -0,0 +1,106 @@ +[role="xpack"] +[[monitoring-settings-legacy]] +==== Monitoring settings for legacy internal collection +++++ +Monitoring Settings +++++ + +You can set the following `xpack.monitoring` settings in `logstash.yml` to +control how monitoring data is collected from your Logstash nodes. However, the +defaults work best in most circumstances. For more information about configuring +Logstash, see <>. + + +[[monitoring-general-settings-legacy]] +===== General monitoring settings + +`xpack.monitoring.enabled`:: + +Monitoring is disabled by default. Set to `true` to enable {xpack} monitoring. + +`xpack.monitoring.elasticsearch.hosts`:: + +The {es} instances that you want to ship your Logstash metrics to. This might be +the same {es} instance specified in the `outputs` section in your Logstash +configuration, or a different one. This is *not* the URL of your dedicated +monitoring cluster. Even if you are using a dedicated monitoring cluster, the +Logstash metrics must be routed through your production cluster. You can specify +a single host as a string, or specify multiple hosts as an array. Defaults to +`http://localhost:9200`. + +NOTE: If your Elasticsearch cluster is configured with dedicated master-eliglble +nodes, Logstash metrics should _not_ be routed to these nodes, as doing so can +create resource contention and impact the stability of the Elasticsearch +cluster. Therefore, do not include such nodes in +`xpack.monitoring.elasticsearch.hosts`. + +`xpack.monitoring.elasticsearch.username` and `xpack.monitoring.elasticsearch.password`:: + +If your {es} is protected with basic authentication, these settings provide the +username and password that the Logstash instance uses to authenticate for +shipping monitoring data. + + +[[monitoring-collection-settings-legacy]] +===== Monitoring collection settings + +`xpack.monitoring.collection.interval`:: + +Controls how often data samples are collected and shipped on the Logstash side. +Defaults to `10s`. If you modify the collection interval, set the +`xpack.monitoring.min_interval_seconds` option in `kibana.yml` to the same value. + + +[[monitoring-ssl-settings-legacy]] +===== Monitoring TLS/SSL settings + +You can configure the following Transport Layer Security (TLS) or +Secure Sockets Layer (SSL) settings. For more information, see +<>. + +`xpack.monitoring.elasticsearch.ssl.certificate_authority`:: + +Optional setting that enables you to specify a path to the `.pem` file for the +certificate authority for your {es} instance. + +`xpack.monitoring.elasticsearch.ssl.truststore.path`:: + +Optional settings that provide the paths to the Java keystore (JKS) to validate +the server’s certificate. + +`xpack.monitoring.elasticsearch.ssl.truststore.password`:: + +Optional settings that provide the password to the truststore. + +`xpack.monitoring.elasticsearch.ssl.keystore.path`:: + +Optional settings that provide the paths to the Java keystore (JKS) to validate +the client’s certificate. + +`xpack.monitoring.elasticsearch.ssl.keystore.password`:: + +Optional settings that provide the password to the keystore. + +`xpack.monitoring.elasticsearch.ssl.verification_mode`:: + +Option to validate the server’s certificate. Defaults to `certificate`. To +disable, set to `none`. Disabling this severely compromises security. + +[[monitoring-additional-settings-legacy]] +===== Additional settings + +`xpack.monitoring.elasticsearch.cloud_id`:: + +If you're using {es} in {ecloud}, you should specify the identifier here. +This setting is an alternative to `xpack.monitoring.elasticsearch.hosts`. +If `cloud_id` is configured, `xpack.monitoring.elasticsearch.hosts` should not be used. +The {es} instances that you want to ship your Logstash metrics to. This might be +the same {es} instance specified in the `outputs` section in your Logstash +configuration, or a different one. + +`xpack.monitoring.elasticsearch.cloud_auth`:: + +If you're using {es} in {ecloud}, you can set your auth credentials here. +This setting is an alternative to both `xpack.monitoring.elasticsearch.username` +and `xpack.monitoring.elasticsearch.password`. If `cloud_auth` is configured, +those settings should not be used. diff --git a/docs/static/settings/monitoring-settings.asciidoc b/docs/static/settings/monitoring-settings.asciidoc index 0574663f9..26caee9bb 100644 --- a/docs/static/settings/monitoring-settings.asciidoc +++ b/docs/static/settings/monitoring-settings.asciidoc @@ -5,7 +5,7 @@ Monitoring Settings ++++ -You can set the following `xpack.monitoring` settings in `logstash.yml` to +You can set the following `monitoring` settings in `logstash.yml` to control how monitoring data is collected from your Logstash nodes. However, the defaults work best in most circumstances. For more information about configuring Logstash, see <>. @@ -14,27 +14,25 @@ Logstash, see <>. [[monitoring-general-settings]] ===== General monitoring settings -`xpack.monitoring.enabled`:: +`monitoring.enabled`:: -Monitoring is disabled by default. Set to `true` to enable {xpack} monitoring. +Monitoring is disabled by default. Set to `true` to enable monitoring. -`xpack.monitoring.elasticsearch.hosts`:: +`monitoring.elasticsearch.hosts`:: -The {es} instances that you want to ship your Logstash metrics to. This might be -the same {es} instance specified in the `outputs` section in your Logstash -configuration, or a different one. This is *not* the URL of your dedicated -monitoring cluster. Even if you are using a dedicated monitoring cluster, the -Logstash metrics must be routed through your production cluster. You can specify -a single host as a string, or specify multiple hosts as an array. Defaults to +The {es} monitoring cluster that you want to ship your Logstash metrics to. This +might be the same {es} instance specified in the `outputs` section in your +Logstash configuration, or a dedicated monitoring cluster. You can specify a +single host as a string, or specify multiple hosts as an array. Defaults to `http://localhost:9200`. -NOTE: If your Elasticsearch cluster is configured with dedicated master-eliglble +NOTE: If your Elasticsearch cluster is configured with dedicated master-eligible nodes, Logstash metrics should _not_ be routed to these nodes, as doing so can create resource contention and impact the stability of the Elasticsearch cluster. Therefore, do not include such nodes in -`xpack.monitoring.elasticsearch.hosts`. +`monitoring.elasticsearch.hosts`. -`xpack.monitoring.elasticsearch.username` and `xpack.monitoring.elasticsearch.password`:: +`monitoring.elasticsearch.username` and `monitoring.elasticsearch.password`:: If your {es} is protected with basic authentication, these settings provide the username and password that the Logstash instance uses to authenticate for @@ -44,65 +42,80 @@ shipping monitoring data. [[monitoring-collection-settings]] ===== Monitoring collection settings -`xpack.monitoring.collection.interval`:: +`monitoring.collection.interval`:: Controls how often data samples are collected and shipped on the Logstash side. Defaults to `10s`. If you modify the collection interval, set the -`xpack.monitoring.min_interval_seconds` option in `kibana.yml` to the same value. +`monitoring.min_interval_seconds` option in `kibana.yml` to the same value. +[[monitoring-cluster-uuid]] +`monitoring.cluster_uuid`:: + +The universally unique identifier (UUID) for the monitoring cluster. +By default, {ls} identifies and uses the `cluster uuid` value from each +elasticsearch output defined in the pipelines, and ignores this +setting. ++ +If no `cluster_uuid` is discovered in elasticsearch outputs, then {ls} +uses this value to tag the data shipped to the monitoring cluster. [[monitoring-ssl-settings]] -===== {monitoring} TLS/SSL settings +===== Monitoring TLS/SSL settings You can configure the following Transport Layer Security (TLS) or Secure Sockets Layer (SSL) settings. For more information, see <>. -`xpack.monitoring.elasticsearch.ssl.certificate_authority`:: +`monitoring.elasticsearch.ssl.certificate_authority`:: Optional setting that enables you to specify a path to the `.pem` file for the certificate authority for your {es} instance. -`xpack.monitoring.elasticsearch.ssl.truststore.path`:: +`monitoring.elasticsearch.ssl.truststore.path`:: Optional settings that provide the paths to the Java keystore (JKS) to validate the server’s certificate. -`xpack.monitoring.elasticsearch.ssl.truststore.password`:: +`monitoring.elasticsearch.ssl.truststore.password`:: Optional settings that provide the password to the truststore. -`xpack.monitoring.elasticsearch.ssl.keystore.path`:: +`monitoring.elasticsearch.ssl.keystore.path`:: Optional settings that provide the paths to the Java keystore (JKS) to validate the client’s certificate. -`xpack.monitoring.elasticsearch.ssl.keystore.password`:: +`monitoring.elasticsearch.ssl.keystore.password`:: Optional settings that provide the password to the keystore. -`xpack.monitoring.elasticsearch.ssl.verification_mode`:: +`monitoring.elasticsearch.ssl.verification_mode`:: Option to validate the server’s certificate. Defaults to `certificate`. To disable, set to `none`. Disabling this severely compromises security. +`monitoring.elasticsearch.sniffing`:: + +Finds all {es} cluster nodes and adds them to the hosts list. +Defaults to `false`. + [[monitoring-additional-settings]] ===== Additional settings -`xpack.monitoring.elasticsearch.cloud_id`:: +`monitoring.elasticsearch.cloud_id`:: If you're using {es} in {ecloud}, you should specify the identifier here. -This setting is an alternative to `xpack.monitoring.elasticsearch.hosts`. -If `cloud_id` is configured, `xpack.monitoring.elasticsearch.hosts` should not be used. +This setting is an alternative to `monitoring.elasticsearch.hosts`. +If `cloud_id` is configured, `monitoring.elasticsearch.hosts` should not be used. The {es} instances that you want to ship your Logstash metrics to. This might be the same {es} instance specified in the `outputs` section in your Logstash configuration, or a different one. -`xpack.monitoring.elasticsearch.cloud_auth`:: +`monitoring.elasticsearch.cloud_auth`:: If you're using {es} in {ecloud}, you can set your auth credentials here. -This setting is an alternative to both `xpack.monitoring.elasticsearch.username` -and `xpack.monitoring.elasticsearch.password`. If `cloud_auth` is configured, +This setting is an alternative to both `monitoring.elasticsearch.username` +and `monitoring.elasticsearch.password`. If `cloud_auth` is configured, those settings should not be used. diff --git a/docs/static/upgrading.asciidoc b/docs/static/upgrading.asciidoc index c81e4b5a9..958301389 100644 --- a/docs/static/upgrading.asciidoc +++ b/docs/static/upgrading.asciidoc @@ -11,7 +11,7 @@ Before upgrading Logstash: While upgrading Logstash: -* If you use {monitoring}, you must re-use the data directory when you +* If you use monitoring, you must re-use the data directory when you upgrade Logstash. Otherwise, the Logstash node is assigned a new persistent UUID and becomes a new node in the monitoring data. =========================================== From 6eebf24d508c951cf96172eb7b1d3ef69711935c Mon Sep 17 00:00:00 2001 From: Karen Metts Date: Tue, 7 Apr 2020 20:23:47 -0400 Subject: [PATCH 0420/1126] Fix typo in pipeline ordered description Fixes #11763 --- docs/static/running-logstash-command-line.asciidoc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/static/running-logstash-command-line.asciidoc b/docs/static/running-logstash-command-line.asciidoc index 51657380a..f077be517 100644 --- a/docs/static/running-logstash-command-line.asciidoc +++ b/docs/static/running-logstash-command-line.asciidoc @@ -138,7 +138,7 @@ With this command, Logstash concatenates three config files, `/tmp/one`, `/tmp/t This setting will work only when also using a single worker for the pipeline. Note that when enabled, it may impact the performance of the filters - and ouput processing. + and output processing. The `auto` option will automatically enable ordering if the `pipeline.workers` setting is set to `1`. Use `true` to enable ordering on the pipeline and prevent logstash From 28ae8fa21f0402892c78b248d7fc6988c7ef23a1 Mon Sep 17 00:00:00 2001 From: Karen Metts Date: Tue, 14 Apr 2020 18:37:16 -0400 Subject: [PATCH 0421/1126] Add redirects page Fixes #11790 --- docs/index.asciidoc | 4 +++- docs/static/redirects.asciidoc | 5 +++++ 2 files changed, 8 insertions(+), 1 deletion(-) create mode 100644 docs/static/redirects.asciidoc diff --git a/docs/index.asciidoc b/docs/index.asciidoc index 45abb59c7..e1d36dc7b 100644 --- a/docs/index.asciidoc +++ b/docs/index.asciidoc @@ -272,6 +272,8 @@ include::static/breaking-changes.asciidoc[] // Release Notes -:edit_url: https://github.com/elastic/logstash/edit/{branch}/docs/static/releasenotes.asciidoc +:edit_url!: include::static/releasenotes.asciidoc[] +:edit_url: +include::static/redirects.asciidoc[] diff --git a/docs/static/redirects.asciidoc b/docs/static/redirects.asciidoc new file mode 100644 index 000000000..4a517acf4 --- /dev/null +++ b/docs/static/redirects.asciidoc @@ -0,0 +1,5 @@ +["appendix",role="exclude",id="redirects"] += Deleted pages + +The following pages have moved or been deleted. + From 54f5ac14f363e94509daada6d895da0d8c3d32e2 Mon Sep 17 00:00:00 2001 From: Joao Duarte Date: Wed, 15 Apr 2020 10:42:07 +0100 Subject: [PATCH 0422/1126] update guava and httpclient dependencies Fixes #11791 --- logstash-core/benchmarks/build.gradle | 2 +- logstash-core/build.gradle | 2 +- tools/benchmark-cli/build.gradle | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/logstash-core/benchmarks/build.gradle b/logstash-core/benchmarks/build.gradle index f9093f9da..71d816023 100644 --- a/logstash-core/benchmarks/build.gradle +++ b/logstash-core/benchmarks/build.gradle @@ -58,7 +58,7 @@ dependencies { implementation project(':logstash-core') implementation "org.openjdk.jmh:jmh-core:$jmh" annotationProcessor "org.openjdk.jmh:jmh-generator-annprocess:$jmh" - implementation 'com.google.guava:guava:21.0' + implementation 'com.google.guava:guava:24.1.1-jre' implementation 'commons-io:commons-io:2.5' runtimeOnly 'joda-time:joda-time:2.8.2' api "org.jruby:jruby-core:$jrubyVersion" diff --git a/logstash-core/build.gradle b/logstash-core/build.gradle index c16dda7fd..61fe4e062 100644 --- a/logstash-core/build.gradle +++ b/logstash-core/build.gradle @@ -167,7 +167,7 @@ dependencies { } else { api files(customJRubyDir + "/maven/jruby-complete/target/jruby-complete-${customJRubyVersion}.jar") } - implementation group: 'com.google.guava', name: 'guava', version: '22.0' + implementation group: 'com.google.guava', name: 'guava', version: '24.1.1-jre' // WARNING: DO NOT UPGRADE "google-java-format" // later versions require GPL licensed code in javac-shaded that is // Apache2 incompatible diff --git a/tools/benchmark-cli/build.gradle b/tools/benchmark-cli/build.gradle index e1338e425..794450d6a 100644 --- a/tools/benchmark-cli/build.gradle +++ b/tools/benchmark-cli/build.gradle @@ -50,7 +50,7 @@ ext { dependencies { implementation 'net.sf.jopt-simple:jopt-simple:5.0.3' - implementation group: 'org.apache.httpcomponents', name: 'httpclient', version: '4.5.3' + implementation group: 'org.apache.httpcomponents', name: 'httpclient', version: '4.5.12' implementation group: 'org.apache.commons', name: 'commons-compress', version: '1.20' implementation group: 'org.apache.commons', name: 'commons-lang3', version: '3.10' implementation group: 'commons-io', name: 'commons-io', version: '2.6' From 21b1ef531e39c6210866c3ba2b9023c72d1fdcf1 Mon Sep 17 00:00:00 2001 From: Joao Duarte Date: Fri, 6 Dec 2019 17:19:48 +0000 Subject: [PATCH 0423/1126] add rootProject.name Fixes #11400 --- settings.gradle | 2 ++ 1 file changed, 2 insertions(+) diff --git a/settings.gradle b/settings.gradle index e01a199ed..ef679f816 100644 --- a/settings.gradle +++ b/settings.gradle @@ -1,3 +1,5 @@ +rootProject.name = "logstash" + include ':logstash-core', 'logstash-core-benchmarks', 'ingest-converter', 'benchmark-cli', 'logstash-integration-tests', 'dependencies-report' project(':logstash-core').projectDir = new File('./logstash-core') project(':logstash-core-benchmarks').projectDir = new File('./logstash-core/benchmarks') From ee2d819d442c76c1461a7579fd548afb8c4486ac Mon Sep 17 00:00:00 2001 From: Karol Bucek Date: Thu, 16 Apr 2020 18:01:06 +0200 Subject: [PATCH 0424/1126] Fix: cloud_id not propagating from monitoring config Fixes #11800 --- x-pack/lib/license_checker/license_reader.rb | 11 +++--- .../license_checker/license_reader_spec.rb | 37 ++++++++++++++++--- 2 files changed, 37 insertions(+), 11 deletions(-) diff --git a/x-pack/lib/license_checker/license_reader.rb b/x-pack/lib/license_checker/license_reader.rb index be978ae1d..5da6aad56 100644 --- a/x-pack/lib/license_checker/license_reader.rb +++ b/x-pack/lib/license_checker/license_reader.rb @@ -4,8 +4,6 @@ require 'logstash/logging/logger' require 'logstash/outputs/elasticsearch' -require 'logstash/json' -require 'json' module LogStash module LicenseChecker @@ -17,8 +15,7 @@ module LogStash def initialize(settings, feature, options) @namespace = "xpack.#{feature}" @settings = settings - @es_options = options - @es_options.merge!("resurrect_delay" => 30) + @es_options = options.merge('resurrect_delay' => 30) end ## @@ -62,8 +59,10 @@ module LogStash # # log originate from the `ElasticsearchSource` def build_client es = LogStash::Outputs::ElasticSearch.new(@es_options) - new_logger = logger - es.instance_eval { @logger = new_logger } + es.instance_variable_set :@logger, logger + es.fill_hosts_from_cloud_id + es.fill_user_password_from_cloud_auth + es.setup_hosts es.build_client end diff --git a/x-pack/spec/license_checker/license_reader_spec.rb b/x-pack/spec/license_checker/license_reader_spec.rb index ce52189a6..fc25e1de4 100644 --- a/x-pack/spec/license_checker/license_reader_spec.rb +++ b/x-pack/spec/license_checker/license_reader_spec.rb @@ -3,15 +3,13 @@ # you may not use this file except in compliance with the Elastic License. require "spec_helper" -require "logstash/json" +require 'support/helpers' require "license_checker/license_reader" require "helpers/elasticsearch_options" require "monitoring/monitoring" -require "stud/temporary" - describe LogStash::LicenseChecker::LicenseReader do - let(:elasticsearch_url) { ["https://localhost:9898"] } + let(:elasticsearch_url) { "https://localhost:9898" } let(:elasticsearch_username) { "elastictest" } let(:elasticsearch_password) { "testchangeme" } let(:extension) { LogStash::MonitoringExtension.new } @@ -25,7 +23,7 @@ describe LogStash::LicenseChecker::LicenseReader do let(:settings) do { "xpack.monitoring.enabled" => true, - "xpack.monitoring.elasticsearch.hosts" => elasticsearch_url, + "xpack.monitoring.elasticsearch.hosts" => [ elasticsearch_url ], "xpack.monitoring.elasticsearch.username" => elasticsearch_username, "xpack.monitoring.elasticsearch.password" => elasticsearch_password, } @@ -101,4 +99,33 @@ describe LogStash::LicenseChecker::LicenseReader do end end end + + it "builds ES client" do + expect( subject.client.options[:hosts].size ).to eql 1 + expect( subject.client.options[:hosts][0].to_s ).to eql elasticsearch_url # URI#to_s + expect( subject.client.options ).to include(:user => elasticsearch_username, :password => elasticsearch_password) + end + + context 'with cloud_id' do + let(:cloud_id) do + 'westeurope-1:d2VzdGV1cm9wZS5henVyZS5lbGFzdGljLWNsb3VkLmNvbTo5MjQzJGUxZTYzMTIwMWZiNjRkNTVhNzVmNDMxZWI2MzQ5NTg5JDljYzYwMGUwMGQwYjRhMThiNmY2NmU2ZTcyMTQwODA3' + end + let(:cloud_auth) do + 'elastic:LnWMLeK3EQPTf3G3F1IBdFvO' + end + + let(:settings) do + { + "xpack.monitoring.enabled" => true, + "xpack.monitoring.elasticsearch.cloud_id" => cloud_id, + "xpack.monitoring.elasticsearch.cloud_auth" => cloud_auth + } + end + + it "builds ES client" do + expect( subject.client.options[:hosts].size ).to eql 1 + expect( subject.client.options[:hosts][0].to_s ).to eql 'https://e1e631201fb64d55a75f431eb6349589.westeurope.azure.elastic-cloud.com:9243' + expect( subject.client.options ).to include(:user => 'elastic', :password => 'LnWMLeK3EQPTf3G3F1IBdFvO') + end + end end From b67ffceb53dda1ddf69f023c2666226e98d360fa Mon Sep 17 00:00:00 2001 From: Karen Metts Date: Tue, 14 Apr 2020 16:39:27 -0400 Subject: [PATCH 0425/1126] Doc updates for internal collectors Fixes #11789 --- docs/static/monitoring/monitoring-internal.asciidoc | 6 +----- docs/static/monitoring/monitoring-output.asciidoc | 5 +++++ 2 files changed, 6 insertions(+), 5 deletions(-) diff --git a/docs/static/monitoring/monitoring-internal.asciidoc b/docs/static/monitoring/monitoring-internal.asciidoc index dd23d16bb..136b2d95c 100644 --- a/docs/static/monitoring/monitoring-internal.asciidoc +++ b/docs/static/monitoring/monitoring-internal.asciidoc @@ -96,8 +96,6 @@ host, and select **Monitoring** from the side navigation. Metrics reported from your Logstash nodes should be visible in the Logstash section. When security is enabled, you must log in to {kib} as a user who has the `kibana_user` and `monitoring_user` roles. -+ -image::images/monitoring-ui.png["Monitoring",link="monitoring/images/monitoring-ui.png"] include::../settings/monitoring-settings.asciidoc[] @@ -112,9 +110,7 @@ Monitoring {ls} with internal collectors uses these components: These pieces live outside of the default Logstash pipeline in a dedicated monitoring pipeline. This configuration ensures that all data and processing has -a minimal impact on ordinary Logstash processing. Existing Logstash features, -such as the <>, can be -reused to benefit from its retry policies. +a minimal impact on ordinary Logstash processing. NOTE: The `elasticsearch` output for Logstash monitoring is configured exclusively through settings in `logstash.yml`. diff --git a/docs/static/monitoring/monitoring-output.asciidoc b/docs/static/monitoring/monitoring-output.asciidoc index 18a226351..4c30a014a 100644 --- a/docs/static/monitoring/monitoring-output.asciidoc +++ b/docs/static/monitoring/monitoring-output.asciidoc @@ -28,6 +28,8 @@ the following default configuration is used: monitoring.elasticsearch.hosts: [ "http://localhost:9200" ] --------------------------------------------------- +//TODO: Verify the following sentence: + All data produced by Logstash monitoring is indexed in the monitoring cluster by using the `.monitoring-logstash` template, which is managed by the {ref}/es-monitoring-exporters.html[exporters] within {es}. @@ -36,6 +38,9 @@ If you are working with a cluster that has {security-features} enabled, extra steps are necessary to properly configure Logstash. For more information, see <>. + +//TODO: Verify the following sentence: + IMPORTANT: When discussing security relative to the `elasticsearch` output, remember that all users are managed on the production cluster, which is identified in the `monitoring.elasticsearch.hosts` setting. This is particularly From 7b68aee7f3dc575594ca614f516c7be88614b4f7 Mon Sep 17 00:00:00 2001 From: Karen Metts Date: Thu, 16 Apr 2020 15:08:25 -0400 Subject: [PATCH 0426/1126] Incorporate review comments Fixes #11789 --- .../monitoring/monitoring-internal.asciidoc | 7 +++++-- .../static/monitoring/monitoring-output.asciidoc | 16 +++++----------- 2 files changed, 10 insertions(+), 13 deletions(-) diff --git a/docs/static/monitoring/monitoring-internal.asciidoc b/docs/static/monitoring/monitoring-internal.asciidoc index 136b2d95c..43056c31c 100644 --- a/docs/static/monitoring/monitoring-internal.asciidoc +++ b/docs/static/monitoring/monitoring-internal.asciidoc @@ -11,6 +11,9 @@ install and maintain. <> is available as an alternative. +IMPORTANT: All Logstash nodes must share the same setup. +Otherwise, monitoring data might be routed in different ways or to different places. + [[configure-internal-collectors]] ==== Configure {ls} monitoring with internal collectors ++++ @@ -23,7 +26,7 @@ To monitor Logstash nodes: monitoring architectures, see {ref}/how-monitoring-works.html[How monitoring works] in the {ref}[Elasticsearch Reference]. -. Verify that the `monitoring.collection.enabled` setting is `true` on the +. Verify that the `xpack.monitoring.collection.enabled` setting is `true` on the monitoring cluster. If that setting is `false`, the collection of monitoring data is disabled in {es}, and data is ignored from all other sources. @@ -36,7 +39,7 @@ information about these settings, see <>. -- [source,yaml] -------------------------------------------------- -monitoring.elasticsearch.hosts: ["http://es-prod-node-1:9200", "http://es-prod-node-2:9200"] +monitoring.elasticsearch.hosts: ["http://es-monitoring-node-1:9200", "http://es-monitoring-node-2:9200"] monitoring.elasticsearch.username: "logstash_system" monitoring.elasticsearch.password: "changeme" -------------------------------------------------- diff --git a/docs/static/monitoring/monitoring-output.asciidoc b/docs/static/monitoring/monitoring-output.asciidoc index 4c30a014a..811a9faec 100644 --- a/docs/static/monitoring/monitoring-output.asciidoc +++ b/docs/static/monitoring/monitoring-output.asciidoc @@ -28,23 +28,17 @@ the following default configuration is used: monitoring.elasticsearch.hosts: [ "http://localhost:9200" ] --------------------------------------------------- -//TODO: Verify the following sentence: - All data produced by Logstash monitoring is indexed in the monitoring -cluster by using the `.monitoring-logstash` template, which is managed by the -{ref}/es-monitoring-exporters.html[exporters] within {es}. +cluster using the `.monitoring-logstash` template. If you are working with a cluster that has {security-features} enabled, extra steps are necessary to properly configure Logstash. For more information, see <>. - -//TODO: Verify the following sentence: - -IMPORTANT: When discussing security relative to the `elasticsearch` output, -remember that all users are managed on the production cluster, which is -identified in the `monitoring.elasticsearch.hosts` setting. This is particularly -important when you move from development environments to production +IMPORTANT: When discussing security relative to the `monitoring.elasticsearch` +settings, remember that all users are managed on the monitoring cluster, which +is identified in the `monitoring.elasticsearch.hosts` setting. This is +particularly important when you move from development environments to production environments, where you often have dedicated monitoring clusters. For more information about the configuration options for the output, see From da7de67ed7f380e319fb3e6d90643e423e29d3b7 Mon Sep 17 00:00:00 2001 From: Karen Metts Date: Thu, 16 Apr 2020 15:25:46 -0400 Subject: [PATCH 0427/1126] More review comments Fixes #11789 --- docs/static/settings/monitoring-settings.asciidoc | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/docs/static/settings/monitoring-settings.asciidoc b/docs/static/settings/monitoring-settings.asciidoc index 26caee9bb..5cadb14da 100644 --- a/docs/static/settings/monitoring-settings.asciidoc +++ b/docs/static/settings/monitoring-settings.asciidoc @@ -26,10 +26,10 @@ Logstash configuration, or a dedicated monitoring cluster. You can specify a single host as a string, or specify multiple hosts as an array. Defaults to `http://localhost:9200`. -NOTE: If your Elasticsearch cluster is configured with dedicated master-eligible -nodes, Logstash metrics should _not_ be routed to these nodes, as doing so can -create resource contention and impact the stability of the Elasticsearch -cluster. Therefore, do not include such nodes in +NOTE: If your Elasticsearch monitoring cluster is configured with dedicated +master-eligible nodes, Logstash metrics should _not_ be routed to these nodes. +Doing so can create resource contention and impact the stability of the +Elasticsearch cluster. Therefore, do not include such nodes in `monitoring.elasticsearch.hosts`. `monitoring.elasticsearch.username` and `monitoring.elasticsearch.password`:: From 8b223093cbd281eebedc5a7aa1eda116c5676b29 Mon Sep 17 00:00:00 2001 From: Karen Metts <35154725+karenzone@users.noreply.github.com> Date: Fri, 17 Apr 2020 16:41:35 -0400 Subject: [PATCH 0428/1126] Release Notes for 7.7 (continued) (#11762) (#11805) * [WIP] Release notes for 7.7.0 Co-Authored-By: Karen Metts <35154725+karenzone@users.noreply.github.com> Co-authored-by: Rob Bavey --- docs/static/releasenotes.asciidoc | 149 +++++++++++++++++++++++++++++- 1 file changed, 148 insertions(+), 1 deletion(-) diff --git a/docs/static/releasenotes.asciidoc b/docs/static/releasenotes.asciidoc index effd6bd70..563acd9c1 100644 --- a/docs/static/releasenotes.asciidoc +++ b/docs/static/releasenotes.asciidoc @@ -3,6 +3,7 @@ This section summarizes the changes in the following releases: +* <> * <> * <> * <> @@ -27,6 +28,152 @@ This section summarizes the changes in the following releases: * <> * <> +[[logstash-7-7-0]] +=== Logstash 7.7.0 Release Notes + +==== New features and improvements + +===== Improving Stack communication - Monitoring + +As the {stack} continues to evolve, improvements across stack components become +necessary to improve performance, internal communication or usability of our +products. {ls} is no different, as we continuously strive to improve its +interaction with the rest of the stack. As such, this release brings +improvements to how Logstash sends monitoring data (from its Internal +Collection) to {es}. + +Previous versions of {es} received monitoring data in a Production cluster to +then forward it (internally) to the dedicated Monitoring cluster. Newer versions +improved the process by allowing the data to be sent directly to the Monitoring +cluster instead, in a different data format. Following those changes, Logstash +has now added support to send the monitoring data directly to the Monitoring +cluster, with the caveat that the Production cluster only has to retrieve the +`cluster_uuid`. +https://github.com/elastic/logstash/pull/11106[#11106], +https://github.com/elastic/logstash/pull/11640[#11640], +https://github.com/elastic/logstash/pull/11641[#11641] + +Migrating from legacy internal collection to new +<> is straightforward. + +** Drop the `xpack.` prefix from your configuration settings. +For example, `xpack.monitoring.enabled` is now `monitoring.enabled`. See +<> for the full list. +** Change the hosts settings and configuration options to point to monitoring +cluster instead of production. +** If you don’t have an Elasticsearch output plugin configured in the pipelines, +add the setting monitoring.cluster_uuid to your logstash.yml. + +See <> for more information +about this and other monitoring options. + + +===== Improving Logging + +Continuing with the Logging improvements made in the past couple of releases, +log messages have been expanded to more accurately display information about +plugins. These changes allow users to better identify log messages with plugins +or pipelines. +https://github.com/elastic/logstash/pull/11078[#11078], +https://github.com/elastic/logstash/pull/11593[#11593], +https://github.com/elastic/logstash/pull/11567[#11567] + +Changes include: + +* Added `plugin.name` to all log entries. +* Added `plugin.id` and `pipeline.id` to docker images. + +===== Improving the Java (Pipeline) Execution Engine + +The improvements available in {ls} 7.7 give users more control over event +ordering for single worker pipelines. + +Historically, Logstash event ordering between an input plugin and output plugin +were preserved when a single worker executed a pipeline. This behaviour was +never officially documented, but it was a feature that many users relied upon. + +When the Java Execution engine was introduced, it broke the single worker +ordering preservation. This has now been fixed with the introduction of the +`pipeline.ordered` setting. +https://github.com/elastic/logstash/pull/11552[#11552], +https://github.com/elastic/logstash/pull/11710[#11710] + +The `pipeline.ordered` setting allows three modes: + +* `auto (default)` - to automatically enable ordering if there’s only one pipeline +worker. +* `true` - enforces ordering while preventing logstash from starting if there are +multiple workers. +* `false` - ordering will not be guaranteed. + +==== Notable issues fixed + +* Fixed: Add `sudo` into the rpm import of GPG-KEY +https://github.com/elastic/logstash/pull/11684[#11684] + +* Fixed: Use lightweight regex matching (which does not depend on frames) +https://github.com/elastic/logstash/pull/11653[#11653] + +* Fixed: Issue where monitoring API does not properly resolve ids including +environment variable expansion +https://github.com/elastic/logstash/pull/11592[#11592] + +* Fixed: Change Javadoc to conform to updated requirements for JDK13 +https://github.com/elastic/logstash/pull/11642[#11642] + +==== Logstash Plugin changes + +*Grok Filter* + +* Feature: Added support for placing matches into a target namespace +https://github.com/logstash-plugins/logstash-filter-grok/pull/156[#156] + +*Xml Filter* + +* Feature: Added parser_options to allow for more control of the parsing process. +Includes the option of `strict` parsing to force the XML parser to fail early +when parsing invalid XML. +https://github.com/logstash-plugins/logstash-filter-xml/pull/68[#68] + +*Azure_event_hubs Input* + +* Fixed: Now honors `max_batch_size` setting - previously this was ignored +https://github.com/logstash-plugins/logstash-input-azure_event_hubs/pull/52[#52] +* Changed: The default number of threads is now `16` instead of `4`to match the +default number from the Azure-Sdk EventProcessorHost +https://github.com/logstash-plugins/logstash-input-azure_event_hubs/pull/54[#54] +* Refactor: scope and review global java_imports +https://github.com/logstash-plugins/logstash-input-azure_event_hubs/pull/57[#57] +* [DOC] Changed documentation to update the default number of threads +https://github.com/logstash-plugins/logstash-input-azure_event_hubs/pull/55[#55] +* [DOC] Added clarification for threads parameter +https://github.com/logstash-plugins/logstash-input-azure_event_hubs/pull/50[#50] + +*Elasticsearch Input* + +* Feature: Added option to specify proxy for Elasticsearch +https://github.com/logstash-plugins/logstash-input-elasticsearch/pull/114[#114] + +*S3 Input* + +* Feature: Added support for including objects restored from Glacier or Glacier +Deep https://github.com/logstash-plugins/logstash-input-s3/issues/199[#199] +* Feature: `gzip_pattern` option, enabling more flexible determination of whether +a file is gzipped +https://github.com/logstash-plugins/logstash-input-s3/issues/165[#165] +* Refactor: log exception: class + unify logging messages a bit +https://github.com/logstash-plugins/logstash-input-s3/pull/201[#201] + +*S3 Output* + +* Feature: Added retry_count and retry_delay config. This allows opting out from +infinite upload retries under error conditions. +https://github.com/logstash-plugins/logstash-output-s3/pull/218[#218] + +* [DOC] Updated setting descriptions for clarity +https://github.com/logstash-plugins/logstash-output-s3/pull/219[#219] and +https://github.com/logstash-plugins/logstash-output-s3/pull/220[#220] + [[logstash-7-6-2]] === Logstash 7.6.2 Release Notes @@ -1174,4 +1321,4 @@ Here are the plugin changes. - Tweaked logging statements to reduce verbosity - Fixed numerous issues relating to builds on Travis https://github.com/logstash-plugins/logstash-output-elasticsearch/pull/799[#799] * logstash-output-s3 - - Fixed issue where on restart, 0 byte files could erroneously be uploaded to s3 https://github.com/logstash-plugins/logstash-output-s3/issues/195[#195] \ No newline at end of file + - Fixed issue where on restart, 0 byte files could erroneously be uploaded to s3 https://github.com/logstash-plugins/logstash-output-s3/issues/195[#195] From 33efbf38718a9392151d0bee1f416f507d1539a5 Mon Sep 17 00:00:00 2001 From: Rob Bavey Date: Fri, 17 Apr 2020 16:23:02 -0400 Subject: [PATCH 0429/1126] Update kafka version for integration tests. Fixes #11806 --- qa/integration/services/kafka_setup.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/qa/integration/services/kafka_setup.sh b/qa/integration/services/kafka_setup.sh index 7369ab309..4331599c6 100755 --- a/qa/integration/services/kafka_setup.sh +++ b/qa/integration/services/kafka_setup.sh @@ -10,7 +10,7 @@ if [ -n "${KAFKA_VERSION+1}" ]; then echo "KAFKA_VERSION is $KAFKA_VERSION" version=$KAFKA_VERSION else - version=2.1.1 + version=2.4.1 fi KAFKA_HOME=$INSTALL_DIR/kafka From 59e4ac8b86df734504482c603617ee2f67366188 Mon Sep 17 00:00:00 2001 From: Laurent Huet Date: Wed, 8 Apr 2020 16:54:18 +0200 Subject: [PATCH 0430/1126] add proxy support (central management & monitoring) Fixes #11799 --- .../settings/configuration-management-settings.asciidoc | 5 +++++ docs/static/settings/monitoring-settings.asciidoc | 4 ++++ x-pack/lib/config_management/extension.rb | 1 + x-pack/lib/helpers/elasticsearch_options.rb | 7 ++++++- x-pack/lib/monitoring/monitoring.rb | 8 +++++++- x-pack/lib/template.cfg.erb | 3 +++ 6 files changed, 26 insertions(+), 2 deletions(-) diff --git a/docs/static/settings/configuration-management-settings.asciidoc b/docs/static/settings/configuration-management-settings.asciidoc index 1190cb643..f48953c59 100644 --- a/docs/static/settings/configuration-management-settings.asciidoc +++ b/docs/static/settings/configuration-management-settings.asciidoc @@ -56,6 +56,11 @@ authenticate for accessing the configuration data. The username you specify here should have the `logstash_admin` role, which provides access to `.logstash-*` indices for managing configurations. +`xpack.management.elasticsearch.proxy`:: + +Optional setting that allows you to specify a proxy URL if Logstash needs to use a proxy +to reach your Elasticsearch cluster. + `xpack.management.elasticsearch.ssl.certificate_authority`:: Optional setting that enables you to specify a path to the `.pem` file for the diff --git a/docs/static/settings/monitoring-settings.asciidoc b/docs/static/settings/monitoring-settings.asciidoc index 5cadb14da..255d14df3 100644 --- a/docs/static/settings/monitoring-settings.asciidoc +++ b/docs/static/settings/monitoring-settings.asciidoc @@ -38,6 +38,10 @@ If your {es} is protected with basic authentication, these settings provide the username and password that the Logstash instance uses to authenticate for shipping monitoring data. +`monitoring.elasticsearch.proxy`:: + +Optional setting that allows you to specify a proxy URL if Logstash needs to use a proxy +to reach your Elasticsearch cluster. [[monitoring-collection-settings]] ===== Monitoring collection settings diff --git a/x-pack/lib/config_management/extension.rb b/x-pack/lib/config_management/extension.rb index 34a745cbd..9c694efcb 100644 --- a/x-pack/lib/config_management/extension.rb +++ b/x-pack/lib/config_management/extension.rb @@ -29,6 +29,7 @@ module LogStash settings.register(LogStash::Setting::ArrayCoercible.new("xpack.management.elasticsearch.hosts", String, [ "https://localhost:9200" ] )) settings.register(LogStash::Setting::NullableString.new("xpack.management.elasticsearch.cloud_id")) settings.register(LogStash::Setting::NullableString.new("xpack.management.elasticsearch.cloud_auth")) + settings.register(LogStash::Setting::NullableString.new("xpack.management.elasticsearch.proxy")) settings.register(LogStash::Setting::NullableString.new("xpack.management.elasticsearch.ssl.certificate_authority")) settings.register(LogStash::Setting::NullableString.new("xpack.management.elasticsearch.ssl.truststore.path")) settings.register(LogStash::Setting::NullableString.new("xpack.management.elasticsearch.ssl.truststore.password")) diff --git a/x-pack/lib/helpers/elasticsearch_options.rb b/x-pack/lib/helpers/elasticsearch_options.rb index b24b575e5..f5d5b9ee9 100644 --- a/x-pack/lib/helpers/elasticsearch_options.rb +++ b/x-pack/lib/helpers/elasticsearch_options.rb @@ -15,6 +15,7 @@ module LogStash module Helpers password cloud_id cloud_auth + proxy ) # Retrieve elasticsearch options from either specific settings, or modules if the setting is not there and the @@ -47,6 +48,10 @@ module LogStash module Helpers opts['user'] = settings.get("#{prefix}#{feature}.elasticsearch.username") opts['password'] = settings.get("#{prefix}#{feature}.elasticsearch.password") end + if proxysetting = settings.get("#{prefix}#{feature}.elasticsearch.proxy") + opts['proxy'] = proxysetting + end + opts['sniffing'] = settings.get("#{prefix}#{feature}.elasticsearch.sniffing") opts['ssl_certificate_verification'] = settings.get("#{prefix}#{feature}.elasticsearch.ssl.verification_mode") == 'certificate' @@ -157,4 +162,4 @@ module LogStash module Helpers "specified, please only use one of those.") end - end end end \ No newline at end of file + end end end diff --git a/x-pack/lib/monitoring/monitoring.rb b/x-pack/lib/monitoring/monitoring.rb index e9b9de997..a48cf3571 100644 --- a/x-pack/lib/monitoring/monitoring.rb +++ b/x-pack/lib/monitoring/monitoring.rb @@ -32,6 +32,7 @@ module LogStash @password = es_settings['password'] @cloud_id = es_settings['cloud_id'] @cloud_auth = es_settings['cloud_auth'] + @proxy = es_settings['proxy'] @ca_path = es_settings['cacert'] @truststore_path = es_settings['truststore'] @truststore_password = es_settings['truststore_password'] @@ -41,7 +42,7 @@ module LogStash @ssl_certificate_verification = (es_settings['verification_mode'] == 'certificate') end - attr_accessor :system_api_version, :es_hosts, :user, :password, :node_uuid, :cloud_id, :cloud_auth + attr_accessor :system_api_version, :es_hosts, :user, :password, :node_uuid, :cloud_id, :cloud_auth, :proxy attr_accessor :ca_path, :truststore_path, :truststore_password attr_accessor :keystore_path, :keystore_password, :sniffing, :ssl_certificate_verification @@ -61,6 +62,10 @@ module LogStash !!cloud_auth && cloud_id? end + def proxy? + proxy + end + def auth? user && password end @@ -254,6 +259,7 @@ module LogStash settings.register(LogStash::Setting::TimeValue.new("#{prefix}monitoring.collection.timeout_interval", "10m")) settings.register(LogStash::Setting::NullableString.new("#{prefix}monitoring.elasticsearch.username", "logstash_system")) settings.register(LogStash::Setting::NullableString.new("#{prefix}monitoring.elasticsearch.password")) + settings.register(LogStash::Setting::NullableString.new("#{prefix}monitoring.elasticsearch.proxy")) settings.register(LogStash::Setting::NullableString.new("#{prefix}monitoring.elasticsearch.cloud_id")) settings.register(LogStash::Setting::NullableString.new("#{prefix}monitoring.elasticsearch.cloud_auth")) settings.register(LogStash::Setting::NullableString.new("#{prefix}monitoring.elasticsearch.ssl.certificate_authority")) diff --git a/x-pack/lib/template.cfg.erb b/x-pack/lib/template.cfg.erb index 5bebfa0aa..af7c50a22 100644 --- a/x-pack/lib/template.cfg.erb +++ b/x-pack/lib/template.cfg.erb @@ -25,6 +25,9 @@ output { document_type => "%{[@metadata][document_type]}" index => "<%= monitoring_index %>" sniffing => <%= sniffing %> + <% if proxy? %> + proxy => "<%= proxy %>" + <% end %> <% if auth? && !cloud_auth? %> user => "<%= user %>" password => "<%= password %>" From e06d2195d028d8e0ade5fda50c4065568d4dd8ab Mon Sep 17 00:00:00 2001 From: Ry Biesemeyer Date: Thu, 16 Apr 2020 17:02:21 +0000 Subject: [PATCH 0431/1126] settings: deprecate unit-less TimeValue values We have "required" units for a variety of `TimeValue` settings when they are provided as a `String`, but unquoted values in YAML have been passed through as Integers, where we long assumed nanosecond units. This frequently leads to surprise (e.g., when `config.reload.interval` is set to `60`, we consume 100% of CPU in a tight loop trying to reload and re-parse the configs every 60 nanoseconds). By making the setting retain the TimeValue object for the entirety of its lifecycle, we can issue a deprecation notice the first time an Integer value is encountered. As a secondary benefit, our usage of the setting value in code becomes more clear since we are empowered to ask `TimeValue` for a numeric value in a specific scale. Fixes #11803 --- logstash-core/lib/logstash/agent.rb | 2 +- logstash-core/lib/logstash/java_pipeline.rb | 2 +- logstash-core/lib/logstash/plugin.rb | 8 ++++---- logstash-core/lib/logstash/settings.rb | 15 ++++++++++++--- logstash-core/lib/logstash/util/time_value.rb | 13 +++++++++---- .../spec/logstash/agent/converge_spec.rb | 2 +- .../spec/logstash/settings/time_value_spec.rb | 15 ++++++++++++--- x-pack/lib/monitoring/monitoring.rb | 4 ++-- .../config_management/bootstrap_check_spec.rb | 2 +- x-pack/spec/config_management/extension_spec.rb | 2 +- 10 files changed, 44 insertions(+), 21 deletions(-) diff --git a/logstash-core/lib/logstash/agent.rb b/logstash-core/lib/logstash/agent.rb index f0eb7123d..99f956d0d 100644 --- a/logstash-core/lib/logstash/agent.rb +++ b/logstash-core/lib/logstash/agent.rb @@ -83,7 +83,7 @@ class LogStash::Agent end # Normalize time interval to seconds - @reload_interval = setting("config.reload.interval") / 1_000_000_000.0 + @reload_interval = setting("config.reload.interval").to_seconds @collect_metric = setting("metric.collect") diff --git a/logstash-core/lib/logstash/java_pipeline.rb b/logstash-core/lib/logstash/java_pipeline.rb index 67733058e..0917693d0 100644 --- a/logstash-core/lib/logstash/java_pipeline.rb +++ b/logstash-core/lib/logstash/java_pipeline.rb @@ -239,7 +239,7 @@ module LogStash; class JavaPipeline < JavaBasePipeline config_metric.gauge(:batch_size, batch_size) config_metric.gauge(:batch_delay, batch_delay) config_metric.gauge(:config_reload_automatic, settings.get("config.reload.automatic")) - config_metric.gauge(:config_reload_interval, settings.get("config.reload.interval")) + config_metric.gauge(:config_reload_interval, settings.get("config.reload.interval").to_nanos) config_metric.gauge(:dead_letter_queue_enabled, dlq_enabled?) config_metric.gauge(:dead_letter_queue_path, dlq_writer.get_path.to_absolute_path.to_s) if dlq_enabled? config_metric.gauge(:ephemeral_id, ephemeral_id) diff --git a/logstash-core/lib/logstash/plugin.rb b/logstash-core/lib/logstash/plugin.rb index 2e45b66d9..b376bd7d7 100644 --- a/logstash-core/lib/logstash/plugin.rb +++ b/logstash-core/lib/logstash/plugin.rb @@ -65,10 +65,10 @@ class LogStash::Plugin @deprecation_logger = self.deprecation_logger # need to access settings statically because plugins are initialized in config_ast with no context. settings = LogStash::SETTINGS - @slow_logger = self.slow_logger(settings.get("slowlog.threshold.warn"), - settings.get("slowlog.threshold.info"), - settings.get("slowlog.threshold.debug"), - settings.get("slowlog.threshold.trace")) + @slow_logger = self.slow_logger(settings.get("slowlog.threshold.warn").to_nanos, + settings.get("slowlog.threshold.info").to_nanos, + settings.get("slowlog.threshold.debug").to_nanos, + settings.get("slowlog.threshold.trace").to_nanos) @params = LogStash::Util.deep_clone(params) # The id should always be defined normally, but in tests that might not be the case # In the future we may make this more strict in the Plugin API diff --git a/logstash-core/lib/logstash/settings.rb b/logstash-core/lib/logstash/settings.rb index 7994b058a..5f648c1e1 100644 --- a/logstash-core/lib/logstash/settings.rb +++ b/logstash-core/lib/logstash/settings.rb @@ -588,13 +588,22 @@ module LogStash end class TimeValue < Coercible + include LogStash::Util::Loggable + def initialize(name, default, strict=true, &validator_proc) - super(name, ::Integer, default, strict, &validator_proc) + super(name, Util::TimeValue, default, strict, &validator_proc) end def coerce(value) - return value if value.is_a?(::Integer) - Util::TimeValue.from_value(value).to_nanos + if value.is_a?(::Integer) + deprecation_logger.deprecated("Integer value for `#{name}` does not have a time unit and will be interpreted in nanoseconds. " + + "Time units will be required in a future release of Logstash. " + + "Acceptable unit suffixes are: `d`, `h`, `m`, `s`, `ms`, `micros`, and `nanos`.") + + return Util::TimeValue.new(value, :nanosecond) + end + + Util::TimeValue.from_value(value) end end diff --git a/logstash-core/lib/logstash/util/time_value.rb b/logstash-core/lib/logstash/util/time_value.rb index f1291f232..b2814d22f 100644 --- a/logstash-core/lib/logstash/util/time_value.rb +++ b/logstash-core/lib/logstash/util/time_value.rb @@ -24,9 +24,10 @@ module LogStash end def self.from_value(value) - if value.is_a?(TimeValue) - TimeValue.new(value.duration, value.time_unit) - elsif value.is_a?(::String) + case value + when TimeValue + return value # immutable + when ::String normalized = value.downcase.strip if normalized.end_with?("nanos") TimeValue.new(parse(normalized, 5), :nanosecond) @@ -71,8 +72,12 @@ module LogStash end end + def to_seconds + self.to_nanos / 1_000_000_000.0 + end + def ==(other) - self.duration == other.duration and self.time_unit == other.time_unit + (self.duration == other.duration && self.time_unit == other.time_unit) || self.to_nanos == other.to_nanos end def self.parse(value, suffix) diff --git a/logstash-core/spec/logstash/agent/converge_spec.rb b/logstash-core/spec/logstash/agent/converge_spec.rb index 85d4f264b..84d536100 100644 --- a/logstash-core/spec/logstash/agent/converge_spec.rb +++ b/logstash-core/spec/logstash/agent/converge_spec.rb @@ -191,7 +191,7 @@ describe LogStash::Agent do end it "it will keep trying to converge" do - sleep(agent_settings.get("config.reload.interval") / 1_000_000_000.0 * 20) # let the interval reload a few times + sleep(agent_settings.get("config.reload.interval").to_seconds * 20) # let the interval reload a few times expect(subject.pipelines_count).to eq(0) expect(source_loader.fetch_count).to be > 1 end diff --git a/logstash-core/spec/logstash/settings/time_value_spec.rb b/logstash-core/spec/logstash/settings/time_value_spec.rb index e71ca7b66..526a6812f 100644 --- a/logstash-core/spec/logstash/settings/time_value_spec.rb +++ b/logstash-core/spec/logstash/settings/time_value_spec.rb @@ -22,7 +22,8 @@ describe LogStash::Setting::TimeValue do subject { described_class.new("option", "-1") } describe "#set" do it "should coerce the default correctly" do - expect(subject.value).to eq(LogStash::Util::TimeValue.new(-1, :nanosecond).to_nanos) + expect(subject.value).to eq(LogStash::Util::TimeValue.new(-1, :nanosecond)) + expect(subject.value.to_nanos).to eq(-1) end context "when a value is given outside of possible_values" do @@ -33,14 +34,22 @@ describe LogStash::Setting::TimeValue do context "when a value is given as a time value" do it "should set the value" do subject.set("18m") - expect(subject.value).to eq(LogStash::Util::TimeValue.new(18, :minute).to_nanos) + expect(subject.value).to eq(LogStash::Util::TimeValue.new(18, :minute)) + expect(subject.value.to_nanos).to eq(18 * 60 * 1_000_000_000) end end context "when a value is given as a nanosecond" do + let(:deprecation_logger_stub) { double("DeprecationLogger").as_null_object } + before(:each) do + allow(subject).to receive(:deprecation_logger).and_return(deprecation_logger_stub) + end it "should set the value" do subject.set(5) - expect(subject.value).to eq(LogStash::Util::TimeValue.new(5, :nanosecond).to_nanos) + expect(subject.value).to eq(LogStash::Util::TimeValue.new(5, :nanosecond)) + expect(subject.value.to_nanos).to eq(5) + + expect(deprecation_logger_stub).to have_received(:deprecated).with(/units will be required/).once end end end diff --git a/x-pack/lib/monitoring/monitoring.rb b/x-pack/lib/monitoring/monitoring.rb index a48cf3571..dd836344a 100644 --- a/x-pack/lib/monitoring/monitoring.rb +++ b/x-pack/lib/monitoring/monitoring.rb @@ -207,8 +207,8 @@ module LogStash private def retrieve_collection_settings(settings, prefix="") opt = {} - opt[:collection_interval] = settings.get("#{prefix}monitoring.collection.interval") - opt[:collection_timeout_interval] = settings.get("#{prefix}monitoring.collection.timeout_interval") + opt[:collection_interval] = settings.get("#{prefix}monitoring.collection.interval").to_nanos + opt[:collection_timeout_interval] = settings.get("#{prefix}monitoring.collection.timeout_interval").to_nanos opt[:extended_performance_collection] = settings.get("#{prefix}monitoring.collection.pipeline.details.enabled") opt[:config_collection] = settings.get("#{prefix}monitoring.collection.config.enabled") opt diff --git a/x-pack/spec/config_management/bootstrap_check_spec.rb b/x-pack/spec/config_management/bootstrap_check_spec.rb index 77d4f7586..fdfc34513 100644 --- a/x-pack/spec/config_management/bootstrap_check_spec.rb +++ b/x-pack/spec/config_management/bootstrap_check_spec.rb @@ -40,7 +40,7 @@ describe LogStash::ConfigManagement::BootstrapCheck do it "sets the `config.reload.interval`" do expect { subject.check(settings) } - .to change { settings.get_value("config.reload.interval") }.to(interval * 1_000_000_000) + .to change { settings.get_value("config.reload.interval").to_nanos }.to(interval * 1_000_000_000) end diff --git a/x-pack/spec/config_management/extension_spec.rb b/x-pack/spec/config_management/extension_spec.rb index f48731ef2..2ef464677 100644 --- a/x-pack/spec/config_management/extension_spec.rb +++ b/x-pack/spec/config_management/extension_spec.rb @@ -29,7 +29,7 @@ describe LogStash::ConfigManagement::Extension do describe "#additionals_settings" do define_settings( "xpack.management.enabled" => [LogStash::Setting::Boolean, false], - "xpack.management.logstash.poll_interval" => [LogStash::Setting::TimeValue, 5000000000], + "xpack.management.logstash.poll_interval" => [LogStash::Setting::TimeValue, LogStash::Util::TimeValue.from_value("5s")], "xpack.management.pipeline.id" => [LogStash::Setting::ArrayCoercible, ["main"]], "xpack.management.elasticsearch.hosts" => [LogStash::Setting::ArrayCoercible, ["https://localhost:9200"]], "xpack.management.elasticsearch.username" => [LogStash::Setting::String, "logstash_system"], From ba89b217e5c784711fab7c7eb0cd3d04529520ae Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Andr=C3=A9=20Letterer?= Date: Sun, 5 Apr 2020 00:11:21 +0200 Subject: [PATCH 0432/1126] tools convert to batch files (#11753) Fixes #11754 --- bin/benchmark.bat | 11 +++++++++++ bin/ingest-convert.bat | 10 ++++++++++ bin/pqcheck.bat | 29 +++++++++++++++++++++++++++++ bin/pqrepair.bat | 29 +++++++++++++++++++++++++++++ 4 files changed, 79 insertions(+) create mode 100644 bin/benchmark.bat create mode 100644 bin/ingest-convert.bat create mode 100644 bin/pqcheck.bat create mode 100644 bin/pqrepair.bat diff --git a/bin/benchmark.bat b/bin/benchmark.bat new file mode 100644 index 000000000..6351d9fc6 --- /dev/null +++ b/bin/benchmark.bat @@ -0,0 +1,11 @@ +rem @echo off +setlocal enabledelayedexpansion + +cd /d "%~dp0.." +for /f %%i in ('cd') do set RESULT=%%i +echo !!RESULT!! + +java -cp "!!RESULT!!\tools\benchmark-cli\build\libs\benchmark-cli.jar;*" ^ + org.logstash.benchmark.cli.Main %* + +endlocal diff --git a/bin/ingest-convert.bat b/bin/ingest-convert.bat new file mode 100644 index 000000000..b11eba743 --- /dev/null +++ b/bin/ingest-convert.bat @@ -0,0 +1,10 @@ +@echo off +setlocal enabledelayedexpansion + +cd /d "%~dp0\.." +for /f %%i in ('cd') do set RESULT=%%i + +java -cp "!!RESULT!!\tools\ingest-converter\build\libs\ingest-converter.jar;*" ^ + org.logstash.ingest.Pipeline %* + +endlocal diff --git a/bin/pqcheck.bat b/bin/pqcheck.bat new file mode 100644 index 000000000..8fcfab09a --- /dev/null +++ b/bin/pqcheck.bat @@ -0,0 +1,29 @@ +@echo off +setlocal enabledelayedexpansion + +call "%~dp0setup.bat" || exit /b 1 +if errorlevel 1 ( + if not defined nopauseonerror ( + pause + ) + exit /B %ERRORLEVEL% +) + + +set JAVA_OPTS=%LS_JAVA_OPTS% + +for %%i in ("%LS_HOME%\logstash-core\lib\jars\*.jar") do ( + call :concat "%%i" +) + +%JAVA% %JAVA_OPTS% -cp "%CLASSPATH%" org.logstash.ackedqueue.PqCheck %* + +:concat +IF not defined CLASSPATH ( + set CLASSPATH="%~1" +) ELSE ( + set CLASSPATH=%CLASSPATH%;"%~1" +) +goto :eof + +endlocal \ No newline at end of file diff --git a/bin/pqrepair.bat b/bin/pqrepair.bat new file mode 100644 index 000000000..23a15acfb --- /dev/null +++ b/bin/pqrepair.bat @@ -0,0 +1,29 @@ +@echo off +setlocal enabledelayedexpansion + +call "%~dp0setup.bat" || exit /b 1 +if errorlevel 1 ( + if not defined nopauseonerror ( + pause + ) + exit /B %ERRORLEVEL% +) + + +set JAVA_OPTS=%LS_JAVA_OPTS% + +for %%i in ("%LS_HOME%\logstash-core\lib\jars\*.jar") do ( + call :concat "%%i" +) + +%JAVA% %JAVA_OPTS% -cp "%CLASSPATH%" org.logstash.ackedqueue.PqRepair %* + +:concat +IF not defined CLASSPATH ( + set CLASSPATH="%~1" +) ELSE ( + set CLASSPATH=%CLASSPATH%;"%~1" +) +goto :eof + +endlocal \ No newline at end of file From 6bbf54ab43204ade182e954a56b69cebabd84d8e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Andr=C3=A9=20Letterer?= <48132449+111andre111@users.noreply.github.com> Date: Thu, 16 Apr 2020 00:27:19 +0200 Subject: [PATCH 0433/1126] Update benchmark.bat Fixes #11754 --- bin/benchmark.bat | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/bin/benchmark.bat b/bin/benchmark.bat index 6351d9fc6..eb164b3bf 100644 --- a/bin/benchmark.bat +++ b/bin/benchmark.bat @@ -1,4 +1,4 @@ -rem @echo off +@echo off setlocal enabledelayedexpansion cd /d "%~dp0.." From 9198afd3683396daf1e64c09e7bc99bb25ca3e86 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Andr=C3=A9=20Letterer?= <48132449+111andre111@users.noreply.github.com> Date: Sat, 18 Apr 2020 14:31:49 +0200 Subject: [PATCH 0434/1126] Update pqcheck.bat Fixes #11754 --- bin/pqcheck.bat | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/bin/pqcheck.bat b/bin/pqcheck.bat index 8fcfab09a..9a67952fa 100644 --- a/bin/pqcheck.bat +++ b/bin/pqcheck.bat @@ -26,4 +26,4 @@ IF not defined CLASSPATH ( ) goto :eof -endlocal \ No newline at end of file +endlocal From 5a0e10b2a846ef2bc608e26211ef193d0d6c6d91 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Andr=C3=A9=20Letterer?= <48132449+111andre111@users.noreply.github.com> Date: Sat, 18 Apr 2020 14:32:15 +0200 Subject: [PATCH 0435/1126] Update pqrepair.bat Fixes #11754 --- bin/pqrepair.bat | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/bin/pqrepair.bat b/bin/pqrepair.bat index 23a15acfb..53818ebe9 100644 --- a/bin/pqrepair.bat +++ b/bin/pqrepair.bat @@ -26,4 +26,4 @@ IF not defined CLASSPATH ( ) goto :eof -endlocal \ No newline at end of file +endlocal From 3962b05acae3c03554fa042a3a1b2aee22795b25 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Andr=C3=A9=20Letterer?= <48132449+111andre111@users.noreply.github.com> Date: Mon, 20 Apr 2020 16:45:54 +0200 Subject: [PATCH 0436/1126] Update benchmark.bat Fixes #11754 --- bin/benchmark.bat | 1 - 1 file changed, 1 deletion(-) diff --git a/bin/benchmark.bat b/bin/benchmark.bat index eb164b3bf..249317ae1 100644 --- a/bin/benchmark.bat +++ b/bin/benchmark.bat @@ -3,7 +3,6 @@ setlocal enabledelayedexpansion cd /d "%~dp0.." for /f %%i in ('cd') do set RESULT=%%i -echo !!RESULT!! java -cp "!!RESULT!!\tools\benchmark-cli\build\libs\benchmark-cli.jar;*" ^ org.logstash.benchmark.cli.Main %* From c0db7f43506f65aa7e3af88b72e9c1b7c6f7d09c Mon Sep 17 00:00:00 2001 From: Joao Duarte Date: Mon, 20 Apr 2020 15:38:07 +0100 Subject: [PATCH 0437/1126] dont use qualifier or snapshot in logstash core version Fixes #11813 --- .../lib/logstash-core-plugin-api/version.rb | 3 +-- logstash-core/lib/logstash-core/version.rb | 3 +-- 2 files changed, 2 insertions(+), 4 deletions(-) diff --git a/logstash-core-plugin-api/lib/logstash-core-plugin-api/version.rb b/logstash-core-plugin-api/lib/logstash-core-plugin-api/version.rb index c21b973fd..678377460 100644 --- a/logstash-core-plugin-api/lib/logstash-core-plugin-api/version.rb +++ b/logstash-core-plugin-api/lib/logstash-core-plugin-api/version.rb @@ -28,6 +28,5 @@ unless defined?(LOGSTASH_CORE_PLUGIN_API) end unless defined?(LOGSTASH_CORE_VERSION) - # PACKAGE_SUFFIX is declared in the artifact namespace from artifacts.rake - LOGSTASH_CORE_VERSION = defined?(PACKAGE_SUFFIX) ? "#{ALL_VERSIONS.fetch("logstash-core")}#{PACKAGE_SUFFIX}" : ALL_VERSIONS.fetch("logstash-core") + LOGSTASH_CORE_VERSION = ALL_VERSIONS.fetch("logstash-core") end diff --git a/logstash-core/lib/logstash-core/version.rb b/logstash-core/lib/logstash-core/version.rb index c8340b1d6..8fb26f3f6 100644 --- a/logstash-core/lib/logstash-core/version.rb +++ b/logstash-core/lib/logstash-core/version.rb @@ -24,6 +24,5 @@ if !defined?(ALL_VERSIONS) end if !defined?(LOGSTASH_CORE_VERSION) - # PACKAGE_SUFFIX is declared in the artifact namespace from artifacts.rake - LOGSTASH_CORE_VERSION = defined?(PACKAGE_SUFFIX) ? "#{ALL_VERSIONS.fetch("logstash-core")}#{PACKAGE_SUFFIX}" : ALL_VERSIONS.fetch("logstash-core") + LOGSTASH_CORE_VERSION = ALL_VERSIONS.fetch("logstash-core") end From 3fbe846b8b4752cd79badce45c5dea8fea133bc7 Mon Sep 17 00:00:00 2001 From: Karen Metts <35154725+karenzone@users.noreply.github.com> Date: Tue, 21 Apr 2020 13:42:57 -0400 Subject: [PATCH 0438/1126] [Doc]Release notes: Add known issue for monitoring settings (#11816) (#11821) * Add known issue for monitoring settings * Incorporate review comments --- docs/static/releasenotes.asciidoc | 45 +++++++------------------------ 1 file changed, 10 insertions(+), 35 deletions(-) diff --git a/docs/static/releasenotes.asciidoc b/docs/static/releasenotes.asciidoc index 563acd9c1..7b6989b97 100644 --- a/docs/static/releasenotes.asciidoc +++ b/docs/static/releasenotes.asciidoc @@ -31,43 +31,18 @@ This section summarizes the changes in the following releases: [[logstash-7-7-0]] === Logstash 7.7.0 Release Notes +[float] +[[known-issue-7.7.0]] +==== Known issue + +* Monitoring settings. The `xpack.` prefixed monitoring settings were removed +from the `logstash.yml` config template as part of an experimental feature. +Please continue to use the <> prefixed +with `xpack.monitoring`. +https://github.com/elastic/logstash/issues/11815[#11815] + ==== New features and improvements -===== Improving Stack communication - Monitoring - -As the {stack} continues to evolve, improvements across stack components become -necessary to improve performance, internal communication or usability of our -products. {ls} is no different, as we continuously strive to improve its -interaction with the rest of the stack. As such, this release brings -improvements to how Logstash sends monitoring data (from its Internal -Collection) to {es}. - -Previous versions of {es} received monitoring data in a Production cluster to -then forward it (internally) to the dedicated Monitoring cluster. Newer versions -improved the process by allowing the data to be sent directly to the Monitoring -cluster instead, in a different data format. Following those changes, Logstash -has now added support to send the monitoring data directly to the Monitoring -cluster, with the caveat that the Production cluster only has to retrieve the -`cluster_uuid`. -https://github.com/elastic/logstash/pull/11106[#11106], -https://github.com/elastic/logstash/pull/11640[#11640], -https://github.com/elastic/logstash/pull/11641[#11641] - -Migrating from legacy internal collection to new -<> is straightforward. - -** Drop the `xpack.` prefix from your configuration settings. -For example, `xpack.monitoring.enabled` is now `monitoring.enabled`. See -<> for the full list. -** Change the hosts settings and configuration options to point to monitoring -cluster instead of production. -** If you don’t have an Elasticsearch output plugin configured in the pipelines, -add the setting monitoring.cluster_uuid to your logstash.yml. - -See <> for more information -about this and other monitoring options. - - ===== Improving Logging Continuing with the Logging improvements made in the past couple of releases, From 252b7111848a84adf84056f37a19bfddfe9e8b2b Mon Sep 17 00:00:00 2001 From: Ry Biesemeyer Date: Thu, 23 Jan 2020 18:52:17 +0000 Subject: [PATCH 0439/1126] API: avoid starting webserver when `http.enabled=false` In some workflows such as simple file manipulation, starting a webserver is unnecessary overhead, and we should be able to avoid it. Here we introduce a new parameter `http.enabled`, which defaults to `true` to maintain the existing functionality. Resolves: elastic/logstash#9408 Closes: elastic/logstash#11525 Co-authored-by: Benoit Dupont Fixes #11533 --- config/logstash.yml | 21 +++++++++++++++++++++ logstash-core/lib/logstash/agent.rb | 10 +++++++++- logstash-core/lib/logstash/environment.rb | 3 ++- logstash-core/lib/logstash/runner.rb | 5 +++++ logstash-core/locales/en.yml | 3 +++ 5 files changed, 40 insertions(+), 2 deletions(-) diff --git a/config/logstash.yml b/config/logstash.yml index 1f0a7c884..7cc605a4e 100644 --- a/config/logstash.yml +++ b/config/logstash.yml @@ -102,6 +102,27 @@ pipeline.ordered: auto # # config.support_escapes: false # +# ------------ HTTP API Settings ------------- +# Define settings related to the HTTP API here. +# +# The HTTP API is enabled by default. It can be disabled, but features that rely +# on it will not work as intended. +# http.enabled: true +# +# By default, the HTTP API is bound to only the host's local loopback interface, +# ensuring that it is not accessible to the rest of the network. Because the API +# includes neither authentication nor authorization and has not been hardened or +# tested for use as a publicly-reachable API, binding to publicly accessible IPs +# should be avoided where possible. +# +# http.host: 127.0.0.1 +# +# The HTTP API web server will listen on an available port from the given range. +# Values can be specified as a single port (e.g., `9600`), or an inclusive range +# of ports (e.g., `9600-9700`). +# +# http.port: 9600-9700 +# # ------------ Module Settings --------------- # Define modules here. Modules definitions must be defined as an array. # The simple way to see this is to prepend each `name` with a `-`, and keep diff --git a/logstash-core/lib/logstash/agent.rb b/logstash-core/lib/logstash/agent.rb index 99f956d0d..3ecd47e16 100644 --- a/logstash-core/lib/logstash/agent.rb +++ b/logstash-core/lib/logstash/agent.rb @@ -112,7 +112,7 @@ class LogStash::Agent converge_state_and_update - start_webserver + start_webserver_if_enabled if auto_reload? # `sleep_then_run` instead of firing the interval right away @@ -384,6 +384,14 @@ class LogStash::Agent end end + def start_webserver_if_enabled + if @settings.get_value("http.enabled") + start_webserver + else + @logger.info("HTTP API is disabled (`http.enabled=false`); webserver will not be started.") + end + end + def start_webserver @webserver_control_lock.synchronize do options = {:http_host => @http_host, :http_ports => @http_port, :http_environment => @http_environment } diff --git a/logstash-core/lib/logstash/environment.rb b/logstash-core/lib/logstash/environment.rb index 27d6f1160..89d5ad1c8 100644 --- a/logstash-core/lib/logstash/environment.rb +++ b/logstash-core/lib/logstash/environment.rb @@ -69,8 +69,9 @@ module LogStash Setting::Boolean.new("version", false), Setting::Boolean.new("help", false), Setting::String.new("log.format", "plain", true, ["json", "plain"]), + Setting::Boolean.new("http.enabled", true), Setting::String.new("http.host", "127.0.0.1"), - Setting::PortRange.new("http.port", 9600..9700), + Setting::PortRange.new("http.port", 9600..9700), Setting::String.new("http.environment", "production"), Setting::String.new("queue.type", "memory", true, ["persisted", "memory"]), Setting::Boolean.new("queue.drain", false), diff --git a/logstash-core/lib/logstash/runner.rb b/logstash-core/lib/logstash/runner.rb index d0324b822..04a48b5b7 100644 --- a/logstash-core/lib/logstash/runner.rb +++ b/logstash-core/lib/logstash/runner.rb @@ -204,6 +204,11 @@ class LogStash::Runner < Clamp::StrictCommand :attribute_name => "config.reload.interval", :default => LogStash::SETTINGS.get_default("config.reload.interval") + option ["--http.enabled"], "ENABLED", + I18n.t("logstash.runner.flag.http_enabled"), + :attribute_name => 'http.enabled', + :default => LogStash::SETTINGS.get_default('http.enabled') + option ["--http.host"], "HTTP_HOST", I18n.t("logstash.runner.flag.http_host"), :attribute_name => "http.host", diff --git a/logstash-core/locales/en.yml b/logstash-core/locales/en.yml index 27347484e..25a8304e2 100644 --- a/logstash-core/locales/en.yml +++ b/logstash-core/locales/en.yml @@ -282,6 +282,9 @@ en: e.g. 'username:' configtest: |+ Check configuration for valid syntax and then exit. + http_enabled: |+ + Can be used to disable the Web API, which is + enabled by default. http_host: Web API binding host http_port: Web API http port pipeline-id: |+ From beec172e224c7cbfb0cd1e44f4eb7c9363c5f081 Mon Sep 17 00:00:00 2001 From: Karen Metts Date: Wed, 22 Apr 2020 10:01:24 -0400 Subject: [PATCH 0440/1126] Remove known issue Fixes #11825 --- docs/static/releasenotes.asciidoc | 10 ---------- 1 file changed, 10 deletions(-) diff --git a/docs/static/releasenotes.asciidoc b/docs/static/releasenotes.asciidoc index 7b6989b97..800bfad71 100644 --- a/docs/static/releasenotes.asciidoc +++ b/docs/static/releasenotes.asciidoc @@ -31,16 +31,6 @@ This section summarizes the changes in the following releases: [[logstash-7-7-0]] === Logstash 7.7.0 Release Notes -[float] -[[known-issue-7.7.0]] -==== Known issue - -* Monitoring settings. The `xpack.` prefixed monitoring settings were removed -from the `logstash.yml` config template as part of an experimental feature. -Please continue to use the <> prefixed -with `xpack.monitoring`. -https://github.com/elastic/logstash/issues/11815[#11815] - ==== New features and improvements ===== Improving Logging From cf890d0df709502b5bcce1aa6145cc79a43fca41 Mon Sep 17 00:00:00 2001 From: Karen Metts Date: Mon, 20 Apr 2020 16:38:28 -0400 Subject: [PATCH 0441/1126] Add experimental tags for internal collection Fixes #11823 --- .../monitoring-internal-legacy.asciidoc | 19 ------------------- .../monitoring/monitoring-internal.asciidoc | 9 ++++----- .../monitoring/monitoring-overview.asciidoc | 5 ++--- .../settings/monitoring-settings.asciidoc | 1 + 4 files changed, 7 insertions(+), 27 deletions(-) diff --git a/docs/static/monitoring/monitoring-internal-legacy.asciidoc b/docs/static/monitoring/monitoring-internal-legacy.asciidoc index a86f81501..4ea831933 100644 --- a/docs/static/monitoring/monitoring-internal-legacy.asciidoc +++ b/docs/static/monitoring/monitoring-internal-legacy.asciidoc @@ -5,25 +5,6 @@ Legacy internal collection ++++ -IMPORTANT: Use <> or -<> instead of legacy -internal collection. If you are currently using legacy internal collection, you -should migrate to either Metricbeat collection or internal collection. - -==== Migrating from legacy internal collection to new internal collection - -Migrating from legacy internal collection to new -<> is straightforward. - -** Drop the `xpack.` prefix from your configuration settings. -For example, `xpack.monitoring.enabled` is now `monitoring.enabled`. See -<> for the full list. -** Change the hosts settings and configuration options to point to the monitoring -cluster instead of the production cluster. -** If you don’t have an Elasticsearch output plugin configured in the pipelines, -add the <> setting to your -logstash.yml. - ==== Components for legacy internal collection Monitoring {ls} with legacy internal collection uses these components: diff --git a/docs/static/monitoring/monitoring-internal.asciidoc b/docs/static/monitoring/monitoring-internal.asciidoc index 43056c31c..f7bd95aae 100644 --- a/docs/static/monitoring/monitoring-internal.asciidoc +++ b/docs/static/monitoring/monitoring-internal.asciidoc @@ -1,14 +1,12 @@ [role="xpack"] [[monitoring-internal-collection]] -=== Use internal collectors to send monitoring data +=== Use internal collectors to send monitoring data (Experimental) +experimental[] ++++ -Internal collection +Internal collection (Experimental) ++++ Internal collectors send {ls} monitoring data directly to your _monitoring_ cluster. -The benefit of internal collection is that you have fewer pieces of software to -install and maintain. - <> is available as an alternative. IMPORTANT: All Logstash nodes must share the same setup. @@ -16,6 +14,7 @@ Otherwise, monitoring data might be routed in different ways or to different pla [[configure-internal-collectors]] ==== Configure {ls} monitoring with internal collectors +experimental[] ++++ Configure internal collection ++++ diff --git a/docs/static/monitoring/monitoring-overview.asciidoc b/docs/static/monitoring/monitoring-overview.asciidoc index 5e6e994ee..73ec05a89 100644 --- a/docs/static/monitoring/monitoring-overview.asciidoc +++ b/docs/static/monitoring/monitoring-overview.asciidoc @@ -21,9 +21,8 @@ monitoring data from your {ls} instance and sends it directly to your monitoring cluster. The benefit of Metricbeat collection is that the monitoring agent remains active even if the {ls} instance does not. -* <>. Internal collectors send -monitoring data directly to your monitoring cluster. The benefit of internal -collection is that you have fewer pieces of software to install and maintain. +* <>. +Internal collectors send monitoring data directly to your monitoring cluster. * <>. Legacy internal collectors send monitoring data to your production cluster. diff --git a/docs/static/settings/monitoring-settings.asciidoc b/docs/static/settings/monitoring-settings.asciidoc index 255d14df3..f0092a4e0 100644 --- a/docs/static/settings/monitoring-settings.asciidoc +++ b/docs/static/settings/monitoring-settings.asciidoc @@ -1,6 +1,7 @@ [role="xpack"] [[monitoring-settings]] ==== Monitoring settings for internal collection +experimental[] ++++ Monitoring Settings ++++ From 5dbe95bfae81a81f52dc038f15b7854ad3355109 Mon Sep 17 00:00:00 2001 From: Karen Metts Date: Wed, 22 Apr 2020 08:15:02 -0400 Subject: [PATCH 0442/1126] Incorporate review comments Fixes #11823 --- docs/static/monitoring/monitoring-overview.asciidoc | 4 ---- 1 file changed, 4 deletions(-) diff --git a/docs/static/monitoring/monitoring-overview.asciidoc b/docs/static/monitoring/monitoring-overview.asciidoc index 73ec05a89..aa62cafed 100644 --- a/docs/static/monitoring/monitoring-overview.asciidoc +++ b/docs/static/monitoring/monitoring-overview.asciidoc @@ -26,10 +26,6 @@ Internal collectors send monitoring data directly to your monitoring cluster. * <>. Legacy internal collectors send monitoring data to your production cluster. -This is no longer a preferred approach. Use -<> or -<> instead. - include::monitoring-mb.asciidoc[] include::monitoring-internal.asciidoc[] From cbc6209b75b3c241bd4726d0332362876bd59bcc Mon Sep 17 00:00:00 2001 From: Karen Metts Date: Wed, 22 Apr 2020 09:01:29 -0400 Subject: [PATCH 0443/1126] Remove new internal collection Fixes #11823 --- docs/static/monitoring/collectors.asciidoc | 49 ------- .../monitoring/monitoring-internal.asciidoc | 127 ------------------ docs/static/monitoring/monitoring-mb.asciidoc | 3 - .../monitoring/monitoring-output.asciidoc | 45 ------- .../monitoring/monitoring-overview.asciidoc | 4 - .../settings/monitoring-settings.asciidoc | 126 ----------------- 6 files changed, 354 deletions(-) delete mode 100644 docs/static/monitoring/collectors.asciidoc delete mode 100644 docs/static/monitoring/monitoring-internal.asciidoc delete mode 100644 docs/static/monitoring/monitoring-output.asciidoc delete mode 100644 docs/static/settings/monitoring-settings.asciidoc diff --git a/docs/static/monitoring/collectors.asciidoc b/docs/static/monitoring/collectors.asciidoc deleted file mode 100644 index 8b09cf6a0..000000000 --- a/docs/static/monitoring/collectors.asciidoc +++ /dev/null @@ -1,49 +0,0 @@ -[float] -[role="xpack"] -[[logstash-monitoring-collectors]] -===== Collectors - -Collectors, as their name implies, collect things. In monitoring for Logstash, -collectors are just <> in the same way that ordinary Logstash -configurations provide inputs. - -Like monitoring for {es}, each collector can create zero or more monitoring -documents. As it is currently implemented, each Logstash node runs two types of -collectors: one for node stats and one for pipeline stats. - -[options="header"] -|======================= -| Collector | Data Types | Description -| Node Stats | `logstash_stats` -| Gathers details about the running node, such as memory utilization and CPU -usage (for example, `GET /_stats`). - -This runs on every Logstash node with monitoring enabled. One common -failure is that Logstash directories are copied with their `path.data` directory -included (`./data` by default), which copies the persistent UUID of the Logstash -node along with it. As a result, it generally appears that one or more Logstash -nodes are failing to collect monitoring data, when in fact they are all really -misreporting as the _same_ Logstash node. Re-use `path.data` directories only -when upgrading Logstash, such that upgraded nodes replace the previous versions. -| Pipeline Stats | `logstash_state` -| Gathers details about the node's running pipelines, which powers the -Monitoring Pipeline UI. -|======================= - -Per collection interval, which defaults to 10 seconds (`10s`), each collector is -run. The failure of an individual collector does not impact any other collector. -Each collector, as an ordinary Logstash input, creates a separate Logstash event -in its isolated monitoring pipeline. The Logstash output then sends the data. - -The collection interval can be configured dynamically and you can also disable -data collection. For more information about the configuration options for the -collectors, see <>. - -WARNING: Unlike for {es} and {kib} monitoring, there is no -`monitoring.collection.enabled` setting on Logstash. You must use the -`monitoring.enabled` setting to enable and disable data collection. - -If gaps exist in the monitoring charts in {kib}, it is typically because either -a collector failed or the monitoring cluster did not receive the data (for -example, it was being restarted). In the event that a collector fails, a logged -error should exist on the node that attempted to perform the collection. diff --git a/docs/static/monitoring/monitoring-internal.asciidoc b/docs/static/monitoring/monitoring-internal.asciidoc deleted file mode 100644 index f7bd95aae..000000000 --- a/docs/static/monitoring/monitoring-internal.asciidoc +++ /dev/null @@ -1,127 +0,0 @@ -[role="xpack"] -[[monitoring-internal-collection]] -=== Use internal collectors to send monitoring data (Experimental) -experimental[] -++++ -Internal collection (Experimental) -++++ - -Internal collectors send {ls} monitoring data directly to your _monitoring_ cluster. -<> is available as an alternative. - -IMPORTANT: All Logstash nodes must share the same setup. -Otherwise, monitoring data might be routed in different ways or to different places. - -[[configure-internal-collectors]] -==== Configure {ls} monitoring with internal collectors -experimental[] -++++ -Configure internal collection -++++ - -To monitor Logstash nodes: - -. Specify the location of the _monitoring cluster_. For examples of typical -monitoring architectures, see {ref}/how-monitoring-works.html[How monitoring -works] in the {ref}[Elasticsearch Reference]. - -. Verify that the `xpack.monitoring.collection.enabled` setting is `true` on the -monitoring cluster. If that setting is `false`, the collection of monitoring data -is disabled in {es}, and data is ignored from all other sources. - -. Configure your Logstash nodes to send metrics by setting the -`monitoring.elasticsearch.hosts` in `logstash.yml`. If {security-features} -are enabled, you also need to specify the credentials for the -{ref}/built-in-users.html[built-in `logstash_system` user]. For more -information about these settings, see <>. -+ --- -[source,yaml] --------------------------------------------------- -monitoring.elasticsearch.hosts: ["http://es-monitoring-node-1:9200", "http://es-monitoring-node-2:9200"] -monitoring.elasticsearch.username: "logstash_system" -monitoring.elasticsearch.password: "changeme" --------------------------------------------------- - -If SSL/TLS is enabled on the monitoring cluster, you must connect through HTTPS. -You can specify a single host as a string, or multiple Elasticsearch hosts as an -array. If multiple URLs are specified, Logstash can round-robin requests to -these monitoring nodes. --- - -. If SSL/TLS is enabled on the monitoring {es} cluster, specify the trusted -CA certificates that will be used to verify the identity of the nodes -in the cluster. -+ --- -To add a CA certificate to a Logstash node's trusted certificates, you -can specify the location of the PEM encoded certificate with the -`certificate_authority` setting: - -[source,yaml] --------------------------------------------------- -monitoring.elasticsearch.ssl.certificate_authority: /path/to/ca.crt --------------------------------------------------- - -Alternatively, you can configure trusted certificates using a truststore -(a Java Keystore file that contains the certificates): - -[source,yaml] --------------------------------------------------- -monitoring.elasticsearch.ssl.truststore.path: /path/to/file -monitoring.elasticsearch.ssl.truststore.password: password --------------------------------------------------- - -Also, optionally, you can set up client certificate using a keystore -(a Java Keystore file that contains the certificate): - -[source,yaml] --------------------------------------------------- -monitoring.elasticsearch.ssl.keystore.path: /path/to/file -monitoring.elasticsearch.ssl.keystore.password: password --------------------------------------------------- - -Set sniffing to `true` to enable discovery of other nodes of the {es} cluster. -It defaults to `false`. - -[source,yaml] --------------------------------------------------- -monitoring.elasticsearch.sniffing: false --------------------------------------------------- - --- - -. Restart your Logstash nodes. - -. To verify your monitoring configuration, point your web browser at your {kib} -host, and select **Monitoring** from the side navigation. Metrics reported from -your Logstash nodes should be visible in the Logstash section. When security is -enabled, you must log in to {kib} as a user who has the `kibana_user` and -`monitoring_user` roles. - -include::../settings/monitoring-settings.asciidoc[] - - -[[internal-collector-components]] -==== How {ls} monitoring with internal collectors works - -Monitoring {ls} with internal collectors uses these components: - -* <> -* <> - -These pieces live outside of the default Logstash pipeline in a dedicated -monitoring pipeline. This configuration ensures that all data and processing has -a minimal impact on ordinary Logstash processing. - -NOTE: The `elasticsearch` output for Logstash monitoring is configured -exclusively through settings in `logstash.yml`. - -The monitoring {es} cluster should be configured to receive {ls} monitoring -data directly from {ls}. For more information about typical monitoring -architectures, see {ref}/how-monitoring-works.html[How monitoring works] in the -{ref}[Elasticsearch Reference]. - - -include::collectors.asciidoc[] -include::monitoring-output.asciidoc[] diff --git a/docs/static/monitoring/monitoring-mb.asciidoc b/docs/static/monitoring/monitoring-mb.asciidoc index dec7f6925..a6bd60edc 100644 --- a/docs/static/monitoring/monitoring-mb.asciidoc +++ b/docs/static/monitoring/monitoring-mb.asciidoc @@ -10,9 +10,6 @@ You can use {metricbeat} to collect data about {ls} and ship it to the monitoring cluster. The benefit of Metricbeat collection is that the monitoring agent remains active even if the {ls} instance does not. -<> is available as an -alternative. - //NOTE: The tagged regions are re-used in the Stack Overview. To collect and ship monitoring data: diff --git a/docs/static/monitoring/monitoring-output.asciidoc b/docs/static/monitoring/monitoring-output.asciidoc deleted file mode 100644 index 811a9faec..000000000 --- a/docs/static/monitoring/monitoring-output.asciidoc +++ /dev/null @@ -1,45 +0,0 @@ -[float] -[role="xpack"] -[[logstash-monitoring-output]] -==== Output - -Like all Logstash pipelines, the purpose of the dedicated monitoring pipeline is -to send events to outputs. In the case of Logstash monitoring, the output -is always an `elasticsearch` output. However, unlike ordinary Logstash pipelines, -the output is configured within the `logstash.yml` settings file via the -`monitoring.elasticsearch.*` settings. - -Other than its unique manner of configuration, this `elasticsearch` output -behaves like all `elasticsearch` outputs, including its ability to pause data -collection when issues exist with the output. - -IMPORTANT: It is critical that all Logstash nodes share the same setup. -Otherwise, monitoring data might be routed in different ways or to different places. - -[float] -[[logstash-monitoring-default]] -===== Default Configuration - -If a Logstash node does not explicitly define a monitoring output setting, -the following default configuration is used: - -[source,yaml] ---------------------------------------------------- -monitoring.elasticsearch.hosts: [ "http://localhost:9200" ] ---------------------------------------------------- - -All data produced by Logstash monitoring is indexed in the monitoring -cluster using the `.monitoring-logstash` template. - -If you are working with a cluster that has {security-features} enabled, extra -steps are necessary to properly configure Logstash. For more information, see -<>. - -IMPORTANT: When discussing security relative to the `monitoring.elasticsearch` -settings, remember that all users are managed on the monitoring cluster, which -is identified in the `monitoring.elasticsearch.hosts` setting. This is -particularly important when you move from development environments to production -environments, where you often have dedicated monitoring clusters. - -For more information about the configuration options for the output, see -<>. \ No newline at end of file diff --git a/docs/static/monitoring/monitoring-overview.asciidoc b/docs/static/monitoring/monitoring-overview.asciidoc index aa62cafed..dc7fb369c 100644 --- a/docs/static/monitoring/monitoring-overview.asciidoc +++ b/docs/static/monitoring/monitoring-overview.asciidoc @@ -21,14 +21,10 @@ monitoring data from your {ls} instance and sends it directly to your monitoring cluster. The benefit of Metricbeat collection is that the monitoring agent remains active even if the {ls} instance does not. -* <>. -Internal collectors send monitoring data directly to your monitoring cluster. - * <>. Legacy internal collectors send monitoring data to your production cluster. include::monitoring-mb.asciidoc[] -include::monitoring-internal.asciidoc[] include::monitoring-internal-legacy.asciidoc[] include::monitoring-ui.asciidoc[] include::pipeline-viewer.asciidoc[] diff --git a/docs/static/settings/monitoring-settings.asciidoc b/docs/static/settings/monitoring-settings.asciidoc deleted file mode 100644 index f0092a4e0..000000000 --- a/docs/static/settings/monitoring-settings.asciidoc +++ /dev/null @@ -1,126 +0,0 @@ -[role="xpack"] -[[monitoring-settings]] -==== Monitoring settings for internal collection -experimental[] -++++ -Monitoring Settings -++++ - -You can set the following `monitoring` settings in `logstash.yml` to -control how monitoring data is collected from your Logstash nodes. However, the -defaults work best in most circumstances. For more information about configuring -Logstash, see <>. - - -[[monitoring-general-settings]] -===== General monitoring settings - -`monitoring.enabled`:: - -Monitoring is disabled by default. Set to `true` to enable monitoring. - -`monitoring.elasticsearch.hosts`:: - -The {es} monitoring cluster that you want to ship your Logstash metrics to. This -might be the same {es} instance specified in the `outputs` section in your -Logstash configuration, or a dedicated monitoring cluster. You can specify a -single host as a string, or specify multiple hosts as an array. Defaults to -`http://localhost:9200`. - -NOTE: If your Elasticsearch monitoring cluster is configured with dedicated -master-eligible nodes, Logstash metrics should _not_ be routed to these nodes. -Doing so can create resource contention and impact the stability of the -Elasticsearch cluster. Therefore, do not include such nodes in -`monitoring.elasticsearch.hosts`. - -`monitoring.elasticsearch.username` and `monitoring.elasticsearch.password`:: - -If your {es} is protected with basic authentication, these settings provide the -username and password that the Logstash instance uses to authenticate for -shipping monitoring data. - -`monitoring.elasticsearch.proxy`:: - -Optional setting that allows you to specify a proxy URL if Logstash needs to use a proxy -to reach your Elasticsearch cluster. - -[[monitoring-collection-settings]] -===== Monitoring collection settings - -`monitoring.collection.interval`:: - -Controls how often data samples are collected and shipped on the Logstash side. -Defaults to `10s`. If you modify the collection interval, set the -`monitoring.min_interval_seconds` option in `kibana.yml` to the same value. - -[[monitoring-cluster-uuid]] -`monitoring.cluster_uuid`:: - -The universally unique identifier (UUID) for the monitoring cluster. -By default, {ls} identifies and uses the `cluster uuid` value from each -elasticsearch output defined in the pipelines, and ignores this -setting. -+ -If no `cluster_uuid` is discovered in elasticsearch outputs, then {ls} -uses this value to tag the data shipped to the monitoring cluster. - -[[monitoring-ssl-settings]] -===== Monitoring TLS/SSL settings - -You can configure the following Transport Layer Security (TLS) or -Secure Sockets Layer (SSL) settings. For more information, see -<>. - -`monitoring.elasticsearch.ssl.certificate_authority`:: - -Optional setting that enables you to specify a path to the `.pem` file for the -certificate authority for your {es} instance. - -`monitoring.elasticsearch.ssl.truststore.path`:: - -Optional settings that provide the paths to the Java keystore (JKS) to validate -the server’s certificate. - -`monitoring.elasticsearch.ssl.truststore.password`:: - -Optional settings that provide the password to the truststore. - -`monitoring.elasticsearch.ssl.keystore.path`:: - -Optional settings that provide the paths to the Java keystore (JKS) to validate -the client’s certificate. - -`monitoring.elasticsearch.ssl.keystore.password`:: - -Optional settings that provide the password to the keystore. - -`monitoring.elasticsearch.ssl.verification_mode`:: - -Option to validate the server’s certificate. Defaults to `certificate`. To -disable, set to `none`. Disabling this severely compromises security. - -`monitoring.elasticsearch.sniffing`:: - -Finds all {es} cluster nodes and adds them to the hosts list. -Defaults to `false`. - -[[monitoring-additional-settings]] -===== Additional settings - -`monitoring.elasticsearch.cloud_id`:: - -If you're using {es} in {ecloud}, you should specify the identifier here. -This setting is an alternative to `monitoring.elasticsearch.hosts`. -If `cloud_id` is configured, `monitoring.elasticsearch.hosts` should not be used. -The {es} instances that you want to ship your Logstash metrics to. This might be -the same {es} instance specified in the `outputs` section in your Logstash -configuration, or a different one. - -`monitoring.elasticsearch.cloud_auth`:: - -If you're using {es} in {ecloud}, you can set your auth credentials here. -This setting is an alternative to both `monitoring.elasticsearch.username` -and `monitoring.elasticsearch.password`. If `cloud_auth` is configured, -those settings should not be used. - - From 65bca0ca6c48b726af478833c77f4e43d1a999e3 Mon Sep 17 00:00:00 2001 From: Karen Metts Date: Wed, 22 Apr 2020 14:18:16 -0400 Subject: [PATCH 0444/1126] Review comments Fixes #11823 --- .../static/monitoring/monitoring-internal-legacy.asciidoc | 8 ++++---- docs/static/monitoring/monitoring-overview.asciidoc | 4 ++-- docs/static/settings/monitoring-settings-legacy.asciidoc | 2 +- 3 files changed, 7 insertions(+), 7 deletions(-) diff --git a/docs/static/monitoring/monitoring-internal-legacy.asciidoc b/docs/static/monitoring/monitoring-internal-legacy.asciidoc index 4ea831933..e63ff6e3f 100644 --- a/docs/static/monitoring/monitoring-internal-legacy.asciidoc +++ b/docs/static/monitoring/monitoring-internal-legacy.asciidoc @@ -1,13 +1,13 @@ [role="xpack"] [[monitoring-internal-collection-legacy]] -=== Collect {ls} monitoring data using legacy internal collectors +=== Collect {ls} monitoring data using internal collectors ++++ -Legacy internal collection +Internal collection ++++ -==== Components for legacy internal collection +==== Components for internal collection -Monitoring {ls} with legacy internal collection uses these components: +Monitoring {ls} with internal collection uses these components: * <> * <> diff --git a/docs/static/monitoring/monitoring-overview.asciidoc b/docs/static/monitoring/monitoring-overview.asciidoc index dc7fb369c..cb017c2c2 100644 --- a/docs/static/monitoring/monitoring-overview.asciidoc +++ b/docs/static/monitoring/monitoring-overview.asciidoc @@ -21,8 +21,8 @@ monitoring data from your {ls} instance and sends it directly to your monitoring cluster. The benefit of Metricbeat collection is that the monitoring agent remains active even if the {ls} instance does not. -* <>. Legacy -internal collectors send monitoring data to your production cluster. +* <>. +Internal collectors send monitoring data to your production cluster. include::monitoring-mb.asciidoc[] include::monitoring-internal-legacy.asciidoc[] diff --git a/docs/static/settings/monitoring-settings-legacy.asciidoc b/docs/static/settings/monitoring-settings-legacy.asciidoc index 686c237bd..c0d46975f 100644 --- a/docs/static/settings/monitoring-settings-legacy.asciidoc +++ b/docs/static/settings/monitoring-settings-legacy.asciidoc @@ -1,6 +1,6 @@ [role="xpack"] [[monitoring-settings-legacy]] -==== Monitoring settings for legacy internal collection +==== Monitoring settings for internal collection ++++ Monitoring Settings ++++ From c73544f1ed6e2553f6abbf1df2c8ef2111778f01 Mon Sep 17 00:00:00 2001 From: Joao Duarte Date: Wed, 22 Apr 2020 06:57:01 +0100 Subject: [PATCH 0445/1126] reinstate x-pack.monitoring settings in logstash.yml --- config/logstash.yml | 40 ++++++++++++++--------------- x-pack/lib/monitoring/monitoring.rb | 4 +-- 2 files changed, 20 insertions(+), 24 deletions(-) diff --git a/config/logstash.yml b/config/logstash.yml index 7cc605a4e..c86332125 100644 --- a/config/logstash.yml +++ b/config/logstash.yml @@ -249,29 +249,27 @@ pipeline.ordered: auto # Default is false # pipeline.separate_logs: false # -# ------------ Monitoring Settings (not applicable for OSS build)-------------- -# -# https://www.elastic.co/guide/en/logstash/current/monitoring-internal-collection.html -# Enable monitoring via internal collector to an Elasticsearch monitoring cluster -#monitoring.enabled: false -#monitoring.cluster_uuid: elasticsearch_cluster_uuid -#monitoring.elasticsearch.username: logstash_system -#monitoring.elasticsearch.password: password -#monitoring.elasticsearch.hosts: ["https://es1:9200", "https://es2:9200"] -# an alternative to hosts + username/password settings is to use cloud_id/cloud_auth -#monitoring.elasticsearch.cloud_id: monitoring_cluster_id:xxxxxxxxxx -#monitoring.elasticsearch.cloud_auth: logstash_system:password -#monitoring.elasticsearch.ssl.certificate_authority: [ "/path/to/ca.crt" ] -#monitoring.elasticsearch.ssl.truststore.path: path/to/file -#monitoring.elasticsearch.ssl.truststore.password: password -#monitoring.elasticsearch.ssl.keystore.path: /path/to/file -#monitoring.elasticsearch.ssl.keystore.password: password -#monitoring.elasticsearch.ssl.verification_mode: certificate -#monitoring.elasticsearch.sniffing: false -#monitoring.collection.interval: 10s -#monitoring.collection.pipeline.details.enabled: true # ------------ X-Pack Settings (not applicable for OSS build)-------------- # +# X-Pack Monitoring +# https://www.elastic.co/guide/en/logstash/current/monitoring-logstash.html +#xpack.monitoring.enabled: false +#xpack.monitoring.elasticsearch.username: logstash_system +#xpack.monitoring.elasticsearch.password: password +#xpack.monitoring.elasticsearch.hosts: ["https://es1:9200", "https://es2:9200"] +# an alternative to hosts + username/password settings is to use cloud_id/cloud_auth +#xpack.monitoring.elasticsearch.cloud_id: monitoring_cluster_id:xxxxxxxxxx +#xpack.monitoring.elasticsearch.cloud_auth: logstash_system:password +#xpack.monitoring.elasticsearch.ssl.certificate_authority: [ "/path/to/ca.crt" ] +#xpack.monitoring.elasticsearch.ssl.truststore.path: path/to/file +#xpack.monitoring.elasticsearch.ssl.truststore.password: password +#xpack.monitoring.elasticsearch.ssl.keystore.path: /path/to/file +#xpack.monitoring.elasticsearch.ssl.keystore.password: password +#xpack.monitoring.elasticsearch.ssl.verification_mode: certificate +#xpack.monitoring.elasticsearch.sniffing: false +#xpack.monitoring.collection.interval: 10s +#xpack.monitoring.collection.pipeline.details.enabled: true +# # X-Pack Management # https://www.elastic.co/guide/en/logstash/current/logstash-centralized-pipeline-management.html #xpack.management.enabled: false diff --git a/x-pack/lib/monitoring/monitoring.rb b/x-pack/lib/monitoring/monitoring.rb index dd836344a..ec4924e0e 100644 --- a/x-pack/lib/monitoring/monitoring.rb +++ b/x-pack/lib/monitoring/monitoring.rb @@ -191,7 +191,6 @@ module LogStash opt = retrieve_collection_settings(settings) else opt = retrieve_collection_settings(settings, "xpack.") - deprecation_logger.deprecated("xpack.monitoring.* settings are deprecated use the new monitoring.*. Please see https://www.elastic.co/guide/en/logstash/current/monitoring-internal-collection.html") end es_settings = es_options_from_settings_or_modules('monitoring', settings) data = TemplateData.new(LogStash::SETTINGS.get("node.uuid"), API_VERSION, @@ -235,9 +234,8 @@ module LogStash def additionals_settings(settings) logger.trace("registering additionals_settings") - # Deprecated settings from 7.7 register_monitoring_settings(settings, "xpack.") - # Direct shipping settings + # (Experimental) Direct shipping settings register_monitoring_settings(settings) # These Settings were renamed and deprecated in 6.x timeframe and removed for 7.0; provide guidance to ease transition. From 770d9b27198d382b7096912b57a816bf33170938 Mon Sep 17 00:00:00 2001 From: Colin Surprenant Date: Mon, 20 Apr 2020 18:34:27 -0400 Subject: [PATCH 0446/1126] remove plugin internal validation call Fixes #11818 --- x-pack/lib/license_checker/license_reader.rb | 3 --- 1 file changed, 3 deletions(-) diff --git a/x-pack/lib/license_checker/license_reader.rb b/x-pack/lib/license_checker/license_reader.rb index 5da6aad56..29e2e873e 100644 --- a/x-pack/lib/license_checker/license_reader.rb +++ b/x-pack/lib/license_checker/license_reader.rb @@ -60,9 +60,6 @@ module LogStash def build_client es = LogStash::Outputs::ElasticSearch.new(@es_options) es.instance_variable_set :@logger, logger - es.fill_hosts_from_cloud_id - es.fill_user_password_from_cloud_auth - es.setup_hosts es.build_client end From 62154e0ad699f6657638438ccd89368698736bc1 Mon Sep 17 00:00:00 2001 From: Colin Surprenant Date: Thu, 23 Apr 2020 12:06:45 -0400 Subject: [PATCH 0447/1126] depend on the elasticsearch output plugin >= 10.4.2 Fixes #11830 --- Gemfile.template | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Gemfile.template b/Gemfile.template index 6f561eee4..8e6b8a418 100644 --- a/Gemfile.template +++ b/Gemfile.template @@ -11,7 +11,7 @@ gem "paquet", "~> 0.2" gem "pleaserun", "~>0.0.28" gem "rake", "~> 12" gem "ruby-progressbar", "~> 1" -gem "logstash-output-elasticsearch" +gem "logstash-output-elasticsearch", ">= 10.4.2" gem "childprocess", "~> 0.9", :group => :build gem "fpm", "~> 1.3.3", :group => :build gem "gems", "~> 1", :group => :build From caa40036bc2d4915a8a8b4033c2ffcf3374dce71 Mon Sep 17 00:00:00 2001 From: Rob Bavey Date: Tue, 14 Apr 2020 14:39:29 -0400 Subject: [PATCH 0448/1126] Avoid using deprecated `getSystemCpuLoad` method with JDK14 JDK14 prefers the use of `getCpuLoad` over `getSystemCpuLoad`. This commit reworks the call to use reflection to use the appropriate method call depending on the version of the JDK being used. Fixes #11786 --- .../java/org/logstash/LogstashJavaCompat.java | 19 ++++++++++ .../instrument/monitors/ProcessMonitor.java | 36 +++++++++++++++++-- 2 files changed, 52 insertions(+), 3 deletions(-) diff --git a/logstash-core/src/main/java/org/logstash/LogstashJavaCompat.java b/logstash-core/src/main/java/org/logstash/LogstashJavaCompat.java index 636b9452e..d0aa9e5bf 100644 --- a/logstash-core/src/main/java/org/logstash/LogstashJavaCompat.java +++ b/logstash-core/src/main/java/org/logstash/LogstashJavaCompat.java @@ -90,4 +90,23 @@ public final class LogstashJavaCompat { final int end = version.indexOf('.'); return Integer.parseInt(version.substring(0, end > 0 ? end : version.length())) >= 9; } + + /** + * Identifies whether we are running on a versiongreater than or equal to the version parameter specified. + * @param version The version to test against. This must be the Major version of Java + * @return True if running on Java whose major version is greater than or equal to the + * specified version. + */ + public static boolean isJavaAtLeast(int version){ + final String value = System.getProperty("java.specification.version"); + final int actualVersion; + // Java specification version prior to Java 9 were of the format `1.X`, and after the format `X` + // See https://openjdk.java.net/jeps/223 + if (value.startsWith("1.")) { + actualVersion = Integer.parseInt(value.split("\\.")[1]); + } else { + actualVersion = Integer.parseInt(value); + } + return actualVersion >= version; + } } diff --git a/logstash-core/src/main/java/org/logstash/instrument/monitors/ProcessMonitor.java b/logstash-core/src/main/java/org/logstash/instrument/monitors/ProcessMonitor.java index c63db2af4..499744b97 100644 --- a/logstash-core/src/main/java/org/logstash/instrument/monitors/ProcessMonitor.java +++ b/logstash-core/src/main/java/org/logstash/instrument/monitors/ProcessMonitor.java @@ -23,14 +23,17 @@ package org.logstash.instrument.monitors; import com.sun.management.UnixOperatingSystemMXBean; import java.lang.management.ManagementFactory; import java.lang.management.OperatingSystemMXBean; +import java.lang.reflect.Method; import java.util.HashMap; import java.util.Map; import java.util.concurrent.TimeUnit; -import javax.management.MBeanServer; + +import org.logstash.LogstashJavaCompat; public class ProcessMonitor { + private static final OperatingSystemMXBean osMxBean = ManagementFactory.getOperatingSystemMXBean(); - private static final MBeanServer platformMxBean = ManagementFactory.getPlatformMBeanServer(); + private static final Method CPU_LOAD_METHOD = getCpuLoadMethod(); public static class Report { private long memTotalVirtualInBytes = -1; @@ -55,7 +58,7 @@ public class ProcessMonitor { unixOsBean.getProcessCpuTime(), TimeUnit.NANOSECONDS ); this.cpuProcessPercent = scaleLoadToPercent(unixOsBean.getProcessCpuLoad()); - this.cpuSystemPercent = scaleLoadToPercent(unixOsBean.getSystemCpuLoad()); + this.cpuSystemPercent = getSystemCpuLoad(); this.memTotalVirtualInBytes = unixOsBean.getCommittedVirtualMemorySize(); } @@ -90,6 +93,33 @@ public class ProcessMonitor { return -1; } } + + // The method `getSystemCpuLoad` is deprecated in favour of `getCpuLoad` since JDK14 + // This method uses reflection to use the correct method depending on the version of + // the JDK being used. + private short getSystemCpuLoad(){ + if (CPU_LOAD_METHOD == null){ + return -1; + } + try { + return scaleLoadToPercent((double)CPU_LOAD_METHOD.invoke(osMxBean)); + } catch (Exception e){ + return -1; + } + } + } + + /** + * Retrieve the correct name of the method to get CPU load. + * @return Method if the method could be found, null otherwise + */ + private static Method getCpuLoadMethod(){ + try{ + String methodName = (LogstashJavaCompat.isJavaAtLeast(14)) ? "getCpuLoad" : "getSystemCpuLoad"; + return Class.forName("com.sun.management.OperatingSystemMXBean").getMethod(methodName); + } catch (ReflectiveOperationException e){ + return null; + } } public static Report detect() { From 51431af405423335acdf0d9108b058c68d6afabf Mon Sep 17 00:00:00 2001 From: Rob Bavey Date: Fri, 24 Apr 2020 10:08:46 -0400 Subject: [PATCH 0449/1126] Added warning message if OperatingSystemMXBean not available Also corrected spacing after code review comments. Fixes #11786 --- .../src/main/java/org/logstash/LogstashJavaCompat.java | 2 +- .../org/logstash/instrument/monitors/ProcessMonitor.java | 7 ++++++- 2 files changed, 7 insertions(+), 2 deletions(-) diff --git a/logstash-core/src/main/java/org/logstash/LogstashJavaCompat.java b/logstash-core/src/main/java/org/logstash/LogstashJavaCompat.java index d0aa9e5bf..75e9da830 100644 --- a/logstash-core/src/main/java/org/logstash/LogstashJavaCompat.java +++ b/logstash-core/src/main/java/org/logstash/LogstashJavaCompat.java @@ -97,7 +97,7 @@ public final class LogstashJavaCompat { * @return True if running on Java whose major version is greater than or equal to the * specified version. */ - public static boolean isJavaAtLeast(int version){ + public static boolean isJavaAtLeast(int version) { final String value = System.getProperty("java.specification.version"); final int actualVersion; // Java specification version prior to Java 9 were of the format `1.X`, and after the format `X` diff --git a/logstash-core/src/main/java/org/logstash/instrument/monitors/ProcessMonitor.java b/logstash-core/src/main/java/org/logstash/instrument/monitors/ProcessMonitor.java index 499744b97..287fa061e 100644 --- a/logstash-core/src/main/java/org/logstash/instrument/monitors/ProcessMonitor.java +++ b/logstash-core/src/main/java/org/logstash/instrument/monitors/ProcessMonitor.java @@ -28,12 +28,16 @@ import java.util.HashMap; import java.util.Map; import java.util.concurrent.TimeUnit; +import org.apache.logging.log4j.LogManager; +import org.apache.logging.log4j.Logger; +import org.logstash.Logstash; import org.logstash.LogstashJavaCompat; public class ProcessMonitor { private static final OperatingSystemMXBean osMxBean = ManagementFactory.getOperatingSystemMXBean(); private static final Method CPU_LOAD_METHOD = getCpuLoadMethod(); + private static final Logger LOGGER = LogManager.getLogger(ProcessMonitor.class); public static class Report { private long memTotalVirtualInBytes = -1; @@ -97,7 +101,7 @@ public class ProcessMonitor { // The method `getSystemCpuLoad` is deprecated in favour of `getCpuLoad` since JDK14 // This method uses reflection to use the correct method depending on the version of // the JDK being used. - private short getSystemCpuLoad(){ + private short getSystemCpuLoad() { if (CPU_LOAD_METHOD == null){ return -1; } @@ -118,6 +122,7 @@ public class ProcessMonitor { String methodName = (LogstashJavaCompat.isJavaAtLeast(14)) ? "getCpuLoad" : "getSystemCpuLoad"; return Class.forName("com.sun.management.OperatingSystemMXBean").getMethod(methodName); } catch (ReflectiveOperationException e){ + LOGGER.warn("OperatingSystemMXBean CPU load method not available, CPU load will not be measured", e); return null; } } From ba78c05e0d7420700d02986fa35b4362d5b74ce3 Mon Sep 17 00:00:00 2001 From: Rob Bavey Date: Tue, 28 Apr 2020 09:31:57 -0400 Subject: [PATCH 0450/1126] [7.x] Backport JDK Unit Testing Matrices (#11839) * Defined the versions of JDK to use in test build separated by OS (#11768) * Added JDK 11 and 14 to Unix testing matrix (#11801) - OpenJDK14 AdoptOpenJDK11 Zulu11 - OpenJDK14 AdoptOpenJDK14 Zulu14 Close #11801 Co-authored-by: Andrea Selva --- .ci/matrix-unix-runtime-javas.yml | 18 ++++++++++++++++++ .ci/matrix-windows-runtime-javas.yml | 12 ++++++++++++ ci/unit_tests.bat | 3 +++ 3 files changed, 33 insertions(+) create mode 100644 .ci/matrix-unix-runtime-javas.yml create mode 100644 .ci/matrix-windows-runtime-javas.yml diff --git a/.ci/matrix-unix-runtime-javas.yml b/.ci/matrix-unix-runtime-javas.yml new file mode 100644 index 000000000..1857ed9bc --- /dev/null +++ b/.ci/matrix-unix-runtime-javas.yml @@ -0,0 +1,18 @@ +# This file is used as part of a matrix build in Jenkins where the +# values below are included as an axis of the matrix. + +# This axis of the build matrix represents the versions of Java on +# which Elasticsearch will be tested. Valid Java versions are 'java' +# or 'openjdk' followed by the major release number. + +LS_RUNTIME_JAVA: +# - java8 +# - zulu8 +# - adoptopenjdk8 +# - java11 + - openjdk11 + - adoptopenjdk11 + - zulu11 + - openjdk14 + - adoptopenjdk14 + - zulu14 \ No newline at end of file diff --git a/.ci/matrix-windows-runtime-javas.yml b/.ci/matrix-windows-runtime-javas.yml new file mode 100644 index 000000000..2a3fc7388 --- /dev/null +++ b/.ci/matrix-windows-runtime-javas.yml @@ -0,0 +1,12 @@ +# This file is used as part of a matrix build in Jenkins where the +# values below are included as an axis of the matrix. + +# This axis of the build matrix represents the versions of Java on +# which Elasticsearch will be tested. Valid Java versions are 'java' +# or 'openjdk' followed by the major release number. + +LS_RUNTIME_JAVA: +# - zulu8 +# - adoptopenjdk8 + - zulu11 +# - adoptopenjdk11 diff --git a/ci/unit_tests.bat b/ci/unit_tests.bat index e1c1148a6..f9c9f5481 100644 --- a/ci/unit_tests.bat +++ b/ci/unit_tests.bat @@ -40,6 +40,9 @@ echo Using drive !use_drive! for %WORKSPACE% !use_drive! echo Running core tests.. +if "%BUILD_JAVA_HOME%" == "" ( + GRADLE_OPTS="%GRADLE_OPTS% -Dorg.gradle.java.home=%BUILD_JAVA_HOME%" +) call .\gradlew.bat test --console=plain --no-daemon --info if errorlevel 1 ( From 8f142fc8bc7cd5bc16ed739a0adca81625f6adf7 Mon Sep 17 00:00:00 2001 From: Rob Bavey Date: Tue, 28 Apr 2020 14:38:09 -0400 Subject: [PATCH 0451/1126] Update JrJackson and Jackson Databind versions Update the versions of JrJackson and jackson databind to the latest available versions Fixes #11844 --- versions.yml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/versions.yml b/versions.yml index 284de3f1c..d30751f68 100644 --- a/versions.yml +++ b/versions.yml @@ -21,6 +21,6 @@ jruby: # Note: this file is copied to the root of logstash-core because its gemspec needs it when # bundler evaluates the gemspec via bin/logstash # Ensure Jackson version here is kept in sync with version used by jrjackson gem -jrjackson: 0.4.11 +jrjackson: 0.4.12 jackson: 2.9.10 -jackson-databind: 2.9.10.1 +jackson-databind: 2.9.10.4 From 4b8797bd9f5b0e8fb809b21eacc2b624f9f26767 Mon Sep 17 00:00:00 2001 From: Karen Metts <35154725+karenzone@users.noreply.github.com> Date: Thu, 30 Apr 2020 14:28:30 -0400 Subject: [PATCH 0452/1126] [doc] missing role for config management integration (#10341) (#11856) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit logstash_admin role is not enough. As the ls-security page mentions correctly: "The user you specify here must have the built-in logstash_admin role as well as the logstash_writer role that you created earlier" Updates static settings for extra role needed Co-authored-by: Karen Metts <35154725+karenzone@users.noreply.github.com> Co-authored-by: Edu González de la Herrán <25320357+eedugon@users.noreply.github.com> --- .../management/configuring-centralized-pipelines.asciidoc | 4 ++-- .../settings/configuration-management-settings.asciidoc | 6 +++--- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/docs/static/management/configuring-centralized-pipelines.asciidoc b/docs/static/management/configuring-centralized-pipelines.asciidoc index 3923f1ebd..db5390dff 100644 --- a/docs/static/management/configuring-centralized-pipelines.asciidoc +++ b/docs/static/management/configuring-centralized-pipelines.asciidoc @@ -31,8 +31,8 @@ centrally manage. . Restart Logstash. . If your Elasticsearch cluster is protected with basic authentication, assign -the `logstash_admin` role to any users who will use centralized pipeline -management. See <>. +the built-in `logstash_admin` role as well as the `logstash_writer` role to any users who will use centralized pipeline +management. See <> for more information. NOTE: Centralized management is disabled until you configure and enable {security-features}. diff --git a/docs/static/settings/configuration-management-settings.asciidoc b/docs/static/settings/configuration-management-settings.asciidoc index f48953c59..803354460 100644 --- a/docs/static/settings/configuration-management-settings.asciidoc +++ b/docs/static/settings/configuration-management-settings.asciidoc @@ -52,9 +52,9 @@ section in your Logstash configuration, or a different one. Defaults to If your {es} cluster is protected with basic authentication, these settings provide the username and password that the Logstash instance uses to -authenticate for accessing the configuration data. -The username you specify here should have the `logstash_admin` role, which -provides access to `.logstash-*` indices for managing configurations. +authenticate for accessing the configuration data. The username you specify here +should have the built-in `logstash_admin` role and the customized `logstash_writer` role, which provides access to `.logstash-*` +indices for managing configurations. `xpack.management.elasticsearch.proxy`:: From 18f1444316ff6081dfe0c37b7baaca70ec26fa98 Mon Sep 17 00:00:00 2001 From: Joao Duarte Date: Thu, 30 Apr 2020 12:37:17 +0100 Subject: [PATCH 0453/1126] RUNNER: print RUBY_DESCRIPTION at startup to facilitate debugging Often when browsing logstash logs for debugging purposes we miss the information about the Java version and platform being used. Printing the global RUBY_PLATFORM gives us all of this information plus the JRuby version as well. Fixes #11852 --- logstash-core/lib/logstash/runner.rb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/logstash-core/lib/logstash/runner.rb b/logstash-core/lib/logstash/runner.rb index 04a48b5b7..1959c09bc 100644 --- a/logstash-core/lib/logstash/runner.rb +++ b/logstash-core/lib/logstash/runner.rb @@ -381,7 +381,7 @@ class LogStash::Runner < Clamp::StrictCommand # lock path.data before starting the agent @data_path_lock = FileLockFactory.obtainLock(java.nio.file.Paths.get(setting("path.data")).to_absolute_path, ".lock") - logger.info("Starting Logstash", "logstash.version" => LOGSTASH_VERSION) + logger.info("Starting Logstash", "logstash.version" => LOGSTASH_VERSION, "jruby.version" => RUBY_DESCRIPTION) @dispatcher.fire(:before_agent) @agent = create_agent(@settings, @source_loader) From 2217e3478329344edb8522c69cc2731d8a1d1cd3 Mon Sep 17 00:00:00 2001 From: Karen Metts Date: Thu, 30 Apr 2020 15:11:02 -0400 Subject: [PATCH 0454/1126] Doc:Rename internal collection to legacy collection Fixes #11858 --- .../monitoring/monitoring-internal-legacy.asciidoc | 12 ++++++------ docs/static/monitoring/monitoring-overview.asciidoc | 4 ++-- .../settings/monitoring-settings-legacy.asciidoc | 2 +- 3 files changed, 9 insertions(+), 9 deletions(-) diff --git a/docs/static/monitoring/monitoring-internal-legacy.asciidoc b/docs/static/monitoring/monitoring-internal-legacy.asciidoc index e63ff6e3f..fb26404aa 100644 --- a/docs/static/monitoring/monitoring-internal-legacy.asciidoc +++ b/docs/static/monitoring/monitoring-internal-legacy.asciidoc @@ -1,13 +1,13 @@ [role="xpack"] [[monitoring-internal-collection-legacy]] -=== Collect {ls} monitoring data using internal collectors +=== Collect {ls} monitoring data using legacy collectors ++++ -Internal collection +Legacy collection ++++ -==== Components for internal collection +==== Components for legacy collection -Monitoring {ls} with internal collection uses these components: +Monitoring {ls} with legacy collection uses these components: * <> * <> @@ -37,9 +37,9 @@ include::monitoring-output-legacy.asciidoc[] [[configure-internal-collectors-legacy]] -==== Configure {ls} monitoring with internal collectors +==== Configure {ls} monitoring with legacy collectors ++++ -Configure internal collection +Configure legacy collection ++++ To monitor Logstash nodes: diff --git a/docs/static/monitoring/monitoring-overview.asciidoc b/docs/static/monitoring/monitoring-overview.asciidoc index cb017c2c2..e71ef4daa 100644 --- a/docs/static/monitoring/monitoring-overview.asciidoc +++ b/docs/static/monitoring/monitoring-overview.asciidoc @@ -21,8 +21,8 @@ monitoring data from your {ls} instance and sends it directly to your monitoring cluster. The benefit of Metricbeat collection is that the monitoring agent remains active even if the {ls} instance does not. -* <>. -Internal collectors send monitoring data to your production cluster. +* <>. +Legacy collectors send monitoring data to your production cluster. include::monitoring-mb.asciidoc[] include::monitoring-internal-legacy.asciidoc[] diff --git a/docs/static/settings/monitoring-settings-legacy.asciidoc b/docs/static/settings/monitoring-settings-legacy.asciidoc index c0d46975f..cbab903db 100644 --- a/docs/static/settings/monitoring-settings-legacy.asciidoc +++ b/docs/static/settings/monitoring-settings-legacy.asciidoc @@ -1,6 +1,6 @@ [role="xpack"] [[monitoring-settings-legacy]] -==== Monitoring settings for internal collection +==== Monitoring settings for legacy collection ++++ Monitoring Settings ++++ From f31d9193c34e86d965c8a0c502c2d5867dd4f3f0 Mon Sep 17 00:00:00 2001 From: Joao Duarte Date: Wed, 6 May 2020 10:23:50 +0100 Subject: [PATCH 0455/1126] bump version to 7.9.0 --- README.md | 16 ++++++++-------- versions.yml | 4 ++-- 2 files changed, 10 insertions(+), 10 deletions(-) diff --git a/README.md b/README.md index d5996bd78..cc75a3553 100644 --- a/README.md +++ b/README.md @@ -28,14 +28,14 @@ These builds are created nightly and have undergone no formal QA, so they should | [deb-complete][] | [deb-oss][] | | [rpm-complete][] | [rpm-oss][] | -[tar-complete]: https://snapshots.elastic.co/downloads/logstash/logstash-7.8.0-SNAPSHOT.tar.gz -[zip-complete]: https://snapshots.elastic.co/downloads/logstash/logstash-7.8.0-SNAPSHOT.zip -[deb-complete]: https://snapshots.elastic.co/downloads/logstash/logstash-7.8.0-SNAPSHOT.deb -[rpm-complete]: https://snapshots.elastic.co/downloads/logstash/logstash-7.8.0-SNAPSHOT.rpm -[tar-oss]: https://snapshots.elastic.co/downloads/logstash/logstash-oss-7.8.0-SNAPSHOT.tar.gz -[zip-oss]: https://snapshots.elastic.co/downloads/logstash/logstash-oss-7.8.0-SNAPSHOT.zip -[deb-oss]: https://snapshots.elastic.co/downloads/logstash/logstash-oss-7.8.0-SNAPSHOT.deb -[rpm-oss]: https://snapshots.elastic.co/downloads/logstash/logstash-oss-7.8.0-SNAPSHOT.rpm +[tar-complete]: https://snapshots.elastic.co/downloads/logstash/logstash-7.9.0-SNAPSHOT.tar.gz +[zip-complete]: https://snapshots.elastic.co/downloads/logstash/logstash-7.9.0-SNAPSHOT.zip +[deb-complete]: https://snapshots.elastic.co/downloads/logstash/logstash-7.9.0-SNAPSHOT.deb +[rpm-complete]: https://snapshots.elastic.co/downloads/logstash/logstash-7.9.0-SNAPSHOT.rpm +[tar-oss]: https://snapshots.elastic.co/downloads/logstash/logstash-oss-7.9.0-SNAPSHOT.tar.gz +[zip-oss]: https://snapshots.elastic.co/downloads/logstash/logstash-oss-7.9.0-SNAPSHOT.zip +[deb-oss]: https://snapshots.elastic.co/downloads/logstash/logstash-oss-7.9.0-SNAPSHOT.deb +[rpm-oss]: https://snapshots.elastic.co/downloads/logstash/logstash-oss-7.9.0-SNAPSHOT.rpm ## Need Help? diff --git a/versions.yml b/versions.yml index d30751f68..3f13ba807 100644 --- a/versions.yml +++ b/versions.yml @@ -1,7 +1,7 @@ --- # alpha and beta qualifiers are now added via VERSION_QUALIFIER environment var -logstash: 7.8.0 -logstash-core: 7.8.0 +logstash: 7.9.0 +logstash-core: 7.9.0 logstash-core-plugin-api: 2.1.16 # jruby must reference a *released* version of jruby which can be downloaded from the official download url From b3fd033e27d1f4788ab8e26b50ebc51964381054 Mon Sep 17 00:00:00 2001 From: Karen Metts Date: Tue, 5 May 2020 20:40:24 -0400 Subject: [PATCH 0456/1126] Doc:Expand and clarify guidance for jvm settings Change fixed heap size recommendation to a percentage. Note that large configs may require more stack space Fixes: #11605 #11842 Fixes #11867 --- docs/static/config-details.asciidoc | 52 ++++++++++++++++------ docs/static/performance-checklist.asciidoc | 18 +++++--- docs/static/setting-up-logstash.asciidoc | 2 + 3 files changed, 51 insertions(+), 21 deletions(-) diff --git a/docs/static/config-details.asciidoc b/docs/static/config-details.asciidoc index 81cdb3e1b..d64196a12 100644 --- a/docs/static/config-details.asciidoc +++ b/docs/static/config-details.asciidoc @@ -1,20 +1,25 @@ +[[jvm-settings]] +=== JVM settings + +Configure the jvm settings in the `jvm.options` <>. + [[heap-size]] -=== Setting the heap size +==== Setting the JVM heap size -Set the jvm heap size in the `jvm.options` <>. +Here are some tips for adjusting the JVM heap size: -NOTE: The recommended heap size for typical ingestion scenarios should be no +// tag::heap-size-tips[] +* The recommended heap size for typical ingestion scenarios should be no less than 4GB and no more than 8GB. -Here are some additional tips for adjusting the JVM heap size: - * CPU utilization can increase unnecessarily if the heap size is too low, resulting in the JVM constantly garbage collecting. You can check for this issue by doubling the heap size to see if performance improves. -* Do not increase the heap size past the amount of physical -memory. Leave at least 1GB free for the OS and other processes. +* Do not increase the heap size past the amount of physical memory. Some memory +must be left to run the OS and other processes. As a general guideline for most +installations, don't exceed 50-75% of physical memory. The more memory you have, +the higher percentage you can use. * Set the minimum (Xms) and maximum (Xmx) heap allocation size to the same value to prevent the heap from resizing at runtime, which is a very costly @@ -23,12 +28,31 @@ process. * You can make more accurate measurements of the JVM heap by using either the `jmap` command line utility distributed with Java or by using VisualVM. For more info, see <>. - - - - - - +// end::heap-size-tips[] + +[[stacks-size]] +==== Setting the JVM stack size + +Large configurations may require additional JVM stack memory. +If you see a stack overflow error, try increasing the JVM stack size. +Add an entry similar to this one in the `jvm.options` +<>: + +[source,sh] +----- +-Xss4M +----- + +Note that the default stack size is different per platform and per OS +flavor. You can find out what the default is by running: + +[source,sh] +----- +java -XX:+PrintFlagsFinal -version | grep ThreadStackSize +----- + +Depending on the default stack size, start by multiplying by 4x, then 8x, and +then 16x until the overflow error resolves. diff --git a/docs/static/performance-checklist.asciidoc b/docs/static/performance-checklist.asciidoc index 704c14eac..4d0824f4a 100644 --- a/docs/static/performance-checklist.asciidoc +++ b/docs/static/performance-checklist.asciidoc @@ -8,11 +8,18 @@ performance: * <> [[performance-troubleshooting]] -=== Performance Troubleshooting Guide +=== Performance Troubleshooting -You can use this troubleshooting guide to quickly diagnose and resolve Logstash performance problems. Advanced knowledge of pipeline internals is not required to understand this guide. However, the <> is recommended reading if you want to go beyond this guide. +You can use these troubleshooting tips to quickly diagnose and resolve Logstash performance problems. +Advanced knowledge of pipeline internals is not required to understand this guide. +However, the <> is recommended reading if you want to go beyond these tips. -You may be tempted to jump ahead and change settings like `pipeline.workers` (`-w`) as a first attempt to improve performance. In our experience, changing this setting makes it more difficult to troubleshoot performance problems because you increase the number of variables in play. Instead, make one change at a time and measure the results. Starting at the end of this list is a sure-fire way to create a confusing situation. +You may be tempted to jump ahead and change settings like `pipeline.workers` +(`-w`) as a first attempt to improve performance. In our experience, changing +this setting makes it more difficult to troubleshoot performance problems +because you increase the number of variables in play. Instead, make one change +at a time and measure the results. Starting at the end of this list is a +sure-fire way to create a confusing situation. [float] ==== Performance Checklist @@ -40,10 +47,7 @@ You may be tempted to jump ahead and change settings like `pipeline.workers` (`- . *Check the JVM heap:* + -* Often times CPU utilization can go through the roof if the heap size is too low, resulting in the JVM constantly garbage collecting. -* A quick way to check for this issue is to double the heap size and see if performance improves. Do not increase the heap size past the amount of physical memory. Leave at least 1GB free for the OS and other processes. -* You can make more accurate measurements of the JVM heap by using either the `jmap` command line utility distributed with Java or by using VisualVM. For more info, see <>. -* Always make sure to set the minimum (Xms) and maximum (Xmx) heap allocation size to the same value to prevent the heap from resizing at runtime, which is a very costly process. +include::config-details.asciidoc[tag=heap-size-tips] . *Tune Logstash worker settings:* + diff --git a/docs/static/setting-up-logstash.asciidoc b/docs/static/setting-up-logstash.asciidoc index 7a0ab5af0..be3f221f3 100644 --- a/docs/static/setting-up-logstash.asciidoc +++ b/docs/static/setting-up-logstash.asciidoc @@ -168,6 +168,7 @@ to standard output. Logstash has two types of configuration files: _pipeline configuration files_, which define the Logstash processing pipeline, and _settings files_, which specify options that control Logstash startup and execution. +[[pipeline-config-files]] ==== Pipeline Configuration Files You create pipeline configuration files when you define the stages of your Logstash processing pipeline. On deb and @@ -176,6 +177,7 @@ files with `.conf` extension in the `/etc/logstash/conf.d directory` and ignores See <> for more info. +[[settings-files]] ==== Settings Files The settings files are already defined in the Logstash installation. Logstash includes the following settings files: From 1cc1ce390ab74af4d4ca3a230b4458d8efe2a6c8 Mon Sep 17 00:00:00 2001 From: Karol Bucek Date: Wed, 15 Apr 2020 18:44:24 +0200 Subject: [PATCH 0457/1126] Performance: improve event.clone memory usage for Strings with copy-on-write semantics when deep cloning. motivated by "big" events reaching plugins such as split, which might produce several new events out of a single one. Fixes #11794 --- .../src/main/java/org/logstash/Cloner.java | 3 +- .../test/java/org/logstash/ClonerTest.java | 62 +++++++++++++++++-- 2 files changed, 58 insertions(+), 7 deletions(-) diff --git a/logstash-core/src/main/java/org/logstash/Cloner.java b/logstash-core/src/main/java/org/logstash/Cloner.java index 65bb2f87f..7d4b67fc5 100644 --- a/logstash-core/src/main/java/org/logstash/Cloner.java +++ b/logstash-core/src/main/java/org/logstash/Cloner.java @@ -42,7 +42,8 @@ public final class Cloner { } else if (input instanceof List) { return (T) deepList((List) input); } else if (input instanceof RubyString) { - return (T) ((RubyString) input).doClone(); + // new instance but sharing ByteList (until either String is modified) + return (T) ((RubyString) input).dup(); } else if (input instanceof Collection) { throw new ClassCastException("unexpected Collection type " + input.getClass()); } diff --git a/logstash-core/src/test/java/org/logstash/ClonerTest.java b/logstash-core/src/test/java/org/logstash/ClonerTest.java index 0522b3567..738e211b7 100644 --- a/logstash-core/src/test/java/org/logstash/ClonerTest.java +++ b/logstash-core/src/test/java/org/logstash/ClonerTest.java @@ -21,6 +21,9 @@ package org.logstash; import org.jruby.RubyString; +import org.jruby.runtime.ThreadContext; +import org.jruby.runtime.builtin.IRubyObject; +import org.jruby.util.ByteList; import org.junit.Test; import static org.junit.Assert.*; @@ -33,14 +36,61 @@ public class ClonerTest { RubyString result = Cloner.deep(original); // Check object identity - assertTrue(result != original); - - // Check different underlying bytes - assertTrue(result.getByteList() != original.getByteList()); - + assertNotSame(original, result); // Check string equality - assertEquals(result, original); + assertEquals(original, result); assertEquals(javaString, result.asJavaString()); } + + @Test + public void testRubyStringCloningAndAppend() { + String javaString = "fooBar"; + RubyString original = RubyString.newString(RubyUtil.RUBY, javaString); + + RubyString result = Cloner.deep(original); + + result.append(RubyUtil.RUBY.newString("X")); + + assertNotEquals(result, original); + + ThreadContext context = RubyUtil.RUBY.getCurrentContext(); + assertTrue(original.op_equal(context, RubyString.newString(RubyUtil.RUBY, javaString)).isTrue()); + assertEquals(javaString, original.asJavaString()); + } + + @Test + public void testRubyStringCloningAndChangeOriginal() { + String javaString = "fooBar"; + RubyString original = RubyString.newString(RubyUtil.RUBY, javaString); + + RubyString result = Cloner.deep(original); + + ThreadContext context = RubyUtil.RUBY.getCurrentContext(); + IRubyObject index = RubyUtil.RUBY.newFixnum(5); + original.op_aset(context, index, RubyUtil.RUBY.newString("z")); // original[5] = 'z' + + assertNotEquals(result, original); + + assertTrue(result.op_equal(context, RubyString.newString(RubyUtil.RUBY, javaString)).isTrue()); + assertEquals(javaString, result.asJavaString()); + assertEquals("fooBaz", original.asJavaString()); + } + + @Test // @Tag("Performance Optimization") + public void testRubyStringCloningMemoryOptimization() { + ByteList bytes = ByteList.create("0123456789"); + RubyString original = RubyString.newString(RubyUtil.RUBY, bytes); + + RubyString result = Cloner.deep(original); + assertNotSame(original, result); + + assertSame(bytes, original.getByteList()); + // NOTE: this is an implementation detail or the underlying sharing : + assertSame(bytes, result.getByteList()); // bytes-list shared + + // but when string is modified it will stop using the same byte container + result.concat(RubyUtil.RUBY.getCurrentContext(), RubyUtil.RUBY.newString(" ")); + assertNotSame(bytes, result.getByteList()); // byte-list copied on write + } } \ No newline at end of file From ecdf8715e7cf78efd8320a58036b8a2b3f5aff0c Mon Sep 17 00:00:00 2001 From: Karol Bucek Date: Wed, 6 May 2020 18:11:30 +0200 Subject: [PATCH 0458/1126] Fix: avoid gsub (frame dependent) usage from Java `RubyString#gsub` requires a (Ruby) frame to be present. The method attempts to set a backref for the current caller's frame. When the frame stack is empty there isn't really a place to set $~. This can happen when a LogStash::Util::Loggable#logger is retrieved, from the input worker thread while not being nested in any block. Fixes #11874 --- .../logstash/log/DeprecationLoggerExt.java | 11 +++- .../java/org/logstash/log/LoggableExt.java | 52 ++++++++----------- .../java/org/logstash/log/SlowLoggerExt.java | 31 ++++++++--- 3 files changed, 56 insertions(+), 38 deletions(-) diff --git a/logstash-core/src/main/java/org/logstash/log/DeprecationLoggerExt.java b/logstash-core/src/main/java/org/logstash/log/DeprecationLoggerExt.java index a410e506a..f4a926412 100644 --- a/logstash-core/src/main/java/org/logstash/log/DeprecationLoggerExt.java +++ b/logstash-core/src/main/java/org/logstash/log/DeprecationLoggerExt.java @@ -40,12 +40,21 @@ public class DeprecationLoggerExt extends RubyObject { super(runtime, metaClass); } + DeprecationLoggerExt(final Ruby runtime, final RubyClass metaClass, final String loggerName) { + super(runtime, metaClass); + initialize(loggerName); + } + @JRubyMethod public DeprecationLoggerExt initialize(final ThreadContext context, final IRubyObject loggerName) { - logger = new DefaultDeprecationLogger(loggerName.asJavaString()); + initialize(loggerName.asJavaString()); return this; } + private void initialize(final String loggerName) { + logger = new DefaultDeprecationLogger(loggerName); + } + @JRubyMethod(name = "deprecated", required = 1, optional = 1) public IRubyObject rubyDeprecated(final ThreadContext context, final IRubyObject[] args) { if (args.length > 1) { diff --git a/logstash-core/src/main/java/org/logstash/log/LoggableExt.java b/logstash-core/src/main/java/org/logstash/log/LoggableExt.java index e5e119941..a85dd7239 100644 --- a/logstash-core/src/main/java/org/logstash/log/LoggableExt.java +++ b/logstash-core/src/main/java/org/logstash/log/LoggableExt.java @@ -22,16 +22,16 @@ package org.logstash.log; import org.jruby.RubyClass; import org.jruby.RubyModule; -import org.jruby.RubyString; import org.jruby.anno.JRubyMethod; import org.jruby.anno.JRubyModule; -import org.jruby.runtime.Block; import org.jruby.runtime.ThreadContext; import org.jruby.runtime.builtin.IRubyObject; import org.jruby.runtime.builtin.InstanceVariables; import org.logstash.RubyUtil; -import static org.logstash.RubyUtil.RUBY; +import java.util.Locale; + +import static org.logstash.log.SlowLoggerExt.toLong; @JRubyModule(name = "Loggable") public final class LoggableExt { @@ -64,24 +64,18 @@ public final class LoggableExt { return self.getSingletonClass().callMethod(context, "deprecation_logger"); } - private static RubyString log4jName(final ThreadContext context, final RubyModule self) { - IRubyObject name = self.name(context); - if (name.isNil()) { - final RubyClass clazz; + private static String log4jName(final RubyModule self) { + String name; + if (self.getBaseName() == null) { // anonymous module/class + RubyModule real = self; if (self instanceof RubyClass) { - clazz = ((RubyClass) self).getRealClass(); - } else { - clazz = self.getMetaClass(); - } - name = clazz.name(context); - if (name.isNil()) { - name = clazz.to_s(); + real = ((RubyClass) self).getRealClass(); } + name = real.getName(); // for anonymous: "#" + } else { + name = self.getName(); } - return ((RubyString) ((RubyString) name).gsub( - context, RUBY.newString("::"), RUBY.newString("."), - Block.NULL_BLOCK - )).downcase(context); + return name.replace("::", ".").toLowerCase(Locale.ENGLISH); } /** @@ -105,9 +99,8 @@ public final class LoggableExt { } IRubyObject logger = instanceVariables.getInstanceVariable("logger"); if (logger == null || logger.isNil()) { - logger = RubyUtil.LOGGER.callMethod(context, "new", - LoggableExt.log4jName(context, (RubyModule) self) - ); + final String loggerName = log4jName((RubyModule) self); + logger = RubyUtil.LOGGER.callMethod(context, "new", context.runtime.newString(loggerName)); instanceVariables.setInstanceVariable("logger", logger); } return logger; @@ -117,18 +110,15 @@ public final class LoggableExt { public static SlowLoggerExt slowLogger(final ThreadContext context, final IRubyObject self, final IRubyObject[] args) { final InstanceVariables instanceVariables = self.getInstanceVariables(); - SlowLoggerExt logger = - (SlowLoggerExt) instanceVariables.getInstanceVariable("slow_logger"); + IRubyObject logger = instanceVariables.getInstanceVariable("slow_logger"); if (logger == null || logger.isNil()) { - logger = new SlowLoggerExt(context.runtime, RubyUtil.SLOW_LOGGER).initialize( - context, new IRubyObject[]{ - LoggableExt.log4jName(context, (RubyModule) self), args[0], args[1], - args[2], args[3] - } + final String loggerName = log4jName((RubyModule) self); + logger = new SlowLoggerExt(context.runtime, RubyUtil.SLOW_LOGGER, loggerName, + toLong(args[0]), toLong(args[1]), toLong(args[2]), toLong(args[3]) ); instanceVariables.setInstanceVariable("slow_logger", logger); } - return logger; + return (SlowLoggerExt) logger; } @JRubyMethod(name = "deprecation_logger", meta = true) @@ -141,8 +131,8 @@ public final class LoggableExt { } IRubyObject logger = instanceVariables.getInstanceVariable("deprecation_logger"); if (logger == null || logger.isNil()) { - logger = new DeprecationLoggerExt(context.runtime, RubyUtil.DEPRECATION_LOGGER) - .initialize(context, LoggableExt.log4jName(context, (RubyModule) self)); + final String loggerName = log4jName((RubyModule) self); + logger = new DeprecationLoggerExt(context.runtime, RubyUtil.DEPRECATION_LOGGER, loggerName); instanceVariables.setInstanceVariable("deprecation_logger", logger); } return logger; diff --git a/logstash-core/src/main/java/org/logstash/log/SlowLoggerExt.java b/logstash-core/src/main/java/org/logstash/log/SlowLoggerExt.java index 8635d62f5..21f63c730 100644 --- a/logstash-core/src/main/java/org/logstash/log/SlowLoggerExt.java +++ b/logstash-core/src/main/java/org/logstash/log/SlowLoggerExt.java @@ -55,17 +55,36 @@ public class SlowLoggerExt extends RubyObject { super(runtime, metaClass); } + SlowLoggerExt(final Ruby runtime, final RubyClass metaClass, final String loggerName, + final long warnThreshold, final long infoThreshold, + final long debugThreshold, final long traceThreshold) { + super(runtime, metaClass); + initialize(loggerName, warnThreshold, infoThreshold, debugThreshold, traceThreshold); + } + @JRubyMethod(required = 5) public SlowLoggerExt initialize(final ThreadContext context, final IRubyObject[] args) { - String loggerName = args[0].asJavaString(); - slowLogger = LogManager.getLogger("slowlog." + loggerName); - warnThreshold = ((RubyNumeric) args[1]).getLongValue(); - infoThreshold = ((RubyNumeric) args[2]).getLongValue(); - debugThreshold = ((RubyNumeric) args[3]).getLongValue(); - traceThreshold = ((RubyNumeric) args[4]).getLongValue(); + initialize(args[0].asJavaString(), toLong(args[1]), toLong(args[2]), toLong(args[3]), toLong(args[4])); return this; } + private void initialize(final String loggerName, + final long warnThreshold, final long infoThreshold, + final long debugThreshold, final long traceThreshold) { + slowLogger = LogManager.getLogger("slowlog." + loggerName); + this.warnThreshold = warnThreshold; + this.infoThreshold = infoThreshold; + this.debugThreshold = debugThreshold; + this.traceThreshold = traceThreshold; + } + + static long toLong(final IRubyObject value) { + if (!(value instanceof RubyNumeric)) { + throw RubyUtil.RUBY.newTypeError("Numeric expected, got " + value.getMetaClass()); + } + return ((RubyNumeric) value).getLongValue(); + } + private RubyHash asData(final ThreadContext context, final IRubyObject pluginParams, final IRubyObject event, final IRubyObject durationNanos) { RubyHash data = RubyHash.newHash(context.runtime); From 881099c39f05fc10f134c7a765db5ee8c79575b1 Mon Sep 17 00:00:00 2001 From: Joao Duarte Date: Mon, 11 May 2020 07:42:47 +0100 Subject: [PATCH 0459/1126] download kafka from another mirror the current mirror now refuses connections for the past 36 hours Fixes #11887 --- qa/integration/services/kafka_setup.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/qa/integration/services/kafka_setup.sh b/qa/integration/services/kafka_setup.sh index 4331599c6..e874883af 100755 --- a/qa/integration/services/kafka_setup.sh +++ b/qa/integration/services/kafka_setup.sh @@ -22,7 +22,7 @@ setup_kafka() { local version=$1 if [ ! -d $KAFKA_HOME ]; then echo "Downloading Kafka version $version" - curl -s -o $INSTALL_DIR/kafka.tgz "http://ftp.wayne.edu/apache/kafka/$version/kafka_2.11-$version.tgz" + curl -s -o $INSTALL_DIR/kafka.tgz "https://mirrors.ocf.berkeley.edu/apache/kafka/$version/kafka_2.11-$version.tgz" mkdir $KAFKA_HOME && tar xzf $INSTALL_DIR/kafka.tgz -C $KAFKA_HOME --strip-components 1 rm $INSTALL_DIR/kafka.tgz fi From 24987d4fdd9831658a3fc34dc536459ee554038f Mon Sep 17 00:00:00 2001 From: Karen Metts Date: Tue, 12 May 2020 18:03:45 -0400 Subject: [PATCH 0460/1126] Doc:Add deprecation notice for azure module --- docs/static/azure-module.asciidoc | 12 ++++++------ docs/static/modules.asciidoc | 2 +- 2 files changed, 7 insertions(+), 7 deletions(-) diff --git a/docs/static/azure-module.asciidoc b/docs/static/azure-module.asciidoc index ed91fa8c1..14c9caea3 100644 --- a/docs/static/azure-module.asciidoc +++ b/docs/static/azure-module.asciidoc @@ -3,6 +3,12 @@ === Azure Module experimental[] +++++ +Azure Module (deprecated) +++++ + +deprecated[7.8.0, "We recommend using the Azure modules in {filebeat-ref}/filebeat-module-azure.html[{Filebeat}] and {metricbeat-ref}/metricbeat-module-azure.html[{metricbeat}], which are compliant with the {ecs-ref}/index.html[Elastic Common Schema (ECS)]"] + The https://azure.microsoft.com/en-us/overview/what-is-azure/[Microsoft Azure] module in Logstash helps you easily integrate your Azure activity logs and SQL diagnostic logs with the Elastic Stack. @@ -19,12 +25,6 @@ and decreasing overall time to resolution. The Azure module helps you: * Perform root-cause analysis by investigating user activity * Monitor and optimize your SQL DB deployments. -NOTE: The Logstash Azure module is an -https://www.elastic.co/products/x-pack[{xpack}] feature under the Basic License -and is therefore free to use. Please contact -mailto:monitor-azure@elastic.co[monitor-azure@elastic.co] for questions or more -information. - The Azure module uses the {logstash-ref}/plugins-inputs-azure_event_hubs.html[Logstash Azure Event Hubs input plugin] to consume data from Azure Event Hubs. The module taps directly into the diff --git a/docs/static/modules.asciidoc b/docs/static/modules.asciidoc index a9827d5bf..06824779d 100644 --- a/docs/static/modules.asciidoc +++ b/docs/static/modules.asciidoc @@ -9,7 +9,7 @@ These modules are available: * <> * <> * <> -* <> +* <> Each module comes pre-packaged with Logstash configurations, Kibana dashboards, and other meta files that make it easier for you to set up the Elastic Stack for From 1c4df35e0cff853e7e05d930078ac3e4edd4d94a Mon Sep 17 00:00:00 2001 From: Karen Metts Date: Thu, 7 May 2020 16:53:22 -0400 Subject: [PATCH 0461/1126] Doc:Replace cloud trial notice with attribute Replaces free text with an attribute that pulls in shared content to keep content up-to-date and consistent across documents. --- docs/static/advanced-pipeline.asciidoc | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/docs/static/advanced-pipeline.asciidoc b/docs/static/advanced-pipeline.asciidoc index a83edde05..63668aa0e 100644 --- a/docs/static/advanced-pipeline.asciidoc +++ b/docs/static/advanced-pipeline.asciidoc @@ -414,10 +414,7 @@ Notice that the event now contains geographic location information: Now that the web logs are broken down into specific fields, you're ready to get your data into Elasticsearch. -TIP: You can run Elasticsearch on your own hardware, or use our -https://www.elastic.co/cloud/elasticsearch-service[hosted {es} Service] on -Elastic Cloud. The Elasticsearch Service is available on both AWS and GCP. -{ess-trial}[Try the {es} Service for free]. +TIP: {ess-leadin} The Logstash pipeline can index the data into an Elasticsearch cluster. Edit the `first-pipeline.conf` file and replace the entire `output` section with the following From ffcba6faf9dc0ff56487307ae3ab6e7cf3102f25 Mon Sep 17 00:00:00 2001 From: Rob Bavey Date: Tue, 19 May 2020 09:47:10 -0400 Subject: [PATCH 0462/1126] Quieten down kafka teardown script Kafka teardown script can exit with failure, typically when trying to stop the broker. This commit logs the error code if the scripts fail rather than crash out causing build failure. Fixes #11905 --- qa/integration/services/kafka_teardown.sh | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/qa/integration/services/kafka_teardown.sh b/qa/integration/services/kafka_teardown.sh index 0d10cffe8..10c1806ca 100755 --- a/qa/integration/services/kafka_teardown.sh +++ b/qa/integration/services/kafka_teardown.sh @@ -8,14 +8,17 @@ KAFKA_HOME=$INSTALL_DIR/kafka stop_kafka() { echo "Stopping Kafka broker" - $KAFKA_HOME/bin/kafka-server-stop.sh + $KAFKA_HOME/bin/kafka-server-stop.sh || EXIT=$? + echo "Kafka broker stopped with exit code $EXIT" echo "Stopping zookeeper" - $KAFKA_HOME/bin/zookeeper-server-stop.sh + $KAFKA_HOME/bin/zookeeper-server-stop.sh || EXIT=$? + echo "Zookeeper stopped with exit code $EXIT" } # delete test topic echo "Deleting test topic in Kafka" -$KAFKA_HOME/bin/kafka-topics.sh --delete --topic logstash_topic_plain --zookeeper localhost:2181 --if-exists +$KAFKA_HOME/bin/kafka-topics.sh --delete --topic logstash_topic_plain --zookeeper localhost:2181 --if-exists || EXIT=$? +echo "Deleted test topic in Kafka with exit code $EXIT" stop_kafka rm -rf /tmp/ls_integration/kafka-logs rm -rf /tmp/zookeeper From 84dd62a0a1d11eea94d4220c64cc005f1597037e Mon Sep 17 00:00:00 2001 From: Rob Bavey Date: Tue, 26 May 2020 11:07:56 -0400 Subject: [PATCH 0463/1126] Ignore flaky `testTimeCallable` test Flaky test issue #11925 --- .../java/org/logstash/plugins/NamespacedMetricImplTest.java | 2 ++ 1 file changed, 2 insertions(+) diff --git a/logstash-core/src/test/java/org/logstash/plugins/NamespacedMetricImplTest.java b/logstash-core/src/test/java/org/logstash/plugins/NamespacedMetricImplTest.java index 9f16d1524..8c506b6c4 100644 --- a/logstash-core/src/test/java/org/logstash/plugins/NamespacedMetricImplTest.java +++ b/logstash-core/src/test/java/org/logstash/plugins/NamespacedMetricImplTest.java @@ -24,6 +24,7 @@ import co.elastic.logstash.api.Metric; import co.elastic.logstash.api.NamespacedMetric; import org.assertj.core.data.Percentage; import org.jruby.RubyHash; +import org.junit.Ignore; import org.junit.Test; import static org.assertj.core.api.Assertions.assertThat; @@ -80,6 +81,7 @@ public class NamespacedMetricImplTest extends MetricTestCase { } } + @Ignore("Test failing intermittently for some time. See https://github.com/elastic/logstash/issues/11925") @Test public void testTimeCallable() { final NamespacedMetric metrics = this.getInstance().namespace("test"); From c5b6a853d6d2099b0d983be7fcac0a6b5522a231 Mon Sep 17 00:00:00 2001 From: Andrea Selva Date: Wed, 27 May 2020 16:48:39 +0200 Subject: [PATCH 0464/1126] Introduced JDK environment variable to explicitly pass the JAVA_HOME to use and defined .ci/ with OS and JDK preferences (#11934) --- ...atrix-unix-compatibility-linux-distros.yml | 28 +++++++++++++++++++ .ci/matrix-unix-linux-distros.yml | 9 ++++++ .ci/matrix-unix-runtime-javas.yml | 8 +----- .ci/matrix-windows-compatibility-versions.yml | 10 +++++++ .ci/matrix-windows-runtime-javas.yml | 1 + ci/acceptance_tests.sh | 2 +- ci/docker_run.sh | 8 +++++- ci/integration_tests.sh | 6 +++- ci/unit_tests.bat | 9 ++++-- ci/unit_tests.sh | 6 +++- qa/integration/services/logstash_service.rb | 8 ++++-- x-pack/ci/docker_integration_tests.sh | 2 -- x-pack/ci/docker_unit_tests.sh | 1 - x-pack/ci/integration_tests.sh | 6 +++- x-pack/ci/unit_tests.sh | 6 +++- 15 files changed, 90 insertions(+), 20 deletions(-) create mode 100644 .ci/matrix-unix-compatibility-linux-distros.yml create mode 100644 .ci/matrix-unix-linux-distros.yml create mode 100644 .ci/matrix-windows-compatibility-versions.yml diff --git a/.ci/matrix-unix-compatibility-linux-distros.yml b/.ci/matrix-unix-compatibility-linux-distros.yml new file mode 100644 index 000000000..eeb68ab09 --- /dev/null +++ b/.ci/matrix-unix-compatibility-linux-distros.yml @@ -0,0 +1,28 @@ +# This file is used as part of a matrix build in Jenkins where the +# values below are included as an axis of the matrix. + +# This axis of the build matrix represents the Linux distributions on +# which Logstash will be tested. + +#os: +# - amazon +# - centos-6&&immutable +# - centos-7&&immutable +# - debian-8&&immutable +# - debian-9&&immutable +# - debian-10&&immutable +# - fedora-29&&immutable +# - opensuse-15-1&&immutable +# - oraclelinux-6&&immutable +# - oraclelinux-7&&immutable +# - ubuntu-18.04&&immutable +# - ubuntu-20.04&&immutable + +os: + - amazon + - centos&&immutable + - debian&&immutable + - fedora-29&&immutable + - opensuse-15-1&&immutable + - oraclelinux&&immutable + - ubuntu&&immutable diff --git a/.ci/matrix-unix-linux-distros.yml b/.ci/matrix-unix-linux-distros.yml new file mode 100644 index 000000000..fdfb75dea --- /dev/null +++ b/.ci/matrix-unix-linux-distros.yml @@ -0,0 +1,9 @@ +# This file is used as part of a matrix build in Jenkins where the +# values below are included as an axis of the matrix. + +# This axis of the build matrix represents the Linux distributions on +# which Logstash will be tested. + +os: + - centos-7&&immutable + - ubuntu-18.04&&immutable \ No newline at end of file diff --git a/.ci/matrix-unix-runtime-javas.yml b/.ci/matrix-unix-runtime-javas.yml index 1857ed9bc..d97c9d82b 100644 --- a/.ci/matrix-unix-runtime-javas.yml +++ b/.ci/matrix-unix-runtime-javas.yml @@ -6,13 +6,7 @@ # or 'openjdk' followed by the major release number. LS_RUNTIME_JAVA: -# - java8 -# - zulu8 -# - adoptopenjdk8 -# - java11 - openjdk11 - adoptopenjdk11 - - zulu11 - openjdk14 - - adoptopenjdk14 - - zulu14 \ No newline at end of file + - adoptopenjdk14 \ No newline at end of file diff --git a/.ci/matrix-windows-compatibility-versions.yml b/.ci/matrix-windows-compatibility-versions.yml new file mode 100644 index 000000000..b3b9f3585 --- /dev/null +++ b/.ci/matrix-windows-compatibility-versions.yml @@ -0,0 +1,10 @@ +# This file is used as part of a matrix build in Jenkins where the +# values below are included as an axis of the matrix. + +# This axis of the build matrix represents the Linux distributions on +# which Logstash will be tested. + +nodes: + - "windows-2012-r2" + - "windows-2016" + - "windows-2019" diff --git a/.ci/matrix-windows-runtime-javas.yml b/.ci/matrix-windows-runtime-javas.yml index 2a3fc7388..63b11fef2 100644 --- a/.ci/matrix-windows-runtime-javas.yml +++ b/.ci/matrix-windows-runtime-javas.yml @@ -9,4 +9,5 @@ LS_RUNTIME_JAVA: # - zulu8 # - adoptopenjdk8 - zulu11 + - zulu14 # - adoptopenjdk11 diff --git a/ci/acceptance_tests.sh b/ci/acceptance_tests.sh index 67bd1af28..acb556626 100755 --- a/ci/acceptance_tests.sh +++ b/ci/acceptance_tests.sh @@ -6,7 +6,7 @@ set -x # uses at least 1g of memory, If we don't do this we can get OOM issues when # installing gems. See https://github.com/elastic/logstash/issues/5179 export JRUBY_OPTS="-J-Xmx1g" -export GRADLE_OPTS="-Xmx2g -Dorg.gradle.daemon=false -Dorg.gradle.logging.level=info -Dfile.encoding=UTF-8" +export GRADLE_OPTS="-Xmx4g -Dorg.gradle.daemon=false -Dorg.gradle.logging.level=info -Dfile.encoding=UTF-8" export OSS=true SELECTED_TEST_SUITE=$1 diff --git a/ci/docker_run.sh b/ci/docker_run.sh index 4963cc05a..f3c088c1c 100755 --- a/ci/docker_run.sh +++ b/ci/docker_run.sh @@ -6,6 +6,7 @@ set -x # We want verbosity here, this mostly runs on CI and we want to easily de #Note - ensure that the -e flag is NOT set, and explicitly check the $? status to allow for clean up REMOVE_IMAGE=false +DOCKER_EXTERNAL_JDK="" if [ -z "$branch_specifier" ]; then # manual REMOVE_IMAGE=true @@ -33,8 +34,13 @@ cleanup() { } trap cleanup EXIT +if [ -n "$JDK" ]; then + echo "JDK to use $JDK" + DOCKER_EXTERNAL_JDK="--mount type=bind,source=$JDK,target=$JDK,readonly --env BUILD_JAVA_HOME=$JDK" +fi + # Run the command, skip the first argument, which is the image name -docker run $DOCKER_ENV_OPTS --cidfile=docker_cid --sig-proxy=true --rm $IMAGE_NAME ${@:2} +docker run $DOCKER_ENV_OPTS --cidfile=docker_cid --sig-proxy=true $DOCKER_EXTERNAL_JDK --rm $IMAGE_NAME ${@:2} exit_code=$? # Remove the container cid since we ran cleanly, no need to force rm it if we got to this point diff --git a/ci/integration_tests.sh b/ci/integration_tests.sh index 4954d4420..5d6576022 100755 --- a/ci/integration_tests.sh +++ b/ci/integration_tests.sh @@ -5,12 +5,16 @@ # uses at least 1g of memory, If we don't do this we can get OOM issues when # installing gems. See https://github.com/elastic/logstash/issues/5179 export JRUBY_OPTS="-J-Xmx1g" -export GRADLE_OPTS="-Xmx2g -Dorg.gradle.daemon=false -Dorg.gradle.logging.level=info -Dfile.encoding=UTF-8" +export GRADLE_OPTS="-Xmx4g -Dorg.gradle.jvmargs=-Xmx4g -Dorg.gradle.daemon=false -Dorg.gradle.logging.level=info -Dfile.encoding=UTF-8" export SPEC_OPTS="--order rand --format documentation" export CI=true export OSS=true +if [ -n "$BUILD_JAVA_HOME" ]; then + GRADLE_OPTS="$GRADLE_OPTS -Dorg.gradle.java.home=$BUILD_JAVA_HOME" +fi + if [[ $1 = "setup" ]]; then echo "Setup only, no tests will be run" exit 0 diff --git a/ci/unit_tests.bat b/ci/unit_tests.bat index f9c9f5481..5d7858657 100644 --- a/ci/unit_tests.bat +++ b/ci/unit_tests.bat @@ -40,9 +40,14 @@ echo Using drive !use_drive! for %WORKSPACE% !use_drive! echo Running core tests.. -if "%BUILD_JAVA_HOME%" == "" ( - GRADLE_OPTS="%GRADLE_OPTS% -Dorg.gradle.java.home=%BUILD_JAVA_HOME%" +if defined BUILD_JAVA_HOME ( + if defined GRADLE_OPTS ( + set GRADLE_OPTS=%GRADLE_OPTS% -Dorg.gradle.java.home=%BUILD_JAVA_HOME% + ) else ( + set GRADLE_OPTS=-Dorg.gradle.java.home=%BUILD_JAVA_HOME% + ) ) +echo Invoking Gradle, GRADLE_OPTS: %GRADLE_OPTS%, BUILD_JAVA_HOME: %BUILD_JAVA_HOME% call .\gradlew.bat test --console=plain --no-daemon --info if errorlevel 1 ( diff --git a/ci/unit_tests.sh b/ci/unit_tests.sh index 113d544d6..5968dd7d4 100755 --- a/ci/unit_tests.sh +++ b/ci/unit_tests.sh @@ -5,13 +5,17 @@ # uses at least 1g of memory, If we don't do this we can get OOM issues when # installing gems. See https://github.com/elastic/logstash/issues/5179 export JRUBY_OPTS="-J-Xmx1g" -export GRADLE_OPTS="-Xmx2g -Dorg.gradle.daemon=false -Dorg.gradle.logging.level=info -Dfile.encoding=UTF-8" +export GRADLE_OPTS="-Xmx4g -Dorg.gradle.jvmargs=-Xmx4g -Dorg.gradle.daemon=false -Dorg.gradle.logging.level=info -Dfile.encoding=UTF-8" export SPEC_OPTS="--order rand --format documentation" export CI=true export OSS=true export TEST_DEBUG=true +if [ -n "$BUILD_JAVA_HOME" ]; then + GRADLE_OPTS="$GRADLE_OPTS -Dorg.gradle.java.home=$BUILD_JAVA_HOME" +fi + SELECTED_TEST_SUITE=$1 if [[ $SELECTED_TEST_SUITE == $"java" ]]; then diff --git a/qa/integration/services/logstash_service.rb b/qa/integration/services/logstash_service.rb index 33539b7f3..630822916 100644 --- a/qa/integration/services/logstash_service.rb +++ b/qa/integration/services/logstash_service.rb @@ -118,9 +118,11 @@ class LogstashService < Service # pipe STDOUT and STDERR to a file @process.io.stdout = @process.io.stderr = out @process.duplex = true + java_home = java.lang.System.getProperty('java.home') + @process.environment['JAVA_HOME'] = java_home @process.start wait_for_logstash - puts "Logstash started with PID #{@process.pid}" if alive? + puts "Logstash started with PID #{@process.pid}, JAVA_HOME: #{java_home}" if alive? end end @@ -135,9 +137,11 @@ class LogstashService < Service Bundler.with_clean_env do @process = build_child_process(*args) @env_variables.map { |k, v| @process.environment[k] = v} unless @env_variables.nil? + java_home = java.lang.System.getProperty('java.home') + @process.environment['JAVA_HOME'] = java_home @process.io.inherit! @process.start - puts "Logstash started with PID #{@process.pid}" if @process.alive? + puts "Logstash started with PID #{@process.pid}, JAVA_HOME: #{java_home}" if @process.alive? end end diff --git a/x-pack/ci/docker_integration_tests.sh b/x-pack/ci/docker_integration_tests.sh index 479154337..fdb084a71 100755 --- a/x-pack/ci/docker_integration_tests.sh +++ b/x-pack/ci/docker_integration_tests.sh @@ -3,9 +3,7 @@ # 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. - if [ -n "${ELASTICSEARCH_SNAPSHOT_URL}" ]; then export DOCKER_ENV_OPTS="${DOCKER_ENV_OPTS} --env ELASTICSEARCH_SNAPSHOT_URL=${ELASTICSEARCH_SNAPSHOT_URL}" fi - ci/docker_run.sh logstash-xpack-integration-tests x-pack/ci/integration_tests.sh $@ diff --git a/x-pack/ci/docker_unit_tests.sh b/x-pack/ci/docker_unit_tests.sh index 74ed9dc3e..f76b645ce 100755 --- a/x-pack/ci/docker_unit_tests.sh +++ b/x-pack/ci/docker_unit_tests.sh @@ -3,5 +3,4 @@ # 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. - ci/docker_run.sh logstash-xpack-unit-tests x-pack/ci/unit_tests.sh $@ diff --git a/x-pack/ci/integration_tests.sh b/x-pack/ci/integration_tests.sh index 79e616b77..e85c89504 100755 --- a/x-pack/ci/integration_tests.sh +++ b/x-pack/ci/integration_tests.sh @@ -9,7 +9,11 @@ # uses at least 1g of memory, If we don't do this we can get OOM issues when # installing gems. See https://github.com/elastic/logstash/issues/5179 export JRUBY_OPTS="-J-Xmx1g" -export GRADLE_OPTS="-Xmx2g -Dorg.gradle.daemon=false -Dorg.gradle.logging.level=info" +export GRADLE_OPTS="-Xmx4g -Dorg.gradle.jvmargs=-Xmx4g -Dorg.gradle.daemon=false -Dorg.gradle.logging.level=info" export CI=true +if [ -n "$BUILD_JAVA_HOME" ]; then + GRADLE_OPTS="$GRADLE_OPTS -Dorg.gradle.java.home=$BUILD_JAVA_HOME" +fi + ./gradlew runXPackIntegrationTests \ No newline at end of file diff --git a/x-pack/ci/unit_tests.sh b/x-pack/ci/unit_tests.sh index 182f0138b..8ac523c4a 100755 --- a/x-pack/ci/unit_tests.sh +++ b/x-pack/ci/unit_tests.sh @@ -9,7 +9,11 @@ # uses at least 1g of memory, If we don't do this we can get OOM issues when # installing gems. See https://github.com/elastic/logstash/issues/5179 export JRUBY_OPTS="-J-Xmx1g" -export GRADLE_OPTS="-Xmx2g -Dorg.gradle.daemon=false -Dorg.gradle.logging.level=info" +export GRADLE_OPTS="-Xmx4g -Dorg.gradle.jvmargs=-Xmx4g -Dorg.gradle.daemon=false -Dorg.gradle.logging.level=info" export CI=true +if [ -n "$BUILD_JAVA_HOME" ]; then + GRADLE_OPTS="$GRADLE_OPTS -Dorg.gradle.java.home=$BUILD_JAVA_HOME" +fi + ./gradlew runXPackUnitTests \ No newline at end of file From aeb46de6cc86b5b9f66c12aea1fd617411e23de6 Mon Sep 17 00:00:00 2001 From: Joao Duarte Date: Thu, 28 May 2020 16:40:15 +0100 Subject: [PATCH 0465/1126] emit deprecation entry for netflow and azure modules point users towards the beats modules instead --- logstash-core/lib/logstash/modules/logstash_config.rb | 1 + modules/netflow/configuration/logstash/netflow.conf.erb | 1 + x-pack/modules/azure/configuration/logstash/azure.conf.erb | 1 + 3 files changed, 3 insertions(+) diff --git a/logstash-core/lib/logstash/modules/logstash_config.rb b/logstash-core/lib/logstash/modules/logstash_config.rb index b7bd34fca..02fae5253 100644 --- a/logstash-core/lib/logstash/modules/logstash_config.rb +++ b/logstash-core/lib/logstash/modules/logstash_config.rb @@ -19,6 +19,7 @@ require_relative "file_reader" require "logstash/settings" module LogStash module Modules class LogStashConfig + include LogStash::Util::Loggable # We name it `modul` here because `module` has meaning in Ruby. def initialize(modul, settings) @directory = ::File.join(modul.directory, "logstash") diff --git a/modules/netflow/configuration/logstash/netflow.conf.erb b/modules/netflow/configuration/logstash/netflow.conf.erb index 69772e7b1..cc8c57583 100644 --- a/modules/netflow/configuration/logstash/netflow.conf.erb +++ b/modules/netflow/configuration/logstash/netflow.conf.erb @@ -15,6 +15,7 @@ # specific language governing permissions and limitations # under the License. +<% deprecation_logger.deprecated("The Netflow module has been deprecated in favor of the Beats Netflow module and may be removed in a future release. Learn more about the Beats Netflow module at https://www.elastic.co/guide/en/beats/filebeat/master/filebeat-module-netflow.html") %> input { udp { type => "netflow" diff --git a/x-pack/modules/azure/configuration/logstash/azure.conf.erb b/x-pack/modules/azure/configuration/logstash/azure.conf.erb index a762198b0..a612050d2 100644 --- a/x-pack/modules/azure/configuration/logstash/azure.conf.erb +++ b/x-pack/modules/azure/configuration/logstash/azure.conf.erb @@ -4,6 +4,7 @@ input{ <%= +deprecation_logger.deprecated("The Azure module has been deprecated in favor of the Beats Azure module, and may be removed in a future release. Learn more about the Beats Azure module at https://www.elastic.co/guide/en/beats/filebeat/master/filebeat-module-azure.html") require 'azure_module_config_generator' config_generator = LogStash::Azure::ConfigGenerator.new config_generator.generate_input(@settings) From b2da4449a57ffbd261fbd8a3a304c01acd523d1b Mon Sep 17 00:00:00 2001 From: Rob Bavey Date: Fri, 29 May 2020 11:52:01 -0400 Subject: [PATCH 0466/1126] Use task avoidance API in gradle scripts (#11914) (#11943) * Use task avoidance API in gradle scripts This commit uses the task avoidance api (tasks.register vs task.create/ task DSL), as recommended since Gradle 5.1 This should reduce the execution of unnecessary tasks in build jobs, and hopefully improve build resiliency and execution time. --- build.gradle | 68 +++++++++++++++++---------- logstash-core/benchmarks/build.gradle | 4 +- logstash-core/build.gradle | 17 ++++--- qa/integration/build.gradle | 2 +- rubyUtils.gradle | 13 +++-- x-pack/build.gradle | 4 +- 6 files changed, 66 insertions(+), 42 deletions(-) diff --git a/build.gradle b/build.gradle index 2f6fefb6c..f5ee79650 100644 --- a/build.gradle +++ b/build.gradle @@ -148,39 +148,45 @@ def assemblyDeps = [downloadAndInstallJRuby, assemble] + subprojects.collect { it.tasks.findByName("assemble") } -task installBundler(dependsOn: assemblyDeps) { - outputs.files file("${projectDir}/vendor/bundle/jruby/2.5.0/bin/bundle") - doLast { +tasks.register("installBundler") { + dependsOn assemblyDeps + outputs.files file("${projectDir}/vendor/bundle/jruby/2.5.0/bin/bundle") + doLast { gem(projectDir, buildDir, "bundler", "1.17.3", "${projectDir}/vendor/bundle/jruby/2.5.0") } } -task bootstrap(dependsOn: installBundler) { - doLast { +tasks.register("bootstrap"){ + dependsOn installBundler + doLast { setupJruby(projectDir, buildDir) } } -task installDefaultGems(dependsOn: bootstrap) { +tasks.register("installDefaultGems") { + dependsOn bootstrap doLast { rake(projectDir, buildDir, 'plugin:install-default') } } -task installTestGems(dependsOn: bootstrap) { - doLast { +tasks.register("installTestGems") { + dependsOn bootstrap + doLast { rake(projectDir, buildDir, 'plugin:install-development-dependencies') } } -task compileGrammar(dependsOn: bootstrap) { +tasks.register("compileGrammar") { + dependsOn bootstrap doLast { rake(projectDir, buildDir, 'compile:grammar') } } -task assembleTarDistribution(dependsOn: bootstrap) { +tasks.register("assembleTarDistribution") { + dependsOn bootstrap inputs.files fileTree("${projectDir}/rakelib") inputs.files fileTree("${projectDir}/bin") inputs.files fileTree("${projectDir}/config") @@ -196,7 +202,8 @@ task assembleTarDistribution(dependsOn: bootstrap) { } } -task assembleOssTarDistribution(dependsOn: bootstrap) { +tasks.register("assembleOssTarDistribution") { + dependsOn bootstrap inputs.files fileTree("${projectDir}/rakelib") inputs.files fileTree("${projectDir}/bin") inputs.files fileTree("${projectDir}/config") @@ -210,7 +217,8 @@ task assembleOssTarDistribution(dependsOn: bootstrap) { } } -task assembleZipDistribution(dependsOn: bootstrap) { +tasks.register("assembleZipDistribution") { + dependsOn bootstrap inputs.files fileTree("${projectDir}/rakelib") inputs.files fileTree("${projectDir}/bin") inputs.files fileTree("${projectDir}/config") @@ -226,7 +234,8 @@ task assembleZipDistribution(dependsOn: bootstrap) { } } -task assembleOssZipDistribution(dependsOn: bootstrap) { +tasks.register("assembleOssZipDistribution") { + dependsOn bootstrap inputs.files fileTree("${projectDir}/rakelib") inputs.files fileTree("${projectDir}/bin") inputs.files fileTree("${projectDir}/config") @@ -252,7 +261,8 @@ project(":logstash-core") { def logstashBuildDir = "${buildDir}/logstash-${project.version}-SNAPSHOT" -task unpackTarDistribution(dependsOn: assembleTarDistribution, type: Copy) { +tasks.register("unpackTarDistribution", Copy) { + dependsOn assembleTarDistribution def tar = file("${buildDir}/logstash-${project.version}-SNAPSHOT.tar.gz") inputs.files tar outputs.files fileTree(logstashBuildDir) @@ -264,14 +274,16 @@ def qaVendorPath = "${buildDir}/qa/integration/vendor" def qaBundledGemPath = "${qaVendorPath}/jruby/2.5.0" def qaBundleBin = "${qaBundledGemPath}/bin/bundle" -task installIntegrationTestBundler(dependsOn: unpackTarDistribution) { - outputs.files fileTree("${qaBundledGemPath}/gems/bundler-1.17.3") +tasks.register("installIntegrationTestBundler"){ + dependsOn unpackTarDistribution + outputs.files fileTree("${qaBundledGemPath}/gems/bundler-1.17.3") doLast { gem(projectDir, buildDir, "bundler", "1.17.3", qaBundledGemPath) } } -task installIntegrationTestGems(dependsOn: installIntegrationTestBundler) { +tasks.register("installIntegrationTestGems") { + dependsOn installIntegrationTestBundler inputs.files file("${projectDir}/qa/integration/Gemfile") inputs.files file("${projectDir}/qa/integration/integration_tests.gemspec") inputs.files file("${logstashBuildDir}/Gemfile") @@ -300,11 +312,13 @@ project(":logstash-integration-tests") { } } -task runIntegrationTests(dependsOn: [tasks.getByPath(":logstash-integration-tests:integrationTests")]) {} +tasks.register("runIntegrationTests"){ + dependsOn tasks.getByPath(":logstash-integration-tests:integrationTests") +} -task generateLicenseReport(type: JavaExec) { - dependsOn("generateLicenseReportInputs") - dependsOn(":dependencies-report:assemble") +tasks.register("generateLicenseReport", JavaExec) { + dependsOn generateLicenseReportInputs + dependsOn ":dependencies-report:assemble" def jarFile = project('dependencies-report').getBuildDir().toString() + "/libs/dependencies-report.jar" @@ -319,7 +333,7 @@ task generateLicenseReport(type: JavaExec) { licenseReportOutputCSV, noticePath } -task generateLicenseReportInputs() { +tasks.register("generateLicenseReportInputs") { dependsOn subprojects.generateLicenseReport // write location of all license reports for subprojects containing artifacts that are distributed to single file @@ -342,7 +356,8 @@ task generateLicenseReportInputs() { } } -task generatePluginsVersion(dependsOn: installDefaultGems) { +tasks.register("generatePluginsVersion") { + dependsOn installDefaultGems doLast { rake(projectDir, buildDir, 'generate_plugins_version') } @@ -355,7 +370,7 @@ check.dependsOn runIntegrationTests String artifactsVersionApi = "https://artifacts-api.elastic.co/v1/versions/" -task downloadEs(type: Download) { +tasks.register("downloadEs", Download) { description "Download ES Snapshot for current branch version: ${version}" doFirst { @@ -425,11 +440,12 @@ task downloadEs(type: Download) { } } -task deleteLocalEs(type: Delete) { +tasks.register("deleteLocalEs", Delete) { delete ('./build/elasticsearch') } -task copyEs(type: Copy, dependsOn: [downloadEs, deleteLocalEs]) { +tasks.register("copyEs", Copy){ + dependsOn = [downloadEs, deleteLocalEs] from tarTree(resources.gzip(project.ext.elasticsearchDownloadLocation)) into "./build/" doLast { diff --git a/logstash-core/benchmarks/build.gradle b/logstash-core/benchmarks/build.gradle index 71d816023..3c4977960 100644 --- a/logstash-core/benchmarks/build.gradle +++ b/logstash-core/benchmarks/build.gradle @@ -76,7 +76,9 @@ shadowJar { archiveVersion = '' } -task jmh(type: JavaExec, dependsOn: [':logstash-core-benchmarks:clean', ':logstash-core-benchmarks:shadowJar']) { +tasks.register("jmh", JavaExec) { + + dependsOn=[':logstash-core-benchmarks:clean', ':logstash-core-benchmarks:shadowJar'] main = "-jar" diff --git a/logstash-core/build.gradle b/logstash-core/build.gradle index 61fe4e062..bc16ae1ca 100644 --- a/logstash-core/build.gradle +++ b/logstash-core/build.gradle @@ -43,31 +43,34 @@ buildscript { } } -task sourcesJar(type: Jar, dependsOn: classes) { +tasks.register("sourcesJar", Jar) { + dependsOn classes from sourceSets.main.allSource archiveClassifier = 'sources' archiveExtension = 'jar' } -task javadocJar(type: Jar, dependsOn: javadoc) { +tasks.register("javadocJar", Jar) { + dependsOn javadoc from javadoc.destinationDir archiveClassifier = 'javadoc' archiveExtension = 'jar' } -task copyRuntimeLibs(type: Copy) { +tasks.register("copyRuntimeLibs", Copy) { into project.file('lib/jars/') from configurations.compileClasspath, configurations.runtimeClasspath } // copy jar file into the gem lib dir but without the version number in filename -task copyGemjar(type: Copy, dependsOn: [sourcesJar, copyRuntimeLibs]) { +tasks.register("copyGemjar", Copy) { + dependsOn=[sourcesJar, copyRuntimeLibs] from project.jar into project.file('lib/jars/') rename(/(.+)-${project.version}.jar/, '$1.jar') } -task cleanGemjar { +tasks.register("cleanGemjar") { delete fileTree(project.file('lib/jars/')) { include '*.jar' } @@ -84,7 +87,7 @@ configurations.archives { extendsFrom configurations.javadoc } -task javaTests(type: Test) { +tasks.register("javaTests", Test) { exclude '/org/logstash/RSpecTests.class' exclude '/org/logstash/config/ir/ConfigCompilerTest.class' exclude '/org/logstash/config/ir/CompiledPipelineTest.class' @@ -96,7 +99,7 @@ task javaTests(type: Test) { exclude '/org/logstash/plugins/PluginFactoryExtTest.class' } -task rubyTests(type: Test) { +tasks.register("rubyTests", Test) { inputs.files fileTree("${projectDir}/lib") inputs.files fileTree("${projectDir}/spec") systemProperty 'logstash.core.root.dir', projectDir.absolutePath diff --git a/qa/integration/build.gradle b/qa/integration/build.gradle index 451d11983..bb618804b 100644 --- a/qa/integration/build.gradle +++ b/qa/integration/build.gradle @@ -39,7 +39,7 @@ test { exclude '/**' } -task integrationTests(type: Test) { +tasks.register("integrationTests", Test) { inputs.files fileTree("${projectDir}/services") inputs.files fileTree("${projectDir}/framework") inputs.files fileTree("${projectDir}/fixtures") diff --git a/rubyUtils.gradle b/rubyUtils.gradle index 8d00fc2cd..b6ff3f11f 100644 --- a/rubyUtils.gradle +++ b/rubyUtils.gradle @@ -208,7 +208,7 @@ def customJRubyDir = project.hasProperty("custom.jruby.path") ? project.property def customJRubyVersion = customJRubyDir == "" ? "" : Files.readAllLines(Paths.get(customJRubyDir, "VERSION")).get(0).trim() def customJRubyTar = customJRubyDir == "" ? "" : (customJRubyDir + "/maven/jruby-dist/target/jruby-dist-${customJRubyVersion}-bin.tar.gz") -task downloadJRuby(type: Download) { +tasks.register("downloadJRuby", Download) { description "Download JRuby artifact from this specific URL: ${jRubyURL}" src jRubyURL onlyIfNewer true @@ -219,7 +219,8 @@ task downloadJRuby(type: Download) { downloadJRuby.onlyIf { customJRubyDir == "" } -task verifyFile(dependsOn: downloadJRuby, type: Verify) { +tasks.register("verifyFile", Verify) { + dependsOn downloadJRuby description "Verify the SHA1 of the download JRuby artifact" inputs.file(jrubyTarPath) outputs.file(jrubyTarPath) @@ -231,7 +232,7 @@ task verifyFile(dependsOn: downloadJRuby, type: Verify) { verifyFile.onlyIf { customJRubyDir == "" } verifyFile.onlyIf { doChecksum } -task buildCustomJRuby(type: Exec) { +tasks.register("buildCustomJRuby", Exec) { description "Build tar.gz and .jar artifacts from JRuby source directory" workingDir (customJRubyDir == "" ? "./" : customJRubyDir) commandLine './mvnw', 'clean', 'install', '-Pdist', '-Pcomplete' @@ -244,7 +245,8 @@ task buildCustomJRuby(type: Exec) { buildCustomJRuby.onlyIf { customJRubyDir != "" } -task installCustomJRuby(dependsOn: buildCustomJRuby, type: Copy) { +tasks.register("installCustomJRuby", Copy) { + dependsOn buildCustomJRuby description "Install custom built JRuby in the vendor directory" inputs.file(customJRubyTar) outputs.dir("${projectDir}/vendor/jruby") @@ -260,7 +262,8 @@ task installCustomJRuby(dependsOn: buildCustomJRuby, type: Copy) { installCustomJRuby.onlyIf { customJRubyDir != "" } -task downloadAndInstallJRuby(dependsOn: [verifyFile, installCustomJRuby], type: Copy) { +tasks.register("downloadAndInstallJRuby", Copy) { + dependsOn=[verifyFile, installCustomJRuby] description "Install JRuby in the vendor directory" inputs.file(jrubyTarPath) outputs.dir("${projectDir}/vendor/jruby") diff --git a/x-pack/build.gradle b/x-pack/build.gradle index 61fcf0170..5f78f0388 100644 --- a/x-pack/build.gradle +++ b/x-pack/build.gradle @@ -26,7 +26,7 @@ test { exclude '/**' } -task rubyTests(type: Test) { +tasks.register("rubyTests", Test) { inputs.files fileTree("${projectDir}/spec") inputs.files fileTree("${projectDir}/lib") inputs.files fileTree("${projectDir}/modules") @@ -34,7 +34,7 @@ task rubyTests(type: Test) { include '/org/logstash/xpack/test/RSpecTests.class' } -task rubyIntegrationTests(type: Test) { +tasks.register("rubyIntegrationTests", Test) { inputs.files fileTree("${projectDir}/qa") inputs.files fileTree("${projectDir}/lib") inputs.files fileTree("${projectDir}/modules") From e4a5134760b2caf32e72ef8663276aab5f4d0561 Mon Sep 17 00:00:00 2001 From: Rob Bavey Date: Thu, 28 May 2020 17:07:07 -0400 Subject: [PATCH 0467/1126] Enable fallback to sleep if nc not installed Fixture test scripts use `nc` to wait for the port to determine whether a test fixture is up and running. This commit adds a fall back option to sleep if `nc` is not available - it is not installed on Jenkins centos worker nodes. Fixes #11942 --- qa/integration/services/helpers.sh | 14 ++++++++++++++ 1 file changed, 14 insertions(+) diff --git a/qa/integration/services/helpers.sh b/qa/integration/services/helpers.sh index dbf970a3e..bbaac8e7a 100644 --- a/qa/integration/services/helpers.sh +++ b/qa/integration/services/helpers.sh @@ -12,6 +12,14 @@ setup_install_dir() { } wait_for_port() { + if command -v nc 2>/dev/null; then + wait_for_port_nc "$@" + else + wait_for_port_sleep "$@" + fi +} + +wait_for_port_nc() { count=$PORT_WAIT_COUNT port=$1 while ! nc -z localhost $port && [[ $count -ne 0 ]]; do @@ -21,6 +29,12 @@ wait_for_port() { done # just in case, one more time nc -z localhost $port + +} + +wait_for_port_sleep() { + echo "nc not installed on this machine. Sleeping for 10 seconds" + sleep 10 } clean_install_dir() { From 8cce2091d338f673bbe26de00b572e1fa53cb082 Mon Sep 17 00:00:00 2001 From: Rob Bavey Date: Fri, 29 May 2020 11:40:57 -0400 Subject: [PATCH 0468/1126] Switch 'no nc' port checker to ruby Use ruby to test for port, rather than just sleeping Fixes #11942 --- qa/integration/services/helpers.sh | 31 +++++++++++++++--------------- 1 file changed, 16 insertions(+), 15 deletions(-) diff --git a/qa/integration/services/helpers.sh b/qa/integration/services/helpers.sh index bbaac8e7a..0893a31c5 100644 --- a/qa/integration/services/helpers.sh +++ b/qa/integration/services/helpers.sh @@ -12,29 +12,30 @@ setup_install_dir() { } wait_for_port() { - if command -v nc 2>/dev/null; then - wait_for_port_nc "$@" - else - wait_for_port_sleep "$@" - fi -} - -wait_for_port_nc() { count=$PORT_WAIT_COUNT - port=$1 - while ! nc -z localhost $port && [[ $count -ne 0 ]]; do + while ! test_port "$1" && [[ $count -ne 0 ]]; do count=$(( $count - 1 )) [[ $count -eq 0 ]] && return 1 sleep 0.5 done # just in case, one more time - nc -z localhost $port - + test_port "$1" } -wait_for_port_sleep() { - echo "nc not installed on this machine. Sleeping for 10 seconds" - sleep 10 +test_port() { + if command -v ncd 2>/dev/null; then + test_port_nc "$1" + else + test_port_ruby "$1" + fi +} + +test_port_nc() { + nc -z localhost $1 +} + +test_port_ruby() { + ruby -rsocket -e "TCPSocket.new('localhost', $1) rescue exit(1)" } clean_install_dir() { From 1ed6523e834b16e79b39bd58edf658dabf016bd0 Mon Sep 17 00:00:00 2001 From: Rob Bavey Date: Fri, 29 May 2020 12:12:41 -0400 Subject: [PATCH 0469/1126] Fix typo Fixes #11942 --- qa/integration/services/helpers.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/qa/integration/services/helpers.sh b/qa/integration/services/helpers.sh index 0893a31c5..1e1d82265 100644 --- a/qa/integration/services/helpers.sh +++ b/qa/integration/services/helpers.sh @@ -23,7 +23,7 @@ wait_for_port() { } test_port() { - if command -v ncd 2>/dev/null; then + if command -v nc 2>/dev/null; then test_port_nc "$1" else test_port_ruby "$1" From b28fa3e7dfae2393598adf74ad13e85b304e6fad Mon Sep 17 00:00:00 2001 From: Rob Bavey Date: Mon, 1 Jun 2020 10:03:28 -0400 Subject: [PATCH 0470/1126] Set beats permission checking to strict=false When running filebeats integration tests on centos-7, the tests fail due to permsisions checks on the temporary configuration file created for the test. This commit sets strict permissions checks to false in order for the tests to be able to succeed. Fixes #11949 --- qa/integration/services/filebeat_service.rb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/qa/integration/services/filebeat_service.rb b/qa/integration/services/filebeat_service.rb index f7d104473..d735e8a1e 100644 --- a/qa/integration/services/filebeat_service.rb +++ b/qa/integration/services/filebeat_service.rb @@ -16,7 +16,7 @@ # under the License. class FilebeatService < Service - FILEBEAT_CMD = [File.join(File.dirname(__FILE__), "installed", "filebeat", "filebeat"), "-c"] + FILEBEAT_CMD = [File.join(File.dirname(__FILE__), "installed", "filebeat", "filebeat"), "--strict.perms=false", "-c"] class BackgroundProcess def initialize(cmd) From 94f282c88004687d1bd7083588861985b126886f Mon Sep 17 00:00:00 2001 From: Colin Surprenant Date: Fri, 3 Apr 2020 15:09:11 -0400 Subject: [PATCH 0471/1126] display Java pipeline initialization time Fixes #11749 --- logstash-core/lib/logstash/java_pipeline.rb | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/logstash-core/lib/logstash/java_pipeline.rb b/logstash-core/lib/logstash/java_pipeline.rb index 0917693d0..a0b4f582c 100644 --- a/logstash-core/lib/logstash/java_pipeline.rb +++ b/logstash-core/lib/logstash/java_pipeline.rb @@ -263,12 +263,16 @@ module LogStash; class JavaPipeline < JavaBasePipeline # First launch WorkerLoop initialization in separate threads which concurrently # compiles and initializes the worker pipelines + workers_init_start = Time.now worker_loops = pipeline_workers.times .map { Thread.new { init_worker_loop } } .map(&:value) + workers_init_elapsed = Time.now - workers_init_start fail("Some worker(s) were not correctly initialized") if worker_loops.any?{|v| v.nil?} + @logger.info("Pipeline Java execution initialization time", "seconds" => workers_init_elapsed.round(2)) + # Once all WorkerLoop have been initialized run them in separate threads worker_loops.each_with_index do |worker_loop, t| From 85e505778802d677d5962c6be2497607c5126706 Mon Sep 17 00:00:00 2001 From: Rob Bavey Date: Tue, 2 Jun 2020 10:45:01 -0400 Subject: [PATCH 0472/1126] [7.x backport] Fix service script execution when path includes `&&` (#11944) (#11948) Backport of #11944 A previous commit attempted to fix this issue by adding Shellwords.escape to setup_script and teardown_script locations, but File.exists? returns false when called against a filename escaped by Shellwords.escape. This commit localizes the escaping to where the file is executed. This commit also adds Shellwords.escape to teardown script runner and the method used to execute logstash to retrieve version. This is to enable tests to run correctly when Jenkins creates execution environments with folders named with &&, eg centos-7&&immutable --- qa/integration/services/logstash_service.rb | 2 +- qa/integration/services/service.rb | 6 ++++-- 2 files changed, 5 insertions(+), 3 deletions(-) diff --git a/qa/integration/services/logstash_service.rb b/qa/integration/services/logstash_service.rb index 630822916..a7f6602ef 100644 --- a/qa/integration/services/logstash_service.rb +++ b/qa/integration/services/logstash_service.rb @@ -206,7 +206,7 @@ class LogstashService < Service end def get_version - `#{@logstash_bin} --version`.split("\n").last + `#{Shellwords.escape(@logstash_bin)} --version`.split("\n").last end def get_version_yml diff --git a/qa/integration/services/service.rb b/qa/integration/services/service.rb index 11b5dbb99..b9e3beb23 100644 --- a/qa/integration/services/service.rb +++ b/qa/integration/services/service.rb @@ -32,7 +32,8 @@ class Service def setup puts "Setting up #{@name} service" if File.exists?(@setup_script) - `#{@setup_script}` + `#{Shellwords.escape(@setup_script)}` + raise "#{@setup_script} FAILED with exit status #{$?}" unless $?.success? else puts "Setup script not found for #{@name}" end @@ -42,7 +43,8 @@ class Service def teardown puts "Tearing down #{@name} service" if File.exists?(@teardown_script) - `#{@teardown_script}` + `#{Shellwords.escape(@teardown_script)}` + raise "#{@teardown_script} FAILED with exit status #{$?}" unless $?.success? else puts "Teardown script not found for #{@name}" end From fa75ac27805237b8619b14067195f984395e7386 Mon Sep 17 00:00:00 2001 From: Rob Bavey Date: Tue, 2 Jun 2020 16:36:43 -0400 Subject: [PATCH 0473/1126] Disable flaky multiReceiveRecordsDurationInMillis test Relates #11956 --- .../org/logstash/config/ir/compiler/OutputDelegatorTest.java | 2 ++ 1 file changed, 2 insertions(+) diff --git a/logstash-core/src/test/java/org/logstash/config/ir/compiler/OutputDelegatorTest.java b/logstash-core/src/test/java/org/logstash/config/ir/compiler/OutputDelegatorTest.java index 44d6b6159..a808fec3b 100644 --- a/logstash-core/src/test/java/org/logstash/config/ir/compiler/OutputDelegatorTest.java +++ b/logstash-core/src/test/java/org/logstash/config/ir/compiler/OutputDelegatorTest.java @@ -29,6 +29,7 @@ import org.jruby.RubySymbol; import org.jruby.runtime.ThreadContext; import org.jruby.runtime.builtin.IRubyObject; import org.junit.Before; +import org.junit.Ignore; import org.junit.Test; import org.logstash.Event; @@ -99,6 +100,7 @@ public class OutputDelegatorTest extends PluginDelegatorTestCase { assertEquals(EVENT_COUNT, getMetricLongValue("out")); } + @Ignore("Test failing intermittently for some time. See https://github.com/elastic/logstash/issues/11956") @Test public void multiReceiveRecordsDurationInMillis() { final int delay = 100; From 5e62c96c19c44d62cc06c858ad1e1912da2c01f2 Mon Sep 17 00:00:00 2001 From: Colin Surprenant Date: Wed, 3 Jun 2020 10:57:36 -0400 Subject: [PATCH 0474/1126] add support for api_key authentication in xpack management and monitoring. (#11953) 7.x backport of #11864 --- ...configuration-management-settings.asciidoc | 7 + .../monitoring-settings-legacy.asciidoc | 7 + .../config_management/elasticsearch_source.rb | 15 +- x-pack/lib/config_management/extension.rb | 1 + x-pack/lib/helpers/elasticsearch_options.rb | 178 ++++++++---- .../monitoring/internal_pipeline_source.rb | 4 +- x-pack/lib/monitoring/monitoring.rb | 15 +- x-pack/lib/template.cfg.erb | 17 +- .../elasticsearch_source_spec.rb | 24 +- .../helpers/elasticsearch_options_spec.rb | 273 +++++++++++++++--- .../license_checker/license_reader_spec.rb | 18 +- x-pack/spec/monitoring/inputs/metrics_spec.rb | 1 + .../internal_pipeline_source_spec.rb | 13 +- 13 files changed, 437 insertions(+), 136 deletions(-) diff --git a/docs/static/settings/configuration-management-settings.asciidoc b/docs/static/settings/configuration-management-settings.asciidoc index 803354460..c83863d75 100644 --- a/docs/static/settings/configuration-management-settings.asciidoc +++ b/docs/static/settings/configuration-management-settings.asciidoc @@ -99,3 +99,10 @@ and `xpack.management.elasticsearch.password`. If `cloud_auth` is configured, those settings should not be used. The credentials you specify here should be for a user with the `logstash_admin` role, which provides access to `.logstash-*` indices for managing configurations. + +`xpack.management.elasticsearch.api_key`:: + +Authenticate using an Elasticsearch API key. Note that this option also requires using SSL. + +The API key Format is `id:api_key` where `id` and `api_key` are as returned by the Elasticsearch +https://www.elastic.co/guide/en/elasticsearch/reference/current/security-api-create-api-key.html[Create API key API]. diff --git a/docs/static/settings/monitoring-settings-legacy.asciidoc b/docs/static/settings/monitoring-settings-legacy.asciidoc index cbab903db..72f836e29 100644 --- a/docs/static/settings/monitoring-settings-legacy.asciidoc +++ b/docs/static/settings/monitoring-settings-legacy.asciidoc @@ -104,3 +104,10 @@ If you're using {es} in {ecloud}, you can set your auth credentials here. This setting is an alternative to both `xpack.monitoring.elasticsearch.username` and `xpack.monitoring.elasticsearch.password`. If `cloud_auth` is configured, those settings should not be used. + +`xpack.monitoring.elasticsearch.api_key`:: + +Authenticate using an Elasticsearch API key. Note that this option also requires using SSL. + +The API key Format is `id:api_key` where `id` and `api_key` are as returned by the Elasticsearch +https://www.elastic.co/guide/en/elasticsearch/reference/current/security-api-create-api-key.html[Create API key API]. diff --git a/x-pack/lib/config_management/elasticsearch_source.rb b/x-pack/lib/config_management/elasticsearch_source.rb index 6db650646..edc4af3b1 100644 --- a/x-pack/lib/config_management/elasticsearch_source.rb +++ b/x-pack/lib/config_management/elasticsearch_source.rb @@ -35,22 +35,9 @@ module LogStash def initialize(settings) super(settings) - if @settings.get("xpack.management.enabled") - if @settings.get_setting("xpack.management.elasticsearch.cloud_id").set? - if !@settings.get_setting("xpack.management.elasticsearch.cloud_auth").set? - raise ArgumentError.new("You must set credentials using \"xpack.management.elasticsearch.cloud_auth\", " + - "when using \"xpack.management.elasticsearch.cloud_id\" in logstash.yml") - end - else - if !@settings.get_setting("xpack.management.elasticsearch.password").set? - raise ArgumentError.new("You must set the password using \"xpack.management.elasticsearch.password\" in logstash.yml") - end - end - end - - @es_options = es_options_from_settings('management', settings) if enabled? + @es_options = es_options_from_settings('management', settings) setup_license_checker(FEATURE_INTERNAL) license_check(true) end diff --git a/x-pack/lib/config_management/extension.rb b/x-pack/lib/config_management/extension.rb index 9c694efcb..80ca77408 100644 --- a/x-pack/lib/config_management/extension.rb +++ b/x-pack/lib/config_management/extension.rb @@ -29,6 +29,7 @@ module LogStash settings.register(LogStash::Setting::ArrayCoercible.new("xpack.management.elasticsearch.hosts", String, [ "https://localhost:9200" ] )) settings.register(LogStash::Setting::NullableString.new("xpack.management.elasticsearch.cloud_id")) settings.register(LogStash::Setting::NullableString.new("xpack.management.elasticsearch.cloud_auth")) + settings.register(LogStash::Setting::NullableString.new("xpack.management.elasticsearch.api_key")) settings.register(LogStash::Setting::NullableString.new("xpack.management.elasticsearch.proxy")) settings.register(LogStash::Setting::NullableString.new("xpack.management.elasticsearch.ssl.certificate_authority")) settings.register(LogStash::Setting::NullableString.new("xpack.management.elasticsearch.ssl.truststore.path")) diff --git a/x-pack/lib/helpers/elasticsearch_options.rb b/x-pack/lib/helpers/elasticsearch_options.rb index f5d5b9ee9..26bd6d82a 100644 --- a/x-pack/lib/helpers/elasticsearch_options.rb +++ b/x-pack/lib/helpers/elasticsearch_options.rb @@ -6,17 +6,34 @@ module LogStash module Helpers module ElasticsearchOptions extend self - ES_SETTINGS =%w( - ssl.certificate_authority - ssl.truststore.path - ssl.keystore.path - hosts - username - password - cloud_id - cloud_auth - proxy - ) + ES_SETTINGS = %w( + ssl.certificate_authority + ssl.truststore.path + ssl.keystore.path + hosts + username + password + cloud_id + cloud_auth + api_key + proxy + ) + + # xpack setting to ES output setting + SETTINGS_MAPPINGS = { + "cloud_id" => "cloud_id", + "cloud_auth" => "cloud_auth", + "username" => "user", + "password" => "password", + "api_key" => "api_key", + "proxy" => "proxy", + "sniffing" => "sniffing", + "ssl.certificate_authority" => "cacert", + "ssl.truststore.path" => "truststore", + "ssl.truststore.password" => "truststore_password", + "ssl.keystore.path" => "keystore", + "ssl.keystore.password" => "keystore_password", + } # Retrieve elasticsearch options from either specific settings, or modules if the setting is not there and the # feature supports falling back to modules if the feature is not specified in logstash.yml @@ -27,53 +44,53 @@ module LogStash module Helpers # Populate the Elasticsearch options from LogStashSettings file, based on the feature that is being used. # @return Hash def es_options_from_settings(feature, settings) - prefix = if feature == "monitoring" && - LogStash::MonitoringExtension.use_direct_shipping?(settings) - "" - else - "xpack." - end + prefix = (feature == "monitoring" && LogStash::MonitoringExtension.use_direct_shipping?(settings)) ? "" : "xpack." opts = {} - if cloud_id = settings.get("#{prefix}#{feature}.elasticsearch.cloud_id") - opts['cloud_id'] = cloud_id - check_cloud_id_configuration!(feature, settings, prefix) - else + validate_authentication!(feature, settings, prefix) + + # transpose all directly mappable settings + SETTINGS_MAPPINGS.each do |xpack_setting, es_setting| + v = settings.get("#{prefix}#{feature}.elasticsearch.#{xpack_setting}") + opts[es_setting] = v unless v.nil? + end + + # process remaining settings + + unless settings.get("#{prefix}#{feature}.elasticsearch.cloud_id") opts['hosts'] = settings.get("#{prefix}#{feature}.elasticsearch.hosts") end - if cloud_auth = settings.get("#{prefix}#{feature}.elasticsearch.cloud_auth") - opts['cloud_auth'] = cloud_auth - check_cloud_auth_configuration!(feature, settings, prefix) - else - opts['user'] = settings.get("#{prefix}#{feature}.elasticsearch.username") - opts['password'] = settings.get("#{prefix}#{feature}.elasticsearch.password") - end - if proxysetting = settings.get("#{prefix}#{feature}.elasticsearch.proxy") - opts['proxy'] = proxysetting - end - - opts['sniffing'] = settings.get("#{prefix}#{feature}.elasticsearch.sniffing") opts['ssl_certificate_verification'] = settings.get("#{prefix}#{feature}.elasticsearch.ssl.verification_mode") == 'certificate' - if cacert = settings.get("#{prefix}#{feature}.elasticsearch.ssl.certificate_authority") - opts['cacert'] = cacert + # if all hosts are using https or any of the ssl related settings are set + if ssl?(feature, settings, prefix) opts['ssl'] = true end - if truststore = settings.get("#{prefix}#{feature}.elasticsearch.ssl.truststore.path") - opts['truststore'] = truststore - opts['truststore_password'] = settings.get("#{prefix}#{feature}.elasticsearch.ssl.truststore.password") - opts['ssl'] = true + # the username setting has a default value and should not be included when using another authentication + # it is safe to silently remove here since all authentication verifications have been validated at this point. + if settings.set?("#{prefix}#{feature}.elasticsearch.cloud_auth") || settings.set?("#{prefix}#{feature}.elasticsearch.api_key") + opts.delete('user') end - if keystore = settings.get("#{prefix}#{feature}.elasticsearch.ssl.keystore.path") - opts['keystore'] = keystore - opts['keystore_password']= settings.get("#{prefix}#{feature}.elasticsearch.ssl.keystore.password") - opts['ssl'] = true - end opts end + def ssl?(feature, settings, prefix) + return true if verify_https_scheme(feature, settings, prefix) + return true if settings.set?("#{prefix}#{feature}.elasticsearch.cloud_id") # cloud_id always resolves to https hosts + return true if settings.set?("#{prefix}#{feature}.elasticsearch.ssl.certificate_authority") + return true if settings.set?("#{prefix}#{feature}.elasticsearch.ssl.truststore.path") && settings.set?("#{prefix}#{feature}.elasticsearch.ssl.truststore.password") + return true if settings.set?("#{prefix}#{feature}.elasticsearch.ssl.keystore.path") && settings.set?("#{prefix}#{feature}.elasticsearch.ssl.keystore.password") + + return false + end + + HTTPS_SCHEME = /^https:\/\/.+/ + def verify_https_scheme(feature, settings, prefix) + hosts = Array(settings.get("#{prefix}#{feature}.elasticsearch.hosts")) + hosts.all? {|host| host.match?(HTTPS_SCHEME)} + end # Elasticsearch settings can be extracted from the modules settings inside the configuration. # Few options will be supported, however - the modules security configuration is @@ -113,9 +130,6 @@ module LogStash module Helpers end # If no settings are configured, then assume that the feature has not been configured. - # The assumption is that with security setup, at least one setting (password or certificates) - # should be configured. If security is not setup, and defaults 'just work' for monitoring, then - # this will need to be reconsidered. def feature_configured?(feature, settings) ES_SETTINGS.each do |option| return true if settings.set?("xpack.#{feature}.elasticsearch.#{option}") @@ -146,20 +160,62 @@ module LogStash module Helpers private - def check_cloud_id_configuration!(feature, settings, prefix) - return if !settings.set?("#{prefix}#{feature}.elasticsearch.hosts") + def validate_authentication!(feature, settings, prefix) + provided_cloud_id = settings.set?("#{prefix}#{feature}.elasticsearch.cloud_id") + provided_hosts = settings.set?("#{prefix}#{feature}.elasticsearch.hosts") + provided_cloud_auth = settings.set?("#{prefix}#{feature}.elasticsearch.cloud_auth") + provided_api_key = settings.set?("#{prefix}#{feature}.elasticsearch.api_key") + provided_username = settings.set?("#{prefix}#{feature}.elasticsearch.username") + provided_password = settings.set?("#{prefix}#{feature}.elasticsearch.password") - raise ArgumentError.new("Both \"#{prefix}#{feature}.elasticsearch.cloud_id\" and " + - "\"#{prefix}#{feature}.elasticsearch.hosts\" specified, please only use one of those.") + # note that the username setting has a default value and in the verifications below + # we can test on the password option being set as a proxy to using basic auth because + # if the username is not explicitly set it will use its default value. + + if provided_cloud_auth && (provided_username || provided_password) + raise ArgumentError.new( + "Both #{prefix}#{feature}.elasticsearch.cloud_auth and " + + "#{prefix}#{feature}.elasticsearch.username/password " + + "specified, please only use one of those" + ) + end + + if provided_username && !provided_password + raise(ArgumentError, + "When using #{prefix}#{feature}.elasticsearch.username, " + + "#{prefix}#{feature}.elasticsearch.password must also be set" + ) + end + + if provided_cloud_id + if provided_hosts + raise(ArgumentError, + "Both #{prefix}#{feature}.elasticsearch.cloud_id and " + + "#{prefix}#{feature}.elasticsearch.hosts specified, please only use one of those" + ) + end + end + + authentication_count = 0 + authentication_count += 1 if provided_cloud_auth + authentication_count += 1 if provided_password + authentication_count += 1 if provided_api_key + + if authentication_count == 0 + # when no explicit authentication is set it is relying on default username + # but without and explicit password set + raise(ArgumentError, + "With the default #{prefix}#{feature}.elasticsearch.username, " + + "#{prefix}#{feature}.elasticsearch.password must be set" + ) + end + + if authentication_count > 1 + raise(ArgumentError, "Multiple authentication options are specified, please only use one of #{prefix}#{feature}.elasticsearch.username/password, #{prefix}#{feature}.elasticsearch.cloud_auth or #{prefix}#{feature}.elasticsearch.api_key") + end + + if provided_api_key && !ssl?(feature, settings, prefix) + raise(ArgumentError, "Using api_key authentication requires SSL/TLS secured communication") + end end - - def check_cloud_auth_configuration!(feature, settings, prefix) - return if !settings.set?("#{prefix}#{feature}.elasticsearch.username") && - !settings.set?("#{prefix}#{feature}.elasticsearch.password") - - raise ArgumentError.new("Both \"#{prefix}#{feature}.elasticsearch.cloud_auth\" and " + - "\"#{prefix}#{feature}.elasticsearch.username\"/\"#{prefix}#{feature}.elasticsearch.password\" " + - "specified, please only use one of those.") - end - end end end diff --git a/x-pack/lib/monitoring/internal_pipeline_source.rb b/x-pack/lib/monitoring/internal_pipeline_source.rb index bbf2133d5..256e1c07d 100644 --- a/x-pack/lib/monitoring/internal_pipeline_source.rb +++ b/x-pack/lib/monitoring/internal_pipeline_source.rb @@ -13,10 +13,10 @@ module LogStash module Monitoring include LogStash::Util::Loggable FEATURE = 'monitoring' - def initialize(pipeline_config, agent) + def initialize(pipeline_config, agent, settings) super(pipeline_config.settings) @pipeline_config = pipeline_config - @settings = LogStash::SETTINGS.clone + @settings = settings @agent = agent @es_options = es_options_from_settings_or_modules(FEATURE, @settings) setup_license_checker(FEATURE) diff --git a/x-pack/lib/monitoring/monitoring.rb b/x-pack/lib/monitoring/monitoring.rb index ec4924e0e..4d1ff269e 100644 --- a/x-pack/lib/monitoring/monitoring.rb +++ b/x-pack/lib/monitoring/monitoring.rb @@ -32,7 +32,9 @@ module LogStash @password = es_settings['password'] @cloud_id = es_settings['cloud_id'] @cloud_auth = es_settings['cloud_auth'] + @api_key = es_settings['api_key'] @proxy = es_settings['proxy'] + @ssl = es_settings['ssl'] @ca_path = es_settings['cacert'] @truststore_path = es_settings['truststore'] @truststore_password = es_settings['truststore_password'] @@ -42,8 +44,8 @@ module LogStash @ssl_certificate_verification = (es_settings['verification_mode'] == 'certificate') end - attr_accessor :system_api_version, :es_hosts, :user, :password, :node_uuid, :cloud_id, :cloud_auth, :proxy - attr_accessor :ca_path, :truststore_path, :truststore_password + attr_accessor :system_api_version, :es_hosts, :user, :password, :node_uuid, :cloud_id, :cloud_auth, :api_key + attr_accessor :proxy, :ssl, :ca_path, :truststore_path, :truststore_password attr_accessor :keystore_path, :keystore_password, :sniffing, :ssl_certificate_verification def collection_interval @@ -70,8 +72,12 @@ module LogStash user && password end + def api_key? + api_key + end + def ssl? - ca_path || (truststore_path && truststore_password) || (keystore_path && keystore_password) + ssl || ca_path || (truststore_path && truststore_password) || (keystore_path && keystore_password) end def truststore? @@ -133,7 +139,7 @@ module LogStash logger.trace("registering the metrics pipeline") LogStash::SETTINGS.set("node.uuid", runner.agent.id) - internal_pipeline_source = LogStash::Monitoring::InternalPipelineSource.new(setup_metrics_pipeline, runner.agent) + internal_pipeline_source = LogStash::Monitoring::InternalPipelineSource.new(setup_metrics_pipeline, runner.agent, LogStash::SETTINGS.clone) runner.source_loader.add_source(internal_pipeline_source) rescue => e logger.error("Failed to set up the metrics pipeline", :message => e.message, :backtrace => e.backtrace) @@ -260,6 +266,7 @@ module LogStash settings.register(LogStash::Setting::NullableString.new("#{prefix}monitoring.elasticsearch.proxy")) settings.register(LogStash::Setting::NullableString.new("#{prefix}monitoring.elasticsearch.cloud_id")) settings.register(LogStash::Setting::NullableString.new("#{prefix}monitoring.elasticsearch.cloud_auth")) + settings.register(LogStash::Setting::NullableString.new("#{prefix}monitoring.elasticsearch.api_key")) settings.register(LogStash::Setting::NullableString.new("#{prefix}monitoring.elasticsearch.ssl.certificate_authority")) settings.register(LogStash::Setting::NullableString.new("#{prefix}monitoring.elasticsearch.ssl.truststore.path")) settings.register(LogStash::Setting::NullableString.new("#{prefix}monitoring.elasticsearch.ssl.truststore.password")) diff --git a/x-pack/lib/template.cfg.erb b/x-pack/lib/template.cfg.erb index af7c50a22..1926a6324 100644 --- a/x-pack/lib/template.cfg.erb +++ b/x-pack/lib/template.cfg.erb @@ -12,13 +12,20 @@ input { } output { elasticsearch_monitoring { + <% if auth? %> + user => "<%= user %>" + password => "<%= password %>" + <% end %> + <% if api_key? %> + api_key => "<%= api_key %>" + <% end %> <% if cloud_id? %> cloud_id => "<%= cloud_id %>" - <% if cloud_auth %> - cloud_auth => "<%= cloud_auth %>" - <% end %> <% else %> hosts => <%= es_hosts %> + <% end %> + <% if cloud_auth %> + cloud_auth => "<%= cloud_auth %>" <% end %> bulk_path => "<%= monitoring_endpoint %>" manage_template => false @@ -28,10 +35,6 @@ output { <% if proxy? %> proxy => "<%= proxy %>" <% end %> - <% if auth? && !cloud_auth? %> - user => "<%= user %>" - password => "<%= password %>" - <% end %> <% if ssl? %> ssl => true <% if ca_path %> diff --git a/x-pack/spec/config_management/elasticsearch_source_spec.rb b/x-pack/spec/config_management/elasticsearch_source_spec.rb index 3e204412b..d7d3250ef 100644 --- a/x-pack/spec/config_management/elasticsearch_source_spec.rb +++ b/x-pack/spec/config_management/elasticsearch_source_spec.rb @@ -4,6 +4,7 @@ require "spec_helper" require "logstash/json" +require "logstash/runner" require "config_management/elasticsearch_source" require "config_management/extension" require "license_checker/license_manager" @@ -164,9 +165,12 @@ describe LogStash::ConfigManagement::ElasticsearchSource do end let(:pipeline_id) { "foobar" } - let(:settings) { { "xpack.management.pipeline.id" => pipeline_id, - "xpack.management.elasticsearch.password" => "testpassword" - } } + let(:settings) do + { + "xpack.management.pipeline.id" => pipeline_id, + "xpack.management.elasticsearch.password" => "testpassword" + } + end it "generates the path to get the configuration" do expect(subject.config_path).to eq("#{described_class::PIPELINE_INDEX}/_mget") @@ -182,10 +186,13 @@ describe LogStash::ConfigManagement::ElasticsearchSource do end context "when enabled" do - let(:settings) { { - "xpack.management.enabled" => true, - "xpack.management.elasticsearch.password" => "testpassword" - } } + let(:settings) do + { + "xpack.management.enabled" => true, + "xpack.management.elasticsearch.username" => "testuser", + "xpack.management.elasticsearch.password" => "testpassword" + } + end it "returns true" do expect(subject.match?).to be_truthy @@ -357,7 +364,8 @@ describe LogStash::ConfigManagement::ElasticsearchSource do context 'when security is enabled in Elasticsearch' do let(:security_enabled) { true } it 'should not raise an error' do - expect { subject.pipeline_configs }.not_to raise_error(LogStash::LicenseChecker::LicenseError) + expect_any_instance_of(described_class).to receive(:build_client).and_return(mock_client) + expect { subject.pipeline_configs }.not_to raise_error end end end diff --git a/x-pack/spec/helpers/elasticsearch_options_spec.rb b/x-pack/spec/helpers/elasticsearch_options_spec.rb index 83e73b86c..3fb5b4922 100644 --- a/x-pack/spec/helpers/elasticsearch_options_spec.rb +++ b/x-pack/spec/helpers/elasticsearch_options_spec.rb @@ -4,6 +4,7 @@ require "spec_helper" require "logstash/json" +require "logstash/runner" require 'helpers/elasticsearch_options' require "license_checker/license_manager" require 'monitoring/monitoring' @@ -97,65 +98,267 @@ describe LogStash::Helpers::ElasticsearchOptions do end describe "es_options_from_settings" do - let(:settings) do - { + + context "with implicit username" do + let(:settings) do + { + "xpack.monitoring.enabled" => true, + "xpack.monitoring.elasticsearch.hosts" => elasticsearch_url, + } + end + + it "fails without password" do + expect { + test_class.es_options_from_settings_or_modules('monitoring', system_settings) + }.to raise_error(ArgumentError, /password must be set/) + end + + context "with cloud_auth" do + let(:cloud_username) { 'elastic' } + let(:cloud_password) { 'passw0rd'} + let(:cloud_auth) { "#{cloud_username}:#{cloud_password}" } + + let(:settings) do + super.merge( + "xpack.monitoring.elasticsearch.cloud_auth" => cloud_auth, + ) + end + + it "silently ignores the default username" do + es_options = test_class.es_options_from_settings_or_modules('monitoring', system_settings) + expect(es_options).to include("cloud_auth") + expect(es_options).to_not include("user") + end + end + + + context "with api_key" do + let(:settings) do + super.merge( + "xpack.monitoring.elasticsearch.api_key" => 'foo:bar' + ) + end + + it "silently ignores the default username" do + es_options = test_class.es_options_from_settings_or_modules('monitoring', system_settings) + expect(es_options).to include("api_key") + expect(es_options).to_not include("user") + end + + context "and explicit password" do + let(:settings) do + super.merge( + "xpack.monitoring.elasticsearch.password" => elasticsearch_password + ) + end + + it "fails for multiple authentications" do + expect { + test_class.es_options_from_settings_or_modules('monitoring', system_settings) + }.to raise_error(ArgumentError, /Multiple authentication options are specified/) + end + end + end + end + + context "with explicit username" do + let(:settings) do + { + "xpack.monitoring.enabled" => true, + "xpack.monitoring.elasticsearch.hosts" => elasticsearch_url, + "xpack.monitoring.elasticsearch.username" => "foo", + } + end + + it "fails without password" do + expect { + test_class.es_options_from_settings_or_modules('monitoring', system_settings) + }.to raise_error(ArgumentError, /password must also be set/) + end + + context "with cloud_auth" do + let(:settings) do + super.merge( + "xpack.monitoring.elasticsearch.password" => "bar", + "xpack.monitoring.elasticsearch.cloud_auth" => "foo:bar", + ) + end + + it "fails for multiple authentications" do + expect { + test_class.es_options_from_settings_or_modules('monitoring', system_settings) + }.to raise_error(ArgumentError, /Both.*?cloud_auth.*?and.*?username.*?specified/) + end + end + + context "with api_key" do + let(:settings) do + super.merge( + "xpack.monitoring.elasticsearch.password" => "bar", + "xpack.monitoring.elasticsearch.api_key" => 'foo:bar' + ) + end + + it "fails for multiple authentications" do + expect { + test_class.es_options_from_settings_or_modules('monitoring', system_settings) + }.to raise_error(ArgumentError, /Multiple authentication options are specified/) + end + end + end + + context "with username and password" do + let(:settings) do + { "xpack.monitoring.enabled" => true, "xpack.monitoring.elasticsearch.hosts" => elasticsearch_url, "xpack.monitoring.elasticsearch.username" => elasticsearch_username, "xpack.monitoring.elasticsearch.password" => elasticsearch_password, - } - end - - it_behaves_like 'elasticsearch options hash is populated without security' - it_behaves_like 'elasticsearch options hash is populated with secure options' - - context 'when cloud id and auth are set' do - let(:cloud_name) { 'thebigone'} - let(:cloud_domain) { 'elastic.co'} - let(:cloud_id) { "monitoring:#{Base64.urlsafe_encode64("#{cloud_domain}$#{cloud_name}$ignored")}" } - let(:cloud_username) { 'elastic' } - let(:cloud_password) { 'passw0rd'} - let(:cloud_auth) { "#{cloud_username}:#{cloud_password}" } - let(:expected_url) { ["https://#{cloud_name}.#{cloud_domain}:443"] } - let(:settings) do - { - "xpack.monitoring.enabled" => true, - "xpack.monitoring.elasticsearch.cloud_id" => cloud_id, - "xpack.monitoring.elasticsearch.cloud_auth" => cloud_auth, } end - it "creates the elasticsearch output options hash" do - es_options = test_class.es_options_from_settings_or_modules('monitoring', system_settings) - expect(es_options).to include("cloud_id" => cloud_id, "cloud_auth" => cloud_auth) - expect(es_options.keys).to_not include("hosts") - expect(es_options.keys).to_not include("username") - expect(es_options.keys).to_not include("password") + it_behaves_like 'elasticsearch options hash is populated without security' + it_behaves_like 'elasticsearch options hash is populated with secure options' + end + + + context 'when cloud_id' do + let(:cloud_name) { 'thebigone'} + let(:cloud_domain) { 'elastic.co'} + let(:cloud_id) { "monitoring:#{Base64.urlsafe_encode64("#{cloud_domain}$#{cloud_name}$ignored")}" } + let(:expected_url) { ["https://#{cloud_name}.#{cloud_domain}:443"] } + let(:settings) do + { + "xpack.monitoring.enabled" => true, + "xpack.monitoring.elasticsearch.cloud_id" => cloud_id, + } end context 'hosts also set' do let(:settings) do super.merge( - "xpack.monitoring.elasticsearch.hosts" => 'https://localhost:9200' + "xpack.monitoring.elasticsearch.hosts" => 'https://localhost:9200' ) end it "raises due invalid configuration" do - expect { test_class.es_options_from_settings_or_modules('monitoring', system_settings) }. - to raise_error(ArgumentError, /Both.*?cloud_id.*?and.*?hosts.*?specified/) + expect { + test_class.es_options_from_settings_or_modules('monitoring', system_settings) + }.to raise_error(ArgumentError, /Both.*?cloud_id.*?and.*?hosts.*?specified/) end end - context 'username also set' do + context "when cloud_auth is set" do + let(:cloud_username) { 'elastic' } + let(:cloud_password) { 'passw0rd'} + let(:cloud_auth) { "#{cloud_username}:#{cloud_password}" } let(:settings) do super.merge( - "xpack.monitoring.elasticsearch.username" => 'elastic' + "xpack.monitoring.elasticsearch.cloud_auth" => cloud_auth, ) end - it "raises due invalid configuration" do - expect { test_class.es_options_from_settings_or_modules('monitoring', system_settings) }. - to raise_error(ArgumentError, /Both.*?cloud_auth.*?and.*?username.*?specified/) + it "creates the elasticsearch output options hash" do + es_options = test_class.es_options_from_settings_or_modules('monitoring', system_settings) + expect(es_options).to include("cloud_id" => cloud_id, "cloud_auth" => cloud_auth) + expect(es_options.keys).to_not include("hosts") + expect(es_options.keys).to_not include("username") + expect(es_options.keys).to_not include("password") + end + + context 'username also set' do + let(:settings) do + super.merge( + "xpack.monitoring.elasticsearch.username" => 'elastic' + ) + end + + it "raises for invalid configuration" do + expect { + test_class.es_options_from_settings_or_modules('monitoring', system_settings) + }.to raise_error(ArgumentError, /Both.*?cloud_auth.*?and.*?username.*?specified/) + end + end + + context 'api_key also set' do + let(:settings) do + super.merge( + "xpack.monitoring.elasticsearch.api_key" => 'foo:bar', + ) + end + + it "raises for invalid configuration" do + expect { + test_class.es_options_from_settings_or_modules('monitoring', system_settings) + }.to raise_error(ArgumentError, /Multiple authentication options are specified/) + end + end + end + + context "when cloud_auth is not set" do + + it "raises for invalid configuration" do + # if not other authn is provided it will assume basic auth using the default username + # but the password is missing. + expect { + test_class.es_options_from_settings_or_modules('monitoring', system_settings) + }.to raise_error(ArgumentError, /With the default.*?username,.*?password must be set/) + end + + context 'username and password set' do + let(:settings) do + super.merge( + "xpack.monitoring.elasticsearch.username" => 'foo', + "xpack.monitoring.elasticsearch.password" => 'bar' + ) + end + + it "creates the elasticsearch output options hash" do + es_options = test_class.es_options_from_settings_or_modules('monitoring', system_settings) + expect(es_options).to include("cloud_id", "user", "password") + expect(es_options.keys).to_not include("hosts") + end + end + + context 'api_key set' do + let(:settings) do + super.merge( + "xpack.monitoring.elasticsearch.api_key" => 'foo:bar' + ) + end + + it "creates the elasticsearch output options hash" do + es_options = test_class.es_options_from_settings_or_modules('monitoring', system_settings) + expect(es_options).to include("cloud_id", "api_key") + expect(es_options.keys).to_not include("hosts") + end + end + end + end + + context 'when api_key is set' do + let(:api_key) { 'foo:bar'} + let(:settings) do + { + "xpack.monitoring.enabled" => true, + "xpack.monitoring.elasticsearch.hosts" => elasticsearch_url, + "xpack.monitoring.elasticsearch.api_key" => api_key, + } + end + + it "creates the elasticsearch output options hash" do + es_options = test_class.es_options_from_settings_or_modules('monitoring', system_settings) + expect(es_options).to include("api_key" => api_key) + expect(es_options.keys).to include("hosts") + end + + context "with a non https host" do + let(:elasticsearch_url) { ["https://host1", "http://host2"] } + + it "fails at options validation" do + expect { + test_class.es_options_from_settings_or_modules('monitoring', system_settings) + }.to raise_error(ArgumentError, /api_key authentication requires SSL\/TLS/) end end end diff --git a/x-pack/spec/license_checker/license_reader_spec.rb b/x-pack/spec/license_checker/license_reader_spec.rb index fc25e1de4..5acdecf80 100644 --- a/x-pack/spec/license_checker/license_reader_spec.rb +++ b/x-pack/spec/license_checker/license_reader_spec.rb @@ -7,6 +7,7 @@ require 'support/helpers' require "license_checker/license_reader" require "helpers/elasticsearch_options" require "monitoring/monitoring" +require "logstash/runner" describe LogStash::LicenseChecker::LicenseReader do let(:elasticsearch_url) { "https://localhost:9898" } @@ -23,7 +24,7 @@ describe LogStash::LicenseChecker::LicenseReader do let(:settings) do { "xpack.monitoring.enabled" => true, - "xpack.monitoring.elasticsearch.hosts" => [ elasticsearch_url ], + "xpack.monitoring.elasticsearch.hosts" => [ elasticsearch_url], "xpack.monitoring.elasticsearch.username" => elasticsearch_username, "xpack.monitoring.elasticsearch.password" => elasticsearch_password, } @@ -128,4 +129,19 @@ describe LogStash::LicenseChecker::LicenseReader do expect( subject.client.options ).to include(:user => 'elastic', :password => 'LnWMLeK3EQPTf3G3F1IBdFvO') end end + + context 'with api_key' do + let(:api_key) { "foo:bar" } + let(:settings) do + { + "xpack.monitoring.enabled" => true, + "xpack.monitoring.elasticsearch.hosts" => [elasticsearch_url], + "xpack.monitoring.elasticsearch.api_key" => api_key, + } + end + + it "builds ES client" do + expect( subject.client.options[:client_settings][:headers] ).to include("Authorization" => "ApiKey Zm9vOmJhcg==") + end + end end diff --git a/x-pack/spec/monitoring/inputs/metrics_spec.rb b/x-pack/spec/monitoring/inputs/metrics_spec.rb index 47e1db9c3..65d7aecd1 100644 --- a/x-pack/spec/monitoring/inputs/metrics_spec.rb +++ b/x-pack/spec/monitoring/inputs/metrics_spec.rb @@ -4,6 +4,7 @@ require 'spec_helper' require "logstash-core" +require "logstash/runner" require "logstash/agent" require "monitoring/inputs/metrics" require "rspec/wait" diff --git a/x-pack/spec/monitoring/internal_pipeline_source_spec.rb b/x-pack/spec/monitoring/internal_pipeline_source_spec.rb index 508ccdbb1..3ebaabf12 100644 --- a/x-pack/spec/monitoring/internal_pipeline_source_spec.rb +++ b/x-pack/spec/monitoring/internal_pipeline_source_spec.rb @@ -4,7 +4,7 @@ require "logstash-core" require "logstash/agent" -require "logstash/agent" +require "logstash/runner" require "monitoring/inputs/metrics" require "logstash/config/pipeline_config" require "logstash/config/source/local" @@ -23,11 +23,17 @@ describe LogStash::Monitoring::InternalPipelineSource do let(:options) { { "collection_interval" => xpack_monitoring_interval, "collection_timeout_interval" => 600 } } - subject { described_class.new(pipeline_config, mock_agent) } + subject { described_class.new(pipeline_config, mock_agent, system_settings) } let(:mock_agent) { double("agent")} let(:mock_license_client) { double("es_client")} let(:license_reader) { LogStash::LicenseChecker::LicenseReader.new(system_settings, 'monitoring', es_options)} - let(:system_settings) { LogStash::Runner::SYSTEM_SETTINGS.clone } + let(:extension) { LogStash::MonitoringExtension.new } + let(:system_settings) do + LogStash::Runner::SYSTEM_SETTINGS.clone.tap do |system_settings| + extension.additionals_settings(system_settings) # register defaults from extension + apply_settings(settings, system_settings) # apply `settings` + end + end let(:license_status) { 'active'} let(:license_type) { 'trial' } let(:license_expiry_date) { Time.now + (60 * 60 * 24)} @@ -70,7 +76,6 @@ describe LogStash::Monitoring::InternalPipelineSource do end before :each do - allow(subject).to receive(:es_options_from_settings_or_modules).and_return(es_options) allow(subject).to receive(:license_reader).and_return(license_reader) allow(license_reader).to receive(:build_client).and_return(mock_license_client) end From a278276ecfeaeb2eb5cedb5dbd0a5a69c00eaa07 Mon Sep 17 00:00:00 2001 From: Karen Metts <35154725+karenzone@users.noreply.github.com> Date: Wed, 3 Jun 2020 11:58:20 -0400 Subject: [PATCH 0475/1126] Forwardport: Add 7.7.1 release notes to 7.x branch (#11964) Forwardports #11954 to 7.x Co-authored-by: Ry Biesemeyer --- docs/static/releasenotes.asciidoc | 28 +++++++++++++++++++++++++++- 1 file changed, 27 insertions(+), 1 deletion(-) diff --git a/docs/static/releasenotes.asciidoc b/docs/static/releasenotes.asciidoc index 800bfad71..0e59ae361 100644 --- a/docs/static/releasenotes.asciidoc +++ b/docs/static/releasenotes.asciidoc @@ -3,6 +3,7 @@ This section summarizes the changes in the following releases: +* <> * <> * <> * <> @@ -28,6 +29,31 @@ This section summarizes the changes in the following releases: * <> * <> +[[logstash-7-7-1]] +=== Logstash 7.7.1 Release Notes + +==== Notable issues fixed + +* Fixed: empty batches no longer incur processing overhead in the Java Execution Engine +https://github.com/elastic/logstash/pull/11747[#11747] + +* Fixed: when the Keystore is enabled, pipelines with many variable substitutions now load significantly faster +https://github.com/elastic/logstash/pull/11772[#11772] + +* Fixed: when x-pack Monitoring is configured with `cloud_id`, the monitoring pipeline now correctly resolves the hosts. +https://github.com/elastic/logstash/pull/11800[#11800] + +==== Plugins + +*Elasticsearch Output - 10.4.2* + +* Internal: changed cloud id, credential and host setup to happen in `build_client`, enabling Logstash's x-pack monitoring to use these features without caring about this plugin's internals https://github.com/logstash-plugins/logstash-output-elasticsearch/pull/939[#939] + +* [DOC] Added note about `_type` setting change from `doc` to `_doc` https://github.com/logstash-plugins/logstash-output-elasticsearch/pull/884[#884] + +* Fixed default index value to use calendar year instead of the year corresponding to the ISO week year https://github.com/logstash-plugins/logstash-output-elasticsearch/pull/927[#927] + + [[logstash-7-7-0]] === Logstash 7.7.0 Release Notes @@ -1286,4 +1312,4 @@ Here are the plugin changes. - Tweaked logging statements to reduce verbosity - Fixed numerous issues relating to builds on Travis https://github.com/logstash-plugins/logstash-output-elasticsearch/pull/799[#799] * logstash-output-s3 - - Fixed issue where on restart, 0 byte files could erroneously be uploaded to s3 https://github.com/logstash-plugins/logstash-output-s3/issues/195[#195] + - Fixed issue where on restart, 0 byte files could erroneously be uploaded to s3 https://github.com/logstash-plugins/logstash-output-s3/issues/195[#195] \ No newline at end of file From e810f96e6a36858578cdd9ecb5957f9aab89eeb1 Mon Sep 17 00:00:00 2001 From: Rob Bavey Date: Thu, 28 May 2020 10:29:04 -0400 Subject: [PATCH 0476/1126] Use BUILD_JAVA_HOME FOR JAVA_HOME in xpack integration tests --- x-pack/ci/integration_tests.sh | 1 + 1 file changed, 1 insertion(+) diff --git a/x-pack/ci/integration_tests.sh b/x-pack/ci/integration_tests.sh index e85c89504..47dd0a5ff 100755 --- a/x-pack/ci/integration_tests.sh +++ b/x-pack/ci/integration_tests.sh @@ -14,6 +14,7 @@ export CI=true if [ -n "$BUILD_JAVA_HOME" ]; then GRADLE_OPTS="$GRADLE_OPTS -Dorg.gradle.java.home=$BUILD_JAVA_HOME" + export JAVA_HOME="$BUILD_JAVA_HOME" fi ./gradlew runXPackIntegrationTests \ No newline at end of file From 4ab9e9c4f03427c292d0da52cb7f013f515534ff Mon Sep 17 00:00:00 2001 From: Rob Bavey Date: Thu, 4 Jun 2020 13:50:57 -0400 Subject: [PATCH 0477/1126] [7x backport] Add openjdk14 to windows build matrix (#11971) openjdk14 appears to be the only version of java14 installed on jenkins windows worker nodes, so use this instead of zulu14 and adoptopenjdk14 Backport of #11971 --- .ci/matrix-windows-runtime-javas.yml | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/.ci/matrix-windows-runtime-javas.yml b/.ci/matrix-windows-runtime-javas.yml index 63b11fef2..4f0bc994b 100644 --- a/.ci/matrix-windows-runtime-javas.yml +++ b/.ci/matrix-windows-runtime-javas.yml @@ -6,8 +6,6 @@ # or 'openjdk' followed by the major release number. LS_RUNTIME_JAVA: -# - zulu8 -# - adoptopenjdk8 - zulu11 - - zulu14 -# - adoptopenjdk11 + - adoptopenjdk11 + - openjdk14 From 709602d9c04cfe86a191d13d3668a81a38b20128 Mon Sep 17 00:00:00 2001 From: Andres Rodriguez Date: Wed, 3 Jun 2020 10:05:39 -0400 Subject: [PATCH 0478/1126] [7x backport] Drop unnecessary os files from .ci (#11959) This commit drops unnecessary .ci config files defining distros, as it is not used. This also temporarily enables adoptopenjdk11 testing on Windows. --- ...atrix-unix-compatibility-linux-distros.yml | 28 ------------------- .ci/matrix-unix-linux-distros.yml | 9 ------ .ci/matrix-windows-compatibility-versions.yml | 10 ------- 3 files changed, 47 deletions(-) delete mode 100644 .ci/matrix-unix-linux-distros.yml delete mode 100644 .ci/matrix-windows-compatibility-versions.yml diff --git a/.ci/matrix-unix-compatibility-linux-distros.yml b/.ci/matrix-unix-compatibility-linux-distros.yml index eeb68ab09..e69de29bb 100644 --- a/.ci/matrix-unix-compatibility-linux-distros.yml +++ b/.ci/matrix-unix-compatibility-linux-distros.yml @@ -1,28 +0,0 @@ -# This file is used as part of a matrix build in Jenkins where the -# values below are included as an axis of the matrix. - -# This axis of the build matrix represents the Linux distributions on -# which Logstash will be tested. - -#os: -# - amazon -# - centos-6&&immutable -# - centos-7&&immutable -# - debian-8&&immutable -# - debian-9&&immutable -# - debian-10&&immutable -# - fedora-29&&immutable -# - opensuse-15-1&&immutable -# - oraclelinux-6&&immutable -# - oraclelinux-7&&immutable -# - ubuntu-18.04&&immutable -# - ubuntu-20.04&&immutable - -os: - - amazon - - centos&&immutable - - debian&&immutable - - fedora-29&&immutable - - opensuse-15-1&&immutable - - oraclelinux&&immutable - - ubuntu&&immutable diff --git a/.ci/matrix-unix-linux-distros.yml b/.ci/matrix-unix-linux-distros.yml deleted file mode 100644 index fdfb75dea..000000000 --- a/.ci/matrix-unix-linux-distros.yml +++ /dev/null @@ -1,9 +0,0 @@ -# This file is used as part of a matrix build in Jenkins where the -# values below are included as an axis of the matrix. - -# This axis of the build matrix represents the Linux distributions on -# which Logstash will be tested. - -os: - - centos-7&&immutable - - ubuntu-18.04&&immutable \ No newline at end of file diff --git a/.ci/matrix-windows-compatibility-versions.yml b/.ci/matrix-windows-compatibility-versions.yml deleted file mode 100644 index b3b9f3585..000000000 --- a/.ci/matrix-windows-compatibility-versions.yml +++ /dev/null @@ -1,10 +0,0 @@ -# This file is used as part of a matrix build in Jenkins where the -# values below are included as an axis of the matrix. - -# This axis of the build matrix represents the Linux distributions on -# which Logstash will be tested. - -nodes: - - "windows-2012-r2" - - "windows-2016" - - "windows-2019" From 326b1c1ed1da62ed353d9409b0e32af6e0015c1f Mon Sep 17 00:00:00 2001 From: andsel Date: Mon, 25 May 2020 14:32:35 +0200 Subject: [PATCH 0479/1126] Pass FEATURE_FLAG as Docker environment variable Some QA tests reads the FEATURE_FLAG environment variable, for example to test PQ functionality. This PR passthrough the environement variable inside the Docker instance. Fixes #11970 --- ci/docker_integration_tests.sh | 2 ++ 1 file changed, 2 insertions(+) diff --git a/ci/docker_integration_tests.sh b/ci/docker_integration_tests.sh index 0eb78569a..6264f94d5 100755 --- a/ci/docker_integration_tests.sh +++ b/ci/docker_integration_tests.sh @@ -1,2 +1,4 @@ #!/bin/bash +# we may pass "persistent_queues" to FEATURE_FLAG to enable PQ in the integration tests +export DOCKER_ENV_OPTS="${DOCKER_ENV_OPTS} -e FEATURE_FLAG" ci/docker_run.sh logstash-integration-tests ci/integration_tests.sh $@ From f3f6ca049fb2c09b83eb0ff2ad013677baa489e1 Mon Sep 17 00:00:00 2001 From: andsel Date: Tue, 26 May 2020 18:40:28 +0200 Subject: [PATCH 0480/1126] Fix integration tests related to logs when persistent_queue FEATURE_FLAG is enabled Updated log4j definitions used when FEATURE_FLAG=persistent_queue is used. Closes #11924 Fixes #11970 --- .../persistent_queues/log4j2.properties | 73 ++++++++++++++++++- 1 file changed, 70 insertions(+), 3 deletions(-) diff --git a/qa/integration/fixtures/persistent_queues/log4j2.properties b/qa/integration/fixtures/persistent_queues/log4j2.properties index ac9273b64..0791a21b1 100644 --- a/qa/integration/fixtures/persistent_queues/log4j2.properties +++ b/qa/integration/fixtures/persistent_queues/log4j2.properties @@ -4,7 +4,7 @@ name = LogstashPropertiesConfig appender.console.type = Console appender.console.name = plain_console appender.console.layout.type = PatternLayout -appender.console.layout.pattern = [%d{ISO8601}][%-5p][%-25c] %m%n +appender.console.layout.pattern = [%d{ISO8601}][%-5p][%-25c]%notEmpty{[%X{pipeline.id}]}%notEmpty{[%X{plugin.id}]} %m%n appender.json_console.type = Console appender.json_console.name = json_console @@ -21,7 +21,16 @@ appender.rolling.policies.time.type = TimeBasedTriggeringPolicy appender.rolling.policies.time.interval = 1 appender.rolling.policies.time.modulate = true appender.rolling.layout.type = PatternLayout -appender.rolling.layout.pattern = [%d{ISO8601}][%-5p][%-25c] %-.10000m%n +appender.rolling.layout.pattern = [%d{ISO8601}][%-5p][%-25c]%notEmpty{[%X{pipeline.id}]}%notEmpty{[%X{plugin.id}]} %m%n +appender.rolling.policies.size.type = SizeBasedTriggeringPolicy +appender.rolling.policies.size.size = 100MB +appender.rolling.strategy.type = DefaultRolloverStrategy +appender.rolling.strategy.max = 30 +appender.rolling.avoid_pipelined_filter.type = ScriptFilter +appender.rolling.avoid_pipelined_filter.script.type = Script +appender.rolling.avoid_pipelined_filter.script.name = filter_no_pipelined +appender.rolling.avoid_pipelined_filter.script.language = JavaScript +appender.rolling.avoid_pipelined_filter.script.value = ${sys:ls.pipeline.separate_logs} == false || !(logEvent.getContextData().containsKey("pipeline.id")) appender.json_rolling.type = RollingFile appender.json_rolling.name = json_rolling @@ -34,11 +43,43 @@ appender.json_rolling.policies.time.modulate = true appender.json_rolling.layout.type = JSONLayout appender.json_rolling.layout.compact = true appender.json_rolling.layout.eventEol = true +appender.json_rolling.policies.size.type = SizeBasedTriggeringPolicy +appender.json_rolling.policies.size.size = 100MB +appender.json_rolling.strategy.type = DefaultRolloverStrategy +appender.json_rolling.strategy.max = 30 +appender.json_rolling.avoid_pipelined_filter.type = ScriptFilter +appender.json_rolling.avoid_pipelined_filter.script.type = Script +appender.json_rolling.avoid_pipelined_filter.script.name = filter_no_pipelined +appender.json_rolling.avoid_pipelined_filter.script.language = JavaScript +appender.json_rolling.avoid_pipelined_filter.script.value = ${sys:ls.pipeline.separate_logs} == false || !(logEvent.getContextData().containsKey("pipeline.id")) +appender.routing.type = Routing +appender.routing.name = pipeline_routing_appender +appender.routing.routes.type = Routes +appender.routing.routes.script.type = Script +appender.routing.routes.script.name = routing_script +appender.routing.routes.script.language = JavaScript +appender.routing.routes.script.value = logEvent.getContextData().containsKey("pipeline.id") ? logEvent.getContextData().getValue("pipeline.id") : "sink"; +appender.routing.routes.route_pipelines.type = Route +appender.routing.routes.route_pipelines.rolling.type = RollingFile +appender.routing.routes.route_pipelines.rolling.name = appender-${ctx:pipeline.id} +appender.routing.routes.route_pipelines.rolling.fileName = ${sys:ls.logs}/pipeline_${ctx:pipeline.id}.log +appender.routing.routes.route_pipelines.rolling.filePattern = ${sys:ls.logs}/pipeline_${ctx:pipeline.id}.%i.log.gz +appender.routing.routes.route_pipelines.rolling.layout.type = PatternLayout +appender.routing.routes.route_pipelines.rolling.layout.pattern = [%d{ISO8601}][%-5p][%-25c] %m%n +appender.routing.routes.route_pipelines.rolling.policy.type = SizeBasedTriggeringPolicy +appender.routing.routes.route_pipelines.rolling.policy.size = 100MB +appender.routing.routes.route_pipelines.strategy.type = DefaultRolloverStrategy +appender.routing.routes.route_pipelines.strategy.max = 30 +appender.routing.routes.route_sink.type = Route +appender.routing.routes.route_sink.key = sink +appender.routing.routes.route_sink.null.type = Null +appender.routing.routes.route_sink.null.name = drop-appender rootLogger.level = ${sys:ls.log.level} rootLogger.appenderRef.console.ref = ${sys:ls.log.format}_console rootLogger.appenderRef.rolling.ref = ${sys:ls.log.format}_rolling +rootLogger.appenderRef.routing.ref = pipeline_routing_appender # Slowlog @@ -62,7 +103,7 @@ appender.rolling_slowlog.policies.time.type = TimeBasedTriggeringPolicy appender.rolling_slowlog.policies.time.interval = 1 appender.rolling_slowlog.policies.time.modulate = true appender.rolling_slowlog.layout.type = PatternLayout -appender.rolling_slowlog.layout.pattern = [%d{ISO8601}][%-5p][%-25c] %.10000m%n +appender.rolling_slowlog.layout.pattern = [%d{ISO8601}][%-5p][%-25c] %m%n appender.json_rolling_slowlog.type = RollingFile appender.json_rolling_slowlog.name = json_rolling_slowlog @@ -81,3 +122,29 @@ logger.slowlog.level = trace logger.slowlog.appenderRef.console_slowlog.ref = ${sys:ls.log.format}_console_slowlog logger.slowlog.appenderRef.rolling_slowlog.ref = ${sys:ls.log.format}_rolling_slowlog logger.slowlog.additivity = false + +# Deprecation log +appender.deprecation_rolling.type = RollingFile +appender.deprecation_rolling.name = deprecation_plain_rolling +appender.deprecation_rolling.fileName = ${sys:ls.logs}/logstash-deprecation.log +appender.deprecation_rolling.filePattern = ${sys:ls.logs}/logstash-deprecation-%d{yyyy-MM-dd}.log.gz +appender.deprecation_rolling.policies.type = Policies +appender.deprecation_rolling.policies.time.type = TimeBasedTriggeringPolicy +appender.deprecation_rolling.policies.time.interval = 1 +appender.deprecation_rolling.policies.time.modulate = true +appender.deprecation_rolling.layout.type = PatternLayout +appender.deprecation_rolling.layout.pattern = [%d{ISO8601}][%-5p][%-25c]%notEmpty{[%X{pipeline.id}]}%notEmpty{[%X{plugin.id}]} %m%n +appender.deprecation_rolling.policies.size.type = SizeBasedTriggeringPolicy +appender.deprecation_rolling.policies.size.size = 100MB +appender.deprecation_rolling.strategy.type = DefaultRolloverStrategy +appender.deprecation_rolling.strategy.max = 30 + +logger.deprecation.name = org.logstash.deprecation, deprecation +logger.deprecation.level = WARN +logger.deprecation.appenderRef.deprecation_rolling.ref = deprecation_plain_rolling +logger.deprecation.additivity = false + +logger.deprecation_root.name = deprecation +logger.deprecation_root.level = WARN +logger.deprecation_root.appenderRef.deprecation_rolling.ref = deprecation_plain_rolling +logger.deprecation_root.additivity = false From 24d60b81c2a43faca9c047e1c9d7c3725552ac2e Mon Sep 17 00:00:00 2001 From: andsel Date: Mon, 25 May 2020 18:08:40 +0200 Subject: [PATCH 0481/1126] Exposed again the pipelines queue.data and queue.capacity subdocuments for _node/stats Avoid to reassing the subdocument for queue metrics preferring a merge With PR #10576 the PluginsStats.report(stats) overwrites the subsection related to queue instead of merge with newly created entries. Fixes #11970 --- logstash-core/lib/logstash/api/commands/stats.rb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/logstash-core/lib/logstash/api/commands/stats.rb b/logstash-core/lib/logstash/api/commands/stats.rb index 69fe10395..2cd0bd5cd 100644 --- a/logstash-core/lib/logstash/api/commands/stats.rb +++ b/logstash-core/lib/logstash/api/commands/stats.rb @@ -167,7 +167,7 @@ module LogStash # if extended_stats were provided, enrich the return value if extended_stats - ret[:queue] = extended_stats["queue"] if extended_stats.include?("queue") + ret[:queue].merge!(extended_stats["queue"]) if extended_stats.include?("queue") ret[:hash] = extended_stats["hash"] ret[:ephemeral_id] = extended_stats["ephemeral_id"] if opts[:vertices] && extended_stats.include?("vertices") From d4e82663f6823990659a6ec856ad66201b96a8fa Mon Sep 17 00:00:00 2001 From: andsel Date: Thu, 4 Jun 2020 14:24:46 +0200 Subject: [PATCH 0482/1126] added description of xpack.monitoring.elasticsearch.proxy After the merge of PR #11799 to expose the ES proxy configuration the doc should be aligned --- docs/static/settings/monitoring-settings-legacy.asciidoc | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/docs/static/settings/monitoring-settings-legacy.asciidoc b/docs/static/settings/monitoring-settings-legacy.asciidoc index 72f836e29..56eba721b 100644 --- a/docs/static/settings/monitoring-settings-legacy.asciidoc +++ b/docs/static/settings/monitoring-settings-legacy.asciidoc @@ -28,12 +28,19 @@ Logstash metrics must be routed through your production cluster. You can specify a single host as a string, or specify multiple hosts as an array. Defaults to `http://localhost:9200`. -NOTE: If your Elasticsearch cluster is configured with dedicated master-eliglble +NOTE: If your Elasticsearch cluster is configured with dedicated master-eligible nodes, Logstash metrics should _not_ be routed to these nodes, as doing so can create resource contention and impact the stability of the Elasticsearch cluster. Therefore, do not include such nodes in `xpack.monitoring.elasticsearch.hosts`. +`xpack.monitoring.elasticsearch.proxy`:: + +The monitoring {es} instance and monitored Logstash can be separated by a proxy. +To enable Logstash to connect to a proxied {es}, set this value to the URI of the intermediate +proxy using the standard URI format, `://` for example `http://192.168.1.1`. +An empty string is treated as if proxy was not set. + `xpack.monitoring.elasticsearch.username` and `xpack.monitoring.elasticsearch.password`:: If your {es} is protected with basic authentication, these settings provide the From 8b6c524702d806a21db742b20913757fd770d658 Mon Sep 17 00:00:00 2001 From: andsel Date: Thu, 4 Jun 2020 11:05:13 +0200 Subject: [PATCH 0483/1126] better specification of the behaviour of in operator in various contexts --- docs/static/configuration.asciidoc | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/docs/static/configuration.asciidoc b/docs/static/configuration.asciidoc index e3519aecd..bc86f24eb 100644 --- a/docs/static/configuration.asciidoc +++ b/docs/static/configuration.asciidoc @@ -452,7 +452,9 @@ output { } ---------------------------------- -You can use the `in` operator to test whether a field contains a specific string, key, or (for lists) element: +You can use the `in` operator to test whether a field contains a specific string, key, or list element. +Note that the semantic meaning of `in` can vary, based on the target type. For example, when applied to +a string. `in` means "is a substring of". When applied to a collection type, `in` means "collection contains the exact value". [source,js] ---------------------------------- From 3fcd117b8418e62ab56c873a3d7afe8b77ae66bd Mon Sep 17 00:00:00 2001 From: Karen Metts Date: Fri, 5 Jun 2020 11:55:45 -0400 Subject: [PATCH 0484/1126] Doc:Add section to security docs for API keys --- docs/static/security/api-keys.asciidoc | 9 +++++++++ docs/static/security/logstash.asciidoc | 3 +++ 2 files changed, 12 insertions(+) create mode 100644 docs/static/security/api-keys.asciidoc diff --git a/docs/static/security/api-keys.asciidoc b/docs/static/security/api-keys.asciidoc new file mode 100644 index 000000000..370633f00 --- /dev/null +++ b/docs/static/security/api-keys.asciidoc @@ -0,0 +1,9 @@ +[float] +[[ls-api-keys]] +==== Grant access using API keys + + +Instead of using usernames and passwords, you can use API keys to grant +access to {es} resources. You can set API keys to expire at a certain time, +and you can explicitly invalidate them. Any user with the `manage_api_key` +or `manage_own_api_key` cluster privilege can create API keys. diff --git a/docs/static/security/logstash.asciidoc b/docs/static/security/logstash.asciidoc index 8418774d7..62f7927c9 100644 --- a/docs/static/security/logstash.asciidoc +++ b/docs/static/security/logstash.asciidoc @@ -249,3 +249,6 @@ xpack.management.elasticsearch.password: t0p.s3cr3t ---------------------------------------------------------- <1> The user you specify here must have the built-in `logstash_admin` role as well as the `logstash_writer` role that you created earlier. + +include::api-keys.asciidoc[] + From efc31ff842da9579372a499f93754d3be84baca8 Mon Sep 17 00:00:00 2001 From: Andres Rodriguez Date: Fri, 5 Jun 2020 11:46:04 -0400 Subject: [PATCH 0485/1126] Adds matrix-runtime-javas.yml (#11973) This adds the .ci/matrix-runtime-javas.yml file that defines all the JDKs logstash could be tested against. This is meant to be used for the Matrix Combinations Jenkins plugin to be able to select which JDK to test against dynamically. --- .ci/matrix-runtime-javas.yml | 13 +++++++++++++ 1 file changed, 13 insertions(+) create mode 100644 .ci/matrix-runtime-javas.yml diff --git a/.ci/matrix-runtime-javas.yml b/.ci/matrix-runtime-javas.yml new file mode 100644 index 000000000..32be40d08 --- /dev/null +++ b/.ci/matrix-runtime-javas.yml @@ -0,0 +1,13 @@ +# This file is used as part of a matrix build in Jenkins where the +# values below are included as an axis of the matrix. + +# This axis of the build matrix represents the versions of Java on +# which Logstash can be tested against. + +LS_RUNTIME_JAVA: + - openjdk11 + - openjdk14 + - adoptopenjdk11 + - adoptopenjdk14 + - zulu11 + - zulu14 From 20a30f823a7ae4ff6339b13702e64c3d8674e1bb Mon Sep 17 00:00:00 2001 From: Rob Bavey Date: Fri, 5 Jun 2020 09:51:07 -0400 Subject: [PATCH 0486/1126] Give more options for testing with ruby while waiting for port Try system ruby, then LS_HOME/bin/ruby, then relative path from script to LS_HOME/bin/ruby. Use LS_RUBY_HOME variable to avoid testing again on subsequent attempts to wait for port. --- qa/integration/services/helpers.sh | 14 +++++++++++++- 1 file changed, 13 insertions(+), 1 deletion(-) diff --git a/qa/integration/services/helpers.sh b/qa/integration/services/helpers.sh index 1e1d82265..f55be0f30 100644 --- a/qa/integration/services/helpers.sh +++ b/qa/integration/services/helpers.sh @@ -35,7 +35,19 @@ test_port_nc() { } test_port_ruby() { - ruby -rsocket -e "TCPSocket.new('localhost', $1) rescue exit(1)" + if command -v ruby 2>/dev/null; then + ruby -rsocket -e "TCPSocket.new('localhost', $1) rescue exit(1)" + else + if [[ -z $LS_RUBY_HOME ]]; then + if [[ -n $LS_HOME ]]; then + LS_RUBY_HOME=$LS_HOME + else + LS_RUBY_HOME=$current_dir/../../.. + fi + echo "Setting logstash ruby home to $LS_RUBY_HOME" + fi + $LS_RUBY_HOME/bin/ruby -rsocket -e "TCPSocket.new('localhost', $1) rescue exit(1)" + fi } clean_install_dir() { From ace1dd1318feca00c0419ea42c5f24343beb4fff Mon Sep 17 00:00:00 2001 From: Rob Bavey Date: Mon, 8 Jun 2020 10:47:03 -0400 Subject: [PATCH 0487/1126] [7x backport] Escape test fixture service scripts Backport of #11931 Escape test fixture service scripts to avoid test failures when run in Jenkins using multiple yaml configuration files, which causes directories to be constructed like `centos-7&&immutable` which cause issues with the service runners cutting off directory locations before '&&' This commit deviates from the original commit by not setting @setup_script and @teardown_script variable with the Shellwords escape, as this was removed in a subsequent commit (#11944) --- qa/integration/services/logstash_service.rb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/qa/integration/services/logstash_service.rb b/qa/integration/services/logstash_service.rb index a7f6602ef..c104eea85 100644 --- a/qa/integration/services/logstash_service.rb +++ b/qa/integration/services/logstash_service.rb @@ -95,7 +95,7 @@ class LogstashService < Service # Given an input this pipes it to LS. Expects a stdin input in LS def start_with_input(config, input) Bundler.with_clean_env do - `cat #{input} | #{@logstash_bin} -e \'#{config}\'` + `cat #{Shellwords.escape(input)} | #{Shellwords.escape(@logstash_bin)} -e \'#{config}\'` end end From 2deb5c02ada1864010c71690c1452f0ac8b018ed Mon Sep 17 00:00:00 2001 From: Rob Bavey Date: Tue, 26 May 2020 12:47:35 -0400 Subject: [PATCH 0488/1126] Fix prepare_offline_spec.rb test The 'prepare_offline_spec.rb' is failing due to a change in the warning message from JDK11 to JDK14, and JAVA_TOOL_OPTIONS being passed in as an environment variable by Jenkins, which was not happening before due to the dockerized environment. Fixes #11933 --- qa/integration/specs/cli/prepare_offline_pack_spec.rb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/qa/integration/specs/cli/prepare_offline_pack_spec.rb b/qa/integration/specs/cli/prepare_offline_pack_spec.rb index 560a59303..695529d8d 100644 --- a/qa/integration/specs/cli/prepare_offline_pack_spec.rb +++ b/qa/integration/specs/cli/prepare_offline_pack_spec.rb @@ -86,7 +86,7 @@ describe "CLI > logstash-plugin prepare-offline-pack" do filters = @logstash_plugin.list(plugins_to_pack.first) .stderr_and_stdout.split("\n") .delete_if do |line| - line =~ /cext|├──|└──|logstash-integration|JAVA_OPT|fatal|^WARNING|Option \w+ was deprecated/ + line =~ /cext|├──|└──|logstash-integration|JAVA_OPT|fatal|^WARNING|^warning: ignoring JAVA_TOOL_OPTIONS|^OpenJDK 64-Bit Server VM warning|Option \w+ was deprecated/ end expect(unpacked.plugins.collect(&:name)).to include(*filters) From 8b44f37a06c0aa840c772b7146fbfbbab8996b6d Mon Sep 17 00:00:00 2001 From: Joao Duarte Date: Tue, 9 Jun 2020 10:08:40 +0100 Subject: [PATCH 0489/1126] update commons-codec to 1.14 --- logstash-core/build.gradle | 2 +- tools/benchmark-cli/build.gradle | 2 ++ 2 files changed, 3 insertions(+), 1 deletion(-) diff --git a/logstash-core/build.gradle b/logstash-core/build.gradle index bc16ae1ca..7e30ea734 100644 --- a/logstash-core/build.gradle +++ b/logstash-core/build.gradle @@ -158,7 +158,7 @@ dependencies { implementation('org.reflections:reflections:0.9.11') { exclude group: 'com.google.guava', module: 'guava' } - implementation 'commons-codec:commons-codec:1.13' + implementation 'commons-codec:commons-codec:1.14' // Jackson version moved to versions.yml in the project root (the JrJackson version is there too) implementation "com.fasterxml.jackson.core:jackson-core:${jacksonVersion}" api "com.fasterxml.jackson.core:jackson-databind:${jacksonDatabindVersion}" diff --git a/tools/benchmark-cli/build.gradle b/tools/benchmark-cli/build.gradle index 794450d6a..bffded863 100644 --- a/tools/benchmark-cli/build.gradle +++ b/tools/benchmark-cli/build.gradle @@ -53,6 +53,8 @@ dependencies { implementation group: 'org.apache.httpcomponents', name: 'httpclient', version: '4.5.12' implementation group: 'org.apache.commons', name: 'commons-compress', version: '1.20' implementation group: 'org.apache.commons', name: 'commons-lang3', version: '3.10' + implementation group: 'commons-codec', name: 'commons-codec', version: '1.14' + implementation group: 'commons-io', name: 'commons-io', version: '2.6' implementation "com.fasterxml.jackson.core:jackson-core:${jacksonVersion}" api "com.fasterxml.jackson.core:jackson-databind:${jacksonDatabindVersion}" From 216fa60b2326a7518b9644606db27df65d6c4726 Mon Sep 17 00:00:00 2001 From: Joao Duarte Date: Mon, 8 Jun 2020 15:42:49 +0100 Subject: [PATCH 0490/1126] update log4j dependency to 2.13.3 --- logstash-core/build.gradle | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/logstash-core/build.gradle b/logstash-core/build.gradle index 7e30ea734..7555176cd 100644 --- a/logstash-core/build.gradle +++ b/logstash-core/build.gradle @@ -151,10 +151,10 @@ def customJRubyDir = project.hasProperty("custom.jruby.path") ? project.property def customJRubyVersion = customJRubyDir == "" ? "" : Files.readAllLines(Paths.get(customJRubyDir, "VERSION")).get(0).trim() dependencies { - implementation 'org.apache.logging.log4j:log4j-api:2.12.1' - annotationProcessor 'org.apache.logging.log4j:log4j-core:2.12.1' - api 'org.apache.logging.log4j:log4j-core:2.12.1' - runtimeOnly 'org.apache.logging.log4j:log4j-slf4j-impl:2.12.1' + implementation 'org.apache.logging.log4j:log4j-api:2.13.3' + annotationProcessor 'org.apache.logging.log4j:log4j-core:2.13.3' + api 'org.apache.logging.log4j:log4j-core:2.13.3' + runtimeOnly 'org.apache.logging.log4j:log4j-slf4j-impl:2.13.3' implementation('org.reflections:reflections:0.9.11') { exclude group: 'com.google.guava', module: 'guava' } @@ -178,7 +178,7 @@ dependencies { exclude group: 'com.google.guava', module: 'guava' } implementation 'org.javassist:javassist:3.26.0-GA' - testImplementation 'org.apache.logging.log4j:log4j-core:2.12.1:tests' + testImplementation 'org.apache.logging.log4j:log4j-core:2.13.3:tests' testImplementation 'junit:junit:4.12' testImplementation 'net.javacrumbs.json-unit:json-unit:2.3.0' testImplementation 'org.elasticsearch:securemock:1.2' From e5f1e613efbe1987914e0054d54dfcaca0b5931c Mon Sep 17 00:00:00 2001 From: Joao Duarte Date: Tue, 9 Jun 2020 11:18:34 +0100 Subject: [PATCH 0491/1126] update log4j script routes definition fixes the change introduced with https://issues.apache.org/jira/browse/LOG4J2-2647 --- config/log4j2.properties | 6 +++--- .../src/main/resources/log4j2-with-script.properties | 4 ++-- .../src/test/resources/log4j2-log-pipeline-test.properties | 2 +- qa/integration/fixtures/persistent_queues/log4j2.properties | 6 +++--- 4 files changed, 9 insertions(+), 9 deletions(-) diff --git a/config/log4j2.properties b/config/log4j2.properties index 68dd14240..66269e950 100644 --- a/config/log4j2.properties +++ b/config/log4j2.properties @@ -30,7 +30,7 @@ appender.rolling.avoid_pipelined_filter.type = ScriptFilter appender.rolling.avoid_pipelined_filter.script.type = Script appender.rolling.avoid_pipelined_filter.script.name = filter_no_pipelined appender.rolling.avoid_pipelined_filter.script.language = JavaScript -appender.rolling.avoid_pipelined_filter.script.value = ${sys:ls.pipeline.separate_logs} == false || !(logEvent.getContextData().containsKey("pipeline.id")) +appender.rolling.avoid_pipelined_filter.script.scriptText = ${sys:ls.pipeline.separate_logs} == false || !(logEvent.getContextData().containsKey("pipeline.id")) appender.json_rolling.type = RollingFile appender.json_rolling.name = json_rolling @@ -51,7 +51,7 @@ appender.json_rolling.avoid_pipelined_filter.type = ScriptFilter appender.json_rolling.avoid_pipelined_filter.script.type = Script appender.json_rolling.avoid_pipelined_filter.script.name = filter_no_pipelined appender.json_rolling.avoid_pipelined_filter.script.language = JavaScript -appender.json_rolling.avoid_pipelined_filter.script.value = ${sys:ls.pipeline.separate_logs} == false || !(logEvent.getContextData().containsKey("pipeline.id")) +appender.json_rolling.avoid_pipelined_filter.script.scriptText = ${sys:ls.pipeline.separate_logs} == false || !(logEvent.getContextData().containsKey("pipeline.id")) appender.routing.type = Routing appender.routing.name = pipeline_routing_appender @@ -59,7 +59,7 @@ appender.routing.routes.type = Routes appender.routing.routes.script.type = Script appender.routing.routes.script.name = routing_script appender.routing.routes.script.language = JavaScript -appender.routing.routes.script.value = logEvent.getContextData().containsKey("pipeline.id") ? logEvent.getContextData().getValue("pipeline.id") : "sink"; +appender.routing.routes.script.scriptText = logEvent.getContextData().containsKey("pipeline.id") ? logEvent.getContextData().getValue("pipeline.id") : "sink"; appender.routing.routes.route_pipelines.type = Route appender.routing.routes.route_pipelines.rolling.type = RollingFile appender.routing.routes.route_pipelines.rolling.name = appender-${ctx:pipeline.id} diff --git a/logstash-core/benchmarks/src/main/resources/log4j2-with-script.properties b/logstash-core/benchmarks/src/main/resources/log4j2-with-script.properties index 10f087d96..7c326d5fb 100644 --- a/logstash-core/benchmarks/src/main/resources/log4j2-with-script.properties +++ b/logstash-core/benchmarks/src/main/resources/log4j2-with-script.properties @@ -19,7 +19,7 @@ appender.rolling.avoid_pipelined_filter.type = ScriptFilter appender.rolling.avoid_pipelined_filter.script.type = Script appender.rolling.avoid_pipelined_filter.script.name = filter_no_pipelined appender.rolling.avoid_pipelined_filter.script.language = JavaScript -appender.rolling.avoid_pipelined_filter.script.value = ${sys:ls.pipeline.separate_logs} == false || !(logEvent.getContextData().containsKey("pipeline.id")) +appender.rolling.avoid_pipelined_filter.script.scriptText = ${sys:ls.pipeline.separate_logs} == false || !(logEvent.getContextData().containsKey("pipeline.id")) appender.routing.type = Routing appender.routing.name = pipeline_routing_appender @@ -27,7 +27,7 @@ appender.routing.routes.type = Routes appender.routing.routes.script.type = Script appender.routing.routes.script.name = routing_script appender.routing.routes.script.language = JavaScript -appender.routing.routes.script.value = logEvent.getContextData().containsKey("pipeline.id") ? logEvent.getContextData().getValue("pipeline.id") : "sink"; +appender.routing.routes.script.scriptText = logEvent.getContextData().containsKey("pipeline.id") ? logEvent.getContextData().getValue("pipeline.id") : "sink"; appender.routing.routes.route_pipelines.type = Route appender.routing.routes.route_pipelines.rolling.type = RollingFile appender.routing.routes.route_pipelines.rolling.name = appender-${ctx:pipeline.id} diff --git a/logstash-core/src/test/resources/log4j2-log-pipeline-test.properties b/logstash-core/src/test/resources/log4j2-log-pipeline-test.properties index ca06848e2..782af7dc6 100644 --- a/logstash-core/src/test/resources/log4j2-log-pipeline-test.properties +++ b/logstash-core/src/test/resources/log4j2-log-pipeline-test.properties @@ -22,7 +22,7 @@ appender.routing.routes.type = Routes appender.routing.routes.script.type = Script appender.routing.routes.script.name = routing_script appender.routing.routes.script.language = JavaScript -appender.routing.routes.script.value = logEvent.getContextMap().get("pipeline.id") +appender.routing.routes.script.scriptText = logEvent.getContextMap().get("pipeline.id") appender.routing.routes.route1.type = Route appender.routing.routes.route1.list.type = List appender.routing.routes.route1.list.name = appender-${mdc:pipeline.id} diff --git a/qa/integration/fixtures/persistent_queues/log4j2.properties b/qa/integration/fixtures/persistent_queues/log4j2.properties index 0791a21b1..dffe516fe 100644 --- a/qa/integration/fixtures/persistent_queues/log4j2.properties +++ b/qa/integration/fixtures/persistent_queues/log4j2.properties @@ -30,7 +30,7 @@ appender.rolling.avoid_pipelined_filter.type = ScriptFilter appender.rolling.avoid_pipelined_filter.script.type = Script appender.rolling.avoid_pipelined_filter.script.name = filter_no_pipelined appender.rolling.avoid_pipelined_filter.script.language = JavaScript -appender.rolling.avoid_pipelined_filter.script.value = ${sys:ls.pipeline.separate_logs} == false || !(logEvent.getContextData().containsKey("pipeline.id")) +appender.rolling.avoid_pipelined_filter.script.scriptText = ${sys:ls.pipeline.separate_logs} == false || !(logEvent.getContextData().containsKey("pipeline.id")) appender.json_rolling.type = RollingFile appender.json_rolling.name = json_rolling @@ -51,7 +51,7 @@ appender.json_rolling.avoid_pipelined_filter.type = ScriptFilter appender.json_rolling.avoid_pipelined_filter.script.type = Script appender.json_rolling.avoid_pipelined_filter.script.name = filter_no_pipelined appender.json_rolling.avoid_pipelined_filter.script.language = JavaScript -appender.json_rolling.avoid_pipelined_filter.script.value = ${sys:ls.pipeline.separate_logs} == false || !(logEvent.getContextData().containsKey("pipeline.id")) +appender.json_rolling.avoid_pipelined_filter.script.scriptText = ${sys:ls.pipeline.separate_logs} == false || !(logEvent.getContextData().containsKey("pipeline.id")) appender.routing.type = Routing appender.routing.name = pipeline_routing_appender @@ -59,7 +59,7 @@ appender.routing.routes.type = Routes appender.routing.routes.script.type = Script appender.routing.routes.script.name = routing_script appender.routing.routes.script.language = JavaScript -appender.routing.routes.script.value = logEvent.getContextData().containsKey("pipeline.id") ? logEvent.getContextData().getValue("pipeline.id") : "sink"; +appender.routing.routes.script.scriptText = logEvent.getContextData().containsKey("pipeline.id") ? logEvent.getContextData().getValue("pipeline.id") : "sink"; appender.routing.routes.route_pipelines.type = Route appender.routing.routes.route_pipelines.rolling.type = RollingFile appender.routing.routes.route_pipelines.rolling.name = appender-${ctx:pipeline.id} From 3248317eac3ffafdb5f83c898d6e07780c39511a Mon Sep 17 00:00:00 2001 From: Joao Duarte Date: Tue, 9 Jun 2020 15:23:35 +0100 Subject: [PATCH 0492/1126] upgrade google-java-format to 1.8 --- logstash-core/build.gradle | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/logstash-core/build.gradle b/logstash-core/build.gradle index 7555176cd..53f0b359d 100644 --- a/logstash-core/build.gradle +++ b/logstash-core/build.gradle @@ -171,10 +171,7 @@ dependencies { api files(customJRubyDir + "/maven/jruby-complete/target/jruby-complete-${customJRubyVersion}.jar") } implementation group: 'com.google.guava', name: 'guava', version: '24.1.1-jre' - // WARNING: DO NOT UPGRADE "google-java-format" - // later versions require GPL licensed code in javac-shaded that is - // Apache2 incompatible - implementation('com.google.googlejavaformat:google-java-format:1.1') { + implementation('com.google.googlejavaformat:google-java-format:1.8') { exclude group: 'com.google.guava', module: 'guava' } implementation 'org.javassist:javassist:3.26.0-GA' From ecbc7aa15089699264aca03de74a77a8777daca6 Mon Sep 17 00:00:00 2001 From: Joao Duarte Date: Fri, 5 Jun 2020 18:15:05 +0100 Subject: [PATCH 0493/1126] remove explicit return from Mutex#synchronize in Plugin Registry ruby produces a LocalJumpError: unexpected return error if there's a return in a block so this changes just uses the value of the last expression as the value of the block --- logstash-core/lib/logstash/plugins/registry.rb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/logstash-core/lib/logstash/plugins/registry.rb b/logstash-core/lib/logstash/plugins/registry.rb index 9a8de174e..cc87b28b2 100644 --- a/logstash-core/lib/logstash/plugins/registry.rb +++ b/logstash-core/lib/logstash/plugins/registry.rb @@ -188,7 +188,7 @@ module LogStash module Plugins raise LoadError, "Block validation fails for plugin named #{plugin_name} of type #{type}," unless block.call(plugin_spec.klass, plugin_name) end - return plugin_spec.klass + plugin_spec.klass end end From 33b6059aabb110e99ee0ab079e54b4952d671333 Mon Sep 17 00:00:00 2001 From: Joao Duarte Date: Tue, 9 Jun 2020 18:48:01 +0100 Subject: [PATCH 0494/1126] Revert "upgrade google-java-format to 1.8" This reverts commit 2229468f112134b1c7d6102e989e0c0ef057c74f. google-java-format 1.8 is Java 11 only, so we can't use it as Logstash is supported on Java 8. --- logstash-core/build.gradle | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/logstash-core/build.gradle b/logstash-core/build.gradle index 53f0b359d..7555176cd 100644 --- a/logstash-core/build.gradle +++ b/logstash-core/build.gradle @@ -171,7 +171,10 @@ dependencies { api files(customJRubyDir + "/maven/jruby-complete/target/jruby-complete-${customJRubyVersion}.jar") } implementation group: 'com.google.guava', name: 'guava', version: '24.1.1-jre' - implementation('com.google.googlejavaformat:google-java-format:1.8') { + // WARNING: DO NOT UPGRADE "google-java-format" + // later versions require GPL licensed code in javac-shaded that is + // Apache2 incompatible + implementation('com.google.googlejavaformat:google-java-format:1.1') { exclude group: 'com.google.guava', module: 'guava' } implementation 'org.javassist:javassist:3.26.0-GA' From c23360fc444e8cfeee9eda35ed5708eb70541c66 Mon Sep 17 00:00:00 2001 From: Rob Bavey Date: Tue, 9 Jun 2020 13:44:56 -0400 Subject: [PATCH 0495/1126] Add java8 to test matrix --- .ci/matrix-runtime-javas.yml | 1 + .ci/matrix-unix-runtime-javas.yml | 1 + .ci/matrix-windows-runtime-javas.yml | 1 + 3 files changed, 3 insertions(+) diff --git a/.ci/matrix-runtime-javas.yml b/.ci/matrix-runtime-javas.yml index 32be40d08..1a98d58d7 100644 --- a/.ci/matrix-runtime-javas.yml +++ b/.ci/matrix-runtime-javas.yml @@ -5,6 +5,7 @@ # which Logstash can be tested against. LS_RUNTIME_JAVA: + - java8 - openjdk11 - openjdk14 - adoptopenjdk11 diff --git a/.ci/matrix-unix-runtime-javas.yml b/.ci/matrix-unix-runtime-javas.yml index d97c9d82b..e6d36dfb1 100644 --- a/.ci/matrix-unix-runtime-javas.yml +++ b/.ci/matrix-unix-runtime-javas.yml @@ -6,6 +6,7 @@ # or 'openjdk' followed by the major release number. LS_RUNTIME_JAVA: + - java8 - openjdk11 - adoptopenjdk11 - openjdk14 diff --git a/.ci/matrix-windows-runtime-javas.yml b/.ci/matrix-windows-runtime-javas.yml index 4f0bc994b..3534e0d0c 100644 --- a/.ci/matrix-windows-runtime-javas.yml +++ b/.ci/matrix-windows-runtime-javas.yml @@ -6,6 +6,7 @@ # or 'openjdk' followed by the major release number. LS_RUNTIME_JAVA: + - java8 - zulu11 - adoptopenjdk11 - openjdk14 From 9aec9690454454b1b023bfef965f036c114c678f Mon Sep 17 00:00:00 2001 From: Karen Metts Date: Tue, 24 Mar 2020 16:34:21 -0400 Subject: [PATCH 0496/1126] Add section for conceptual info Backport of #11715 to 7.x --- docs/index.asciidoc | 5 +++++ docs/static/life-of-an-event.asciidoc | 1 + docs/static/processing-info.asciidoc | 18 ++++++++++++++++++ 3 files changed, 24 insertions(+) create mode 100644 docs/static/processing-info.asciidoc diff --git a/docs/index.asciidoc b/docs/index.asciidoc index e1d36dc7b..742a11f9a 100644 --- a/docs/index.asciidoc +++ b/docs/index.asciidoc @@ -55,6 +55,11 @@ include::static/advanced-pipeline.asciidoc[] :edit_url: https://github.com/elastic/logstash/edit/{branch}/docs/static/life-of-an-event.asciidoc include::static/life-of-an-event.asciidoc[] +// Processing details + +:edit_url!: +include::static/processing-info.asciidoc[] + // Logstash setup :edit_url: https://github.com/elastic/logstash/edit/{branch}/docs/static/setting-up-logstash.asciidoc diff --git a/docs/static/life-of-an-event.asciidoc b/docs/static/life-of-an-event.asciidoc index 608994cac..b0fa05b6d 100644 --- a/docs/static/life-of-an-event.asciidoc +++ b/docs/static/life-of-an-event.asciidoc @@ -96,3 +96,4 @@ By default, Logstash uses in-memory bounded queues between pipeline stages unsafely, any events that are stored in memory will be lost. To help prevent data loss, you can enable Logstash to persist in-flight events to disk. See <> for more information. + diff --git a/docs/static/processing-info.asciidoc b/docs/static/processing-info.asciidoc new file mode 100644 index 000000000..0dbdbf44c --- /dev/null +++ b/docs/static/processing-info.asciidoc @@ -0,0 +1,18 @@ +[[processing]] +=== Processing Details + +Understanding how {ls} works and how components interrelate can help you make better +decisions when you are setting up or adjusting your {ls} environment. This +section is designed to elevate concepts to assist with that level of +knowledge. + +NOTE: This is a new section. We're still working on it. + +[float] +[[event-ordering]] +==== Event ordering + +Event ordering info goes here. + +//todo: Document event ordering guaranties or lack thereof with multiple worker versus single worker + From 9597ab1eea2ecdca3d2b9bb8d7078fe6f5947bc9 Mon Sep 17 00:00:00 2001 From: Karen Metts Date: Mon, 6 Apr 2020 14:15:33 -0400 Subject: [PATCH 0497/1126] Add content for pipeline ordering and init time Backport of #11715 to 7.x --- docs/static/processing-info.asciidoc | 21 +++++++++++++++++++-- 1 file changed, 19 insertions(+), 2 deletions(-) diff --git a/docs/static/processing-info.asciidoc b/docs/static/processing-info.asciidoc index 0dbdbf44c..f32831be8 100644 --- a/docs/static/processing-info.asciidoc +++ b/docs/static/processing-info.asciidoc @@ -12,7 +12,24 @@ NOTE: This is a new section. We're still working on it. [[event-ordering]] ==== Event ordering -Event ordering info goes here. +The `pipeline.ordered` setting in <> +gives you more control over event ordering for single worker pipelines. + +`auto` automatically enables ordering if the `pipeline.workers` setting is also +set to `1`. `true` will enforce ordering on the pipeline and prevent logstash +from starting if there are multiple workers. `false` will disable the processing +required to preserve order. Ordering will not be guaranteed, but you save the +processing cost required to preserve order. + +[float] +[[pipeline-init-time]] +==== Java pipeline initialization time + +The Java pipeline initialization time appears in the startup logs at INFO level. +Initialization time is the time it takes to compile the pipeline config and +instantiate the compiled execution for all workers. + +If you notice a slowdown, ... + -//todo: Document event ordering guaranties or lack thereof with multiple worker versus single worker From 335032dc3fca89bbb4bcd67f430f4b3006f13be2 Mon Sep 17 00:00:00 2001 From: Karen Metts Date: Tue, 14 Apr 2020 15:01:16 -0400 Subject: [PATCH 0498/1126] Expand event ordering Backport of #11715 to 7.x --- docs/static/processing-info.asciidoc | 26 ++++++++++++++++++-------- 1 file changed, 18 insertions(+), 8 deletions(-) diff --git a/docs/static/processing-info.asciidoc b/docs/static/processing-info.asciidoc index f32831be8..c2c430f0e 100644 --- a/docs/static/processing-info.asciidoc +++ b/docs/static/processing-info.asciidoc @@ -1,9 +1,9 @@ [[processing]] === Processing Details -Understanding how {ls} works and how components interrelate can help you make better -decisions when you are setting up or adjusting your {ls} environment. This -section is designed to elevate concepts to assist with that level of +Understanding how {ls} works and how components interrelate can help you make +better decisions when you are setting up or adjusting your {ls} environment. +This section is designed to elevate concepts to assist with that level of knowledge. NOTE: This is a new section. We're still working on it. @@ -12,6 +12,21 @@ NOTE: This is a new section. We're still working on it. [[event-ordering]] ==== Event ordering +By design and by default, {ls} does not guarantee event order. Reordering can +occur in two places: + +* Events within a batch can be reordered during filter processing. +* In-flight batches can be reordered when one or more batches process faster than +others. + +When maintaining event order is important, use a single worker. +This approach ensures that batches are computed one-after-the-other, and +that events maintain their order within the batch. + +[float] +[[order-setting]] +===== 'pipeline.ordered' setting + The `pipeline.ordered` setting in <> gives you more control over event ordering for single worker pipelines. @@ -28,8 +43,3 @@ processing cost required to preserve order. The Java pipeline initialization time appears in the startup logs at INFO level. Initialization time is the time it takes to compile the pipeline config and instantiate the compiled execution for all workers. - -If you notice a slowdown, ... - - - From 610abaaf99e51acd263ac5cb22f2422d3301b4da Mon Sep 17 00:00:00 2001 From: Karen Metts <35154725+karenzone@users.noreply.github.com> Date: Thu, 16 Apr 2020 17:21:38 -0400 Subject: [PATCH 0499/1126] Wording tweak Backport of #11715 to 7.x --- docs/static/processing-info.asciidoc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/static/processing-info.asciidoc b/docs/static/processing-info.asciidoc index c2c430f0e..34f7bc959 100644 --- a/docs/static/processing-info.asciidoc +++ b/docs/static/processing-info.asciidoc @@ -16,7 +16,7 @@ By design and by default, {ls} does not guarantee event order. Reordering can occur in two places: * Events within a batch can be reordered during filter processing. -* In-flight batches can be reordered when one or more batches process faster than +* In-flight batches can be reordered when one or more batches are processed faster than others. When maintaining event order is important, use a single worker. From 9bb792a0d692ba79384ddae200519d0080a0958b Mon Sep 17 00:00:00 2001 From: Karen Metts <35154725+karenzone@users.noreply.github.com> Date: Tue, 9 Jun 2020 09:40:34 -0400 Subject: [PATCH 0500/1126] Incorporate review comments Backport of #11715 to 7.x --- docs/static/processing-info.asciidoc | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/docs/static/processing-info.asciidoc b/docs/static/processing-info.asciidoc index 34f7bc959..6466c9af0 100644 --- a/docs/static/processing-info.asciidoc +++ b/docs/static/processing-info.asciidoc @@ -19,7 +19,8 @@ occur in two places: * In-flight batches can be reordered when one or more batches are processed faster than others. -When maintaining event order is important, use a single worker. +When maintaining event order is important, use a single worker and set +'pipeline.ordered => true'. This approach ensures that batches are computed one-after-the-other, and that events maintain their order within the batch. From 6832040d28ec5e01156a0a760bafd490caab0c28 Mon Sep 17 00:00:00 2001 From: Karen Metts Date: Fri, 5 Jun 2020 16:03:20 -0400 Subject: [PATCH 0501/1126] Doc:Add section and update JVM settings This work breaks out the JVM setting info into a new section, and expands and updates the content. It adds new subheadings to make scanning the content easier. --- .../getting-started-with-logstash.asciidoc | 29 ++---------- docs/static/jvm.asciidoc | 46 +++++++++++++++++++ 2 files changed, 49 insertions(+), 26 deletions(-) create mode 100644 docs/static/jvm.asciidoc diff --git a/docs/static/getting-started-with-logstash.asciidoc b/docs/static/getting-started-with-logstash.asciidoc index 8f22500d8..224d6c877 100644 --- a/docs/static/getting-started-with-logstash.asciidoc +++ b/docs/static/getting-started-with-logstash.asciidoc @@ -7,40 +7,17 @@ input, parses the logs, and writes the parsed data to an Elasticsearch cluster. This section includes the following topics: +* <> * <> * <> * {logstash-ref}/advanced-pipeline.html[Parsing Logs with Logstash] * {logstash-ref}/multiple-input-output-plugins.html[Stitching Together Multiple Input and Output Plugins] +include::jvm.asciidoc[] + [[installing-logstash]] === Installing Logstash -NOTE: Logstash requires Java 8 or Java 11. Use the -http://www.oracle.com/technetwork/java/javase/downloads/index.html[official Oracle distribution] or an open-source -distribution such as http://openjdk.java.net/[OpenJDK]. - -To check your Java version, run the following command: - -[source,shell] -java -version - -On systems with Java installed, this command produces output similar to the following: - -[source,shell] ------ -java version "11.0.1" 2018-10-16 LTS -Java(TM) SE Runtime Environment 18.9 (build 11.0.1+13-LTS) -Java HotSpot(TM) 64-Bit Server VM 18.9 (build 11.0.1+13-LTS, mixed mode) ------ - -On some Linux systems, you may also need to have the `JAVA_HOME` environment -exported before attempting the install, particularly if you installed Java from -a tarball. This is because Logstash uses Java during installation to -automatically detect your environment and install the correct startup method -(SysV init scripts, Upstart, or systemd). If Logstash is unable to find the -JAVA_HOME environment variable during package installation time, you may get an -error message, and Logstash will be unable to start properly. - [float] [[installing-binary]] === Installing from a Downloaded Binary diff --git a/docs/static/jvm.asciidoc b/docs/static/jvm.asciidoc new file mode 100644 index 000000000..74277625d --- /dev/null +++ b/docs/static/jvm.asciidoc @@ -0,0 +1,46 @@ +[float] +[[ls-jvm]] +=== Java (JVM) version + +{ls} requires one of these versions: + +* Java 8 +* Java 11 +* Java 14 + +Use the +http://www.oracle.com/technetwork/java/javase/downloads/index.html[official +Oracle distribution] or an open-source distribution, such as +http://openjdk.java.net/[OpenJDK]. + +[float] +[[check-jvm]] +==== Check your Java version +Run the following command: + +[source,shell] +java -version + +On systems with Java installed, this command produces output similar to the following: + +[source,shell] +----- +java version "11.0.1" 2018-10-16 LTS +Java(TM) SE Runtime Environment 18.9 (build 11.0.1+13-LTS) +Java HotSpot(TM) 64-Bit Server VM 18.9 (build 11.0.1+13-LTS, mixed mode) +----- + +[float] +[[java-home]] +==== `JAVA_HOME` + +{ls} uses the Java version set in `JAVA_HOME`. The `JAVA_HOME` environment +variable must be set for {ls} to operate correctly. + +On some Linux systems, you may need to have the `JAVA_HOME` environment +exported before installing {ls}, particularly if you installed Java from +a tarball. +{ls} uses Java during installation to automatically detect your environment and +install the correct startup method (SysV init scripts, Upstart, or systemd). If +{ls} is unable to find the `JAVA_HOME` environment variable during package +installation, you may get an error message, and {ls} will not start properly. From 58b6e4d1c6afab69693c8414a10354ca4b11cb9c Mon Sep 17 00:00:00 2001 From: Colin Surprenant Date: Wed, 10 Jun 2020 14:03:52 -0400 Subject: [PATCH 0502/1126] add commented out options for api_key in logstash.yml --- config/logstash.yml | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/config/logstash.yml b/config/logstash.yml index c86332125..d7c544e75 100644 --- a/config/logstash.yml +++ b/config/logstash.yml @@ -260,6 +260,8 @@ pipeline.ordered: auto # an alternative to hosts + username/password settings is to use cloud_id/cloud_auth #xpack.monitoring.elasticsearch.cloud_id: monitoring_cluster_id:xxxxxxxxxx #xpack.monitoring.elasticsearch.cloud_auth: logstash_system:password +# another authentication alternative is to use an Elasticsearch API key +#xpack.monitoring.elasticsearch.api_key: "id:api_key" #xpack.monitoring.elasticsearch.ssl.certificate_authority: [ "/path/to/ca.crt" ] #xpack.monitoring.elasticsearch.ssl.truststore.path: path/to/file #xpack.monitoring.elasticsearch.ssl.truststore.password: password @@ -280,6 +282,8 @@ pipeline.ordered: auto # an alternative to hosts + username/password settings is to use cloud_id/cloud_auth #xpack.management.elasticsearch.cloud_id: management_cluster_id:xxxxxxxxxx #xpack.management.elasticsearch.cloud_auth: logstash_admin_user:password +# another authentication alternative is to use an Elasticsearch API key +#xpack.management.elasticsearch.api_key: "id:api_key" #xpack.management.elasticsearch.ssl.certificate_authority: [ "/path/to/ca.crt" ] #xpack.management.elasticsearch.ssl.truststore.path: /path/to/file #xpack.management.elasticsearch.ssl.truststore.password: password From 8d53676aac17e9c9a15a0a3d012c165240f56eb7 Mon Sep 17 00:00:00 2001 From: Joao Duarte Date: Tue, 9 Jun 2020 21:40:42 +0100 Subject: [PATCH 0503/1126] retry on failed gradlew wrapper command in Dockerfile --- Dockerfile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Dockerfile b/Dockerfile index a62f16d99..bf7ac2fc6 100644 --- a/Dockerfile +++ b/Dockerfile @@ -27,7 +27,7 @@ COPY --chown=logstash:logstash gradlew /opt/logstash/gradlew COPY --chown=logstash:logstash gradle/wrapper /opt/logstash/gradle/wrapper COPY --chown=logstash:logstash settings.gradle /opt/logstash/settings.gradle WORKDIR /opt/logstash -RUN ./gradlew wrapper --warning-mode all +RUN for iter in `seq 1 10`; do ./gradlew wrapper --warning-mode all && exit_code=0 && break || exit_code=$? && echo "gradlew error: retry $iter in 10s" && sleep 10; done; exit $exit_code WORKDIR /home/logstash ADD versions.yml /opt/logstash/versions.yml From addcb8a0a785ed4fb2af49a2fff4c463431205a2 Mon Sep 17 00:00:00 2001 From: Rob Bavey Date: Fri, 12 Jun 2020 09:27:18 -0400 Subject: [PATCH 0504/1126] Retrieve branch version of Filebeat via gradle (#12011) Clean backport of #11958 This commit changes the download to pull the version of beats based on the version pulled from the branch rather than from an environment variable, or 6.5.4. This commit also moves the download logic of Filebeat fromfilebeat_setup.sh to build.gradle in order to use the artifacts API in the same way as the downloadEs task, and does some refactoring to DRY up the artifact download tasks. This commit also fixes the beats integration test to replace the use of a removed setting. This commit also sets retries to 3 for the download tasks, using 'retries' functionality from gradle download task plugin --- build.gradle | 173 ++++++++++++-------- qa/integration/services/filebeat_service.rb | 2 +- qa/integration/services/filebeat_setup.sh | 27 +-- qa/integration/specs/beats_input_spec.rb | 6 +- 4 files changed, 112 insertions(+), 96 deletions(-) diff --git a/build.gradle b/build.gradle index f5ee79650..550fb9a5e 100644 --- a/build.gradle +++ b/build.gradle @@ -121,15 +121,49 @@ subprojects { } } -// fetch version from Logstash's master versions.yml file version = versionMap['logstash-core'] -def versionQualifier = System.getenv('VERSION_QUALIFIER') -if (versionQualifier) { - version = "$version-$versionQualifier" +String artifactVersionsApi = "https://artifacts-api.elastic.co/v1/versions" + +tasks.register("configureArchitecture") { + String arch = "x86_64" + String osName = System.properties['os.name'] + + if (osName ==~ /Mac OS X/) { + osName = "darwin" + } else { + osName = "linux" + } + String architecture = "${osName}-${arch}" + project.ext.set("architecture", architecture) } -// a release build will try to download the exact version artifact and not append -SNAPSHOT to it see -// the downloadEs task below -def isReleaseBuild = System.getenv('RELEASE') == "1" || versionQualifier + +tasks.register("configureArtifactInfo") { + dependsOn configureArchitecture + def versionQualifier = System.getenv('VERSION_QUALIFIER') + if (versionQualifier) { + version = "$version-$versionQualifier" + } + + def isReleaseBuild = System.getenv('RELEASE') == "1" || versionQualifier + String apiResponse = artifactVersionsApi.toURL().text + + def dlVersions = new JsonSlurper().parseText(apiResponse) + String qualifiedVersion = dlVersions['versions'].grep(isReleaseBuild ? ~/^${version}$/ : ~/^${version}-SNAPSHOT/)[0] + if (qualifiedVersion == null) { + throw new GradleException("could not find the current artifact from the artifact-api ${artifactVersionsApi} for ${version}") + } + // find latest reference to last build + String buildsListApi = "${artifactVersionsApi}/${qualifiedVersion}/builds/" + apiResponse = buildsListApi.toURL().text + def dlBuilds = new JsonSlurper().parseText(apiResponse) + def stackBuildVersion = dlBuilds["builds"][0] + + project.ext.set("artifactApiVersionedBuildUrl", "${artifactVersionsApi}/${qualifiedVersion}/builds/${stackBuildVersion}") + project.ext.set("stackArtifactSuffix", "${qualifiedVersion}-${project.ext.get('architecture')}") + project.ext.set("stackArtifactSuffixNoArch", qualifiedVersion) +} + + // Tasks @@ -300,20 +334,68 @@ tasks.register("installIntegrationTestGems") { } } + + +tasks.register("downloadFilebeat", Download) { + dependsOn configureArtifactInfo + description "Download Filebeat Snapshot for current branch version: ${version}" + + project.ext.set("versionFound", true) + + String downloadedFilebeatName = "filebeat-${project.ext.get("stackArtifactSuffix")}" + project.ext.set("unpackedFilebeatName", downloadedFilebeatName) + + // find url of build artifact + String artifactApiUrl = "${project.ext.get("artifactApiVersionedBuildUrl")}/projects/beats/packages/${downloadedFilebeatName}.tar.gz" + String apiResponse = artifactApiUrl.toURL().text + def buildUrls = new JsonSlurper().parseText(apiResponse) + + project.ext.set("filebeatSnapshotUrl", System.getenv("FILEBEAT_SNAPSHOT_URL") ?: buildUrls["package"]["url"]) + project.ext.set("filebeatDownloadLocation", "${projectDir}/build/${downloadedFilebeatName}.tar.gz") + + + src project.ext.filebeatSnapshotUrl + onlyIfNewer true + inputs.file("${projectDir}/versions.yml") + outputs.file(project.ext.filebeatDownloadLocation) + dest new File(project.ext.filebeatDownloadLocation) + retries 3 + doLast { + System.out.println "Downloaded to ${project.ext.filebeatDownloadLocation}" + } +} + +tasks.register("deleteLocalFilebeat", Delete) { + delete ('./build/filebeat') +} + +tasks.register("copyFilebeat", Copy){ + dependsOn = [downloadFilebeat, deleteLocalFilebeat] + from tarTree(resources.gzip(project.ext.filebeatDownloadLocation)) + into "./build/" + doLast { + file("./build/${project.ext.unpackedFilebeatName}").renameTo('./build/filebeat') + System.out.println "Unzipped ${project.ext.filebeatDownloadLocation} to ./build/filebeat" + System.out.println "Deleting ${project.ext.filebeatDownloadLocation}" + delete(project.ext.filebeatDownloadLocation) + } +} + def rubyIntegrationSpecs = project.hasProperty("rubyIntegrationSpecs") ? ((String) project.property("rubyIntegrationSpecs")).split(/\s+/).join(",") : "specs/**/*_spec.rb" def integrationTestPwd = "${projectDir}/qa/integration" project(":logstash-integration-tests") { tasks.getByPath(":logstash-integration-tests:integrationTests").configure { - systemProperty 'org.logstash.integration.specs', rubyIntegrationSpecs - environment "FEATURE_FLAG", System.getenv('FEATURE_FLAG') - workingDir integrationTestPwd - dependsOn installIntegrationTestGems - } + systemProperty 'org.logstash.integration.specs', rubyIntegrationSpecs + environment "FEATURE_FLAG", System.getenv('FEATURE_FLAG') + workingDir integrationTestPwd + dependsOn installIntegrationTestGems + } } tasks.register("runIntegrationTests"){ dependsOn tasks.getByPath(":logstash-integration-tests:integrationTests") + dependsOn copyFilebeat } tasks.register("generateLicenseReport", JavaExec) { @@ -368,69 +450,25 @@ bootstrap.dependsOn assemblyDeps runIntegrationTests.shouldRunAfter tasks.getByPath(":logstash-core:test") check.dependsOn runIntegrationTests -String artifactsVersionApi = "https://artifacts-api.elastic.co/v1/versions/" tasks.register("downloadEs", Download) { + dependsOn configureArtifactInfo description "Download ES Snapshot for current branch version: ${version}" - - doFirst { - if (!project.ext.versionFound) { - throw new GradleException("could not find the current artifact from the artifact-api ${artifactsVersionApi} for " + (isReleaseBuild ? "release" : "snapshot") + " version: ${version}") - } - } - - String apiResponse = artifactsVersionApi.toURL().text - def dlVersions = new JsonSlurper().parseText(apiResponse) - // the version string can be either '7.0.0' or '7.0.0-alpha1', i.e. with the qualifier. - // in the normal PR type builds it is plain '7.0.0' - // in the build invoked by the release manager it is '7.0.0-alpha1' etc. - // the artifacts-api will return JSON like this: `{"versions":["5.6.13-SNAPSHOT","6.4.3-SNAPSHOT","6.5.0-SNAPSHOT","6.6.0-SNAPSHOT","7.0.0-alpha1-SNAPSHOT"]}` - String qualifiedVersion = dlVersions['versions'].grep(isReleaseBuild ? ~/^${version}$/ : ~/^${version}-SNAPSHOT/)[0] + String downloadedElasticsearchName = "elasticsearch-${project.ext.get("stackArtifactSuffix")}" + project.ext.set("unpackedElasticsearchName", "elasticsearch-${project.ext.get("stackArtifactSuffixNoArch")}") - if (qualifiedVersion == null) { - // the version is not found in the versions API, for now just set dummy values so the - // task parameters like src and dest below sees these dummy values but also set - // versionFound to false so that we can fail the task in the doFirst closure. - // this is somewhat convoluted and there is certainly a better way to do this but - // it seems to be an acceptable solution for now. - project.ext.set("versionFound", false) - project.ext.set("elasticsearchSnapshotURL", "http://elastic.co/invalid") - project.ext.set("elasticsearchDownloadLocation", "${projectDir}/build/invalid") - } else { - project.ext.set("versionFound", true) + // find url of build artifact + String artifactApiUrl = "${project.ext.get("artifactApiVersionedBuildUrl")}/projects/elasticsearch/packages/${downloadedElasticsearchName}.tar.gz" + String apiResponse = artifactApiUrl.toURL().text + def buildUrls = new JsonSlurper().parseText(apiResponse) - String arch = "x86_64" - String osName = System.properties['os.name'] - - if (osName ==~ /Mac OS X/) { - osName = "darwin" - } else { - osName = "linux" - } - - String architecture = "${osName}-${arch}" - - String downloadedElasticsearchName = "elasticsearch-${qualifiedVersion}-${architecture}" - project.ext.set("unpackedElasticsearchName", "elasticsearch-${qualifiedVersion}") - - // find latest reference to last build - String buildsListApi = "https://artifacts-api.elastic.co/v1/versions/${qualifiedVersion}/builds/" - apiResponse = buildsListApi.toURL().text - def dlBuilds = new JsonSlurper().parseText(apiResponse) - String build = dlBuilds["builds"][0] - - // find url of build artifact - String artifactApiUrl = "https://artifacts-api.elastic.co/v1/versions/${qualifiedVersion}/builds/${build}/projects/elasticsearch/packages/${downloadedElasticsearchName}.tar.gz" - apiResponse = artifactApiUrl.toURL().text - def buildUrls = new JsonSlurper().parseText(apiResponse) - - project.ext.set("elasticsearchSnapshotURL", System.getenv("ELASTICSEARCH_SNAPSHOT_URL") ?: buildUrls["package"]["url"]) - project.ext.set("elasticsearchDownloadLocation", "${projectDir}/build/${downloadedElasticsearchName}.tar.gz") - } + project.ext.set("elasticsearchSnapshotURL", System.getenv("ELASTICSEARCH_SNAPSHOT_URL") ?: buildUrls["package"]["url"]) + project.ext.set("elasticsearchDownloadLocation", "${projectDir}/build/${downloadedElasticsearchName}.tar.gz") src project.ext.elasticsearchSnapshotURL onlyIfNewer true + retries 3 inputs.file("${projectDir}/versions.yml") outputs.file(project.ext.elasticsearchDownloadLocation) dest new File(project.ext.elasticsearchDownloadLocation) @@ -440,6 +478,7 @@ tasks.register("downloadEs", Download) { } } + tasks.register("deleteLocalEs", Delete) { delete ('./build/elasticsearch') } @@ -451,6 +490,8 @@ tasks.register("copyEs", Copy){ doLast { file("./build/${project.ext.unpackedElasticsearchName}").renameTo('./build/elasticsearch') System.out.println "Unzipped ${project.ext.elasticsearchDownloadLocation} to ./build/elasticsearch" + System.out.println "Deleting ${project.ext.elasticsearchDownloadLocation}" + delete(project.ext.elasticsearchDownloadLocation) } } diff --git a/qa/integration/services/filebeat_service.rb b/qa/integration/services/filebeat_service.rb index d735e8a1e..04decf8c3 100644 --- a/qa/integration/services/filebeat_service.rb +++ b/qa/integration/services/filebeat_service.rb @@ -16,7 +16,7 @@ # under the License. class FilebeatService < Service - FILEBEAT_CMD = [File.join(File.dirname(__FILE__), "installed", "filebeat", "filebeat"), "--strict.perms=false", "-c"] + FILEBEAT_CMD = [File.join(File.dirname(__FILE__), "../../../build", "filebeat", "filebeat"), "--strict.perms=false", "-c"] class BackgroundProcess def initialize(cmd) diff --git a/qa/integration/services/filebeat_setup.sh b/qa/integration/services/filebeat_setup.sh index 3bd73b3a7..bbe995e76 100755 --- a/qa/integration/services/filebeat_setup.sh +++ b/qa/integration/services/filebeat_setup.sh @@ -4,35 +4,10 @@ current_dir="$(dirname "$0")" source "$current_dir/helpers.sh" -if [ -n "${FILEBEAT_VERSION}" ]; then - echo "Filebeat version is $FILEBEAT_VERSION" - version=$FILEBEAT_VERSION -else - version=6.5.4 -fi - -FB_HOME=$INSTALL_DIR/filebeat - -setup_fb() { - local version=$1 - platform=`uname -s | tr '[:upper:]' '[:lower:]'` - architecture=`uname -m | tr '[:upper:]' '[:lower:]'` - download_url=https://artifacts.elastic.co/downloads/beats/filebeat/filebeat-$version-$platform-$architecture.tar.gz - curl -sL $download_url > $INSTALL_DIR/filebeat.tar.gz - mkdir $FB_HOME - tar -xzf $INSTALL_DIR/filebeat.tar.gz --strip-components=1 -C $FB_HOME/. - rm $INSTALL_DIR/filebeat.tar.gz -} - generate_certificate() { target_directory=$current_dir/../fixtures/certificates mkdir -p $target_directory openssl req -subj '/CN=localhost/' -x509 -days $((100 * 365)) -batch -nodes -newkey rsa:2048 -keyout $target_directory/certificate.key -out $target_directory/certificate.crt } -setup_install_dir - -if [ ! -d $FB_HOME ]; then - generate_certificate - setup_fb $version -fi +generate_certificate diff --git a/qa/integration/specs/beats_input_spec.rb b/qa/integration/specs/beats_input_spec.rb index b35956d61..d87e2c248 100644 --- a/qa/integration/specs/beats_input_spec.rb +++ b/qa/integration/specs/beats_input_spec.rb @@ -85,7 +85,7 @@ describe "Beat Input" do { "filebeat" => { "inputs" => [{ "paths" => [log_path], "input_type" => "log" }], - "registry_file" => registry_file, + "registry.path" => registry_file, "scan_frequency" => "1s" }, "output" => { @@ -110,7 +110,7 @@ describe "Beat Input" do { "filebeat" => { "inputs" => [{ "paths" => [log_path], "input_type" => "log" }], - "registry_file" => registry_file, + "registry.path" => registry_file, "scan_frequency" => "1s" }, "output" => { @@ -137,7 +137,7 @@ describe "Beat Input" do { "filebeat" => { "inputs" => [{ "paths" => [log_path], "input_type" => "log" }], - "registry_file" => registry_file, + "registry.path" => registry_file, "scan_frequency" => "1s" }, "output" => { From 7f5859664386c6703a60900db69c97e450abb46d Mon Sep 17 00:00:00 2001 From: Joao Duarte Date: Fri, 12 Jun 2020 10:10:59 +0100 Subject: [PATCH 0505/1126] remove uses of JSON.load in favor or JSON.parse JSON.load allows the creation of complex objects, and should not be given untrusted input. This commit changes the only three uses of JSON.load in the codebase, which aren't user facing or present in bundled product, so not really an attact vector. --- qa/integration/specs/reload_config_spec.rb | 2 +- rakelib/default_plugins.rb | 2 +- rakelib/modules.rake | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/qa/integration/specs/reload_config_spec.rb b/qa/integration/specs/reload_config_spec.rb index b4864e435..4092aa9b2 100644 --- a/qa/integration/specs/reload_config_spec.rb +++ b/qa/integration/specs/reload_config_spec.rb @@ -95,7 +95,7 @@ describe "Test Logstash service when config reload is enabled" do expect(instance_reload_stats["successes"]).to eq(1) expect(instance_reload_stats["failures"]).to eq(0) # parse the results and validate - re = JSON.load(File.new(output_file2)) + re = JSON.parse(IO.read(output_file2)) expect(re["clientip"]).to eq("74.125.176.147") expect(re["response"]).to eq(200) end diff --git a/rakelib/default_plugins.rb b/rakelib/default_plugins.rb index 8df255dd7..08d10e7e9 100644 --- a/rakelib/default_plugins.rb +++ b/rakelib/default_plugins.rb @@ -40,7 +40,7 @@ module LogStash # Lets use the standard library here, in the context of the bootstrap the # logstash-core could have failed to be installed. require "json" - JSON.load(::File.read("rakelib/plugins-metadata.json")).select do |_, metadata| + JSON.parse(::File.read("rakelib/plugins-metadata.json")).select do |_, metadata| metadata[type] end.keys end diff --git a/rakelib/modules.rake b/rakelib/modules.rake index fc09509d4..adf00ad9b 100644 --- a/rakelib/modules.rake +++ b/rakelib/modules.rake @@ -19,7 +19,7 @@ namespace "modules" do def unpacker(src_file, dest_dir) puts "Reading #{src_file}" - array = JSON.load(IO.read(src_file)) + array = JSON.parse(IO.read(src_file)) if !array.is_a?(Array) raise "#{src_file} does not contain a JSON array as the first object" From b5528c5ffac5b4dba76fe2049feecfe2ea726750 Mon Sep 17 00:00:00 2001 From: Karen Metts Date: Thu, 11 Jun 2020 13:10:53 -0400 Subject: [PATCH 0506/1126] Doc:Add link to JVM section of support matrix Add link to support matrix as official word on supported versions. --- docs/static/jvm.asciidoc | 3 +++ 1 file changed, 3 insertions(+) diff --git a/docs/static/jvm.asciidoc b/docs/static/jvm.asciidoc index 74277625d..38a142cfe 100644 --- a/docs/static/jvm.asciidoc +++ b/docs/static/jvm.asciidoc @@ -8,6 +8,9 @@ * Java 11 * Java 14 +See the https://www.elastic.co/support/matrix#matrix_jvm[Elastic Support Matrix] +for the official word on supported versions across releases. + Use the http://www.oracle.com/technetwork/java/javase/downloads/index.html[official Oracle distribution] or an open-source distribution, such as From 1a0d5c961fe15b77769e220e0009e47d179ea631 Mon Sep 17 00:00:00 2001 From: Rob Bavey Date: Mon, 1 Jun 2020 16:58:07 -0400 Subject: [PATCH 0507/1126] Use branch appropriate version of Elasticsearch Carrying on from the work done in #11958, update the gradle build to download the same version of Elasticsearch as is specified in the logstash version.yml file. This commit updates the standard integration tests to use the same version of Elasticsearch that is already downloaded for x-pack integration tests, and also fixes integration tests to allow for the different responses around hits generated by different versions of Elasticsearch. --- build.gradle | 106 ++++++++++-------- .../services/elasticsearch_setup.sh | 22 +--- .../services/elasticsearch_teardown.sh | 2 +- qa/integration/specs/dlq_spec.rb | 5 +- qa/integration/specs/es_output_how_spec.rb | 5 +- qa/integration/specs/spec_helper.rb | 7 ++ 6 files changed, 72 insertions(+), 75 deletions(-) diff --git a/build.gradle b/build.gradle index 550fb9a5e..98e3aab22 100644 --- a/build.gradle +++ b/build.gradle @@ -381,23 +381,75 @@ tasks.register("copyFilebeat", Copy){ } } +tasks.register("downloadEs", Download) { + dependsOn configureArtifactInfo + description "Download ES Snapshot for current branch version: ${version}" + + String downloadedElasticsearchName = "elasticsearch-${project.ext.get("stackArtifactSuffix")}" + project.ext.set("unpackedElasticsearchName", "elasticsearch-${project.ext.get("stackArtifactSuffixNoArch")}") + + // find url of build artifact + String artifactApiUrl = "${project.ext.get("artifactApiVersionedBuildUrl")}/projects/elasticsearch/packages/${downloadedElasticsearchName}.tar.gz" + String apiResponse = artifactApiUrl.toURL().text + def buildUrls = new JsonSlurper().parseText(apiResponse) + + project.ext.set("elasticsearchSnapshotURL", System.getenv("ELASTICSEARCH_SNAPSHOT_URL") ?: buildUrls["package"]["url"]) + project.ext.set("elasticsearchDownloadLocation", "${projectDir}/build/${downloadedElasticsearchName}.tar.gz") + + src project.ext.elasticsearchSnapshotURL + onlyIfNewer true + retries 3 + inputs.file("${projectDir}/versions.yml") + outputs.file(project.ext.elasticsearchDownloadLocation) + dest new File(project.ext.elasticsearchDownloadLocation) + + doLast { + System.out.println "Downloaded to ${project.ext.elasticsearchDownloadLocation}" + } +} + + +tasks.register("deleteLocalEs", Delete) { + delete ('./build/elasticsearch') +} + +tasks.register("copyEs", Copy){ + dependsOn = [downloadEs, deleteLocalEs] + from tarTree(resources.gzip(project.ext.elasticsearchDownloadLocation)) + into "./build/" + doLast { + file("./build/${project.ext.unpackedElasticsearchName}").renameTo('./build/elasticsearch') + System.out.println "Unzipped ${project.ext.elasticsearchDownloadLocation} to ./build/elasticsearch" + System.out.println "Deleting ${project.ext.elasticsearchDownloadLocation}" + delete(project.ext.elasticsearchDownloadLocation) + } +} + + def rubyIntegrationSpecs = project.hasProperty("rubyIntegrationSpecs") ? ((String) project.property("rubyIntegrationSpecs")).split(/\s+/).join(",") : "specs/**/*_spec.rb" def integrationTestPwd = "${projectDir}/qa/integration" project(":logstash-integration-tests") { tasks.getByPath(":logstash-integration-tests:integrationTests").configure { - systemProperty 'org.logstash.integration.specs', rubyIntegrationSpecs - environment "FEATURE_FLAG", System.getenv('FEATURE_FLAG') - workingDir integrationTestPwd - dependsOn installIntegrationTestGems - } + systemProperty 'org.logstash.integration.specs', rubyIntegrationSpecs + environment "FEATURE_FLAG", System.getenv('FEATURE_FLAG') + workingDir integrationTestPwd + dependsOn installIntegrationTestGems + } } tasks.register("runIntegrationTests"){ dependsOn tasks.getByPath(":logstash-integration-tests:integrationTests") + dependsOn copyEs dependsOn copyFilebeat } +bootstrap.dependsOn assemblyDeps + +runIntegrationTests.shouldRunAfter tasks.getByPath(":logstash-core:test") +check.dependsOn runIntegrationTests + + tasks.register("generateLicenseReport", JavaExec) { dependsOn generateLicenseReportInputs dependsOn ":dependencies-report:assemble" @@ -451,50 +503,6 @@ runIntegrationTests.shouldRunAfter tasks.getByPath(":logstash-core:test") check.dependsOn runIntegrationTests -tasks.register("downloadEs", Download) { - dependsOn configureArtifactInfo - description "Download ES Snapshot for current branch version: ${version}" - - String downloadedElasticsearchName = "elasticsearch-${project.ext.get("stackArtifactSuffix")}" - project.ext.set("unpackedElasticsearchName", "elasticsearch-${project.ext.get("stackArtifactSuffixNoArch")}") - - // find url of build artifact - String artifactApiUrl = "${project.ext.get("artifactApiVersionedBuildUrl")}/projects/elasticsearch/packages/${downloadedElasticsearchName}.tar.gz" - String apiResponse = artifactApiUrl.toURL().text - def buildUrls = new JsonSlurper().parseText(apiResponse) - - project.ext.set("elasticsearchSnapshotURL", System.getenv("ELASTICSEARCH_SNAPSHOT_URL") ?: buildUrls["package"]["url"]) - project.ext.set("elasticsearchDownloadLocation", "${projectDir}/build/${downloadedElasticsearchName}.tar.gz") - - src project.ext.elasticsearchSnapshotURL - onlyIfNewer true - retries 3 - inputs.file("${projectDir}/versions.yml") - outputs.file(project.ext.elasticsearchDownloadLocation) - dest new File(project.ext.elasticsearchDownloadLocation) - - doLast { - System.out.println "Downloaded to ${project.ext.elasticsearchDownloadLocation}" - } -} - - -tasks.register("deleteLocalEs", Delete) { - delete ('./build/elasticsearch') -} - -tasks.register("copyEs", Copy){ - dependsOn = [downloadEs, deleteLocalEs] - from tarTree(resources.gzip(project.ext.elasticsearchDownloadLocation)) - into "./build/" - doLast { - file("./build/${project.ext.unpackedElasticsearchName}").renameTo('./build/elasticsearch') - System.out.println "Unzipped ${project.ext.elasticsearchDownloadLocation} to ./build/elasticsearch" - System.out.println "Deleting ${project.ext.elasticsearchDownloadLocation}" - delete(project.ext.elasticsearchDownloadLocation) - } -} - Boolean oss = System.getenv('OSS').equals('true') if (!oss) { diff --git a/qa/integration/services/elasticsearch_setup.sh b/qa/integration/services/elasticsearch_setup.sh index b0bbc1637..c5cebcf1e 100755 --- a/qa/integration/services/elasticsearch_setup.sh +++ b/qa/integration/services/elasticsearch_setup.sh @@ -4,25 +4,7 @@ current_dir="$(dirname "$0")" source "$current_dir/helpers.sh" -if [ -n "${ES_VERSION+1}" ]; then - echo "Elasticsearch version is $ES_VERSION" - version=$ES_VERSION -else - version=6.5.4 -fi - -ES_HOME=$INSTALL_DIR/elasticsearch - -setup_es() { - if [ ! -d $ES_HOME ]; then - local version=$1 - download_url=https://artifacts.elastic.co/downloads/elasticsearch/elasticsearch-$version.tar.gz - curl -sL $download_url > $INSTALL_DIR/elasticsearch.tar.gz - mkdir $ES_HOME - tar -xzf $INSTALL_DIR/elasticsearch.tar.gz --strip-components=1 -C $ES_HOME/. - rm $INSTALL_DIR/elasticsearch.tar.gz - fi -} +ES_HOME="$current_dir/../../../build/elasticsearch" start_es() { es_args=$@ @@ -38,7 +20,5 @@ start_es() { return 0 } -setup_install_dir -setup_es $version export ES_JAVA_OPTS="-Xms512m -Xmx512m" start_es diff --git a/qa/integration/services/elasticsearch_teardown.sh b/qa/integration/services/elasticsearch_teardown.sh index e0531a3e7..516db893a 100755 --- a/qa/integration/services/elasticsearch_teardown.sh +++ b/qa/integration/services/elasticsearch_teardown.sh @@ -4,7 +4,7 @@ current_dir="$(dirname "$0")" source "$current_dir/helpers.sh" -ES_HOME=$INSTALL_DIR/elasticsearch +ES_HOME="$current_dir/../../../build/elasticsearch" stop_es() { pid=$(cat $ES_HOME/elasticsearch.pid) diff --git a/qa/integration/specs/dlq_spec.rb b/qa/integration/specs/dlq_spec.rb index 3145cb55f..ae6cc80c9 100644 --- a/qa/integration/specs/dlq_spec.rb +++ b/qa/integration/specs/dlq_spec.rb @@ -19,6 +19,8 @@ require_relative '../framework/fixture' require_relative '../framework/settings' require_relative '../services/logstash_service' require_relative '../framework/helpers' +require_relative 'spec_helper.rb' + require "logstash/devutils/rspec/spec_helper" describe "Test Dead Letter Queue" do @@ -66,12 +68,11 @@ describe "Test Dead Letter Queue" do try(60) do begin result = es_client.search(index: 'logstash-*', size: 0, q: '*') - hits = result["hits"]["total"] rescue Elasticsearch::Transport::Transport::Errors::ServiceUnavailable => e puts "Elasticsearch unavailable #{e.inspect}" hits = 0 end - expect(hits).to eq(1000) + expect(result).to have_hits(1000) end result = es_client.search(index: 'logstash-*', size: 1, q: '*') diff --git a/qa/integration/specs/es_output_how_spec.rb b/qa/integration/specs/es_output_how_spec.rb index 0272e8511..55fbc3af6 100644 --- a/qa/integration/specs/es_output_how_spec.rb +++ b/qa/integration/specs/es_output_how_spec.rb @@ -18,6 +18,7 @@ require_relative '../framework/fixture' require_relative '../framework/settings' require_relative '../services/logstash_service' +require_relative 'spec_helper.rb' describe "Test Elasticsearch output" do @@ -39,11 +40,11 @@ describe "Test Elasticsearch output" do # now we test if all data was indexed by ES, but first refresh manually es_client.indices.refresh result = es_client.search(index: 'logstash-*', size: 0, q: '*') - expect(result["hits"]["total"]).to eq(37) + expect(result).to have_hits(37) # randomly checked for results and structured fields result = es_client.search(index: 'logstash-*', size: 1, q: 'dynamic') - expect(result["hits"]["total"]).to eq(1) + expect(result).to have_hits(1) s = result["hits"]["hits"][0]["_source"] expect(s["bytes"]).to eq(18848) expect(s["response"]).to eq(200) diff --git a/qa/integration/specs/spec_helper.rb b/qa/integration/specs/spec_helper.rb index a14e6463a..71a1eb420 100644 --- a/qa/integration/specs/spec_helper.rb +++ b/qa/integration/specs/spec_helper.rb @@ -22,3 +22,10 @@ RSpec.configure do |config| config.filter_run_excluding exclude_tags end + +RSpec::Matchers.define :have_hits do |expected| + match do |actual| + # For Elasticsearch versions 7+, the result is in a value field, just in total for > 6 + expected == actual['hits']['total'].is_a?(Hash) ? actual['hits']['total']['value'] : actual['hits']['total'] + end +end From af54d95df849a89f9401f4c81b52ede691e1db1d Mon Sep 17 00:00:00 2001 From: Rob Bavey Date: Fri, 12 Jun 2020 17:02:17 -0400 Subject: [PATCH 0508/1126] Tests: Add support for alternative architectures Enable filebeat and elasticsearch downloads to pull different architectures, Filebeat and Elasticsearch use different suffixes to denote their aarch64 architectures, with beats using arm64 and elasticsearch aarch64 --- build.gradle | 40 ++++++++++++++++++++++++---------------- 1 file changed, 24 insertions(+), 16 deletions(-) diff --git a/build.gradle b/build.gradle index 98e3aab22..53df9822c 100644 --- a/build.gradle +++ b/build.gradle @@ -125,16 +125,27 @@ version = versionMap['logstash-core'] String artifactVersionsApi = "https://artifacts-api.elastic.co/v1/versions" tasks.register("configureArchitecture") { - String arch = "x86_64" + String arch = System.properties['os.arch'] String osName = System.properties['os.name'] + String beatsArch = arch + String esArch = arch + + // For aarch64 architectures, beats and elasticsearch name their artifacts differently + if (arch == "aarch64") {i + beatsArch="arm64" + esArch="aarch64" + } else if (arch == "amd64") { + beatsArch="x86_64" + esArch="x86_64" + } if (osName ==~ /Mac OS X/) { osName = "darwin" } else { osName = "linux" } - String architecture = "${osName}-${arch}" - project.ext.set("architecture", architecture) + project.ext.set("beatsArchitecture", "${osName}-${beatsArch}") + project.ext.set("esArchitecture", "${osName}-${esArch}") } tasks.register("configureArtifactInfo") { @@ -159,8 +170,7 @@ tasks.register("configureArtifactInfo") { def stackBuildVersion = dlBuilds["builds"][0] project.ext.set("artifactApiVersionedBuildUrl", "${artifactVersionsApi}/${qualifiedVersion}/builds/${stackBuildVersion}") - project.ext.set("stackArtifactSuffix", "${qualifiedVersion}-${project.ext.get('architecture')}") - project.ext.set("stackArtifactSuffixNoArch", qualifiedVersion) + project.ext.set("stackArtifactSuffix", qualifiedVersion) } @@ -334,15 +344,13 @@ tasks.register("installIntegrationTestGems") { } } - - tasks.register("downloadFilebeat", Download) { dependsOn configureArtifactInfo description "Download Filebeat Snapshot for current branch version: ${version}" project.ext.set("versionFound", true) - String downloadedFilebeatName = "filebeat-${project.ext.get("stackArtifactSuffix")}" + String downloadedFilebeatName = "filebeat-${project.ext.get("stackArtifactSuffix")}-${project.ext.get("beatsArchitecture")}" project.ext.set("unpackedFilebeatName", downloadedFilebeatName) // find url of build artifact @@ -381,12 +389,13 @@ tasks.register("copyFilebeat", Copy){ } } + tasks.register("downloadEs", Download) { dependsOn configureArtifactInfo description "Download ES Snapshot for current branch version: ${version}" - String downloadedElasticsearchName = "elasticsearch-${project.ext.get("stackArtifactSuffix")}" - project.ext.set("unpackedElasticsearchName", "elasticsearch-${project.ext.get("stackArtifactSuffixNoArch")}") + String downloadedElasticsearchName = "elasticsearch-${project.ext.get("stackArtifactSuffix")}-${project.ext.get("esArchitecture")}" + project.ext.set("unpackedElasticsearchName", "elasticsearch-${project.ext.get("stackArtifactSuffix")}") // find url of build artifact String artifactApiUrl = "${project.ext.get("artifactApiVersionedBuildUrl")}/projects/elasticsearch/packages/${downloadedElasticsearchName}.tar.gz" @@ -425,17 +434,16 @@ tasks.register("copyEs", Copy){ } } - def rubyIntegrationSpecs = project.hasProperty("rubyIntegrationSpecs") ? ((String) project.property("rubyIntegrationSpecs")).split(/\s+/).join(",") : "specs/**/*_spec.rb" def integrationTestPwd = "${projectDir}/qa/integration" project(":logstash-integration-tests") { tasks.getByPath(":logstash-integration-tests:integrationTests").configure { - systemProperty 'org.logstash.integration.specs', rubyIntegrationSpecs - environment "FEATURE_FLAG", System.getenv('FEATURE_FLAG') - workingDir integrationTestPwd - dependsOn installIntegrationTestGems - } + systemProperty 'org.logstash.integration.specs', rubyIntegrationSpecs + environment "FEATURE_FLAG", System.getenv('FEATURE_FLAG') + workingDir integrationTestPwd + dependsOn installIntegrationTestGems + } } tasks.register("runIntegrationTests"){ From 018550f8635f5984d319720205f3aaa1e3ffa95a Mon Sep 17 00:00:00 2001 From: Lisa Cawley Date: Wed, 17 Jun 2020 07:27:42 -0700 Subject: [PATCH 0509/1126] [DOCS] Fixes Stack Overview links (#12025) (#12026) --- docs/gs-index.asciidoc | 1 - docs/static/docker.asciidoc | 2 +- docs/static/getting-started-with-logstash.asciidoc | 2 +- docs/static/management/centralized-pipelines.asciidoc | 2 +- .../management/configuring-centralized-pipelines.asciidoc | 2 +- docs/static/setup/setting-up-xpack.asciidoc | 2 +- 6 files changed, 5 insertions(+), 6 deletions(-) diff --git a/docs/gs-index.asciidoc b/docs/gs-index.asciidoc index 23c39dd8c..feec48b87 100644 --- a/docs/gs-index.asciidoc +++ b/docs/gs-index.asciidoc @@ -20,7 +20,6 @@ release-state can be: released | prerelease | unreleased :filebeat: https://www.elastic.co/guide/en/beats/filebeat/{branch}/ :lsissue: https://github.com/elastic/logstash/issues/ :security: X-Pack Security -:stack: https://www.elastic.co/guide/en/elastic-stack/current/ [[introduction]] == Logstash Introduction diff --git a/docs/static/docker.asciidoc b/docs/static/docker.asciidoc index 366902632..6fdddc8f9 100644 --- a/docs/static/docker.asciidoc +++ b/docs/static/docker.asciidoc @@ -9,7 +9,7 @@ https://github.com/elastic/logstash/tree/{branch}[GitHub]. These images are free to use under the Elastic license. They contain open source and free commercial features and access to paid commercial features. -{stack-ov}/license-management.html[Start a 30-day trial] to try out all of the +{kibana-ref}/managing-licenses.html[Start a 30-day trial] to try out all of the paid commercial features. See the https://www.elastic.co/subscriptions[Subscriptions] page for information about Elastic license levels. diff --git a/docs/static/getting-started-with-logstash.asciidoc b/docs/static/getting-started-with-logstash.asciidoc index 224d6c877..bdb3cca11 100644 --- a/docs/static/getting-started-with-logstash.asciidoc +++ b/docs/static/getting-started-with-logstash.asciidoc @@ -34,7 +34,7 @@ contains colon (:) characters. -- These packages are free to use under the Elastic license. They contain open source and free commercial features and access to paid commercial features. -{stack-ov}/license-management.html[Start a 30-day trial] to try out all of the +{kibana-ref}/managing-licenses.html[Start a 30-day trial] to try out all of the paid commercial features. See the https://www.elastic.co/subscriptions[Subscriptions] page for information about Elastic license levels. diff --git a/docs/static/management/centralized-pipelines.asciidoc b/docs/static/management/centralized-pipelines.asciidoc index 619ba884f..1410119f2 100644 --- a/docs/static/management/centralized-pipelines.asciidoc +++ b/docs/static/management/centralized-pipelines.asciidoc @@ -10,7 +10,7 @@ with the basic license. If you want to try all of the features, you can start a 30-day trial. At the end of the trial period, you can purchase a subscription to keep using the full functionality of the {xpack} components. For more information, see https://www.elastic.co/subscriptions and -{stack-ov}/license-management.html[License +{kibana-ref}/managing-licenses.html[License Management]. You can control multiple Logstash instances from the pipeline management UI in diff --git a/docs/static/management/configuring-centralized-pipelines.asciidoc b/docs/static/management/configuring-centralized-pipelines.asciidoc index db5390dff..6e408093c 100644 --- a/docs/static/management/configuring-centralized-pipelines.asciidoc +++ b/docs/static/management/configuring-centralized-pipelines.asciidoc @@ -13,7 +13,7 @@ feature. + -- For more information, see https://www.elastic.co/subscriptions and -{stack-ov}/license-management.html[License management]. +{kibana-ref}/managing-licenses.html[License management]. -- . Specify diff --git a/docs/static/setup/setting-up-xpack.asciidoc b/docs/static/setup/setting-up-xpack.asciidoc index a8add39c1..fcc731e0c 100644 --- a/docs/static/setup/setting-up-xpack.asciidoc +++ b/docs/static/setup/setting-up-xpack.asciidoc @@ -7,6 +7,6 @@ monitoring, machine learning, pipeline management, and many other capabilities. By default, when you install Logstash, {xpack} is installed. If you want to try all of the {xpack} features, you can -{stack-ov}/license-management.html[start a 30-day trial]. At the end of the +{kibana-ref}/managing-licenses.html[start a 30-day trial]. At the end of the trial period, you can purchase a subscription to keep using the full functionality of the {xpack} components. For more information, see https://www.elastic.co/subscriptions. From 6c50eda135d8d8ff9d779add7bee75679f91628c Mon Sep 17 00:00:00 2001 From: Rob Bavey Date: Thu, 16 Jan 2020 12:00:53 -0500 Subject: [PATCH 0510/1126] [7x_backport] Add link conversion from Markdown to AsciiDoctor (#11508) Backport of #11508 to convert links from Markdown to AsciiDoctor while generating release notes. --- tools/release/generate_release_notes.rb | 1 + 1 file changed, 1 insertion(+) diff --git a/tools/release/generate_release_notes.rb b/tools/release/generate_release_notes.rb index 141783e7f..9ee2f3314 100755 --- a/tools/release/generate_release_notes.rb +++ b/tools/release/generate_release_notes.rb @@ -97,6 +97,7 @@ plugin_changes.each do |plugin, versions| next if line.match(/^##/) line.gsub!(/^\+/, "") line.gsub!(/ #(?\d+)\s*$/, " https://github.com/logstash-plugins/#{plugin}/issues/\\k[#\\k]") + line.gsub!(/\[#(?\d+)\]\((?[^)]*)\)/, "\\k[#\\k]") line.gsub!(/^\s+-/, "*") report << line end From 35d2b391aa7153216257740002681905e5b0c00e Mon Sep 17 00:00:00 2001 From: Karol Bucek Date: Thu, 30 Apr 2020 14:55:07 +0200 Subject: [PATCH 0511/1126] Feat: ship log4j2 commons-logging bridge with LS Having the jar around would allow us to fine tune logging for libraries such as manticore's http-client (4.5) using LS's `log4j2.properties` e.g. ``` logger.apache_http_headers.name = org.apache.http.headers logger.apache_http_headers.level = DEBUG ``` ... to log http headers for each request Co-authored-by: Ry Biesemeyer --- config/log4j2.properties | 6 +++++- logstash-core/build.gradle | 4 ++++ 2 files changed, 9 insertions(+), 1 deletion(-) diff --git a/config/log4j2.properties b/config/log4j2.properties index 66269e950..18e655840 100644 --- a/config/log4j2.properties +++ b/config/log4j2.properties @@ -134,6 +134,10 @@ logger.slowlog.additivity = false logger.licensereader.name = logstash.licensechecker.licensereader logger.licensereader.level = error +# Silence http-client by default +logger.apache_http_client.name = org.apache.http +logger.apache_http_client.level = fatal + # Deprecation log appender.deprecation_rolling.type = RollingFile appender.deprecation_rolling.name = deprecation_plain_rolling @@ -158,4 +162,4 @@ logger.deprecation.additivity = false logger.deprecation_root.name = deprecation logger.deprecation_root.level = WARN logger.deprecation_root.appenderRef.deprecation_rolling.ref = deprecation_plain_rolling -logger.deprecation_root.additivity = false \ No newline at end of file +logger.deprecation_root.additivity = false diff --git a/logstash-core/build.gradle b/logstash-core/build.gradle index 7555176cd..f01e2271d 100644 --- a/logstash-core/build.gradle +++ b/logstash-core/build.gradle @@ -155,6 +155,10 @@ dependencies { annotationProcessor 'org.apache.logging.log4j:log4j-core:2.13.3' api 'org.apache.logging.log4j:log4j-core:2.13.3' runtimeOnly 'org.apache.logging.log4j:log4j-slf4j-impl:2.13.3' + // concerns libraries such as manticore's http-client 4.5 (using commons-logging) + runtimeOnly 'org.apache.logging.log4j:log4j-jcl:2.13.3' + // for the log4j-jcl bridge to work commons-logging needs to be on the same class-path + runtimeOnly 'commons-logging:commons-logging:1.2' implementation('org.reflections:reflections:0.9.11') { exclude group: 'com.google.guava', module: 'guava' } From d767848394539275bb7ee545bc06287b029e008e Mon Sep 17 00:00:00 2001 From: Colin Surprenant Date: Thu, 18 Jun 2020 17:01:57 -0400 Subject: [PATCH 0512/1126] Changed the assignment of plugin.id to load the value dynamically istead of hardcode MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Changed ComputeStepSyntaxElement to generate Java code to retrieve the plugin's id by a method instead of hardcoding the value in the generated code. This permit to share more compiled classes, that differs only by plugin.id and speed up the pipeline compilation. The change has been secured by future regression with unit test that track pipeline compilations times. Co-authored-by: Andrea Selva Co-authored-by: João Duarte Fixes: #12031 --- .../ir/compiler/ComputeStepSyntaxElement.java | 23 ++- .../config/ir/compiler/DatasetCompiler.java | 34 ++-- .../config/ir/CompiledPipelineTest.java | 158 +++++++++++++++++- .../org/logstash/config/ir/IRHelpers.java | 39 ++++- .../logstash/config/ir/cache/pipeline1.conf | 19 +++ .../logstash/config/ir/cache/pipeline2.conf | 24 +++ 6 files changed, 271 insertions(+), 26 deletions(-) create mode 100644 logstash-core/src/test/resources/org/logstash/config/ir/cache/pipeline1.conf create mode 100644 logstash-core/src/test/resources/org/logstash/config/ir/cache/pipeline2.conf diff --git a/logstash-core/src/main/java/org/logstash/config/ir/compiler/ComputeStepSyntaxElement.java b/logstash-core/src/main/java/org/logstash/config/ir/compiler/ComputeStepSyntaxElement.java index 0381435bd..58353aa25 100644 --- a/logstash-core/src/main/java/org/logstash/config/ir/compiler/ComputeStepSyntaxElement.java +++ b/logstash-core/src/main/java/org/logstash/config/ir/compiler/ComputeStepSyntaxElement.java @@ -20,6 +20,7 @@ package org.logstash.config.ir.compiler; +import com.google.common.annotations.VisibleForTesting; import com.google.googlejavaformat.java.Formatter; import com.google.googlejavaformat.java.FormatterException; import java.io.IOException; @@ -84,6 +85,22 @@ public final class ComputeStepSyntaxElement { return new ComputeStepSyntaxElement<>(methods, fields, interfce); } + @VisibleForTesting + public static int classCacheSize() { + return CLASS_CACHE.size(); + } + + /* + * Used in a test to clean start, with class loaders wiped out into Janino compiler and cleared the cached classes. + * */ + @VisibleForTesting + public static void cleanClassCache() { + synchronized (COMPILER) { + CLASS_CACHE.clear(); + COMPILER.setParentClassLoader(null); + } + } + private ComputeStepSyntaxElement( final Iterable methods, final ClassFields fields, @@ -100,9 +117,9 @@ public final class ComputeStepSyntaxElement { @SuppressWarnings("unchecked") public T instantiate() { - try { - final Class clazz = compile(); - return (T) clazz.getConstructor(Map.class).newInstance(ctorArguments()); + try { + final Class clazz = compile(); + return (T) clazz.getConstructor(Map.class).newInstance(ctorArguments()); } catch (final NoSuchMethodException | InvocationTargetException | InstantiationException | IllegalAccessException ex) { throw new IllegalStateException(ex); } diff --git a/logstash-core/src/main/java/org/logstash/config/ir/compiler/DatasetCompiler.java b/logstash-core/src/main/java/org/logstash/config/ir/compiler/DatasetCompiler.java index 2e30d678c..689fb0030 100644 --- a/logstash-core/src/main/java/org/logstash/config/ir/compiler/DatasetCompiler.java +++ b/logstash-core/src/main/java/org/logstash/config/ir/compiler/DatasetCompiler.java @@ -236,11 +236,12 @@ public final class DatasetCompiler { final ClassFields fields = new ClassFields(); final Closure clearSyntax; final Closure computeSyntax; + final ValueSyntaxElement outputField = fields.add(output); if (parents.isEmpty()) { clearSyntax = Closure.EMPTY; computeSyntax = Closure.wrap( - setPluginIdForLog4j(output), - invokeOutput(fields.add(output), BATCH_ARG), + setPluginIdForLog4j(outputField), + invokeOutput(outputField, BATCH_ARG), unsetPluginIdForLog4j()); } else { final Collection parentFields = @@ -258,8 +259,8 @@ public final class DatasetCompiler { final ValueSyntaxElement inputBuffer = fields.add(buffer); computeSyntax = withInputBuffering( Closure.wrap( - setPluginIdForLog4j(output), - invokeOutput(fields.add(output), inputBuffer), + setPluginIdForLog4j(outputField), + invokeOutput(outputField, inputBuffer), inlineClear, unsetPluginIdForLog4j() ), @@ -284,7 +285,7 @@ public final class DatasetCompiler { { final ValueSyntaxElement filterField = fields.add(plugin); final Closure body = Closure.wrap( - setPluginIdForLog4j(plugin), + setPluginIdForLog4j(filterField), buffer(outputBuffer, filterField.call("multiFilter", inputBuffer)) ); if (plugin.hasFlush()) { @@ -393,21 +394,18 @@ public final class DatasetCompiler { } private static MethodLevelSyntaxElement unsetPluginIdForLog4j() { - return () -> "org.apache.logging.log4j.ThreadContext.remove(\"plugin.id\")"; + return SyntaxFactory.value("org.apache.logging.log4j.ThreadContext").call( + "remove", + SyntaxFactory.value("\"plugin.id\"") + ); } - private static MethodLevelSyntaxElement setPluginIdForLog4j(final AbstractFilterDelegatorExt filterPlugin) { - final IRubyObject pluginId = filterPlugin.getId(); - return generateLog4jContextAssignment(pluginId); - } - - private static MethodLevelSyntaxElement setPluginIdForLog4j(final AbstractOutputDelegatorExt outputPlugin) { - final IRubyObject pluginId = outputPlugin.getId(); - return generateLog4jContextAssignment(pluginId); - } - - private static MethodLevelSyntaxElement generateLog4jContextAssignment(IRubyObject pluginId) { - return () -> "org.apache.logging.log4j.ThreadContext.put(\"plugin.id\", \"" + pluginId + "\")"; + private static MethodLevelSyntaxElement setPluginIdForLog4j(final ValueSyntaxElement plugin) { + return SyntaxFactory.value("org.apache.logging.log4j.ThreadContext").call( + "put", + SyntaxFactory.value("\"plugin.id\""), + plugin.call("getId").call("toString") + ); } private static MethodLevelSyntaxElement clear(final ValueSyntaxElement field) { diff --git a/logstash-core/src/test/java/org/logstash/config/ir/CompiledPipelineTest.java b/logstash-core/src/test/java/org/logstash/config/ir/CompiledPipelineTest.java index 638c0cc98..323cea7a7 100644 --- a/logstash-core/src/test/java/org/logstash/config/ir/CompiledPipelineTest.java +++ b/logstash-core/src/test/java/org/logstash/config/ir/CompiledPipelineTest.java @@ -22,6 +22,10 @@ package org.logstash.config.ir; import co.elastic.logstash.api.Codec; import com.google.common.base.Strings; + +import java.io.IOException; +import java.time.LocalTime; +import java.time.temporal.ChronoUnit; import java.util.ArrayList; import java.util.Collection; import java.util.Collections; @@ -45,10 +49,10 @@ import org.logstash.ConvertedList; import org.logstash.ConvertedMap; import org.logstash.Event; import org.logstash.RubyUtil; -import org.logstash.common.IncompleteSourceWithMetadataException; import org.logstash.common.SourceWithMetadata; import org.logstash.config.ir.compiler.AbstractFilterDelegatorExt; import org.logstash.config.ir.compiler.AbstractOutputDelegatorExt; +import org.logstash.config.ir.compiler.ComputeStepSyntaxElement; import org.logstash.config.ir.compiler.FilterDelegatorExt; import org.logstash.config.ir.compiler.PluginFactory; import org.logstash.ext.JrubyEventExtLibrary; @@ -57,6 +61,9 @@ import co.elastic.logstash.api.Filter; import co.elastic.logstash.api.Input; import co.elastic.logstash.api.Context; +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertTrue; + /** * Tests for {@link CompiledPipeline}. */ @@ -560,4 +567,153 @@ public final class CompiledPipelineTest extends RubyEnvTestCase { return null; } } + + @Test + @SuppressWarnings({"unchecked"}) + public void testCompilerCacheCompiledClasses() throws IOException, InvalidIRException { + final FixedPluginFactory pluginFactory = new FixedPluginFactory( + () -> null, + () -> IDENTITY_FILTER, + mockOutputSupplier() + ); + + final PipelineIR baselinePipeline = ConfigCompiler.configToPipelineIR( + IRHelpers.toSourceWithMetadataFromPath("org/logstash/config/ir/cache/pipeline1.conf"), + false); + final CompiledPipeline cBaselinePipeline = new CompiledPipeline(baselinePipeline, pluginFactory); + + final PipelineIR pipelineWithExtraFilter = ConfigCompiler.configToPipelineIR( + IRHelpers.toSourceWithMetadataFromPath("org/logstash/config/ir/cache/pipeline2.conf"), + false); + final CompiledPipeline cPipelineWithExtraFilter = new CompiledPipeline(pipelineWithExtraFilter, pluginFactory); + + // actual test: compiling a pipeline with an extra filter should only create 1 extra class + ComputeStepSyntaxElement.cleanClassCache(); + cBaselinePipeline.buildExecution(); + final int cachedBefore = ComputeStepSyntaxElement.classCacheSize(); + cPipelineWithExtraFilter.buildExecution(); + final int cachedAfter = ComputeStepSyntaxElement.classCacheSize(); + + final String message = String.format("unexpected cache size, cachedAfter: %d, cachedBefore: %d", cachedAfter, cachedBefore); + assertEquals(message, 1, cachedAfter - cachedBefore); + } + + @Test + @SuppressWarnings({"unchecked", "rawtypes"}) + public void compilerBenchmark() throws Exception { + final PipelineIR baselinePipelineIR = createPipelineIR(200); + final PipelineIR testPipelineIR = createPipelineIR(400); + final JrubyEventExtLibrary.RubyEvent testEvent = + JrubyEventExtLibrary.RubyEvent.newRubyEvent(RubyUtil.RUBY, new Event()); + + final FixedPluginFactory pluginFactory = new FixedPluginFactory( + () -> null, + () -> IDENTITY_FILTER, + mockOutputSupplier() + ); + final CompiledPipeline baselineCompiledPipeline = new CompiledPipeline(baselinePipelineIR, pluginFactory); + + final CompiledPipeline testCompiledPipeline = new CompiledPipeline(testPipelineIR, pluginFactory); + + final long compilationBaseline = time(ChronoUnit.SECONDS, () -> { + final CompiledPipeline.CompiledExecution compiledExecution = baselineCompiledPipeline.buildExecution(); + compiledExecution.compute(RubyUtil.RUBY.newArray(testEvent), false, false); + }); + + final long compilationTest = time(ChronoUnit.SECONDS, () -> { + final CompiledPipeline.CompiledExecution compiledExecution = testCompiledPipeline.buildExecution(); + compiledExecution.compute(RubyUtil.RUBY.newArray(testEvent), false, false); + }); + + // sanity checks + final Collection outputEvents = EVENT_SINKS.get(runId); + MatcherAssert.assertThat(outputEvents.size(), CoreMatchers.is(2)); + MatcherAssert.assertThat(outputEvents.contains(testEvent), CoreMatchers.is(true)); + + // regression check + final String testMessage = "regression in pipeline compilation, doubling the filters require more than 5 " + + "time, baseline: " + compilationBaseline + " secs, test: " + compilationTest + " secs"; + assertTrue(testMessage, compilationTest/compilationBaseline <= 5); + } + + private long time(ChronoUnit seconds, Runnable r) { + LocalTime start = LocalTime.now(); + r.run(); + LocalTime stop = LocalTime.now(); + return seconds.between(start, stop); + } + + @SuppressWarnings({"unchecked", "rawtypes"}) + private PipelineIR createPipelineIR(int numFilters) throws InvalidIRException { + final String pipelineConfig = createBigPipelineDefinition(numFilters); + final RubyArray swms = IRHelpers.toSourceWithMetadata(pipelineConfig); + return ConfigCompiler.configToPipelineIR(swms,false); + } + + private String createBigPipelineDefinition(int numFilters) { + return "input { stdin {}} filter {" + createBigFilterSection(numFilters) + "} output { stdout {}}"; + } + + private String createBigFilterSection(int numFilters) { + final StringBuilder sb = new StringBuilder(); + for (int i = 0; i < numFilters; i++) { + sb.append("mutate { id => \"").append(i).append("\" rename => [\"a_field\", \"into_another\"]}\n"); + } + return sb.toString(); + } + + /** + * Fixed Mock {@link PluginFactory} + * */ + static final class FixedPluginFactory implements PluginFactory { + + private Supplier input; + private Supplier filter; + private Supplier>> output; + + FixedPluginFactory(Supplier input, Supplier filter, + Supplier>> output) { + this.input = input; + this.filter = filter; + this.output = output; + } + + @Override + public Input buildInput(String name, String id, Configuration configuration, Context context) { + return null; + } + + @Override + public Filter buildFilter(String name, String id, Configuration configuration, Context context) { + return null; + } + + @Override + public IRubyObject buildInput(RubyString name, SourceWithMetadata source, IRubyObject args, Map pluginArgs) { + return this.input.get(); + } + + @Override + public AbstractOutputDelegatorExt buildOutput(RubyString name, SourceWithMetadata source, IRubyObject args, Map pluginArgs) { + return PipelineTestUtil.buildOutput(this.output.get()); + } + + @Override + public AbstractFilterDelegatorExt buildFilter(RubyString name, SourceWithMetadata source, IRubyObject args, Map pluginArgs) { + final RubyObject configNameDouble = org.logstash.config.ir.PluginConfigNameMethodDouble.create(name); + return new FilterDelegatorExt( + RubyUtil.RUBY, RubyUtil.FILTER_DELEGATOR_CLASS) + .initForTesting(this.filter.get(), configNameDouble); + } + + @Override + public IRubyObject buildCodec(RubyString name, SourceWithMetadata source, IRubyObject args, Map pluginArgs) { + return null; + } + + @Override + public Codec buildDefaultCodec(String codecName) { + return null; + } + } } diff --git a/logstash-core/src/test/java/org/logstash/config/ir/IRHelpers.java b/logstash-core/src/test/java/org/logstash/config/ir/IRHelpers.java index 0856d5eb1..c500a113b 100644 --- a/logstash-core/src/test/java/org/logstash/config/ir/IRHelpers.java +++ b/logstash-core/src/test/java/org/logstash/config/ir/IRHelpers.java @@ -20,9 +20,11 @@ package org.logstash.config.ir; +import com.google.common.io.Files; import org.hamcrest.MatcherAssert; import org.jruby.RubyArray; import org.jruby.javasupport.JavaUtil; +import org.jruby.runtime.builtin.IRubyObject; import org.logstash.RubyUtil; import org.logstash.common.IncompleteSourceWithMetadataException; import org.logstash.common.SourceWithMetadata; @@ -34,10 +36,11 @@ import org.logstash.config.ir.graph.Graph; import org.logstash.config.ir.graph.Vertex; import org.logstash.config.ir.graph.algorithms.GraphDiff; -import java.util.HashMap; -import java.util.Objects; -import java.util.Random; -import java.util.UUID; +import java.io.File; +import java.io.IOException; +import java.net.URL; +import java.nio.charset.Charset; +import java.util.*; import java.util.concurrent.Callable; import static org.logstash.config.ir.DSL.*; @@ -195,4 +198,32 @@ public class IRHelpers { return RubyUtil.RUBY.newArray(JavaUtil.convertJavaToRuby( RubyUtil.RUBY, new SourceWithMetadata("proto", "path", 1, 1, config))); } + + /** + * Load pipeline configuration from a path returning the list of SourceWithMetadata. + * + * The path refers to test's resources, if it point to single file that file is loaded, if reference a directory + * then the full list of contained files is loaded in name order. + * */ + @SuppressWarnings("rawtypes") + public static RubyArray toSourceWithMetadataFromPath(String configPath) throws IncompleteSourceWithMetadataException, IOException { + URL url = IRHelpers.class.getClassLoader().getResource(configPath); + String path = url.getPath(); + final File filePath = new File(path); + final List files; + if (filePath.isDirectory()) { + files = Arrays.asList(filePath.listFiles()); + Collections.sort(files); + } else { + files = Collections.singletonList(filePath); + } + + List rubySwms = new ArrayList<>(); + for (File configFile : files) { + final List fileContent = Files.readLines(configFile, Charset.defaultCharset()); + final SourceWithMetadata swm = new SourceWithMetadata("file", configFile.getPath(), 1, 1, String.join("\n", fileContent)); + rubySwms.add(JavaUtil.convertJavaToRuby(RubyUtil.RUBY, swm)); + } + return RubyUtil.RUBY.newArray(rubySwms); + } } diff --git a/logstash-core/src/test/resources/org/logstash/config/ir/cache/pipeline1.conf b/logstash-core/src/test/resources/org/logstash/config/ir/cache/pipeline1.conf new file mode 100644 index 000000000..e26727ecc --- /dev/null +++ b/logstash-core/src/test/resources/org/logstash/config/ir/cache/pipeline1.conf @@ -0,0 +1,19 @@ +input { + stdin {} +} + +filter { + mutate { + id => "ppl1_1" + rename => ["a_field", "into_another"] + } + + mutate { + id => "ppl1_2" + rename => ["a_field", "into_another"] + } +} + +output { + stdout {} +} \ No newline at end of file diff --git a/logstash-core/src/test/resources/org/logstash/config/ir/cache/pipeline2.conf b/logstash-core/src/test/resources/org/logstash/config/ir/cache/pipeline2.conf new file mode 100644 index 000000000..fbe969dac --- /dev/null +++ b/logstash-core/src/test/resources/org/logstash/config/ir/cache/pipeline2.conf @@ -0,0 +1,24 @@ +input { + stdin {} +} + +filter { + mutate { + id => "ppl2_1" + rename => ["a_field", "into_another"] + } + + mutate { + id => "ppl2_2" + rename => ["a_field", "into_another"] + } + + mutate { + id => "ppl2_3" + rename => ["a_field", "into_another"] + } +} + +output { + stdout {} +} \ No newline at end of file From 72f4e2f8e2d2be2007f765381ab1b07725347924 Mon Sep 17 00:00:00 2001 From: andsel Date: Fri, 10 Apr 2020 17:43:24 +0200 Subject: [PATCH 0513/1126] Backport of PR #11773 to branch 7.x Backports a PR that moved code out of LogStash::Compiler to org.logstash.config.ir.ConfigCompiler --- logstash-core/lib/logstash/compiler.rb | 30 ----- .../spec/logstash/compiler/compiler_spec.rb | 97 ---------------- .../logstash/config/ir/ConfigCompiler.java | 82 ++++++++++++-- .../execution/AbstractPipelineExt.java | 7 +- .../config/ir/CompiledPipelineTest.java | 10 +- .../config/ir/ConfigCompilerTest.java | 105 +++++++++++++++++- .../plugins/PluginFactoryExtTest.java | 5 +- .../state_event/lir_serializer_spec.rb | 4 +- 8 files changed, 194 insertions(+), 146 deletions(-) diff --git a/logstash-core/lib/logstash/compiler.rb b/logstash-core/lib/logstash/compiler.rb index 9a9cf8c2c..113b68278 100644 --- a/logstash-core/lib/logstash/compiler.rb +++ b/logstash-core/lib/logstash/compiler.rb @@ -17,35 +17,9 @@ require 'logstash/compiler/lscl/lscl_grammar' -java_import org.logstash.config.ir.PipelineIR -java_import org.logstash.config.ir.graph.Graph - module LogStash; class Compiler include ::LogStash::Util::Loggable - def self.compile_sources(sources_with_metadata, support_escapes) - graph_sections = sources_with_metadata.map do |swm| - self.compile_graph(swm, support_escapes) - end - - input_graph = Graph.combine(*graph_sections.map {|s| s[:input] }).graph - output_graph = Graph.combine(*graph_sections.map {|s| s[:output] }).graph - - filter_graph = graph_sections.reduce(nil) do |acc, s| - filter_section = s[:filter] - - if acc.nil? - filter_section - else - acc.chain(filter_section) - end - end - - original_source = sources_with_metadata.map(&:text).join("\n") - - PipelineIR.new(input_graph, filter_graph, output_graph, original_source) - end - def self.compile_imperative(source_with_metadata, support_escapes) if !source_with_metadata.is_a?(org.logstash.common.SourceWithMetadata) raise ArgumentError, "Expected 'org.logstash.common.SourceWithMetadata', got #{source_with_metadata.class}" @@ -61,8 +35,4 @@ module LogStash; class Compiler config.process_escape_sequences = support_escapes config.compile(source_with_metadata) end - - def self.compile_graph(source_with_metadata, support_escapes) - Hash[compile_imperative(source_with_metadata, support_escapes).map {|section,icompiled| [section, icompiled.toGraph]}] - end end; end diff --git a/logstash-core/spec/logstash/compiler/compiler_spec.rb b/logstash-core/spec/logstash/compiler/compiler_spec.rb index 95b2b34d7..a25fe2e45 100644 --- a/logstash-core/spec/logstash/compiler/compiler_spec.rb +++ b/logstash-core/spec/logstash/compiler/compiler_spec.rb @@ -49,103 +49,6 @@ describe LogStash::Compiler do end end - describe "compile with empty source" do - let(:sources_with_metadata) do - [ - org.logstash.common.SourceWithMetadata.new("str", "in_plugin", 0, 0, "input { input_0 {} } "), - org.logstash.common.SourceWithMetadata.new("str", "out_plugin", 0, 0, "output { output_0 {} } "), - org.logstash.common.SourceWithMetadata.new("str", "", 0, 0, " ") - ] - end - - it "should compile only the text parts" do - described_class.compile_sources(sources_with_metadata, false) - end - end - - describe "compile with fully commented source" do - let(:sources_with_metadata) do - [ - org.logstash.common.SourceWithMetadata.new("str", "in_plugin", 0, 0, "input { input_0 {} } "), - org.logstash.common.SourceWithMetadata.new("str", "commented_filter", 0, 0, "#filter{...}\n"), - org.logstash.common.SourceWithMetadata.new("str", "out_plugin", 0, 0, "output { output_0 {} } "), - ] - end - - it "should compile only non commented text parts" do - described_class.compile_sources(sources_with_metadata, false) - end - end - - describe "compiling to Pipeline" do - subject(:source_id) { "fake_sourcefile" } - let(:source_with_metadata) { org.logstash.common.SourceWithMetadata.new(source_protocol, source_id, 0, 0, source) } - subject(:compiled) { puts "PCOMP"; described_class.compile_pipeline(source_with_metadata, settings) } - - describe "compiling multiple sources" do - let(:sources) do - [ - "input { input_0 {} } filter { filter_0 {} } output { output_0 {} }", - "input { input_1 {} } filter { filter_1 {} } output { output_1 {} }" - ] - end - - let(:sources_with_metadata) do - sources.map.with_index do |source, idx| - org.logstash.common.SourceWithMetadata.new("#{source_protocol}_#{idx}", "#{source_id}_#{idx}", 0, 0, source) - end - end - - subject(:pipeline) { described_class.compile_sources(sources_with_metadata, false) } - - it "should generate a hash" do - expect(pipeline.unique_hash).to be_a(String) - end - - it "should compile cleanly" do - expect(pipeline).to be_a(org.logstash.config.ir.PipelineIR) - end - - it "should provide the original source" do - expect(pipeline.original_source).to eq(sources.join("\n")) - end - - describe "applying protocol and id metadata" do - it "should apply the correct source metadata to all components" do - # TODO: seems to be a jruby regression we cannot currently call each on a stream - pipeline.get_plugin_vertices.each do |pv| - name_idx = pv.plugin_definition.name.split("_").last - source_protocol_idx = pv.source_with_metadata.protocol.split("_").last - source_id_idx = pv.source_with_metadata.id.split("_").last - - expect(name_idx).to eq(source_protocol_idx) - expect(name_idx).to eq(source_id_idx) - end - end - end - end - - describe "complex configs" do - shared_examples_for "compilable LSCL files" do |path| - describe "parsing #{path}" do - let(:source) { File.read(path) } - - it "should compile" do - expect(compiled).to be_java_kind_of(Java::OrgLogstashConfigIr::Pipeline) - end - - it "should have a hash" do - expect(compiled.uniqueHash) - end - end - end - - Dir.glob(File.join(SUPPORT_DIR, "lscl_configs", "*.conf")).each do |path| - it_should_behave_like "compilable LSCL files", path - end - end - end - describe "compiling imperative" do let(:source_id) { "fake_sourcefile" } let(:source_with_metadata) { org.logstash.common.SourceWithMetadata.new(source_protocol, source_id, 0, 0, source) } diff --git a/logstash-core/src/main/java/org/logstash/config/ir/ConfigCompiler.java b/logstash-core/src/main/java/org/logstash/config/ir/ConfigCompiler.java index 09a51d6e7..de7e3797e 100644 --- a/logstash-core/src/main/java/org/logstash/config/ir/ConfigCompiler.java +++ b/logstash-core/src/main/java/org/logstash/config/ir/ConfigCompiler.java @@ -21,12 +21,20 @@ package org.logstash.config.ir; import org.jruby.RubyArray; -import org.jruby.RubyClass; +import org.jruby.RubyHash; import org.jruby.javasupport.JavaUtil; import org.jruby.runtime.builtin.IRubyObject; import org.logstash.RubyUtil; -import org.logstash.common.IncompleteSourceWithMetadataException; import org.logstash.common.SourceWithMetadata; +import org.logstash.config.ir.graph.Graph; +import org.logstash.config.ir.imperative.Statement; + +import java.util.List; +import java.util.Map; +import java.util.HashMap; +import java.util.stream.Collectors; + +import static java.util.stream.Collectors.*; /** * Java Implementation of the config compiler that is implemented by wrapping the Ruby @@ -42,17 +50,75 @@ public final class ConfigCompiler { * @param sourcesWithMetadata Logstash Config partitioned * @param supportEscapes The value of the setting {@code config.support_escapes} * @return Compiled {@link PipelineIR} + * @throws InvalidIRException if the the configuration contains errors */ + @SuppressWarnings("unchecked") public static PipelineIR configToPipelineIR(final @SuppressWarnings("rawtypes") RubyArray sourcesWithMetadata, - final boolean supportEscapes) { + final boolean supportEscapes) throws InvalidIRException { + return compileSources((List) sourcesWithMetadata, supportEscapes); + } + + public static PipelineIR compileSources(List sourcesWithMetadata, boolean supportEscapes) throws InvalidIRException { + Map> groupedPipelineSections = sourcesWithMetadata.stream() + .map(swm -> compileGraph(swm, supportEscapes)) + .flatMap(m -> m.entrySet().stream()) + .filter(e -> e.getValue() != null) + .collect(groupingBy(Map.Entry::getKey, + mapping(Map.Entry::getValue, toList()))); + + Graph inputGraph = Graph.combine(groupedPipelineSections.get(PluginDefinition.Type.INPUT).toArray(new Graph[0])).graph; + Graph outputGraph = Graph.combine(groupedPipelineSections.get(PluginDefinition.Type.OUTPUT).toArray(new Graph[0])).graph; + Graph filterGraph = groupedPipelineSections.get(PluginDefinition.Type.FILTER).stream() + .reduce(ConfigCompiler::chainWithUntypedException).orElse(null); + + String originalSource = sourcesWithMetadata.stream().map(SourceWithMetadata::getText).collect(Collectors.joining("\n")); + return new PipelineIR(inputGraph, filterGraph, outputGraph, originalSource); + } + + private static Graph chainWithUntypedException(Graph g1, Graph g2) { + try { + return g1.chain(g2); + } catch (InvalidIRException iirex) { + throw new IllegalArgumentException(iirex); + } + } + + private static Map compileImperative(SourceWithMetadata sourceWithMetadata, + boolean supportEscapes) { final IRubyObject compiler = RubyUtil.RUBY.executeScript( "require 'logstash/compiler'\nLogStash::Compiler", "" ); - final IRubyObject code = - compiler.callMethod(RubyUtil.RUBY.getCurrentContext(), "compile_sources", - new IRubyObject[]{sourcesWithMetadata, RubyUtil.RUBY.newBoolean(supportEscapes)} - ); - return code.toJava(PipelineIR.class); + // invoke Ruby interpreter to execute LSCL treetop + final IRubyObject code = compiler.callMethod(RubyUtil.RUBY.getCurrentContext(), "compile_imperative", + new IRubyObject[]{ + JavaUtil.convertJavaToRuby(RubyUtil.RUBY, sourceWithMetadata), + RubyUtil.RUBY.newBoolean(supportEscapes) + }); + RubyHash hash = (RubyHash) code; + Map result = new HashMap<>(); + result.put(PluginDefinition.Type.INPUT, readStatementFromRubyHash(hash, "input")); + result.put(PluginDefinition.Type.FILTER, readStatementFromRubyHash(hash, "filter")); + result.put(PluginDefinition.Type.OUTPUT, readStatementFromRubyHash(hash, "output")); + return result; + } + + private static Statement readStatementFromRubyHash(RubyHash hash, String key) { + IRubyObject inputValue = hash.fastARef(RubyUtil.RUBY.newSymbol(key)); + return inputValue.toJava(Statement.class); + } + + private static Map compileGraph(SourceWithMetadata swm, boolean supportEscapes) { + Map pluginStatements = compileImperative(swm, supportEscapes); + return pluginStatements.entrySet().stream() + .collect(Collectors.toMap(Map.Entry::getKey, e -> toGraphWithUntypedException(e.getValue()))); + } + + private static Graph toGraphWithUntypedException(Statement s) { + try { + return s.toGraph(); + } catch (InvalidIRException iirex) { + throw new IllegalArgumentException(iirex); + } } } diff --git a/logstash-core/src/main/java/org/logstash/execution/AbstractPipelineExt.java b/logstash-core/src/main/java/org/logstash/execution/AbstractPipelineExt.java index 376f967e9..49ce69a52 100644 --- a/logstash-core/src/main/java/org/logstash/execution/AbstractPipelineExt.java +++ b/logstash-core/src/main/java/org/logstash/execution/AbstractPipelineExt.java @@ -53,6 +53,7 @@ import org.logstash.common.DeadLetterQueueFactory; import org.logstash.common.IncompleteSourceWithMetadataException; import org.logstash.common.SourceWithMetadata; import org.logstash.config.ir.ConfigCompiler; +import org.logstash.config.ir.InvalidIRException; import org.logstash.config.ir.PipelineIR; import org.logstash.ext.JRubyAbstractQueueWriteClientExt; import org.logstash.ext.JRubyWrappedWriteClientExt; @@ -178,7 +179,11 @@ public class AbstractPipelineExt extends RubyBasicObject { } } boolean supportEscapes = getSetting(context, "config.support_escapes").isTrue(); - lir = ConfigCompiler.configToPipelineIR(configParts, supportEscapes); + try { + lir = ConfigCompiler.configToPipelineIR(configParts, supportEscapes); + } catch (InvalidIRException iirex) { + throw new IllegalArgumentException(iirex); + } return this; } diff --git a/logstash-core/src/test/java/org/logstash/config/ir/CompiledPipelineTest.java b/logstash-core/src/test/java/org/logstash/config/ir/CompiledPipelineTest.java index 323cea7a7..0b63c0042 100644 --- a/logstash-core/src/test/java/org/logstash/config/ir/CompiledPipelineTest.java +++ b/logstash-core/src/test/java/org/logstash/config/ir/CompiledPipelineTest.java @@ -282,18 +282,18 @@ public final class CompiledPipelineTest extends RubyEnvTestCase { } @Test - public void correctlyCompilesRegexMatchesWithConstant() throws IncompleteSourceWithMetadataException { + public void correctlyCompilesRegexMatchesWithConstant() throws InvalidIRException { verifyRegex("=~", 1); } @Test - public void correctlyCompilesRegexNoMatchesWithConstant() throws IncompleteSourceWithMetadataException { + public void correctlyCompilesRegexNoMatchesWithConstant() throws InvalidIRException { verifyRegex("!~", 0); } @SuppressWarnings({"unchecked"}) private void verifyRegex(String operator, int expectedEvents) - throws IncompleteSourceWithMetadataException { + throws InvalidIRException { final Event event = new Event(); final JrubyEventExtLibrary.RubyEvent testEvent = @@ -457,8 +457,8 @@ public final class CompiledPipelineTest extends RubyEnvTestCase { } @SuppressWarnings({"unchecked"}) - private void verifyComparison(final boolean expected, final String conditional, - final Event event) throws IncompleteSourceWithMetadataException { + private void verifyComparison(final boolean expected, final String conditional, final Event event) + throws InvalidIRException { final JrubyEventExtLibrary.RubyEvent testEvent = JrubyEventExtLibrary.RubyEvent.newRubyEvent(RubyUtil.RUBY, event); diff --git a/logstash-core/src/test/java/org/logstash/config/ir/ConfigCompilerTest.java b/logstash-core/src/test/java/org/logstash/config/ir/ConfigCompilerTest.java index e9f95ebd2..e803bfbec 100644 --- a/logstash-core/src/test/java/org/logstash/config/ir/ConfigCompilerTest.java +++ b/logstash-core/src/test/java/org/logstash/config/ir/ConfigCompilerTest.java @@ -21,7 +21,14 @@ package org.logstash.config.ir; import java.io.ByteArrayOutputStream; +import java.io.IOException; import java.io.InputStream; +import java.nio.file.Files; +import java.nio.file.Path; +import java.nio.file.Paths; +import java.util.Arrays; +import java.util.Collections; +import java.util.List; import org.jruby.javasupport.JavaUtil; import org.jruby.runtime.builtin.IRubyObject; @@ -30,9 +37,11 @@ import org.logstash.RubyUtil; import org.logstash.common.IncompleteSourceWithMetadataException; import org.logstash.common.SourceWithMetadata; import org.logstash.config.ir.graph.Graph; +import org.logstash.config.ir.graph.PluginVertex; import static org.hamcrest.CoreMatchers.is; import static org.hamcrest.MatcherAssert.assertThat; +import static org.junit.Assert.*; public class ConfigCompilerTest extends RubyEnvTestCase { @@ -41,7 +50,7 @@ public class ConfigCompilerTest extends RubyEnvTestCase { IRubyObject swm = JavaUtil.convertJavaToRuby( RubyUtil.RUBY, new SourceWithMetadata("proto", "path", 1, 1, "input {stdin{}} output{stdout{}}")); final PipelineIR pipelineIR = - ConfigCompiler.configToPipelineIR(RubyUtil.RUBY.newArray(swm), false); + ConfigCompiler.configToPipelineIR(RubyUtil.RUBY.newArray(swm), false); assertThat(pipelineIR.getOutputPluginVertices().size(), is(1)); assertThat(pipelineIR.getFilterPluginVertices().size(), is(0)); } @@ -50,6 +59,7 @@ public class ConfigCompilerTest extends RubyEnvTestCase { * Tests that repeatedly parsing the same config (containing a large number of duplicated sections) * into a {@link Graph} repeatedly results in a graph with a constant (i.e. deterministic) * hash code as returned by {@link Graph#uniqueHash()}. + * * @throws Exception On Failure */ @Test @@ -70,6 +80,7 @@ public class ConfigCompilerTest extends RubyEnvTestCase { * Tests that repeatedly parsing the same complex config String into a {@link Graph} repeatedly * results in a graph with a constant (i.e. deterministic) hash code as returned by * {@link Graph#uniqueHash()}. + * * @throws Exception On Failure */ @Test @@ -87,9 +98,99 @@ public class ConfigCompilerTest extends RubyEnvTestCase { assertThat(graphHash(config), is(first)); } - private static String graphHash(final String config) throws IncompleteSourceWithMetadataException { + private static String graphHash(final String config) throws InvalidIRException { IRubyObject swm = JavaUtil.convertJavaToRuby( RubyUtil.RUBY, new SourceWithMetadata("proto", "path", 1, 1, config)); return ConfigCompiler.configToPipelineIR(RubyUtil.RUBY.newArray(swm), false).uniqueHash(); } + + @Test + public void testCompileWithAnEmptySource() throws InvalidIRException { + List sourcesWithMetadata = Arrays.asList( + new SourceWithMetadata("str", "in_plugin", 0, 0, "input { input_0 {} } "), + new SourceWithMetadata("str", "out_plugin", 0, 0, "output { output_0 {} } "), + new SourceWithMetadata("str", "", 0, 0, " ") + ); + + PipelineIR pipeline = ConfigCompiler.compileSources(sourcesWithMetadata, false); + + assertEquals("should compile only the text parts", 2L, pipeline.pluginVertices().count()); + } + + @Test + public void testCompileWithFullyCommentedSource() throws InvalidIRException { + List sourcesWithMetadata = Arrays.asList( + new SourceWithMetadata("str", "in_plugin", 0, 0, "input { input_0 {} } "), + new SourceWithMetadata("str","commented_filter",0,0,"#filter{...}\n"), + new SourceWithMetadata("str","out_plugin",0,0,"output { output_0 {} } ") + ); + + PipelineIR pipeline = ConfigCompiler.compileSources(sourcesWithMetadata, false); + + assertEquals("should compile only non commented text parts", 2L, pipeline.pluginVertices().count()); + } + + @Test + public void testCompilingPipelineWithMultipleSources() throws InvalidIRException { + String sourceId = "fake_sourcefile"; + String sourceProtocol = "test_proto"; + SourceWithMetadata sourceWithMetadata = new SourceWithMetadata(sourceProtocol, sourceId, 0, 0, "booo"); + + String[] sources = new String[] { + "input { input_0 {} } filter { filter_0 {} } output { output_0 {} }", + "input { input_1 {} } filter { filter_1 {} } output { output_1 {} }"}; + + List sourcesWithMetadata = Arrays.asList( + new SourceWithMetadata(sourceProtocol + "_" + 0, sourceId + "_" + 0, 0, 0, sources[0]), + new SourceWithMetadata(sourceProtocol + "_" + 1, sourceId + "_" + 1, 0, 0, sources[1])); + + PipelineIR pipeline = ConfigCompiler.compileSources(sourcesWithMetadata, false); + + assertFalse("should generate a hash", pipeline.uniqueHash().isEmpty()); + assertEquals("should provide the original source", String.join("\n", sources), + pipeline.getOriginalSource()); + verifyApplyingProtocolAndIdMetadata(pipeline); + } + + private void verifyApplyingProtocolAndIdMetadata(PipelineIR pipeline) { + for (PluginVertex pv : pipeline.getPluginVertices()) { + String nameIdx = last(pv.getPluginDefinition().getName().split("_")); + String sourceProtocolIdx = last(pv.getSourceWithMetadata().getProtocol().split("_")); + String sourceIdIdx = last(pv.getSourceWithMetadata().getId().split("_")); + assertEquals("should apply the correct source metadata to protocol", nameIdx, sourceProtocolIdx); + assertEquals("should apply the correct source metadata to id", nameIdx, sourceIdIdx); + } + } + + private static String last(String[] s) { + return s[s.length - 1]; + } + + @Test + public void testComplexConfigs() throws IOException { + Path path = Paths.get(".").toAbsolutePath().resolve("../spec/support/lscl_configs").normalize(); + Files.list(path).forEach(this::verifyComplexConfig); + } + + private void verifyComplexConfig(Path path) { + String configName = path.getFileName().toString(); + + String source = null; + try { + source = new String(Files.readAllBytes(path)); + } catch (IOException e) { + fail(configName + " not readable"); + } + + PipelineIR pipelineIR = null; + try { + SourceWithMetadata sourceWithMetadata = new SourceWithMetadata("test_proto", "fake_sourcefile", 0, 0, source); + pipelineIR = ConfigCompiler.compileSources(Collections.singletonList(sourceWithMetadata), false); + } catch (InvalidIRException iirex) { + fail("error compiling " + configName + ": " + iirex.getMessage()); + } + + assertNotNull(configName + " should compile", pipelineIR); + assertFalse(configName + " should have a hash", pipelineIR.uniqueHash().isEmpty()); + } } diff --git a/logstash-core/src/test/java/org/logstash/plugins/PluginFactoryExtTest.java b/logstash-core/src/test/java/org/logstash/plugins/PluginFactoryExtTest.java index aca712cdb..30d106032 100644 --- a/logstash-core/src/test/java/org/logstash/plugins/PluginFactoryExtTest.java +++ b/logstash-core/src/test/java/org/logstash/plugins/PluginFactoryExtTest.java @@ -31,6 +31,7 @@ import org.logstash.RubyUtil; import org.logstash.common.IncompleteSourceWithMetadataException; import org.logstash.common.SourceWithMetadata; import org.logstash.config.ir.ConfigCompiler; +import org.logstash.config.ir.InvalidIRException; import org.logstash.config.ir.PipelineIR; import org.logstash.config.ir.RubyEnvTestCase; import org.logstash.instrument.metrics.NamespacedMetricExt; @@ -83,7 +84,7 @@ public final class PluginFactoryExtTest extends RubyEnvTestCase { } @Test - public void testPluginIdResolvedWithEnvironmentVariables() throws IncompleteSourceWithMetadataException { + public void testPluginIdResolvedWithEnvironmentVariables() throws InvalidIRException { PluginFactoryExt.PluginResolver mockPluginResolver = wrapWithSearchable(MockInputPlugin.class); SourceWithMetadata sourceWithMetadata = new SourceWithMetadata("proto", "path", 1, 8, "input {mockinput{ id => \"${CUSTOM}\"}} output{mockoutput{}}"); @@ -109,7 +110,7 @@ public final class PluginFactoryExtTest extends RubyEnvTestCase { } @SuppressWarnings("rawtypes") - private static PipelineIR compilePipeline(SourceWithMetadata sourceWithMetadata) { + private static PipelineIR compilePipeline(SourceWithMetadata sourceWithMetadata) throws InvalidIRException { RubyArray sourcesWithMetadata = RubyUtil.RUBY.newArray(JavaUtil.convertJavaToRuby( RubyUtil.RUBY, sourceWithMetadata)); diff --git a/x-pack/spec/monitoring/inputs/metrics/state_event/lir_serializer_spec.rb b/x-pack/spec/monitoring/inputs/metrics/state_event/lir_serializer_spec.rb index 1c4b1b994..a89800fc2 100644 --- a/x-pack/spec/monitoring/inputs/metrics/state_event/lir_serializer_spec.rb +++ b/x-pack/spec/monitoring/inputs/metrics/state_event/lir_serializer_spec.rb @@ -22,7 +22,9 @@ describe ::LogStash::Config::LIRSerializer do end let(:lir_pipeline) do - ::LogStash::Compiler.compile_sources(config_source_with_metadata, LogStash::SETTINGS) +# ::LogStash::Compiler.compile_sources(config_source_with_metadata, true) + java_import org.logstash.config.ir.ConfigCompiler + ConfigCompiler.compileSources(config_source_with_metadata, true) end describe "#serialize" do From c6795731f15f884faeaf67ec2984d808d7e44e18 Mon Sep 17 00:00:00 2001 From: andsel Date: Tue, 14 Apr 2020 18:01:44 +0200 Subject: [PATCH 0514/1126] Backport to 7.x of PR #11824 Refactor: move PipelineConfig from Ruby to Java Reimplement the Ruby class PipelinceConfig in Java trying to keep the method signatures to limit the changes in client code, this is a step of other that intend to move all the configuration code in Java language. Having all that code in Java unlock some reasoning about how to better implement it and probably an improvement in performance during process startup. Moved also the spec into a JUnit and fixed here and there the failing tests Closes: #11824 --- logstash-core/build.gradle | 2 + logstash-core/lib/logstash/agent.rb | 1 + .../lib/logstash/config/pipeline_config.rb | 77 +------ .../lib/logstash/config/source/local.rb | 2 +- .../lib/logstash/config/source/modules.rb | 3 +- .../lib/logstash/config/source_loader.rb | 1 - .../lib/logstash/pipeline_action/create.rb | 2 +- .../lib/logstash/pipeline_action/reload.rb | 2 +- .../lib/logstash/pipelines_registry.rb | 2 +- logstash-core/lib/logstash/state_resolver.rb | 2 +- logstash-core/spec/logstash/agent_spec.rb | 3 +- .../logstash/config/pipeline_config_spec.rb | 166 --------------- .../logstash/config/source_loader_spec.rb | 2 +- logstash-core/spec/logstash/pipeline_spec.rb | 1 + .../spec/logstash/pipelines_registry_spec.rb | 4 +- .../spec/logstash/state_resolver_spec.rb | 1 - logstash-core/spec/support/helpers.rb | 2 +- logstash-core/spec/support/matchers.rb | 1 - .../spec/support/pipeline/pipeline_helpers.rb | 2 +- .../logstash/config/ir/ConfigCompiler.java | 4 +- .../logstash/config/ir/PipelineConfig.java | 177 ++++++++++++++++ .../execution/AbstractPipelineExt.java | 12 +- .../config/ir/ConfigCompilerTest.java | 14 +- .../config/ir/PipelineConfigTest.java | 196 ++++++++++++++++++ .../plugins/PluginFactoryExtTest.java | 9 +- .../config_management/elasticsearch_source.rb | 3 +- x-pack/lib/monitoring/monitoring.rb | 3 +- .../elasticsearch_source_spec.rb | 8 +- .../modules/azure/filters/azure_event_spec.rb | 2 + .../metrics/state_event_factory_spec.rb | 2 +- .../metrics/stats_event_factory_spec.rb | 1 + .../internal_pipeline_source_spec.rb | 3 +- 32 files changed, 415 insertions(+), 295 deletions(-) delete mode 100644 logstash-core/spec/logstash/config/pipeline_config_spec.rb create mode 100644 logstash-core/src/main/java/org/logstash/config/ir/PipelineConfig.java create mode 100644 logstash-core/src/test/java/org/logstash/config/ir/PipelineConfigTest.java diff --git a/logstash-core/build.gradle b/logstash-core/build.gradle index f01e2271d..4d308557b 100644 --- a/logstash-core/build.gradle +++ b/logstash-core/build.gradle @@ -92,6 +92,7 @@ tasks.register("javaTests", Test) { exclude '/org/logstash/config/ir/ConfigCompilerTest.class' exclude '/org/logstash/config/ir/CompiledPipelineTest.class' exclude '/org/logstash/config/ir/EventConditionTest.class' + exclude '/org/logstash/config/ir/PipelineConfigTest.class' exclude '/org/logstash/config/ir/compiler/OutputDelegatorTest.class' exclude '/org/logstash/config/ir/compiler/JavaCodecDelegatorTest.class' exclude '/org/logstash/plugins/NamespacedMetricImplTest.class' @@ -107,6 +108,7 @@ tasks.register("rubyTests", Test) { include '/org/logstash/config/ir/ConfigCompilerTest.class' include '/org/logstash/config/ir/CompiledPipelineTest.class' include '/org/logstash/config/ir/EventConditionTest.class' + include '/org/logstash/config/ir/PipelineConfigTest.class' include '/org/logstash/config/ir/compiler/OutputDelegatorTest.class' include '/org/logstash/config/ir/compiler/JavaCodecDelegatorTest.class' include '/org/logstash/plugins/NamespacedMetricImplTest.class' diff --git a/logstash-core/lib/logstash/agent.rb b/logstash-core/lib/logstash/agent.rb index 3ecd47e16..d8725146f 100644 --- a/logstash-core/lib/logstash/agent.rb +++ b/logstash-core/lib/logstash/agent.rb @@ -22,6 +22,7 @@ require "logstash/instrument/periodic_pollers" require "logstash/pipeline" require "logstash/webserver" require "logstash/config/source_loader" +require "logstash/config/pipeline_config" require "logstash/pipeline_action" require "logstash/state_resolver" require "logstash/pipelines_registry" diff --git a/logstash-core/lib/logstash/config/pipeline_config.rb b/logstash-core/lib/logstash/config/pipeline_config.rb index 66ca1aa4a..32194bf89 100644 --- a/logstash-core/lib/logstash/config/pipeline_config.rb +++ b/logstash-core/lib/logstash/config/pipeline_config.rb @@ -15,77 +15,6 @@ # specific language governing permissions and limitations # under the License. -require "digest" - -module LogStash module Config - class PipelineConfig - include LogStash::Util::Loggable - - LineToSource = Struct.new("LineToSource", :bounds, :source) - - attr_reader :source, :pipeline_id, :config_parts, :settings, :read_at - - def initialize(source, pipeline_id, config_parts, settings) - @source = source - @pipeline_id = pipeline_id - # We can't use Array() since config_parts may be a java object! - config_parts_array = config_parts.is_a?(Array) ? config_parts : [config_parts] - @config_parts = config_parts_array.sort_by { |config_part| [config_part.protocol.to_s, config_part.id] } - @settings = settings - @read_at = Time.now - end - - def config_hash - @config_hash ||= Digest::SHA1.hexdigest(config_string) - end - - def config_string - @config_string = config_parts.collect(&:text).join("\n") - end - - def system? - @settings.get("pipeline.system") - end - - def ==(other) - config_hash == other.config_hash && pipeline_id == other.pipeline_id && settings == other.settings - end - - def display_debug_information - logger.debug("-------- Logstash Config ---------") - logger.debug("Config from source", :source => source, :pipeline_id => pipeline_id) - - config_parts.each do |config_part| - logger.debug("Config string", :protocol => config_part.protocol, :id => config_part.id) - logger.debug("\n\n#{config_part.text}") - end - logger.debug("Merged config") - logger.debug("\n\n#{config_string}") - end - - def lookup_source(global_line_number, source_column) - res = source_references.find { |line_to_source| line_to_source.bounds.include? global_line_number } - if res == nil - raise IndexError, "can't find the config segment related to line #{global_line_number}" - end - swm = res.source - SourceWithMetadata.new(swm.getProtocol(), swm.getId(), global_line_number + 1 - res.bounds.begin, source_column, swm.getText()) - end - - private - def source_references - @source_refs ||= begin - offset = 0 - source_refs = [] - config_parts.each do |config_part| - #line numbers starts from 1 in text files - lines_range = (config_part.getLine() + offset + 1..config_part.getLinesCount() + offset) - source_segment = LineToSource.new(lines_range, config_part) - source_refs << source_segment - offset += config_part.getLinesCount() - end - source_refs.freeze - end - end - end -end end +module LogStash::Config + java_import org.logstash.config.ir.PipelineConfig +end \ No newline at end of file diff --git a/logstash-core/lib/logstash/config/source/local.rb b/logstash-core/lib/logstash/config/source/local.rb index d23ae69de..dc43ba287 100644 --- a/logstash-core/lib/logstash/config/source/local.rb +++ b/logstash-core/lib/logstash/config/source/local.rb @@ -212,7 +212,7 @@ module LogStash module Config module Source return [] if config_parts.empty? - [PipelineConfig.new(self.class, @settings.get("pipeline.id").to_sym, config_parts, @settings)] + [org.logstash.config.ir.PipelineConfig.new(self.class, @settings.get("pipeline.id").to_sym, config_parts, @settings)] end def automatic_reload_with_config_string? diff --git a/logstash-core/lib/logstash/config/source/modules.rb b/logstash-core/lib/logstash/config/source/modules.rb index 9bddbd977..47794465c 100644 --- a/logstash-core/lib/logstash/config/source/modules.rb +++ b/logstash-core/lib/logstash/config/source/modules.rb @@ -17,7 +17,6 @@ require "logstash/config/source/base" require "logstash/config/modules_common" -require "logstash/config/pipeline_config" module LogStash module Config module Source class Modules < Base @@ -29,7 +28,7 @@ module LogStash module Config module Source pipelines = LogStash::Config::ModulesCommon.pipeline_configs(@settings) pipelines.map do |hash| - PipelineConfig.new(self, hash["pipeline_id"].to_sym, + org.logstash.config.ir.PipelineConfig.new(self.class, hash["pipeline_id"].to_sym, org.logstash.common.SourceWithMetadata.new("module", hash["alt_name"], 0, 0, hash["config_string"]), hash["settings"]) end diff --git a/logstash-core/lib/logstash/config/source_loader.rb b/logstash-core/lib/logstash/config/source_loader.rb index 11959eb2a..d7c6d07a3 100644 --- a/logstash-core/lib/logstash/config/source_loader.rb +++ b/logstash-core/lib/logstash/config/source_loader.rb @@ -63,7 +63,6 @@ module LogStash module Config sources do |source| sources_loaders << source if source.match? end - if sources_loaders.empty? # This shouldn't happen with the settings object or with any external plugins. # but lets add a guard so we fail fast. diff --git a/logstash-core/lib/logstash/pipeline_action/create.rb b/logstash-core/lib/logstash/pipeline_action/create.rb index 55c8c6ecf..3a3531e15 100644 --- a/logstash-core/lib/logstash/pipeline_action/create.rb +++ b/logstash-core/lib/logstash/pipeline_action/create.rb @@ -34,7 +34,7 @@ module LogStash module PipelineAction end def pipeline_id - @pipeline_config.pipeline_id + @pipeline_config.pipeline_id.to_sym end # Make sure we execution system pipeline like the monitoring diff --git a/logstash-core/lib/logstash/pipeline_action/reload.rb b/logstash-core/lib/logstash/pipeline_action/reload.rb index 78001e827..4dc9bc77c 100644 --- a/logstash-core/lib/logstash/pipeline_action/reload.rb +++ b/logstash-core/lib/logstash/pipeline_action/reload.rb @@ -29,7 +29,7 @@ module LogStash module PipelineAction end def pipeline_id - @pipeline_config.pipeline_id + @pipeline_config.pipeline_id.to_sym end def to_s diff --git a/logstash-core/lib/logstash/pipelines_registry.rb b/logstash-core/lib/logstash/pipelines_registry.rb index 433a397e6..cb9e37527 100644 --- a/logstash-core/lib/logstash/pipelines_registry.rb +++ b/logstash-core/lib/logstash/pipelines_registry.rb @@ -142,7 +142,7 @@ module LogStash # @param pipeline_id [String, Symbol] the pipeline id # @return [Pipeline] the pipeline object or nil if none for pipeline_id def get_pipeline(pipeline_id) - state = @states.get(pipeline_id) + state = @states.get(pipeline_id.to_sym) state.nil? ? nil : state.pipeline end diff --git a/logstash-core/lib/logstash/state_resolver.rb b/logstash-core/lib/logstash/state_resolver.rb index 72e177978..386921b1f 100644 --- a/logstash-core/lib/logstash/state_resolver.rb +++ b/logstash-core/lib/logstash/state_resolver.rb @@ -41,7 +41,7 @@ module LogStash end end - configured_pipelines = pipeline_configs.collect(&:pipeline_id) + configured_pipelines = pipeline_configs.map { |config| config.pipeline_id.to_sym } # If one of the running pipeline is not in the pipeline_configs, we assume that we need to # stop it. diff --git a/logstash-core/spec/logstash/agent_spec.rb b/logstash-core/spec/logstash/agent_spec.rb index d69c8671b..f49cb7c5a 100644 --- a/logstash-core/spec/logstash/agent_spec.rb +++ b/logstash-core/spec/logstash/agent_spec.rb @@ -18,7 +18,6 @@ require "spec_helper" require "stud/temporary" require "logstash/inputs/generator" -require "logstash/config/pipeline_config" require "logstash/config/source/local" require_relative "../support/mocks_classes" require "fileutils" @@ -85,7 +84,7 @@ describe LogStash::Agent do it "should delegate settings to new pipeline" do expect(LogStash::JavaPipeline).to receive(:new) do |arg1, arg2| - expect(arg1).to eq(config_string) + expect(arg1.to_s).to eq(config_string) expect(arg2.to_hash).to include(agent_args) end subject.converge_state_and_update diff --git a/logstash-core/spec/logstash/config/pipeline_config_spec.rb b/logstash-core/spec/logstash/config/pipeline_config_spec.rb deleted file mode 100644 index a7011b372..000000000 --- a/logstash-core/spec/logstash/config/pipeline_config_spec.rb +++ /dev/null @@ -1,166 +0,0 @@ -# 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 "logstash/config/pipeline_config" -require "logstash/config/source/local" - -describe LogStash::Config::PipelineConfig do - let(:source) { LogStash::Config::Source::Local } - let(:pipeline_id) { :main } - let(:ordered_config_parts) do - [ - org.logstash.common.SourceWithMetadata.new("file", "/tmp/1", 0, 0, "input { generator1 }"), - org.logstash.common.SourceWithMetadata.new("file", "/tmp/2", 0, 0, "input { generator2 }"), - org.logstash.common.SourceWithMetadata.new("file", "/tmp/3", 0, 0, "input { generator3 }"), - org.logstash.common.SourceWithMetadata.new("file", "/tmp/4", 0, 0, "input { generator4 }"), - org.logstash.common.SourceWithMetadata.new("file", "/tmp/5", 0, 0, "input { generator5 }"), - org.logstash.common.SourceWithMetadata.new("file", "/tmp/6", 0, 0, "input { generator6 }"), - org.logstash.common.SourceWithMetadata.new("string", "config_string", 0, 0, "input { generator1 }"), - ] - end - - let(:unordered_config_parts) { ordered_config_parts.shuffle } - let(:settings) { LogStash::SETTINGS } - - subject { described_class.new(source, pipeline_id, unordered_config_parts, settings) } - - it "returns the source" do - expect(subject.source).to eq(source) - end - - it "returns the pipeline id" do - expect(subject.pipeline_id).to eq(pipeline_id) - end - - it "returns the sorted config parts" do - expect(subject.config_parts).to eq(ordered_config_parts) - end - - it "returns the config_hash" do - expect(subject.config_hash).not_to be_nil - end - - it "returns the merged `ConfigPart#config_string`" do - expect(subject.config_string).to eq(ordered_config_parts.collect(&:text).join("\n")) - end - - it "records when the config was read" do - expect(subject.read_at).to be <= Time.now - end - - it "does object equality on config_hash and pipeline_id" do - another_exact_pipeline = described_class.new(source, pipeline_id, ordered_config_parts, settings) - expect(subject).to eq(another_exact_pipeline) - - not_matching_pipeline = described_class.new(source, pipeline_id, [], settings) - expect(subject).not_to eq(not_matching_pipeline) - - not_same_pipeline_id = described_class.new(source, :another_pipeline, unordered_config_parts, settings) - expect(subject).not_to eq(not_same_pipeline_id) - end - - describe "#system?" do - context "when the pipeline is a system pipeline" do - let(:settings) { mock_settings({ "pipeline.system" => true })} - - it "returns true if the pipeline is a system pipeline" do - expect(subject.system?).to be_truthy - end - end - - context "when is not a system pipeline" do - it "returns false if the pipeline is not a system pipeline" do - expect(subject.system?).to be_falsey - end - end - end - - describe "source and line remapping" do - context "when pipeline is constructed from single file single line" do - let (:pipeline_conf_string) { 'input { generator1 }' } - subject { described_class.new(source, pipeline_id, [org.logstash.common.SourceWithMetadata.new("file", "/tmp/1", 0, 0, pipeline_conf_string)], settings) } - it "return the same line of the queried" do - expect(subject.lookup_source(1, 0).getLine()).to eq(1) - end - end - - context "when pipeline is constructed from single file" do - let (:pipeline_conf_string) { 'input { - generator1 - }' } - subject { described_class.new(source, pipeline_id, [org.logstash.common.SourceWithMetadata.new("file", "/tmp/1", 0, 0, pipeline_conf_string)], settings) } - - it "return the same line of the queried" do - expect(subject.lookup_source(1, 0).getLine()).to eq(1) - expect(subject.lookup_source(2, 0).getLine()).to eq(2) - end - - it "throw exception if line is out of bound" do - expect { subject.lookup_source(100, -1) }.to raise_exception(IndexError) - end - end - - context "when pipeline is constructed from multiple files" do - let (:pipeline_conf_string_part1) { 'input { - generator1 - }' } - let (:pipeline_conf_string_part2) { 'output { - stdout - }' } - let(:merged_config_parts) do - [ - org.logstash.common.SourceWithMetadata.new("file", "/tmp/input", 0, 0, pipeline_conf_string_part1), - org.logstash.common.SourceWithMetadata.new("file", "/tmp/output", 0, 0, pipeline_conf_string_part2) - ] - end - subject { described_class.new(source, pipeline_id, merged_config_parts, settings) } - - it "return the line of first segment" do - expect(subject.lookup_source(2, 0).getLine()).to eq(2) - expect(subject.lookup_source(2, 0).getId()).to eq("/tmp/input") - end - - it "return the line of second segment" do - expect(subject.lookup_source(4, 0).getLine()).to eq(1) - expect(subject.lookup_source(4, 0).getId()).to eq("/tmp/output") - end - - it "throw exception if line is out of bound" do - expect { subject.lookup_source(100, 0) }.to raise_exception(IndexError) - end - end - - context "when pipeline is constructed from multiple files and the first has trailing newline" do - let (:pipeline_conf_string_part1) { "input {\n generator1\n}\n" } - let (:pipeline_conf_string_part2) { 'output { - stdout - }' } - let(:merged_config_parts) do - [ - org.logstash.common.SourceWithMetadata.new("file", "/tmp/input", 0, 0, pipeline_conf_string_part1), - org.logstash.common.SourceWithMetadata.new("file", "/tmp/output", 0, 0, pipeline_conf_string_part2) - ] - end - subject { described_class.new(source, pipeline_id, merged_config_parts, settings) } - - it "shouldn't slide the mapping of subsequent" do - expect(subject.lookup_source(4, 0).getLine()).to eq(1) - expect(subject.lookup_source(4, 0).getId()).to eq("/tmp/output") - end - end - end -end diff --git a/logstash-core/spec/logstash/config/source_loader_spec.rb b/logstash-core/spec/logstash/config/source_loader_spec.rb index 309900ee8..87d812d9f 100644 --- a/logstash-core/spec/logstash/config/source_loader_spec.rb +++ b/logstash-core/spec/logstash/config/source_loader_spec.rb @@ -21,7 +21,7 @@ require_relative "../../support/helpers" def temporary_pipeline_config(id, source, reader = "random_reader") config_part = org.logstash.common.SourceWithMetadata.new("local", "...", 0, 0, "input {} output {}") - LogStash::Config::PipelineConfig.new(source, id, [config_part], LogStash::SETTINGS) + org.logstash.config.ir.PipelineConfig.new(source, id.to_sym, [config_part], LogStash::SETTINGS) end class DummySource < LogStash::Config::Source::Base diff --git a/logstash-core/spec/logstash/pipeline_spec.rb b/logstash-core/spec/logstash/pipeline_spec.rb index cf21e1136..d1058e762 100644 --- a/logstash-core/spec/logstash/pipeline_spec.rb +++ b/logstash-core/spec/logstash/pipeline_spec.rb @@ -22,6 +22,7 @@ require_relative "../support/mocks_classes" require_relative "../support/helpers" require "stud/try" require 'timeout' +require 'logstash/config/pipeline_config' class DummyInput < LogStash::Inputs::Base config_name "dummyinput" diff --git a/logstash-core/spec/logstash/pipelines_registry_spec.rb b/logstash-core/spec/logstash/pipelines_registry_spec.rb index 7a7183544..5a36b6332 100644 --- a/logstash-core/spec/logstash/pipelines_registry_spec.rb +++ b/logstash-core/spec/logstash/pipelines_registry_spec.rb @@ -20,9 +20,9 @@ require "logstash/pipelines_registry" describe LogStash::PipelinesRegistry do - let(:pipeline_id) { "test" } + let(:pipeline_id) { "test".to_sym } let(:pipeline) { double("Pipeline") } - let (:logger) { double("Logger") } + let(:logger) { double("Logger") } context "at object creation" do it "should be empty" do diff --git a/logstash-core/spec/logstash/state_resolver_spec.rb b/logstash-core/spec/logstash/state_resolver_spec.rb index 0d301fb16..8775bc3ac 100644 --- a/logstash-core/spec/logstash/state_resolver_spec.rb +++ b/logstash-core/spec/logstash/state_resolver_spec.rb @@ -19,7 +19,6 @@ require "spec_helper" require_relative "../support/helpers" require_relative "../support/matchers" require "logstash/state_resolver" -require "logstash/config/pipeline_config" require "logstash/pipeline" require "ostruct" require "digest" diff --git a/logstash-core/spec/support/helpers.rb b/logstash-core/spec/support/helpers.rb index 9d0e77c9d..52f67964d 100644 --- a/logstash-core/spec/support/helpers.rb +++ b/logstash-core/spec/support/helpers.rb @@ -86,7 +86,7 @@ def mock_pipeline_config(pipeline_id, config_string = nil, settings = {}) config_part = org.logstash.common.SourceWithMetadata.new("config_string", "config_string", 0, 0, config_string) - LogStash::Config::PipelineConfig.new(LogStash::Config::Source::Local, pipeline_id, config_part, settings) + org.logstash.config.ir.PipelineConfig.new(LogStash::Config::Source::Local, pipeline_id.to_sym, [config_part], settings) end def start_agent(agent) diff --git a/logstash-core/spec/support/matchers.rb b/logstash-core/spec/support/matchers.rb index b87f08c17..71a37cd00 100644 --- a/logstash-core/spec/support/matchers.rb +++ b/logstash-core/spec/support/matchers.rb @@ -17,7 +17,6 @@ require "rspec" require "rspec/expectations" -require "logstash/config/pipeline_config" require "stud/try" RSpec::Matchers.define :be_a_metric_event do |namespace, type, *args| diff --git a/logstash-core/spec/support/pipeline/pipeline_helpers.rb b/logstash-core/spec/support/pipeline/pipeline_helpers.rb index 0fccded8a..d6ccbddf0 100644 --- a/logstash-core/spec/support/pipeline/pipeline_helpers.rb +++ b/logstash-core/spec/support/pipeline/pipeline_helpers.rb @@ -76,7 +76,7 @@ module PipelineHelpers let(:pipeline) do settings.set_value("queue.drain", true) LogStash::JavaPipeline.new( - LogStash::Config::PipelineConfig.new( + org.logstash.config.ir.PipelineConfig.new( LogStash::Config::Source::Local, :main, SourceWithMetadata.new( "config_string", "config_string", diff --git a/logstash-core/src/main/java/org/logstash/config/ir/ConfigCompiler.java b/logstash-core/src/main/java/org/logstash/config/ir/ConfigCompiler.java index de7e3797e..f94a3ca47 100644 --- a/logstash-core/src/main/java/org/logstash/config/ir/ConfigCompiler.java +++ b/logstash-core/src/main/java/org/logstash/config/ir/ConfigCompiler.java @@ -53,9 +53,9 @@ public final class ConfigCompiler { * @throws InvalidIRException if the the configuration contains errors */ @SuppressWarnings("unchecked") - public static PipelineIR configToPipelineIR(final @SuppressWarnings("rawtypes") RubyArray sourcesWithMetadata, + public static PipelineIR configToPipelineIR(final List sourcesWithMetadata, final boolean supportEscapes) throws InvalidIRException { - return compileSources((List) sourcesWithMetadata, supportEscapes); + return compileSources(sourcesWithMetadata, supportEscapes); } public static PipelineIR compileSources(List sourcesWithMetadata, boolean supportEscapes) throws InvalidIRException { diff --git a/logstash-core/src/main/java/org/logstash/config/ir/PipelineConfig.java b/logstash-core/src/main/java/org/logstash/config/ir/PipelineConfig.java new file mode 100644 index 000000000..c5ab1b00d --- /dev/null +++ b/logstash-core/src/main/java/org/logstash/config/ir/PipelineConfig.java @@ -0,0 +1,177 @@ +/* + * 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. + */ + +package org.logstash.config.ir; + +import org.apache.commons.codec.digest.DigestUtils; +import org.apache.logging.log4j.LogManager; +import org.apache.logging.log4j.Logger; +import org.jruby.*; +import org.jruby.runtime.builtin.IRubyObject; +import org.logstash.common.IncompleteSourceWithMetadataException; +import org.logstash.common.SourceWithMetadata; + +import java.time.LocalDateTime; +import java.util.*; +import java.util.stream.Collectors; + +import static org.logstash.RubyUtil.RUBY; + +public final class PipelineConfig { + + private static class LineToSource { + private final int startLine; + private final int endLine; + private final SourceWithMetadata source; + + LineToSource(int startLine, int endLine, SourceWithMetadata source) { + this.startLine = startLine; + this.endLine = endLine; + this.source = source; + } + + boolean includeLine(int lineNumber) { + return startLine <= lineNumber && lineNumber <= endLine; + } + } + + private static final Logger logger = LogManager.getLogger(PipelineConfig.class); + + private RubyClass source; + private String pipelineId; + private List confParts; + private RubyObject settings; + private LocalDateTime readAt; + private String configHash; + private String configString; + private List sourceRefs; + + @SuppressWarnings({"rawtypes", "unchecked"}) + public PipelineConfig(RubyClass source, RubySymbol pipelineId, RubyObject uncastedConfigParts, RubyObject logstashSettings) { + IRubyObject uncasted = uncastedConfigParts.checkArrayType(); + final RubyArray configParts = !uncasted.isNil() ? + (RubyArray) uncasted : + RubyArray.newArray(RUBY, uncastedConfigParts); + + this.source = source; + this.pipelineId = pipelineId.toString(); + SourceWithMetadata[] castedConfigParts = (SourceWithMetadata[]) configParts.toJava(SourceWithMetadata[].class); + List confParts = Arrays.asList(castedConfigParts); + confParts.sort(Comparator.comparing(SourceWithMetadata::getProtocol) + .thenComparing(SourceWithMetadata::getId)); + this.confParts = confParts; + this.settings = logstashSettings; + this.readAt = LocalDateTime.now(); + } + + public RubyClass getSource() { + return source; + } + + public String getPipelineId() { + return pipelineId; + } + + public List getConfigParts() { + return confParts; + } + + public LocalDateTime getReadAt() { + return readAt; + } + + public RubyObject getSettings() { + return settings; + } + + public String configHash() { + if (configHash == null) { + configHash = DigestUtils.sha1Hex(configString()); + } + return configHash; + } + + public String configString() { + this.configString = confParts.stream().map(SourceWithMetadata::getText).collect(Collectors.joining("\n")); + return this.configString; + } + + public boolean isSystem() { + return this.settings.callMethod(RUBY.getCurrentContext(), "get_value", + RubyString.newString(RUBY, "pipeline.system")) + .isTrue(); + } + + @Override + public boolean equals(Object other) { + if (!(other instanceof PipelineConfig)) { + return false; + } + PipelineConfig cother = (PipelineConfig) other; + return configHash().equals(cother.configHash()) && + this.pipelineId.equals(cother.pipelineId) && + this.settings.eql(cother.settings); + } + + @Override + public int hashCode() { + return this.configHash().hashCode(); + } + + public void displayDebugInformation() { + logger.debug("-------- Logstash Config ---------"); + logger.debug("Config from source, source: {}, pipeline_id:: {}", source, pipelineId); + + for (SourceWithMetadata configPart : this.confParts) { + logger.debug("Config string, protocol: {}, id: {}", configPart.getProtocol(), configPart.getId()); + logger.debug("\n\n{}", configPart.getText()); + } + logger.debug("Merged config"); + logger.debug("\n\n{}", this.configString()); + } + + public SourceWithMetadata lookupSource(int globalLineNumber, int sourceColumn) + throws IncompleteSourceWithMetadataException { + LineToSource lts = this.sourceReferences().stream() + .filter(lts1 -> lts1.includeLine(globalLineNumber)) + .findFirst() + .orElseThrow(() -> new IllegalArgumentException("can't find the config segment related to line " + globalLineNumber)); + return new SourceWithMetadata(lts.source.getProtocol(), lts.source.getId(), + globalLineNumber + 1 - lts.startLine, sourceColumn, lts.source.getText()); + } + + private List sourceReferences() { + if (this.sourceRefs == null) { + int offset = 0; + List sourceRefs = new ArrayList<>(); + + for (SourceWithMetadata configPart : confParts) { + //line numbers starts from 1 in text files + int startLine = configPart.getLine() + offset + 1; + int endLine = configPart.getLinesCount() + offset; + LineToSource sourceSegment = new LineToSource(startLine, endLine, configPart); + sourceRefs.add(sourceSegment); + offset += configPart.getLinesCount(); + } + this.sourceRefs = Collections.unmodifiableList(sourceRefs); + } + return this.sourceRefs; + } + +} diff --git a/logstash-core/src/main/java/org/logstash/execution/AbstractPipelineExt.java b/logstash-core/src/main/java/org/logstash/execution/AbstractPipelineExt.java index 49ce69a52..148378466 100644 --- a/logstash-core/src/main/java/org/logstash/execution/AbstractPipelineExt.java +++ b/logstash-core/src/main/java/org/logstash/execution/AbstractPipelineExt.java @@ -50,10 +50,10 @@ import org.logstash.ackedqueue.QueueFactoryExt; import org.logstash.ackedqueue.ext.JRubyAckedQueueExt; import org.logstash.ackedqueue.ext.JRubyWrappedAckedQueueExt; import org.logstash.common.DeadLetterQueueFactory; -import org.logstash.common.IncompleteSourceWithMetadataException; import org.logstash.common.SourceWithMetadata; import org.logstash.config.ir.ConfigCompiler; import org.logstash.config.ir.InvalidIRException; +import org.logstash.config.ir.PipelineConfig; import org.logstash.config.ir.PipelineIR; import org.logstash.ext.JRubyAbstractQueueWriteClientExt; import org.logstash.ext.JRubyWrappedWriteClientExt; @@ -115,7 +115,7 @@ public class AbstractPipelineExt extends RubyBasicObject { private RubyString configString; @SuppressWarnings("rawtypes") - private RubyArray configParts; + private List configParts; private RubyString configHash; @@ -151,7 +151,7 @@ public class AbstractPipelineExt extends RubyBasicObject { ); pipelineSettings = pipelineConfig; configString = (RubyString) pipelineSettings.callMethod(context, "config_string"); - configParts = (RubyArray) pipelineSettings.callMethod(context, "config_parts"); + configParts = pipelineSettings.toJava(PipelineConfig.class).getConfigParts(); configHash = context.runtime.newString( Hex.encodeHexString( MessageDigest.getInstance("SHA1").digest(configString.getBytes()) @@ -397,10 +397,8 @@ public class AbstractPipelineExt extends RubyBasicObject { @JRubyMethod(name = "pipeline_source_details", visibility = Visibility.PROTECTED) @SuppressWarnings("rawtypes") public RubyArray getPipelineSourceDetails(final ThreadContext context) { - RubyArray res = configParts; - List pipelineSources = new ArrayList<>(res.size()); - for (IRubyObject part : res.toJavaArray()) { - SourceWithMetadata sourceWithMetadata = part.toJava(SourceWithMetadata.class); + List pipelineSources = new ArrayList<>(configParts.size()); + for (SourceWithMetadata sourceWithMetadata : configParts) { String protocol = sourceWithMetadata.getProtocol(); switch (protocol) { case "string": diff --git a/logstash-core/src/test/java/org/logstash/config/ir/ConfigCompilerTest.java b/logstash-core/src/test/java/org/logstash/config/ir/ConfigCompilerTest.java index e803bfbec..379a67d0e 100644 --- a/logstash-core/src/test/java/org/logstash/config/ir/ConfigCompilerTest.java +++ b/logstash-core/src/test/java/org/logstash/config/ir/ConfigCompilerTest.java @@ -30,11 +30,7 @@ import java.util.Arrays; import java.util.Collections; import java.util.List; -import org.jruby.javasupport.JavaUtil; -import org.jruby.runtime.builtin.IRubyObject; import org.junit.Test; -import org.logstash.RubyUtil; -import org.logstash.common.IncompleteSourceWithMetadataException; import org.logstash.common.SourceWithMetadata; import org.logstash.config.ir.graph.Graph; import org.logstash.config.ir.graph.PluginVertex; @@ -47,10 +43,9 @@ public class ConfigCompilerTest extends RubyEnvTestCase { @Test public void testConfigToPipelineIR() throws Exception { - IRubyObject swm = JavaUtil.convertJavaToRuby( - RubyUtil.RUBY, new SourceWithMetadata("proto", "path", 1, 1, "input {stdin{}} output{stdout{}}")); + SourceWithMetadata swm = new SourceWithMetadata("proto", "path", 1, 1, "input {stdin{}} output{stdout{}}"); final PipelineIR pipelineIR = - ConfigCompiler.configToPipelineIR(RubyUtil.RUBY.newArray(swm), false); + ConfigCompiler.configToPipelineIR(Collections.singletonList(swm), false); assertThat(pipelineIR.getOutputPluginVertices().size(), is(1)); assertThat(pipelineIR.getFilterPluginVertices().size(), is(0)); } @@ -99,9 +94,8 @@ public class ConfigCompilerTest extends RubyEnvTestCase { } private static String graphHash(final String config) throws InvalidIRException { - IRubyObject swm = JavaUtil.convertJavaToRuby( - RubyUtil.RUBY, new SourceWithMetadata("proto", "path", 1, 1, config)); - return ConfigCompiler.configToPipelineIR(RubyUtil.RUBY.newArray(swm), false).uniqueHash(); + SourceWithMetadata swm = new SourceWithMetadata("proto", "path", 1, 1, config); + return ConfigCompiler.configToPipelineIR(Collections.singletonList(swm), false).uniqueHash(); } @Test diff --git a/logstash-core/src/test/java/org/logstash/config/ir/PipelineConfigTest.java b/logstash-core/src/test/java/org/logstash/config/ir/PipelineConfigTest.java new file mode 100644 index 000000000..841042a43 --- /dev/null +++ b/logstash-core/src/test/java/org/logstash/config/ir/PipelineConfigTest.java @@ -0,0 +1,196 @@ +/* + * 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. + */ + +package org.logstash.config.ir; + +import org.jruby.*; +import org.jruby.runtime.builtin.IRubyObject; +import org.junit.Before; +import org.junit.Test; +import org.logstash.RubyUtil; +import org.logstash.common.IncompleteSourceWithMetadataException; +import org.logstash.common.SourceWithMetadata; + +import java.time.LocalDateTime; +import java.util.*; +import java.util.stream.Collectors; + +import static org.junit.Assert.*; + +public class PipelineConfigTest extends RubyEnvTestCase { + + public static final String PIPELINE_ID = "main"; + private RubyClass source; + private RubySymbol pipelineIdSym; + private String configMerged; + private SourceWithMetadata[] unorderedConfigParts; + + private final static RubyObject SETTINGS = (RubyObject) RubyUtil.RUBY.evalScriptlet( + "require 'logstash/environment'\n" + // this is needed to register "pipeline.system" setting + "require 'logstash/settings'\n" + + "LogStash::SETTINGS");; + private PipelineConfig sut; + private SourceWithMetadata[] orderedConfigParts; + public static final String PIPELINE_CONFIG_PART_2 = + "output {\n" + + " stdout\n" + + "}"; + public static final String PIPELINE_CONFIG_PART_1 = + "input {\n" + + " generator1\n" + + "}"; + + @Before + public void setUp() throws IncompleteSourceWithMetadataException { + + source = RubyUtil.RUBY.getClass("LogStash::Config::Source::Local"); + pipelineIdSym = RubySymbol.newSymbol(RubyUtil.RUBY, PIPELINE_ID); + + orderedConfigParts = new SourceWithMetadata[]{ + new SourceWithMetadata("file", "/tmp/1", 0, 0, "input { generator1 }"), + new SourceWithMetadata("file", "/tmp/2", 0, 0, "input { generator2 }"), + new SourceWithMetadata("file", "/tmp/3", 0, 0, "input { generator3 }"), + new SourceWithMetadata("file", "/tmp/4", 0, 0, "input { generator4 }"), + new SourceWithMetadata("file", "/tmp/5", 0, 0, "input { generator5 }"), + new SourceWithMetadata("file", "/tmp/6", 0, 0, "input { generator6 }"), + new SourceWithMetadata("string", "config_string", 0, 0, "input { generator1 }"), + }; + + configMerged = Arrays.stream(orderedConfigParts).map(SourceWithMetadata::getText).collect(Collectors.joining("\n")); + + List unorderedList = Arrays.asList(orderedConfigParts); + Collections.shuffle(unorderedList); + unorderedConfigParts = unorderedList.toArray(new SourceWithMetadata[0]); + + sut = new PipelineConfig(source, pipelineIdSym, toRubyArray(unorderedConfigParts), SETTINGS); + } + + @Test + public void testReturnsTheSource() { + assertEquals("returns the source", source, sut.getSource()); + assertEquals("returns the pipeline id", PIPELINE_ID, sut.getPipelineId()); + assertNotNull("returns the config_hash", sut.configHash()); + assertEquals("returns the merged `ConfigPart#config_string`", configMerged, sut.configString()); + assertTrue("records when the config was read", sut.getReadAt().isBefore(LocalDateTime.now())); + } + + @SuppressWarnings("rawtypes") + private static RubyArray toRubyArray(SourceWithMetadata[] arr) { + List wrappedContent = Arrays.stream(arr).map(RubyUtil::toRubyObject).collect(Collectors.toList()); + return RubyArray.newArray(RubyUtil.RUBY, wrappedContent); + } + + @Test + public void testObjectEqualityOnConfigHashAndPipelineId() { + PipelineConfig anotherExactPipeline = new PipelineConfig(source, pipelineIdSym, toRubyArray(orderedConfigParts), SETTINGS); + assertEquals(anotherExactPipeline, sut); + + PipelineConfig notMatchingPipeline = new PipelineConfig(source, pipelineIdSym, RubyArray.newEmptyArray(RubyUtil.RUBY), SETTINGS); + assertNotEquals(notMatchingPipeline, sut); + + PipelineConfig notSamePipelineId = new PipelineConfig(source, RubySymbol.newSymbol(RubyUtil.RUBY, "another_pipeline"), toRubyArray(unorderedConfigParts), SETTINGS); + assertNotEquals(notSamePipelineId, sut); + } + + @Test + public void testIsSystemWhenPipelineIsNotSystemPipeline() { + assertFalse("returns false if the pipeline is not a system pipeline", sut.isSystem()); + } + + @Test + public void testIsSystemWhenPipelineIsSystemPipeline() { + RubyObject mockedSettings = mockSettings(Collections.singletonMap("pipeline.system", true)); + sut = new PipelineConfig(source, pipelineIdSym, toRubyArray(unorderedConfigParts), mockedSettings); + + assertTrue("returns true if the pipeline is a system pipeline", sut.isSystem()); + } + + public RubyObject mockSettings(Map settingsValues) { + IRubyObject settings = SETTINGS.callMethod("clone"); + settingsValues.forEach((k, v) -> { + RubyString rk = RubyString.newString(RubyUtil.RUBY, k); + IRubyObject rv = RubyUtil.toRubyObject(v); + settings.callMethod(RubyUtil.RUBY.getCurrentContext(), "set", new IRubyObject[]{rk, rv}); + }); + return (RubyObject) settings; + } + + @Test + public void testSourceAndLineRemapping_pipelineDefinedInSingleFileOneLine() throws IncompleteSourceWithMetadataException { + String oneLinerPipeline = "input { generator1 }"; + final SourceWithMetadata swm = new SourceWithMetadata("file", "/tmp/1", 0, 0, oneLinerPipeline); + sut = new PipelineConfig(source, pipelineIdSym, toRubyArray(new SourceWithMetadata[]{swm}), SETTINGS); + + assertEquals("return the same line of the queried", 1, (int) sut.lookupSource(1, 0).getLine()); + } + + @Test + public void testSourceAndLineRemapping_pipelineDefinedInSingleFileMultiLine() throws IncompleteSourceWithMetadataException { + final SourceWithMetadata swm = new SourceWithMetadata("file", "/tmp/1", 0, 0, PIPELINE_CONFIG_PART_1); + sut = new PipelineConfig(source, pipelineIdSym, toRubyArray(new SourceWithMetadata[]{swm}), SETTINGS); + + assertEquals("return the same line of the queried L1", 1, (int) sut.lookupSource(1, 0).getLine()); + assertEquals("return the same line of the queried L2", 2, (int) sut.lookupSource(2, 0).getLine()); + } + + @Test(expected = IllegalArgumentException.class) + public void testSourceAndLineRemapping_pipelineDefinedInSingleFileMultiLine_dontmatch() throws IncompleteSourceWithMetadataException { + final SourceWithMetadata swm = new SourceWithMetadata("file", "/tmp/1", 0, 0, PIPELINE_CONFIG_PART_1); + sut = new PipelineConfig(source, pipelineIdSym, toRubyArray(new SourceWithMetadata[]{swm}), SETTINGS); + + sut.lookupSource(100, -1); + } + + @Test + public void testSourceAndLineRemapping_pipelineDefinedMInMultipleFiles() throws IncompleteSourceWithMetadataException { + final SourceWithMetadata[] parts = { + new SourceWithMetadata("file", "/tmp/input", 0, 0, PIPELINE_CONFIG_PART_1), + new SourceWithMetadata("file", "/tmp/output", 0, 0, PIPELINE_CONFIG_PART_2) + }; + sut = new PipelineConfig(source, pipelineIdSym, toRubyArray(parts), SETTINGS); + + assertEquals("return the line of first segment", 2, (int) sut.lookupSource(2, 0).getLine()); + assertEquals("return the id of first segment", "/tmp/input", sut.lookupSource(2, 0).getId()); + assertEquals("return the line of second segment", 1, (int) sut.lookupSource(4, 0).getLine()); + assertEquals("return the id of second segment", "/tmp/output", sut.lookupSource(4, 0).getId()); + } + + @Test(expected = IllegalArgumentException.class) + public void testSourceAndLineRemapping_pipelineDefinedMInMultipleFiles_dontmatch() throws IncompleteSourceWithMetadataException { + final SourceWithMetadata[] parts = { + new SourceWithMetadata("file", "/tmp/input", 0, 0, PIPELINE_CONFIG_PART_1), + new SourceWithMetadata("file", "/tmp/output", 0, 0, PIPELINE_CONFIG_PART_2) + }; + sut = new PipelineConfig(source, pipelineIdSym, toRubyArray(parts), SETTINGS); + + sut.lookupSource(100, 0); + } + + @Test + public void testSourceAndLineRemapping_pipelineDefinedMInMultipleFiles_withEmptyLinesInTheMiddle() throws IncompleteSourceWithMetadataException { + final SourceWithMetadata[] parts = { + new SourceWithMetadata("file", "/tmp/input", 0, 0, PIPELINE_CONFIG_PART_1 + "\n"), + new SourceWithMetadata("file", "/tmp/output", 0, 0, PIPELINE_CONFIG_PART_2) + }; + sut = new PipelineConfig(source, pipelineIdSym, toRubyArray(parts), SETTINGS); + + assertEquals("shouldn't slide the line mapping of subsequent", 1, (int) sut.lookupSource(4, 0).getLine()); + assertEquals("shouldn't slide the id mapping of subsequent", "/tmp/output", sut.lookupSource(4, 0).getId()); + } +} diff --git a/logstash-core/src/test/java/org/logstash/plugins/PluginFactoryExtTest.java b/logstash-core/src/test/java/org/logstash/plugins/PluginFactoryExtTest.java index 30d106032..f97c21d1b 100644 --- a/logstash-core/src/test/java/org/logstash/plugins/PluginFactoryExtTest.java +++ b/logstash-core/src/test/java/org/logstash/plugins/PluginFactoryExtTest.java @@ -21,14 +21,11 @@ package org.logstash.plugins; import co.elastic.logstash.api.*; -import org.jruby.RubyArray; import org.jruby.RubyHash; import org.jruby.RubyString; -import org.jruby.javasupport.JavaUtil; import org.jruby.runtime.builtin.IRubyObject; import org.junit.Test; import org.logstash.RubyUtil; -import org.logstash.common.IncompleteSourceWithMetadataException; import org.logstash.common.SourceWithMetadata; import org.logstash.config.ir.ConfigCompiler; import org.logstash.config.ir.InvalidIRException; @@ -109,12 +106,8 @@ public final class PluginFactoryExtTest extends RubyEnvTestCase { assertEquals("Resolved config setting MUST be evaluated with substitution", envVars.get("CUSTOM"), id.toString()); } - @SuppressWarnings("rawtypes") private static PipelineIR compilePipeline(SourceWithMetadata sourceWithMetadata) throws InvalidIRException { - RubyArray sourcesWithMetadata = RubyUtil.RUBY.newArray(JavaUtil.convertJavaToRuby( - RubyUtil.RUBY, sourceWithMetadata)); - - return ConfigCompiler.configToPipelineIR(sourcesWithMetadata, false); + return ConfigCompiler.configToPipelineIR(Collections.singletonList(sourceWithMetadata), false); } private static PluginFactoryExt.ExecutionContext createExecutionContextFactory() { diff --git a/x-pack/lib/config_management/elasticsearch_source.rb b/x-pack/lib/config_management/elasticsearch_source.rb index edc4af3b1..9e04121fc 100644 --- a/x-pack/lib/config_management/elasticsearch_source.rb +++ b/x-pack/lib/config_management/elasticsearch_source.rb @@ -2,7 +2,6 @@ # 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/config/pipeline_config" require "logstash/config/source/base" require "logstash/config/source_loader" require "logstash/outputs/elasticsearch" @@ -112,7 +111,7 @@ module LogStash end end - LogStash::Config::PipelineConfig.new(self.class.name, pipeline_id.to_sym, config_part, settings) + Java::OrgLogstashConfigIr::PipelineConfig.new(self.class, pipeline_id.to_sym, [config_part], settings) end # This is a bit of a hack until we refactor the ElasticSearch plugins diff --git a/x-pack/lib/monitoring/monitoring.rb b/x-pack/lib/monitoring/monitoring.rb index 4d1ff269e..9a5fb9100 100644 --- a/x-pack/lib/monitoring/monitoring.rb +++ b/x-pack/lib/monitoring/monitoring.rb @@ -4,7 +4,6 @@ require "logstash/agent" require "monitoring/internal_pipeline_source" -require "logstash/config/pipeline_config" require 'helpers/elasticsearch_options' module LogStash @@ -181,7 +180,7 @@ module LogStash logger.debug("compiled metrics pipeline config: ", :config => config) config_part = org.logstash.common.SourceWithMetadata.new("x-pack-metrics", "internal_pipeline_source", config) - LogStash::Config::PipelineConfig.new(self, PIPELINE_ID.to_sym, config_part, settings) + Java::OrgLogstashConfigIr::PipelineConfig.new(self.class, PIPELINE_ID.to_sym, [config_part], settings) end def generate_pipeline_config(settings) diff --git a/x-pack/spec/config_management/elasticsearch_source_spec.rb b/x-pack/spec/config_management/elasticsearch_source_spec.rb index d7d3250ef..7eb385dd1 100644 --- a/x-pack/spec/config_management/elasticsearch_source_spec.rb +++ b/x-pack/spec/config_management/elasticsearch_source_spec.rb @@ -268,7 +268,7 @@ describe LogStash::ConfigManagement::ElasticsearchSource do pipeline_config = subject.pipeline_configs expect(pipeline_config.first.config_string).to match(config) - expect(pipeline_config.first.pipeline_id).to eq(pipeline_id.to_sym) + expect(pipeline_config.first.pipeline_id.to_sym).to eq(pipeline_id.to_sym) end it "ignores non-whitelisted and invalid settings" do @@ -295,7 +295,7 @@ describe LogStash::ConfigManagement::ElasticsearchSource do pipeline_config = subject.pipeline_configs expect(pipeline_config.first.config_string).to match(config) - expect(pipeline_config.first.pipeline_id).to eq(pipeline_id.to_sym) + expect(pipeline_config.first.pipeline_id.to_sym).to eq(pipeline_id.to_sym) end end @@ -397,7 +397,7 @@ describe LogStash::ConfigManagement::ElasticsearchSource do pipeline_config = subject.pipeline_configs expect(pipeline_config.first.config_string).to match(config) - expect(pipeline_config.first.pipeline_id).to eq(pipeline_id.to_sym) + expect(pipeline_config.first.pipeline_id.to_sym).to eq(pipeline_id.to_sym) end end end @@ -433,7 +433,7 @@ describe LogStash::ConfigManagement::ElasticsearchSource do pipeline_config = subject.pipeline_configs expect(pipeline_config.collect(&:config_string)).to include(*pipelines.values) - expect(pipeline_config.collect(&:pipeline_id)).to include(*pipelines.keys.collect(&:to_sym)) + expect(pipeline_config.map(&:pipeline_id).collect(&:to_sym)).to include(*pipelines.keys.collect(&:to_sym)) end end end diff --git a/x-pack/spec/modules/azure/filters/azure_event_spec.rb b/x-pack/spec/modules/azure/filters/azure_event_spec.rb index 43db6f7e9..a12671193 100644 --- a/x-pack/spec/modules/azure/filters/azure_event_spec.rb +++ b/x-pack/spec/modules/azure/filters/azure_event_spec.rb @@ -6,9 +6,11 @@ require 'x-pack/logstash_registry' require 'logstash/devutils/rspec/spec_helper' require 'logstash/json' require 'filters/azure_event' +require 'logstash/config/pipeline_config' describe LogStash::Filters::AzureEvent do + describe "Parses the admin activity log" do let(:config) do <<-CONFIG diff --git a/x-pack/spec/monitoring/inputs/metrics/state_event_factory_spec.rb b/x-pack/spec/monitoring/inputs/metrics/state_event_factory_spec.rb index ad8498a68..5c6e0cc74 100644 --- a/x-pack/spec/monitoring/inputs/metrics/state_event_factory_spec.rb +++ b/x-pack/spec/monitoring/inputs/metrics/state_event_factory_spec.rb @@ -14,7 +14,7 @@ describe LogStash::Inputs::Metrics::StateEventFactory do let(:config) { config_part = org.logstash.common.SourceWithMetadata.new("local", "...", 0, 0, "input { dummyblockinginput { } } output { null { } }") - LogStash::Config::PipelineConfig.new("DummySource", "fake_main", [config_part], LogStash::SETTINGS) + Java::OrgLogstashConfigIr::PipelineConfig.new("DummySource".class, "fake_main".to_sym, [config_part], LogStash::SETTINGS) } let(:pipeline_settings) { LogStash::Runner::SYSTEM_SETTINGS.clone.merge({ diff --git a/x-pack/spec/monitoring/inputs/metrics/stats_event_factory_spec.rb b/x-pack/spec/monitoring/inputs/metrics/stats_event_factory_spec.rb index 351323a20..905356fe8 100644 --- a/x-pack/spec/monitoring/inputs/metrics/stats_event_factory_spec.rb +++ b/x-pack/spec/monitoring/inputs/metrics/stats_event_factory_spec.rb @@ -3,6 +3,7 @@ # you may not use this file except in compliance with the Elastic License. require "monitoring/inputs/metrics/stats_event_factory" +require "logstash/config/pipeline_config" require 'json' describe LogStash::Inputs::Metrics::StatsEventFactory do diff --git a/x-pack/spec/monitoring/internal_pipeline_source_spec.rb b/x-pack/spec/monitoring/internal_pipeline_source_spec.rb index 3ebaabf12..4a23e9f9c 100644 --- a/x-pack/spec/monitoring/internal_pipeline_source_spec.rb +++ b/x-pack/spec/monitoring/internal_pipeline_source_spec.rb @@ -6,7 +6,6 @@ require "logstash-core" require "logstash/agent" require "logstash/runner" require "monitoring/inputs/metrics" -require "logstash/config/pipeline_config" require "logstash/config/source/local" require 'license_checker/x_pack_info' require "rspec/wait" @@ -53,7 +52,7 @@ describe LogStash::Monitoring::InternalPipelineSource do let(:unordered_config_parts) { ordered_config_parts.shuffle } - let(:pipeline_config) { LogStash::Config::PipelineConfig.new(source, pipeline_id, unordered_config_parts, system_settings) } + let(:pipeline_config) { Java::OrgLogstashConfigIr::PipelineConfig.new(source, pipeline_id, unordered_config_parts, system_settings) } let(:es_options) do { From 3e380bf10f5d591725b93b5d7f7302fe157cb447 Mon Sep 17 00:00:00 2001 From: Andrea Selva Date: Fri, 26 Jun 2020 11:09:08 +0200 Subject: [PATCH 0515/1126] Backport of PR #11457 to 7.x (#12057) Simplified if..else if in PluginFactory for Java plugins part, moved to template method pattern --- logstash-core/build.gradle | 4 +- logstash-core/lib/logstash/pipeline.rb | 2 +- .../src/main/java/org/logstash/RubyUtil.java | 20 +- .../logstash/config/ir/CompiledPipeline.java | 2 +- .../execution/JavaBasePipelineExt.java | 12 +- .../plugins/ConfigVariableExpander.java | 5 +- .../logstash/plugins/PluginFactoryExt.java | 486 ------------------ .../org/logstash/plugins/codecs/Dots.java | 14 +- .../org/logstash/plugins/codecs/Line.java | 18 +- .../org/logstash/plugins/codecs/Plain.java | 17 +- .../factory/AbstractPluginCreator.java | 45 ++ .../plugins/factory/CodecPluginCreator.java | 23 + .../factory/ExecutionContextFactoryExt.java | 77 +++ .../plugins/factory/FilterPluginCreator.java | 21 + .../plugins/factory/InputPluginCreator.java | 27 + .../plugins/factory/OutputPluginCreator.java | 25 + .../plugins/factory/PluginFactoryExt.java | 261 ++++++++++ .../factory/PluginMetricsFactoryExt.java | 61 +++ .../org/logstash/plugins/MetricTestCase.java | 2 +- .../{ => factory}/PluginFactoryExtTest.java | 24 +- 20 files changed, 615 insertions(+), 531 deletions(-) delete mode 100644 logstash-core/src/main/java/org/logstash/plugins/PluginFactoryExt.java create mode 100644 logstash-core/src/main/java/org/logstash/plugins/factory/AbstractPluginCreator.java create mode 100644 logstash-core/src/main/java/org/logstash/plugins/factory/CodecPluginCreator.java create mode 100644 logstash-core/src/main/java/org/logstash/plugins/factory/ExecutionContextFactoryExt.java create mode 100644 logstash-core/src/main/java/org/logstash/plugins/factory/FilterPluginCreator.java create mode 100644 logstash-core/src/main/java/org/logstash/plugins/factory/InputPluginCreator.java create mode 100644 logstash-core/src/main/java/org/logstash/plugins/factory/OutputPluginCreator.java create mode 100644 logstash-core/src/main/java/org/logstash/plugins/factory/PluginFactoryExt.java create mode 100644 logstash-core/src/main/java/org/logstash/plugins/factory/PluginMetricsFactoryExt.java rename logstash-core/src/test/java/org/logstash/plugins/{ => factory}/PluginFactoryExtTest.java (85%) diff --git a/logstash-core/build.gradle b/logstash-core/build.gradle index 4d308557b..5c837b2e6 100644 --- a/logstash-core/build.gradle +++ b/logstash-core/build.gradle @@ -97,7 +97,7 @@ tasks.register("javaTests", Test) { exclude '/org/logstash/config/ir/compiler/JavaCodecDelegatorTest.class' exclude '/org/logstash/plugins/NamespacedMetricImplTest.class' exclude '/org/logstash/plugins/CounterMetricImplTest.class' - exclude '/org/logstash/plugins/PluginFactoryExtTest.class' + exclude '/org/logstash/plugins/factory/PluginFactoryExtTest.class' } tasks.register("rubyTests", Test) { @@ -113,7 +113,7 @@ tasks.register("rubyTests", Test) { include '/org/logstash/config/ir/compiler/JavaCodecDelegatorTest.class' include '/org/logstash/plugins/NamespacedMetricImplTest.class' include '/org/logstash/plugins/CounterMetricImplTest.class' - include '/org/logstash/plugins/PluginFactoryExtTest.class' + include '/org/logstash/plugins/factory/PluginFactoryExtTest.class' } test { diff --git a/logstash-core/lib/logstash/pipeline.rb b/logstash-core/lib/logstash/pipeline.rb index 766d1be49..3afc80677 100644 --- a/logstash-core/lib/logstash/pipeline.rb +++ b/logstash-core/lib/logstash/pipeline.rb @@ -46,7 +46,7 @@ module LogStash; class BasePipeline < AbstractPipeline @plugin_factory = LogStash::Plugins::PluginFactory.new( # use NullMetric if called in the BasePipeline context otherwise use the @metric value - lir, LogStash::Plugins::PluginMetricFactory.new(pipeline_id, metric), + lir, LogStash::Plugins::PluginMetricsFactory.new(pipeline_id, metric), LogStash::Plugins::ExecutionContextFactory.new(@agent, self, dlq_writer), FilterDelegator ) diff --git a/logstash-core/src/main/java/org/logstash/RubyUtil.java b/logstash-core/src/main/java/org/logstash/RubyUtil.java index d5c8ed817..d80267923 100644 --- a/logstash-core/src/main/java/org/logstash/RubyUtil.java +++ b/logstash-core/src/main/java/org/logstash/RubyUtil.java @@ -73,9 +73,11 @@ import org.logstash.log.LoggableExt; import org.logstash.log.LoggerExt; import org.logstash.log.SlowLoggerExt; import org.logstash.plugins.HooksRegistryExt; -import org.logstash.plugins.PluginFactoryExt; import org.logstash.plugins.UniversalPluginExt; import org.logstash.util.UtilExt; +import org.logstash.plugins.factory.ExecutionContextFactoryExt; +import org.logstash.plugins.factory.PluginMetricsFactoryExt; +import org.logstash.plugins.factory.PluginFactoryExt; import java.util.stream.Stream; @@ -193,7 +195,7 @@ public final class RubyUtil { public static final RubyClass EXECUTION_CONTEXT_FACTORY_CLASS; - public static final RubyClass PLUGIN_METRIC_FACTORY_CLASS; + public static final RubyClass PLUGIN_METRICS_FACTORY_CLASS; public static final RubyClass PLUGIN_FACTORY_CLASS; @@ -259,16 +261,16 @@ public final class RubyUtil { METRIC_SNAPSHOT_CLASS.defineAnnotatedMethods(SnapshotExt.class); EXECUTION_CONTEXT_FACTORY_CLASS = PLUGINS_MODULE.defineClassUnder( "ExecutionContextFactory", RUBY.getObject(), - PluginFactoryExt.ExecutionContext::new + ExecutionContextFactoryExt::new ); - PLUGIN_METRIC_FACTORY_CLASS = PLUGINS_MODULE.defineClassUnder( - "PluginMetricFactory", RUBY.getObject(), PluginFactoryExt.Metrics::new + PLUGIN_METRICS_FACTORY_CLASS = PLUGINS_MODULE.defineClassUnder( + "PluginMetricsFactory", RUBY.getObject(), PluginMetricsFactoryExt::new ); SHUTDOWN_WATCHER_CLASS = setupLogstashClass(ShutdownWatcherExt::new, ShutdownWatcherExt.class); - PLUGIN_METRIC_FACTORY_CLASS.defineAnnotatedMethods(PluginFactoryExt.Metrics.class); + PLUGIN_METRICS_FACTORY_CLASS.defineAnnotatedMethods(PluginMetricsFactoryExt.class); EXECUTION_CONTEXT_FACTORY_CLASS.defineAnnotatedMethods( - PluginFactoryExt.ExecutionContext.class + ExecutionContextFactoryExt.class ); METRIC_EXCEPTION_CLASS = instrumentModule.defineClassUnder( "MetricException", RUBY.getException(), MetricExt.MetricException::new @@ -546,9 +548,9 @@ public final class RubyUtil { RUBY_EVENT_CLASS.defineAnnotatedMethods(JrubyEventExtLibrary.RubyEvent.class); RUBY_EVENT_CLASS.defineAnnotatedConstants(JrubyEventExtLibrary.RubyEvent.class); PLUGIN_FACTORY_CLASS = PLUGINS_MODULE.defineClassUnder( - "PluginFactory", RUBY.getObject(), PluginFactoryExt.Plugins::new + "PluginFactory", RUBY.getObject(), PluginFactoryExt::new ); - PLUGIN_FACTORY_CLASS.defineAnnotatedMethods(PluginFactoryExt.Plugins.class); + PLUGIN_FACTORY_CLASS.defineAnnotatedMethods(PluginFactoryExt.class); UNIVERSAL_PLUGIN_CLASS = setupLogstashClass(UniversalPluginExt::new, UniversalPluginExt.class); EVENT_DISPATCHER_CLASS = diff --git a/logstash-core/src/main/java/org/logstash/config/ir/CompiledPipeline.java b/logstash-core/src/main/java/org/logstash/config/ir/CompiledPipeline.java index 3ed4ad9c4..b351c0612 100644 --- a/logstash-core/src/main/java/org/logstash/config/ir/CompiledPipeline.java +++ b/logstash-core/src/main/java/org/logstash/config/ir/CompiledPipeline.java @@ -116,7 +116,7 @@ public final class CompiledPipeline { filters = setupFilters(cve); outputs = setupOutputs(cve); } catch (Exception e) { - throw new IllegalStateException("Unable to configure plugins: " + e.getMessage()); + throw new IllegalStateException("Unable to configure plugins: " + e.getMessage(), e); } } diff --git a/logstash-core/src/main/java/org/logstash/execution/JavaBasePipelineExt.java b/logstash-core/src/main/java/org/logstash/execution/JavaBasePipelineExt.java index 75a78ad70..aea003dde 100644 --- a/logstash-core/src/main/java/org/logstash/execution/JavaBasePipelineExt.java +++ b/logstash-core/src/main/java/org/logstash/execution/JavaBasePipelineExt.java @@ -36,7 +36,9 @@ import org.logstash.common.IncompleteSourceWithMetadataException; import org.logstash.config.ir.CompiledPipeline; import org.logstash.execution.queue.QueueWriter; import org.logstash.ext.JRubyWrappedWriteClientExt; -import org.logstash.plugins.PluginFactoryExt; +import org.logstash.plugins.factory.ExecutionContextFactoryExt; +import org.logstash.plugins.factory.PluginMetricsFactoryExt; +import org.logstash.plugins.factory.PluginFactoryExt; import java.security.NoSuchAlgorithmException; import java.util.Collection; @@ -67,12 +69,12 @@ public final class JavaBasePipelineExt extends AbstractPipelineExt { initialize(context, args[0], args[1], args[2]); lirExecution = new CompiledPipeline( lir, - new PluginFactoryExt.Plugins(context.runtime, RubyUtil.PLUGIN_FACTORY_CLASS).init( + new PluginFactoryExt(context.runtime, RubyUtil.PLUGIN_FACTORY_CLASS).init( lir, - new PluginFactoryExt.Metrics( - context.runtime, RubyUtil.PLUGIN_METRIC_FACTORY_CLASS + new PluginMetricsFactoryExt( + context.runtime, RubyUtil.PLUGIN_METRICS_FACTORY_CLASS ).initialize(context, pipelineId(), metric()), - new PluginFactoryExt.ExecutionContext( + new ExecutionContextFactoryExt( context.runtime, RubyUtil.EXECUTION_CONTEXT_FACTORY_CLASS ).initialize(context, args[3], this, dlqWriter(context)), RubyUtil.FILTER_DELEGATOR_CLASS diff --git a/logstash-core/src/main/java/org/logstash/plugins/ConfigVariableExpander.java b/logstash-core/src/main/java/org/logstash/plugins/ConfigVariableExpander.java index 3dd4d86d0..fb1247f3c 100644 --- a/logstash-core/src/main/java/org/logstash/plugins/ConfigVariableExpander.java +++ b/logstash-core/src/main/java/org/logstash/plugins/ConfigVariableExpander.java @@ -38,8 +38,11 @@ public class ConfigVariableExpander implements AutoCloseable { /** * Creates a ConfigVariableExpander that doesn't lookup any secreted placeholder. + * + * @param envVarProvider EnvironmentVariableProvider to use as source of substitutions + * @return an variable expander that uses envVarProvider as source * */ - static ConfigVariableExpander withoutSecret(EnvironmentVariableProvider envVarProvider) { + public static ConfigVariableExpander withoutSecret(EnvironmentVariableProvider envVarProvider) { return new ConfigVariableExpander(null, envVarProvider); } diff --git a/logstash-core/src/main/java/org/logstash/plugins/PluginFactoryExt.java b/logstash-core/src/main/java/org/logstash/plugins/PluginFactoryExt.java deleted file mode 100644 index fabe2150b..000000000 --- a/logstash-core/src/main/java/org/logstash/plugins/PluginFactoryExt.java +++ /dev/null @@ -1,486 +0,0 @@ -/* - * 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. - */ - - -package org.logstash.plugins; - -import co.elastic.logstash.api.Codec; -import co.elastic.logstash.api.Configuration; -import co.elastic.logstash.api.Context; -import co.elastic.logstash.api.DeadLetterQueueWriter; -import co.elastic.logstash.api.Filter; -import co.elastic.logstash.api.Input; -import co.elastic.logstash.api.Output; -import org.jruby.Ruby; -import org.jruby.RubyArray; -import org.jruby.RubyBasicObject; -import org.jruby.RubyClass; -import org.jruby.RubyHash; -import org.jruby.RubyString; -import org.jruby.RubySymbol; -import org.jruby.anno.JRubyClass; -import org.jruby.anno.JRubyMethod; -import org.jruby.javasupport.JavaUtil; -import org.jruby.runtime.ThreadContext; -import org.jruby.runtime.builtin.IRubyObject; -import org.logstash.RubyUtil; -import org.logstash.common.AbstractDeadLetterQueueWriterExt; -import org.logstash.common.DLQWriterAdapter; -import org.logstash.common.EnvironmentVariableProvider; -import org.logstash.common.NullDeadLetterQueueWriter; -import org.logstash.common.SourceWithMetadata; -import org.logstash.config.ir.PipelineIR; -import org.logstash.config.ir.compiler.AbstractFilterDelegatorExt; -import org.logstash.config.ir.compiler.AbstractOutputDelegatorExt; -import org.logstash.config.ir.compiler.FilterDelegatorExt; -import org.logstash.config.ir.compiler.JavaCodecDelegator; -import org.logstash.config.ir.compiler.JavaFilterDelegatorExt; -import org.logstash.config.ir.compiler.JavaInputDelegatorExt; -import org.logstash.config.ir.compiler.JavaOutputDelegatorExt; -import org.logstash.config.ir.compiler.OutputDelegatorExt; -import org.logstash.config.ir.compiler.OutputStrategyExt; -import org.logstash.config.ir.compiler.RubyIntegration; -import org.logstash.config.ir.graph.Vertex; -import org.logstash.execution.ExecutionContextExt; -import org.logstash.execution.JavaBasePipelineExt; -import org.logstash.instrument.metrics.AbstractMetricExt; -import org.logstash.instrument.metrics.AbstractNamespacedMetricExt; -import org.logstash.instrument.metrics.MetricKeys; -import org.logstash.instrument.metrics.NullMetricExt; - -import java.lang.reflect.Constructor; -import java.lang.reflect.InvocationTargetException; -import java.util.Arrays; -import java.util.Collection; -import java.util.Collections; -import java.util.HashMap; -import java.util.HashSet; -import java.util.Locale; -import java.util.Map; -import java.util.UUID; - -public final class PluginFactoryExt { - - @FunctionalInterface - public interface PluginResolver { - PluginLookup.PluginClass resolve(PluginLookup.PluginType type, String name); - } - - @JRubyClass(name = "PluginFactory") - public static final class Plugins extends RubyBasicObject - implements RubyIntegration.PluginFactory { - - private static final long serialVersionUID = 1L; - - private static final RubyString ID_KEY = RubyUtil.RUBY.newString("id"); - - private final Collection pluginsById = new HashSet<>(); - - private PipelineIR lir; - - private PluginFactoryExt.ExecutionContext executionContext; - - private PluginFactoryExt.Metrics metrics; - - private RubyClass filterClass; - - private ConfigVariableExpander configVariables; - - private PluginResolver pluginResolver; - - @JRubyMethod(name = "filter_delegator", meta = true, required = 5) - public static IRubyObject filterDelegator(final ThreadContext context, - final IRubyObject recv, final IRubyObject[] args) { - final RubyHash arguments = (RubyHash) args[2]; - final IRubyObject filterInstance = args[1].callMethod(context, "new", arguments); - final RubyString id = (RubyString) arguments.op_aref(context, ID_KEY); - filterInstance.callMethod( - context, "metric=", - ((AbstractMetricExt) args[3]).namespace(context, id.intern()) - ); - filterInstance.callMethod(context, "execution_context=", args[4]); - return new FilterDelegatorExt(context.runtime, RubyUtil.FILTER_DELEGATOR_CLASS) - .initialize(context, filterInstance, id); - } - - public Plugins(final Ruby runtime, final RubyClass metaClass) { - this(runtime, metaClass, PluginLookup::lookup); - } - - Plugins(final Ruby runtime, final RubyClass metaClass, PluginResolver pluginResolver) { - super(runtime, metaClass); - this.pluginResolver = pluginResolver; - } - - @JRubyMethod(required = 4) - public PluginFactoryExt.Plugins initialize(final ThreadContext context, - final IRubyObject[] args) { - return init( - args[0].toJava(PipelineIR.class), - (PluginFactoryExt.Metrics) args[1], (PluginFactoryExt.ExecutionContext) args[2], - (RubyClass) args[3] - ); - } - - public PluginFactoryExt.Plugins init(final PipelineIR lir, final PluginFactoryExt.Metrics metrics, - final PluginFactoryExt.ExecutionContext executionContext, - final RubyClass filterClass) { - return this.init(lir, metrics, executionContext, filterClass, EnvironmentVariableProvider.defaultProvider()); - } - - PluginFactoryExt.Plugins init(final PipelineIR lir, final PluginFactoryExt.Metrics metrics, - final PluginFactoryExt.ExecutionContext executionContext, - final RubyClass filterClass, - final EnvironmentVariableProvider envVars) { - this.lir = lir; - this.metrics = metrics; - this.executionContext = executionContext; - this.filterClass = filterClass; - this.configVariables = ConfigVariableExpander.withoutSecret(envVars); - return this; - } - - @SuppressWarnings("unchecked") - @Override - public IRubyObject buildInput(final RubyString name, SourceWithMetadata source, - final IRubyObject args, Map pluginArgs) { - return plugin( - RubyUtil.RUBY.getCurrentContext(), PluginLookup.PluginType.INPUT, name.asJavaString(), - source, (Map) args, pluginArgs - ); - } - - @SuppressWarnings("unchecked") - @Override - public AbstractOutputDelegatorExt buildOutput(final RubyString name, SourceWithMetadata source, - final IRubyObject args, Map pluginArgs) { - return (AbstractOutputDelegatorExt) plugin( - RubyUtil.RUBY.getCurrentContext(), PluginLookup.PluginType.OUTPUT, name.asJavaString(), - source, (Map) args, pluginArgs - ); - } - - @SuppressWarnings("unchecked") - @Override - public AbstractFilterDelegatorExt buildFilter(final RubyString name, SourceWithMetadata source, - final IRubyObject args, Map pluginArgs) { - return (AbstractFilterDelegatorExt) plugin( - RubyUtil.RUBY.getCurrentContext(), PluginLookup.PluginType.FILTER, name.asJavaString(), - source, (Map) args, pluginArgs - ); - } - - @SuppressWarnings("unchecked") - @Override - public IRubyObject buildCodec(final RubyString name, SourceWithMetadata source, final IRubyObject args, - Map pluginArgs) { - return plugin( - RubyUtil.RUBY.getCurrentContext(), PluginLookup.PluginType.CODEC, - name.asJavaString(), source, (Map) args, pluginArgs - ); - } - - @Override - public Codec buildDefaultCodec(String codecName) { - return (Codec) JavaUtil.unwrapJavaValue(plugin( - RubyUtil.RUBY.getCurrentContext(), PluginLookup.PluginType.CODEC, - codecName, null, Collections.emptyMap(), Collections.emptyMap() - )); - } - - @SuppressWarnings("unchecked") - @JRubyMethod(required = 3, optional = 1) - public IRubyObject plugin(final ThreadContext context, final IRubyObject[] args) { - return plugin( - context, - PluginLookup.PluginType.valueOf(args[0].asJavaString().toUpperCase(Locale.ENGLISH)), - args[1].asJavaString(), - JavaUtil.unwrapIfJavaObject(args[2]), - args.length > 3 ? (Map) args[3] : new HashMap<>(), - null - ); - } - @SuppressWarnings("unchecked") - private IRubyObject plugin(final ThreadContext context, final PluginLookup.PluginType type, final String name, - SourceWithMetadata source, final Map args, - Map pluginArgs) { - final String id; - final PluginLookup.PluginClass pluginClass = pluginResolver.resolve(type, name); - - if (type == PluginLookup.PluginType.CODEC) { - id = UUID.randomUUID().toString(); - } else { - String unresolvedId = lir.getGraph().vertices() - .filter(v -> v.getSourceWithMetadata() != null - && v.getSourceWithMetadata().equalsWithoutText(source)) - .findFirst() - .map(Vertex::getId).orElse(null); - id = (String) configVariables.expand(unresolvedId); - } - if (id == null) { - throw context.runtime.newRaiseException( - RubyUtil.CONFIGURATION_ERROR_CLASS, - String.format("Could not determine ID for %s/%s, source don't matched: %s", - type.rubyLabel().asJavaString(), name, source - ) - ); - } - if (pluginsById.contains(id)) { - throw context.runtime.newRaiseException( - RubyUtil.CONFIGURATION_ERROR_CLASS, - String.format("Two plugins have the id '%s', please fix this conflict", id) - ); - } - pluginsById.add(id); - final AbstractNamespacedMetricExt typeScopedMetric = metrics.create(context, type.rubyLabel()); - - if (pluginClass.language() == PluginLookup.PluginLanguage.RUBY) { - - final Map newArgs = new HashMap<>(args); - newArgs.put("id", id); - final RubyClass klass = (RubyClass) pluginClass.klass(); - final ExecutionContextExt executionCntx = executionContext.create( - context, RubyUtil.RUBY.newString(id), klass.callMethod(context, "config_name") - ); - final RubyHash rubyArgs = RubyHash.newHash(context.runtime); - rubyArgs.putAll(newArgs); - if (type == PluginLookup.PluginType.OUTPUT) { - return new OutputDelegatorExt(context.runtime, RubyUtil.RUBY_OUTPUT_DELEGATOR_CLASS).initialize( - context, - new IRubyObject[]{ - klass, typeScopedMetric, executionCntx, - OutputStrategyExt.OutputStrategyRegistryExt.instance(context, null), - rubyArgs - } - ); - } else if (type == PluginLookup.PluginType.FILTER) { - return filterDelegator( - context, null, - new IRubyObject[]{ - filterClass, klass, rubyArgs, typeScopedMetric, executionCntx - } - ); - } else { - final IRubyObject pluginInstance = klass.callMethod(context, "new", rubyArgs); - final AbstractNamespacedMetricExt scopedMetric = typeScopedMetric.namespace(context, RubyUtil.RUBY.newSymbol(id)); - scopedMetric.gauge(context, MetricKeys.NAME_KEY, pluginInstance.callMethod(context, "config_name")); - pluginInstance.callMethod(context, "metric=", scopedMetric); - pluginInstance.callMethod(context, "execution_context=", executionCntx); - return pluginInstance; - } - } else { - if (pluginArgs == null) { - String err = String.format("Cannot start the Java plugin '%s' in the Ruby execution engine." + - " The Java execution engine is required to run Java plugins.", name); - throw new IllegalStateException(err); - } - - if (type == PluginLookup.PluginType.OUTPUT) { - final Class cls = (Class) pluginClass.klass(); - Output output = null; - if (cls != null) { - try { - final Constructor ctor = cls.getConstructor(String.class, Configuration.class, Context.class); - Configuration config = new ConfigurationImpl(pluginArgs, this); - output = ctor.newInstance(id, config, executionContext.toContext(type, metrics.getRoot(context))); - PluginUtil.validateConfig(output, config); - } catch (NoSuchMethodException | IllegalAccessException | InstantiationException | InvocationTargetException ex) { - if (ex instanceof InvocationTargetException && ex.getCause() != null) { - throw new IllegalStateException((ex).getCause()); - } - throw new IllegalStateException(ex); - } - } - - if (output != null) { - return JavaOutputDelegatorExt.create(name, id, typeScopedMetric, output); - } else { - throw new IllegalStateException("Unable to instantiate output: " + pluginClass); - } - } else if (type == PluginLookup.PluginType.FILTER) { - final Class cls = (Class) pluginClass.klass(); - Filter filter = null; - if (cls != null) { - try { - final Constructor ctor = cls.getConstructor(String.class, Configuration.class, Context.class); - Configuration config = new ConfigurationImpl(pluginArgs); - filter = ctor.newInstance(id, config, executionContext.toContext(type, metrics.getRoot(context))); - PluginUtil.validateConfig(filter, config); - } catch (NoSuchMethodException | IllegalAccessException | InstantiationException | InvocationTargetException ex) { - if (ex instanceof InvocationTargetException && ex.getCause() != null) { - throw new IllegalStateException((ex).getCause()); - } - throw new IllegalStateException(ex); - } - } - - if (filter != null) { - return JavaFilterDelegatorExt.create(name, id, typeScopedMetric, filter, pluginArgs); - } else { - throw new IllegalStateException("Unable to instantiate filter: " + pluginClass); - } - } else if (type == PluginLookup.PluginType.INPUT) { - final Class cls = (Class) pluginClass.klass(); - Input input = null; - if (cls != null) { - try { - final Constructor ctor = cls.getConstructor(String.class, Configuration.class, Context.class); - Configuration config = new ConfigurationImpl(pluginArgs, this); - input = ctor.newInstance(id, config, executionContext.toContext(type, metrics.getRoot(context))); - PluginUtil.validateConfig(input, config); - } catch (NoSuchMethodException | IllegalAccessException | InstantiationException | InvocationTargetException ex) { - if (ex instanceof InvocationTargetException && ex.getCause() != null) { - throw new IllegalStateException((ex).getCause()); - } - throw new IllegalStateException(ex); - } - } - - if (input != null) { - return JavaInputDelegatorExt.create((JavaBasePipelineExt) executionContext.pipeline, typeScopedMetric, input, pluginArgs); - } else { - throw new IllegalStateException("Unable to instantiate input: " + pluginClass); - } - } else if (type == PluginLookup.PluginType.CODEC) { - final Class cls = (Class) pluginClass.klass(); - if (cls != null) { - try { - final Constructor ctor = cls.getConstructor(Configuration.class, Context.class); - Configuration config = new ConfigurationImpl(pluginArgs); - final Context pluginContext = executionContext.toContext(type, metrics.getRoot(context)); - final Codec codec = ctor.newInstance(config, pluginContext); - PluginUtil.validateConfig(codec, config); - return JavaUtil.convertJavaToRuby(RubyUtil.RUBY, new JavaCodecDelegator(pluginContext, codec)); - } catch (NoSuchMethodException | IllegalAccessException | InstantiationException | InvocationTargetException ex) { - if (ex instanceof InvocationTargetException && ex.getCause() != null) { - throw new IllegalStateException((ex).getCause()); - } - throw new IllegalStateException(ex); - } - } - - throw new IllegalStateException("Unable to instantiate codec: " + pluginClass); - } - else { - throw new IllegalStateException("Unable to create plugin: " + pluginClass.toReadableString()); - } - } - } - } - - @JRubyClass(name = "ExecutionContextFactory") - public static final class ExecutionContext extends RubyBasicObject { - - private static final long serialVersionUID = 1L; - - private IRubyObject agent; - - private IRubyObject pipeline; - - private IRubyObject dlqWriter; - - public ExecutionContext(final Ruby runtime, final RubyClass metaClass) { - super(runtime, metaClass); - } - - @JRubyMethod - public PluginFactoryExt.ExecutionContext initialize(final ThreadContext context, - final IRubyObject agent, final IRubyObject pipeline, final IRubyObject dlqWriter) { - this.agent = agent; - this.pipeline = pipeline; - this.dlqWriter = dlqWriter; - return this; - } - - @JRubyMethod - public ExecutionContextExt create(final ThreadContext context, final IRubyObject id, - final IRubyObject classConfigName) { - return new ExecutionContextExt( - context.runtime, RubyUtil.EXECUTION_CONTEXT_CLASS - ).initialize( - context, new IRubyObject[]{pipeline, agent, id, classConfigName, dlqWriter} - ); - } - - public Context toContext(PluginLookup.PluginType pluginType, AbstractNamespacedMetricExt metric) { - DeadLetterQueueWriter dlq = NullDeadLetterQueueWriter.getInstance(); - if (dlqWriter instanceof AbstractDeadLetterQueueWriterExt.PluginDeadLetterQueueWriterExt) { - IRubyObject innerWriter = - ((AbstractDeadLetterQueueWriterExt.PluginDeadLetterQueueWriterExt) dlqWriter) - .innerWriter(RubyUtil.RUBY.getCurrentContext()); - if (innerWriter != null) { - if (org.logstash.common.io.DeadLetterQueueWriter.class.isAssignableFrom(innerWriter.getJavaClass())) { - dlq = new DLQWriterAdapter(innerWriter.toJava(org.logstash.common.io.DeadLetterQueueWriter.class)); - } - } - } else if (dlqWriter.getJavaClass().equals(DeadLetterQueueWriter.class)) { - dlq = dlqWriter.toJava(DeadLetterQueueWriter.class); - } - - return new ContextImpl(dlq, new NamespacedMetricImpl(RubyUtil.RUBY.getCurrentContext(), metric)); - } - } - - @JRubyClass(name = "PluginMetricFactory") - public static final class Metrics extends RubyBasicObject { - - private static final long serialVersionUID = 1L; - - private static final RubySymbol PLUGINS = RubyUtil.RUBY.newSymbol("plugins"); - - private RubySymbol pipelineId; - - private AbstractMetricExt metric; - - public Metrics(final Ruby runtime, final RubyClass metaClass) { - super(runtime, metaClass); - } - - @JRubyMethod - public PluginFactoryExt.Metrics initialize(final ThreadContext context, - final IRubyObject pipelineId, final IRubyObject metrics) { - this.pipelineId = pipelineId.convertToString().intern(); - if (metrics.isNil()) { - this.metric = new NullMetricExt(context.runtime, RubyUtil.NULL_METRIC_CLASS); - } else { - this.metric = (AbstractMetricExt) metrics; - } - return this; - } - - AbstractNamespacedMetricExt getRoot(final ThreadContext context) { - return metric.namespace( - context, - RubyArray.newArray( - context.runtime, - Arrays.asList( - MetricKeys.STATS_KEY, MetricKeys.PIPELINES_KEY, pipelineId, PLUGINS - ) - ) - ); - } - - @JRubyMethod - public AbstractNamespacedMetricExt create(final ThreadContext context, final IRubyObject pluginType) { - return getRoot(context).namespace( - context, RubyUtil.RUBY.newSymbol(String.format("%ss", pluginType.asJavaString())) - ); - } - } -} diff --git a/logstash-core/src/main/java/org/logstash/plugins/codecs/Dots.java b/logstash-core/src/main/java/org/logstash/plugins/codecs/Dots.java index 307944409..3326161d0 100644 --- a/logstash-core/src/main/java/org/logstash/plugins/codecs/Dots.java +++ b/logstash-core/src/main/java/org/logstash/plugins/codecs/Dots.java @@ -41,12 +41,16 @@ public class Dots implements Codec { private final String id; - public Dots(final Configuration configuration, final Context context) { - this(); + public Dots(final String id, final Configuration configuration, final Context context) { + this((id != null && !id.isEmpty()) ? id : UUID.randomUUID().toString()); } - private Dots() { - this.id = UUID.randomUUID().toString(); + public Dots(final Configuration configuration, final Context context) { + this(UUID.randomUUID().toString()); + } + + private Dots(String id) { + this.id = id; } @Override @@ -66,7 +70,7 @@ public class Dots implements Codec { @Override public Codec cloneCodec() { - return new Dots(); + return new Dots(UUID.randomUUID().toString()); } @Override diff --git a/logstash-core/src/main/java/org/logstash/plugins/codecs/Line.java b/logstash-core/src/main/java/org/logstash/plugins/codecs/Line.java index d62981aaa..e42c5fa9f 100644 --- a/logstash-core/src/main/java/org/logstash/plugins/codecs/Line.java +++ b/logstash-core/src/main/java/org/logstash/plugins/codecs/Line.java @@ -77,16 +77,26 @@ public class Line implements Codec { /** * Required constructor. * + * @param id plugin id + * @param configuration Logstash Configuration + * @param context Logstash Context + */ + public Line(final String id, final Configuration configuration, final Context context) { + this(context, configuration.get(DELIMITER_CONFIG), configuration.get(CHARSET_CONFIG), configuration.get(FORMAT_CONFIG), + (id != null && !id.isEmpty()) ? id : UUID.randomUUID().toString()); + } + + /* * @param configuration Logstash Configuration * @param context Logstash Context */ public Line(final Configuration configuration, final Context context) { - this(context, configuration.get(DELIMITER_CONFIG), configuration.get(CHARSET_CONFIG), configuration.get(FORMAT_CONFIG)); + this(null, configuration, context); } - private Line(Context context, String delimiter, String charsetName, String format) { + private Line(Context context, String delimiter, String charsetName, String format, String id) { this.context = context; - this.id = UUID.randomUUID().toString(); + this.id = id; this.delimiter = delimiter; this.charset = Charset.forName(charsetName); this.format = format; @@ -165,6 +175,6 @@ public class Line implements Codec { @Override public Codec cloneCodec() { - return new Line(context, delimiter, charset.name(), format); + return new Line(context, delimiter, charset.name(), format, UUID.randomUUID().toString()); } } diff --git a/logstash-core/src/main/java/org/logstash/plugins/codecs/Plain.java b/logstash-core/src/main/java/org/logstash/plugins/codecs/Plain.java index 026aba044..6ea5afd14 100644 --- a/logstash-core/src/main/java/org/logstash/plugins/codecs/Plain.java +++ b/logstash-core/src/main/java/org/logstash/plugins/codecs/Plain.java @@ -71,16 +71,25 @@ public class Plain implements Codec { /** * Required constructor. * + * @param id plugin id + * @param configuration Logstash Configuration + * @param context Logstash Context + */ + public Plain(final String id, final Configuration configuration, final Context context) { + this(context, configuration.get(CHARSET_CONFIG), configuration.get(FORMAT_CONFIG), + (id != null && !id.isEmpty()) ? id : UUID.randomUUID().toString()); + } + /** * @param configuration Logstash Configuration * @param context Logstash Context */ public Plain(final Configuration configuration, final Context context) { - this(context, configuration.get(CHARSET_CONFIG), configuration.get(FORMAT_CONFIG)); + this(null, configuration, context); } - private Plain(Context context, String charsetName, String format) { + private Plain(Context context, String charsetName, String format, String id) { this.context = context; - this.id = UUID.randomUUID().toString(); + this.id = id; this.charset = Charset.forName(charsetName); this.format = format; decoder = charset.newDecoder(); @@ -127,6 +136,6 @@ public class Plain implements Codec { @Override public Codec cloneCodec() { - return new Plain(context, charset.name(), format); + return new Plain(context, charset.name(), format, UUID.randomUUID().toString()); } } diff --git a/logstash-core/src/main/java/org/logstash/plugins/factory/AbstractPluginCreator.java b/logstash-core/src/main/java/org/logstash/plugins/factory/AbstractPluginCreator.java new file mode 100644 index 000000000..4685a01bd --- /dev/null +++ b/logstash-core/src/main/java/org/logstash/plugins/factory/AbstractPluginCreator.java @@ -0,0 +1,45 @@ +package org.logstash.plugins.factory; + +import co.elastic.logstash.api.Configuration; +import co.elastic.logstash.api.Context; +import co.elastic.logstash.api.Plugin; +import org.jruby.runtime.builtin.IRubyObject; +import org.logstash.instrument.metrics.AbstractNamespacedMetricExt; +import org.logstash.plugins.ConfigurationImpl; +import org.logstash.plugins.PluginLookup; +import org.logstash.plugins.PluginUtil; + +import java.lang.reflect.Constructor; +import java.lang.reflect.InvocationTargetException; +import java.util.Map; + +abstract class AbstractPluginCreator { + + protected PluginFactoryExt pluginsFactory = null; + + abstract IRubyObject createDelegator(String name, Map pluginArgs, String id, + AbstractNamespacedMetricExt typeScopedMetric, + PluginLookup.PluginClass pluginClass, Context pluginContext); + + protected T instantiateAndValidate(Map pluginArgs, String id, Context pluginContext, + PluginLookup.PluginClass pluginClass) { + @SuppressWarnings("unchecked") + final Class cls = (Class) pluginClass.klass(); + if (cls == null) { + throw new IllegalStateException("Unable to instantiate type: " + pluginClass); + } + + try { + final Constructor ctor = cls.getConstructor(String.class, Configuration.class, Context.class); + Configuration config = new ConfigurationImpl(pluginArgs, pluginsFactory); + T plugin = ctor.newInstance(id, config, pluginContext); + PluginUtil.validateConfig(plugin, config); + return plugin; + } catch (NoSuchMethodException | IllegalAccessException | InstantiationException | InvocationTargetException ex) { + if (ex instanceof InvocationTargetException && ex.getCause() != null) { + throw new IllegalStateException((ex).getCause()); + } + throw new IllegalStateException(ex); + } + } +} diff --git a/logstash-core/src/main/java/org/logstash/plugins/factory/CodecPluginCreator.java b/logstash-core/src/main/java/org/logstash/plugins/factory/CodecPluginCreator.java new file mode 100644 index 000000000..66f12a83c --- /dev/null +++ b/logstash-core/src/main/java/org/logstash/plugins/factory/CodecPluginCreator.java @@ -0,0 +1,23 @@ +package org.logstash.plugins.factory; + +import co.elastic.logstash.api.Codec; +import co.elastic.logstash.api.Context; +import org.jruby.javasupport.JavaUtil; +import org.jruby.runtime.builtin.IRubyObject; +import org.logstash.RubyUtil; +import org.logstash.config.ir.compiler.JavaCodecDelegator; +import org.logstash.instrument.metrics.AbstractNamespacedMetricExt; +import org.logstash.plugins.PluginLookup; + +import java.util.Map; + +class CodecPluginCreator extends AbstractPluginCreator { + + @Override + public IRubyObject createDelegator(String name, Map pluginArgs, String id, + AbstractNamespacedMetricExt typeScopedMetric, + PluginLookup.PluginClass pluginClass, Context pluginContext) { + Codec codec = instantiateAndValidate(pluginArgs, id, pluginContext, pluginClass); + return JavaUtil.convertJavaToRuby(RubyUtil.RUBY, new JavaCodecDelegator(pluginContext, codec)); + } +} diff --git a/logstash-core/src/main/java/org/logstash/plugins/factory/ExecutionContextFactoryExt.java b/logstash-core/src/main/java/org/logstash/plugins/factory/ExecutionContextFactoryExt.java new file mode 100644 index 000000000..d72ef4a5c --- /dev/null +++ b/logstash-core/src/main/java/org/logstash/plugins/factory/ExecutionContextFactoryExt.java @@ -0,0 +1,77 @@ +package org.logstash.plugins.factory; + +import co.elastic.logstash.api.Context; +import co.elastic.logstash.api.DeadLetterQueueWriter; +import org.jruby.Ruby; +import org.jruby.RubyBasicObject; +import org.jruby.RubyClass; +import org.jruby.anno.JRubyClass; +import org.jruby.anno.JRubyMethod; +import org.jruby.runtime.ThreadContext; +import org.jruby.runtime.builtin.IRubyObject; +import org.logstash.RubyUtil; +import org.logstash.common.AbstractDeadLetterQueueWriterExt; +import org.logstash.common.DLQWriterAdapter; +import org.logstash.common.NullDeadLetterQueueWriter; +import org.logstash.execution.ExecutionContextExt; +import org.logstash.instrument.metrics.AbstractNamespacedMetricExt; +import org.logstash.plugins.ContextImpl; +import org.logstash.plugins.NamespacedMetricImpl; +import org.logstash.plugins.PluginLookup; + +@JRubyClass(name = "ExecutionContextFactory") +public final class ExecutionContextFactoryExt extends RubyBasicObject { + + private static final long serialVersionUID = 1L; + + private IRubyObject agent; + + private IRubyObject pipeline; + + private IRubyObject dlqWriter; + + public ExecutionContextFactoryExt(final Ruby runtime, final RubyClass metaClass) { + super(runtime, metaClass); + } + + @JRubyMethod + public ExecutionContextFactoryExt initialize(final ThreadContext context, final IRubyObject agent, + final IRubyObject pipeline, final IRubyObject dlqWriter) { + this.agent = agent; + this.pipeline = pipeline; + this.dlqWriter = dlqWriter; + return this; + } + + @JRubyMethod + public ExecutionContextExt create(final ThreadContext context, final IRubyObject id, + final IRubyObject classConfigName) { + return new ExecutionContextExt( + context.runtime, RubyUtil.EXECUTION_CONTEXT_CLASS + ).initialize( + context, new IRubyObject[]{pipeline, agent, id, classConfigName, dlqWriter} + ); + } + + Context toContext(PluginLookup.PluginType pluginType, AbstractNamespacedMetricExt metric) { + DeadLetterQueueWriter dlq = NullDeadLetterQueueWriter.getInstance(); + if (dlqWriter instanceof AbstractDeadLetterQueueWriterExt.PluginDeadLetterQueueWriterExt) { + IRubyObject innerWriter = + ((AbstractDeadLetterQueueWriterExt.PluginDeadLetterQueueWriterExt) dlqWriter) + .innerWriter(RubyUtil.RUBY.getCurrentContext()); + if (innerWriter != null) { + if (org.logstash.common.io.DeadLetterQueueWriter.class.isAssignableFrom(innerWriter.getJavaClass())) { + dlq = new DLQWriterAdapter(innerWriter.toJava(org.logstash.common.io.DeadLetterQueueWriter.class)); + } + } + } else if (dlqWriter.getJavaClass().equals(DeadLetterQueueWriter.class)) { + dlq = dlqWriter.toJava(DeadLetterQueueWriter.class); + } + + return new ContextImpl(dlq, new NamespacedMetricImpl(RubyUtil.RUBY.getCurrentContext(), metric)); + } + + IRubyObject getPipeline() { + return pipeline; + } +} diff --git a/logstash-core/src/main/java/org/logstash/plugins/factory/FilterPluginCreator.java b/logstash-core/src/main/java/org/logstash/plugins/factory/FilterPluginCreator.java new file mode 100644 index 000000000..5d98f7d4f --- /dev/null +++ b/logstash-core/src/main/java/org/logstash/plugins/factory/FilterPluginCreator.java @@ -0,0 +1,21 @@ +package org.logstash.plugins.factory; + +import co.elastic.logstash.api.Context; +import co.elastic.logstash.api.Filter; +import org.jruby.runtime.builtin.IRubyObject; +import org.logstash.config.ir.compiler.JavaFilterDelegatorExt; +import org.logstash.instrument.metrics.AbstractNamespacedMetricExt; +import org.logstash.plugins.PluginLookup; + +import java.util.Map; + +class FilterPluginCreator extends AbstractPluginCreator { + + @Override + public IRubyObject createDelegator(String name, Map pluginArgs, String id, + AbstractNamespacedMetricExt typeScopedMetric, + PluginLookup.PluginClass pluginClass, Context pluginContext) { + Filter filter = instantiateAndValidate(pluginArgs, id, pluginContext, pluginClass); + return JavaFilterDelegatorExt.create(name, id, typeScopedMetric, filter, pluginArgs); + } +} diff --git a/logstash-core/src/main/java/org/logstash/plugins/factory/InputPluginCreator.java b/logstash-core/src/main/java/org/logstash/plugins/factory/InputPluginCreator.java new file mode 100644 index 000000000..66929065b --- /dev/null +++ b/logstash-core/src/main/java/org/logstash/plugins/factory/InputPluginCreator.java @@ -0,0 +1,27 @@ +package org.logstash.plugins.factory; + +import co.elastic.logstash.api.Context; +import co.elastic.logstash.api.Input; +import org.jruby.runtime.builtin.IRubyObject; +import org.logstash.config.ir.compiler.JavaInputDelegatorExt; +import org.logstash.execution.JavaBasePipelineExt; +import org.logstash.instrument.metrics.AbstractNamespacedMetricExt; +import org.logstash.plugins.PluginLookup; + +import java.util.Map; + +class InputPluginCreator extends AbstractPluginCreator { + + InputPluginCreator(PluginFactoryExt pluginsFactory) { + this.pluginsFactory = pluginsFactory; + } + + @Override + public IRubyObject createDelegator(String name, Map pluginArgs, String id, + AbstractNamespacedMetricExt typeScopedMetric, + PluginLookup.PluginClass pluginClass, Context pluginContext) { + Input input = instantiateAndValidate(pluginArgs, id, pluginContext, pluginClass); + return JavaInputDelegatorExt.create((JavaBasePipelineExt) pluginsFactory.getExecutionContextFactory().getPipeline(), + typeScopedMetric, input, pluginArgs); + } +} diff --git a/logstash-core/src/main/java/org/logstash/plugins/factory/OutputPluginCreator.java b/logstash-core/src/main/java/org/logstash/plugins/factory/OutputPluginCreator.java new file mode 100644 index 000000000..25039546f --- /dev/null +++ b/logstash-core/src/main/java/org/logstash/plugins/factory/OutputPluginCreator.java @@ -0,0 +1,25 @@ +package org.logstash.plugins.factory; + +import co.elastic.logstash.api.Context; +import co.elastic.logstash.api.Output; +import org.jruby.runtime.builtin.IRubyObject; +import org.logstash.config.ir.compiler.JavaOutputDelegatorExt; +import org.logstash.instrument.metrics.AbstractNamespacedMetricExt; +import org.logstash.plugins.PluginLookup; + +import java.util.Map; + +class OutputPluginCreator extends AbstractPluginCreator { + + OutputPluginCreator(PluginFactoryExt pluginsFactory) { + this.pluginsFactory = pluginsFactory; + } + + @Override + public IRubyObject createDelegator(String name, Map pluginArgs, String id, + AbstractNamespacedMetricExt typeScopedMetric, + PluginLookup.PluginClass pluginClass, Context pluginContext) { + Output output = instantiateAndValidate(pluginArgs, id, pluginContext, pluginClass); + return JavaOutputDelegatorExt.create(name, id, typeScopedMetric, output); + } +} diff --git a/logstash-core/src/main/java/org/logstash/plugins/factory/PluginFactoryExt.java b/logstash-core/src/main/java/org/logstash/plugins/factory/PluginFactoryExt.java new file mode 100644 index 000000000..a226e57d5 --- /dev/null +++ b/logstash-core/src/main/java/org/logstash/plugins/factory/PluginFactoryExt.java @@ -0,0 +1,261 @@ +package org.logstash.plugins.factory; + +import co.elastic.logstash.api.*; +import org.jruby.*; +import org.jruby.anno.JRubyClass; +import org.jruby.anno.JRubyMethod; +import org.jruby.javasupport.JavaUtil; +import org.jruby.runtime.ThreadContext; +import org.jruby.runtime.builtin.IRubyObject; +import org.logstash.RubyUtil; +import org.logstash.common.EnvironmentVariableProvider; +import org.logstash.common.SourceWithMetadata; +import org.logstash.config.ir.PipelineIR; +import org.logstash.config.ir.compiler.*; +import org.logstash.config.ir.graph.Vertex; +import org.logstash.execution.ExecutionContextExt; +import org.logstash.instrument.metrics.AbstractMetricExt; +import org.logstash.instrument.metrics.AbstractNamespacedMetricExt; +import org.logstash.instrument.metrics.MetricKeys; +import org.logstash.plugins.ConfigVariableExpander; +import org.logstash.plugins.PluginLookup; + +import java.util.*; + +@JRubyClass(name = "PluginFactory") +public final class PluginFactoryExt extends RubyBasicObject + implements RubyIntegration.PluginFactory { + + @FunctionalInterface + public interface PluginResolver { + PluginLookup.PluginClass resolve(PluginLookup.PluginType type, String name); + } + + private static final long serialVersionUID = 1L; + + private static final RubyString ID_KEY = RubyUtil.RUBY.newString("id"); + + private final Collection pluginsById = new HashSet<>(); + + private PipelineIR lir; + + private ExecutionContextFactoryExt executionContextFactory; + + private PluginMetricsFactoryExt metrics; + + private RubyClass filterClass; + + private ConfigVariableExpander configVariables; + + private PluginResolver pluginResolver; + + private Map> pluginCreatorsRegistry = new HashMap<>(4); + + @JRubyMethod(name = "filter_delegator", meta = true, required = 5) + public static IRubyObject filterDelegator(final ThreadContext context, + final IRubyObject recv, final IRubyObject... args) { + final RubyHash arguments = (RubyHash) args[2]; + final IRubyObject filterInstance = args[1].callMethod(context, "new", arguments); + final RubyString id = (RubyString) arguments.op_aref(context, ID_KEY); + filterInstance.callMethod( + context, "metric=", + ((AbstractMetricExt) args[3]).namespace(context, id.intern()) + ); + filterInstance.callMethod(context, "execution_context=", args[4]); + return new FilterDelegatorExt(context.runtime, RubyUtil.FILTER_DELEGATOR_CLASS) + .initialize(context, filterInstance, id); + } + + public PluginFactoryExt(final Ruby runtime, final RubyClass metaClass) { + this(runtime, metaClass, PluginLookup::lookup); + } + + PluginFactoryExt(final Ruby runtime, final RubyClass metaClass, PluginResolver pluginResolver) { + super(runtime, metaClass); + this.pluginResolver = pluginResolver; + } + + @JRubyMethod(required = 4) + public PluginFactoryExt initialize(final ThreadContext context, + final IRubyObject[] args) { + return init( + args[0].toJava(PipelineIR.class), + (PluginMetricsFactoryExt) args[1], (ExecutionContextFactoryExt) args[2], + (RubyClass) args[3] + ); + } + + public PluginFactoryExt init(final PipelineIR lir, final PluginMetricsFactoryExt metrics, + final ExecutionContextFactoryExt executionContextFactoryExt, + final RubyClass filterClass) { + return this.init(lir, metrics, executionContextFactoryExt, filterClass, EnvironmentVariableProvider.defaultProvider()); + } + + PluginFactoryExt init(final PipelineIR lir, final PluginMetricsFactoryExt metrics, + final ExecutionContextFactoryExt executionContextFactoryExt, + final RubyClass filterClass, + final EnvironmentVariableProvider envVars) { + this.lir = lir; + this.metrics = metrics; + this.executionContextFactory = executionContextFactoryExt; + this.filterClass = filterClass; + this.pluginCreatorsRegistry.put(PluginLookup.PluginType.INPUT, new InputPluginCreator(this)); + this.pluginCreatorsRegistry.put(PluginLookup.PluginType.CODEC, new CodecPluginCreator()); + this.pluginCreatorsRegistry.put(PluginLookup.PluginType.FILTER, new FilterPluginCreator()); + this.pluginCreatorsRegistry.put(PluginLookup.PluginType.OUTPUT, new OutputPluginCreator(this)); + this.configVariables = ConfigVariableExpander.withoutSecret(envVars); + return this; + } + + @SuppressWarnings("unchecked") + @Override + public IRubyObject buildInput(final RubyString name, SourceWithMetadata source, + final IRubyObject args, Map pluginArgs) { + return plugin( + RubyUtil.RUBY.getCurrentContext(), PluginLookup.PluginType.INPUT, name.asJavaString(), + source, (Map) args, pluginArgs + ); + } + + @SuppressWarnings("unchecked") + @Override + public AbstractOutputDelegatorExt buildOutput(final RubyString name, SourceWithMetadata source, + final IRubyObject args, Map pluginArgs) { + return (AbstractOutputDelegatorExt) plugin( + RubyUtil.RUBY.getCurrentContext(), PluginLookup.PluginType.OUTPUT, name.asJavaString(), + source, (Map) args, pluginArgs + ); + } + + @SuppressWarnings("unchecked") + @Override + public AbstractFilterDelegatorExt buildFilter(final RubyString name, SourceWithMetadata source, + final IRubyObject args, Map pluginArgs) { + return (AbstractFilterDelegatorExt) plugin( + RubyUtil.RUBY.getCurrentContext(), PluginLookup.PluginType.FILTER, name.asJavaString(), + source, (Map) args, pluginArgs + ); + } + + @SuppressWarnings("unchecked") + @Override + public IRubyObject buildCodec(final RubyString name, SourceWithMetadata source, final IRubyObject args, + Map pluginArgs) { + return plugin( + RubyUtil.RUBY.getCurrentContext(), PluginLookup.PluginType.CODEC, + name.asJavaString(), source, (Map) args, pluginArgs + ); + } + + @Override + public Codec buildDefaultCodec(String codecName) { + return (Codec) JavaUtil.unwrapJavaValue(plugin( + RubyUtil.RUBY.getCurrentContext(), PluginLookup.PluginType.CODEC, + codecName, null, Collections.emptyMap(), Collections.emptyMap() + )); + } + + @SuppressWarnings("unchecked") + @JRubyMethod(required = 3, optional = 1) + public IRubyObject plugin(final ThreadContext context, final IRubyObject[] args) { + return plugin( + context, + PluginLookup.PluginType.valueOf(args[0].asJavaString().toUpperCase(Locale.ENGLISH)), + args[1].asJavaString(), + JavaUtil.unwrapIfJavaObject(args[2]), + args.length > 3 ? (Map) args[3] : new HashMap<>(), + null + ); + } + + @SuppressWarnings("unchecked") + private IRubyObject plugin(final ThreadContext context, final PluginLookup.PluginType type, final String name, + SourceWithMetadata source, final Map args, + Map pluginArgs) { + final String id = generateOrRetrievePluginId(context, type, name, source); + pluginsById.add(id); + final AbstractNamespacedMetricExt typeScopedMetric = metrics.create(context, type.rubyLabel()); + + final PluginLookup.PluginClass pluginClass = pluginResolver.resolve(type, name); + if (pluginClass.language() == PluginLookup.PluginLanguage.RUBY) { + + final Map newArgs = new HashMap<>(args); + newArgs.put("id", id); + final RubyClass klass = (RubyClass) pluginClass.klass(); + final ExecutionContextExt executionCntx = executionContextFactory.create( + context, RubyUtil.RUBY.newString(id), klass.callMethod(context, "config_name") + ); + final RubyHash rubyArgs = RubyHash.newHash(context.runtime); + rubyArgs.putAll(newArgs); + if (type == PluginLookup.PluginType.OUTPUT) { + return new OutputDelegatorExt(context.runtime, RubyUtil.RUBY_OUTPUT_DELEGATOR_CLASS).initialize( + context, + new IRubyObject[]{ + klass, typeScopedMetric, executionCntx, + OutputStrategyExt.OutputStrategyRegistryExt.instance(context, null), + rubyArgs + } + ); + } else if (type == PluginLookup.PluginType.FILTER) { + return filterDelegator( + context, null, + filterClass, klass, rubyArgs, typeScopedMetric, executionCntx); + } else { + final IRubyObject pluginInstance = klass.callMethod(context, "new", rubyArgs); + final AbstractNamespacedMetricExt scopedMetric = typeScopedMetric.namespace(context, RubyUtil.RUBY.newSymbol(id)); + scopedMetric.gauge(context, MetricKeys.NAME_KEY, pluginInstance.callMethod(context, "config_name")); + pluginInstance.callMethod(context, "metric=", scopedMetric); + pluginInstance.callMethod(context, "execution_context=", executionCntx); + return pluginInstance; + } + } else { + if (pluginArgs == null) { + String err = String.format("Cannot start the Java plugin '%s' in the Ruby execution engine." + + " The Java execution engine is required to run Java plugins.", name); + throw new IllegalStateException(err); + } + + AbstractPluginCreator pluginCreator = pluginCreatorsRegistry.get(type); + if (pluginCreator == null) { + throw new IllegalStateException("Unable to create plugin: " + pluginClass.toReadableString()); + } + + Context contextWithMetrics = executionContextFactory.toContext(type, metrics.getRoot(context)); + return pluginCreator.createDelegator(name, pluginArgs, id, typeScopedMetric, pluginClass, contextWithMetrics); + } + } + + private String generateOrRetrievePluginId(ThreadContext context, PluginLookup.PluginType type, String name, + SourceWithMetadata source) { + final String id; + if (type == PluginLookup.PluginType.CODEC) { + id = UUID.randomUUID().toString(); + } else { + String unresolvedId = lir.getGraph().vertices() + .filter(v -> v.getSourceWithMetadata() != null + && v.getSourceWithMetadata().equalsWithoutText(source)) + .findFirst() + .map(Vertex::getId).orElse(null); + id = (String) configVariables.expand(unresolvedId); + } + if (id == null) { + throw context.runtime.newRaiseException( + RubyUtil.CONFIGURATION_ERROR_CLASS, + String.format( + "Could not determine ID for %s/%s", type.rubyLabel().asJavaString(), name + ) + ); + } + if (pluginsById.contains(id)) { + throw context.runtime.newRaiseException( + RubyUtil.CONFIGURATION_ERROR_CLASS, + String.format("Two plugins have the id '%s', please fix this conflict", id) + ); + } + return id; + } + + ExecutionContextFactoryExt getExecutionContextFactory() { + return executionContextFactory; + } +} diff --git a/logstash-core/src/main/java/org/logstash/plugins/factory/PluginMetricsFactoryExt.java b/logstash-core/src/main/java/org/logstash/plugins/factory/PluginMetricsFactoryExt.java new file mode 100644 index 000000000..18a8aab33 --- /dev/null +++ b/logstash-core/src/main/java/org/logstash/plugins/factory/PluginMetricsFactoryExt.java @@ -0,0 +1,61 @@ +package org.logstash.plugins.factory; + +import org.jruby.*; +import org.jruby.anno.JRubyClass; +import org.jruby.anno.JRubyMethod; +import org.jruby.runtime.ThreadContext; +import org.jruby.runtime.builtin.IRubyObject; +import org.logstash.RubyUtil; +import org.logstash.instrument.metrics.AbstractMetricExt; +import org.logstash.instrument.metrics.AbstractNamespacedMetricExt; +import org.logstash.instrument.metrics.MetricKeys; +import org.logstash.instrument.metrics.NullMetricExt; + +import java.util.Arrays; + +@JRubyClass(name = "PluginMetricsFactory") +public final class PluginMetricsFactoryExt extends RubyBasicObject { + + private static final long serialVersionUID = 1L; + + private static final RubySymbol PLUGINS = RubyUtil.RUBY.newSymbol("plugins"); + + private RubySymbol pipelineId; + + private AbstractMetricExt metric; + + public PluginMetricsFactoryExt(final Ruby runtime, final RubyClass metaClass) { + super(runtime, metaClass); + } + + @JRubyMethod + public PluginMetricsFactoryExt initialize(final ThreadContext context, + final IRubyObject pipelineId, final IRubyObject metrics) { + this.pipelineId = pipelineId.convertToString().intern(); + if (metrics.isNil()) { + this.metric = new NullMetricExt(context.runtime, RubyUtil.NULL_METRIC_CLASS); + } else { + this.metric = (AbstractMetricExt) metrics; + } + return this; + } + + AbstractNamespacedMetricExt getRoot(final ThreadContext context) { + return metric.namespace( + context, + RubyArray.newArray( + context.runtime, + Arrays.asList( + MetricKeys.STATS_KEY, MetricKeys.PIPELINES_KEY, pipelineId, PLUGINS + ) + ) + ); + } + + @JRubyMethod + public AbstractNamespacedMetricExt create(final ThreadContext context, final IRubyObject pluginType) { + return getRoot(context).namespace( + context, RubyUtil.RUBY.newSymbol(String.format("%ss", pluginType.asJavaString())) + ); + } +} diff --git a/logstash-core/src/test/java/org/logstash/plugins/MetricTestCase.java b/logstash-core/src/test/java/org/logstash/plugins/MetricTestCase.java index 2aad692a4..fbf92213a 100644 --- a/logstash-core/src/test/java/org/logstash/plugins/MetricTestCase.java +++ b/logstash-core/src/test/java/org/logstash/plugins/MetricTestCase.java @@ -51,7 +51,7 @@ public abstract class MetricTestCase extends RubyEnvTestCase { executionContext = new ExecutionContextExt(RUBY, EXECUTION_CONTEXT_CLASS); } - protected static IRubyObject runRubyScript(String script) { + public static IRubyObject runRubyScript(String script) { IRubyObject m = RUBY.evalScriptlet(script); return m; } diff --git a/logstash-core/src/test/java/org/logstash/plugins/PluginFactoryExtTest.java b/logstash-core/src/test/java/org/logstash/plugins/factory/PluginFactoryExtTest.java similarity index 85% rename from logstash-core/src/test/java/org/logstash/plugins/PluginFactoryExtTest.java rename to logstash-core/src/test/java/org/logstash/plugins/factory/PluginFactoryExtTest.java index f97c21d1b..ded3049a6 100644 --- a/logstash-core/src/test/java/org/logstash/plugins/PluginFactoryExtTest.java +++ b/logstash-core/src/test/java/org/logstash/plugins/factory/PluginFactoryExtTest.java @@ -17,8 +17,7 @@ * under the License. */ - -package org.logstash.plugins; +package org.logstash.plugins.factory; import co.elastic.logstash.api.*; import org.jruby.RubyHash; @@ -32,6 +31,8 @@ import org.logstash.config.ir.InvalidIRException; import org.logstash.config.ir.PipelineIR; import org.logstash.config.ir.RubyEnvTestCase; import org.logstash.instrument.metrics.NamespacedMetricExt; +import org.logstash.plugins.MetricTestCase; +import org.logstash.plugins.PluginLookup; import java.util.Collection; import java.util.Collections; @@ -42,10 +43,9 @@ import java.util.function.Consumer; import static org.junit.Assert.assertEquals; import static org.logstash.RubyUtil.NAMESPACED_METRIC_CLASS; import static org.logstash.RubyUtil.RUBY; -import static org.logstash.plugins.MetricTestCase.runRubyScript; /** - * Tests for {@link PluginFactoryExt.Plugins}. + * Tests for {@link PluginFactoryExt}. */ public final class PluginFactoryExtTest extends RubyEnvTestCase { @@ -87,11 +87,11 @@ public final class PluginFactoryExtTest extends RubyEnvTestCase { SourceWithMetadata sourceWithMetadata = new SourceWithMetadata("proto", "path", 1, 8, "input {mockinput{ id => \"${CUSTOM}\"}} output{mockoutput{}}"); final PipelineIR pipelineIR = compilePipeline(sourceWithMetadata); - PluginFactoryExt.Metrics metricsFactory = createMetricsFactory(); - PluginFactoryExt.ExecutionContext execContextFactory = createExecutionContextFactory(); + PluginMetricsFactoryExt metricsFactory = createMetricsFactory(); + ExecutionContextFactoryExt execContextFactory = createExecutionContextFactory(); Map envVars = new HashMap<>(); envVars.put("CUSTOM", "test"); - PluginFactoryExt.Plugins sut = new PluginFactoryExt.Plugins(RubyUtil.RUBY, RubyUtil.PLUGIN_FACTORY_CLASS, + PluginFactoryExt sut = new PluginFactoryExt(RubyUtil.RUBY, RubyUtil.PLUGIN_FACTORY_CLASS, mockPluginResolver); sut.init(pipelineIR, metricsFactory, execContextFactory, RubyUtil.FILTER_DELEGATOR_CLASS, envVars::get); @@ -110,24 +110,24 @@ public final class PluginFactoryExtTest extends RubyEnvTestCase { return ConfigCompiler.configToPipelineIR(Collections.singletonList(sourceWithMetadata), false); } - private static PluginFactoryExt.ExecutionContext createExecutionContextFactory() { - PluginFactoryExt.ExecutionContext execContextFactory = new PluginFactoryExt.ExecutionContext(RubyUtil.RUBY, + private static ExecutionContextFactoryExt createExecutionContextFactory() { + ExecutionContextFactoryExt execContextFactory = new ExecutionContextFactoryExt(RubyUtil.RUBY, RubyUtil.EXECUTION_CONTEXT_FACTORY_CLASS); execContextFactory.initialize(RubyUtil.RUBY.getCurrentContext(), null, null, RubyUtil.RUBY.newString("no DLQ")); return execContextFactory; } - private static PluginFactoryExt.Metrics createMetricsFactory() { + private static PluginMetricsFactoryExt createMetricsFactory() { final IRubyObject metricWithCollector = - runRubyScript("require \"logstash/instrument/collector\"\n" + + MetricTestCase.runRubyScript("require \"logstash/instrument/collector\"\n" + "metricWithCollector = LogStash::Instrument::Metric.new(LogStash::Instrument::Collector.new)"); NamespacedMetricExt metric = new NamespacedMetricExt(RUBY, NAMESPACED_METRIC_CLASS) .initialize(RUBY.getCurrentContext(), metricWithCollector, RUBY.newEmptyArray()); - PluginFactoryExt.Metrics metricsFactory = new PluginFactoryExt.Metrics(RubyUtil.RUBY, RubyUtil.PLUGIN_METRIC_FACTORY_CLASS); + PluginMetricsFactoryExt metricsFactory = new PluginMetricsFactoryExt(RubyUtil.RUBY, RubyUtil.PLUGIN_METRICS_FACTORY_CLASS); metricsFactory.initialize(RubyUtil.RUBY.getCurrentContext(), RubyUtil.RUBY.newString("main"), metric); return metricsFactory; } From 24ac6800c8bd5555f614dc80d6c580640f9abd8a Mon Sep 17 00:00:00 2001 From: Colin Milhaupt Date: Mon, 25 Jun 2018 15:30:47 -0600 Subject: [PATCH 0516/1126] Update proxy_support.rb Backport of #9787 to 7.x --- lib/pluginmanager/proxy_support.rb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/pluginmanager/proxy_support.rb b/lib/pluginmanager/proxy_support.rb index 7c1115a9f..881101534 100644 --- a/lib/pluginmanager/proxy_support.rb +++ b/lib/pluginmanager/proxy_support.rb @@ -117,7 +117,7 @@ def configure_proxy if ::File.exist?(target) if template_content != ::File.read(target) - puts "WARNING: A maven settings file already exist at #{target}, please review the content to make sure it include your proxies configuration." + puts "WARNING: A maven settings file already exist at #{target}, please review the content to make sure it includes your proxies configuration." end else ::File.open(target, "w") { |f| f.write(template_content) } From 126056f3a7b41b8d35fdd07f2b6eada6f2efd3bd Mon Sep 17 00:00:00 2001 From: Andrew Pan <30434519+AndrewPanB@users.noreply.github.com> Date: Fri, 10 Apr 2020 15:52:12 +0800 Subject: [PATCH 0517/1126] Update local.rb for pipe file (#11109) Load pipe file for process communication Co-authored-by: Andrew Pan --- logstash-core/lib/logstash/config/source/local.rb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/logstash-core/lib/logstash/config/source/local.rb b/logstash-core/lib/logstash/config/source/local.rb index dc43ba287..e9601c2b5 100644 --- a/logstash-core/lib/logstash/config/source/local.rb +++ b/logstash-core/lib/logstash/config/source/local.rb @@ -75,7 +75,7 @@ module LogStash module Config module Source end get_matched_files.each do |file| - next unless ::File.file?(file) # skip directory + next unless ::File.file?(file) or ::File.pipe?(file) # skip directory logger.debug("Reading config file", :config_file => file) From 8de6cecc345fcebd605e1875110d1c054eede91f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jo=C3=A3o=20Duarte?= Date: Mon, 2 Sep 2019 12:19:52 +0100 Subject: [PATCH 0518/1126] Improve warning about UDP/TCP not having app level acks --- docs/static/deploying.asciidoc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/static/deploying.asciidoc b/docs/static/deploying.asciidoc index 4f25da382..997753966 100644 --- a/docs/static/deploying.asciidoc +++ b/docs/static/deploying.asciidoc @@ -158,7 +158,7 @@ Logstash can expose endpoint listeners with the respective <> input plugins. The data sources enumerated below are typically ingested through one of these three protocols. -NOTE: The TCP protocol does not support application-level acknowledgements, so +NOTE: The TCP and UDP protocols do not support application-level acknowledgements, so connectivity issues may result in data loss. For high availability scenarios, a third-party hardware or software load From 41272371a50af3f90ad09515621fdc69563c0e9e Mon Sep 17 00:00:00 2001 From: Ry Biesemeyer Date: Fri, 26 Jun 2020 02:46:26 -0700 Subject: [PATCH 0519/1126] support Environment and Keystore substitutions in password-type plugin options (#11783) Backport of #11774 to 7.x Resolves: https://github.com/elastic/logstash/pull/10583 Co-authored-by: Tyler Gregory --- .../logstash/util/substitution_variables.rb | 4 ++ .../spec/logstash/config/mixin_spec.rb | 70 ++++++++++++------- 2 files changed, 50 insertions(+), 24 deletions(-) diff --git a/logstash-core/lib/logstash/util/substitution_variables.rb b/logstash-core/lib/logstash/util/substitution_variables.rb index ea1954c28..ed24a8ec4 100644 --- a/logstash-core/lib/logstash/util/substitution_variables.rb +++ b/logstash-core/lib/logstash/util/substitution_variables.rb @@ -50,6 +50,10 @@ module ::LogStash::Util::SubstitutionVariables # If value matches the pattern, returns the following precedence : Secret store value, Environment entry value, default value as provided in the pattern # If the value does not match the pattern, the 'value' param returns as-is def replace_placeholders(value) + if value.kind_of?(::LogStash::Util::Password) + interpolated = replace_placeholders(value.value) + return ::LogStash::Util::Password.new(interpolated) + end return value unless value.is_a?(String) value.gsub(SUBSTITUTION_PLACEHOLDER_REGEX) do |placeholder| diff --git a/logstash-core/spec/logstash/config/mixin_spec.rb b/logstash-core/spec/logstash/config/mixin_spec.rb index a860d0f7f..2cddf4f7d 100644 --- a/logstash-core/spec/logstash/config/mixin_spec.rb +++ b/logstash-core/spec/logstash/config/mixin_spec.rb @@ -181,36 +181,58 @@ describe LogStash::Config::Mixin do end context "when validating :password" do - let(:klass) do - Class.new(LogStash::Filters::Base) do - config_name "fake" - config :password, :validate => :password + shared_examples 'protected password' do + let(:secret) { 'fancy pants' } + let(:plugin_class) do + Class.new(LogStash::Filters::Base) do + config_name "fake" + config :password, :validate => :password + end + end + subject(:plugin_instance) { plugin_class.new(instance_params) } + + it "should be a Password object" do + expect(plugin_instance.password).to(be_a(LogStash::Util::Password)) + end + + it "should make password values hidden" do + expect(plugin_instance.password.to_s).to(be == "") + expect(plugin_instance.password.inspect).to(be == "") + end + + it "should show password values via #value" do + expect(plugin_instance.password.value).to(be == secret) + end + + it "should correctly copy password types" do + clone = plugin_instance.class.new(plugin_instance.params) + expect(clone.password.value).to(be == secret) + end + + it "should obfuscate original_params" do + expect(plugin_instance.original_params['password']).to(be_a(LogStash::Util::Password)) end end - let(:secret) { "fancy pants" } - subject { klass.new("password" => secret) } - - it "should be a Password object" do - expect(subject.password).to(be_a(LogStash::Util::Password)) + context 'when instantiated with a string literal password' do + it_behaves_like 'protected password' do + let(:instance_params) { { "password" => secret } } + end end - it "should make password values hidden" do - expect(subject.password.to_s).to(be == "") - expect(subject.password.inspect).to(be == "") - end + context 'when instantiated with an environment variable placeholder' do + it_behaves_like 'protected password' do + let(:instance_params) { { "password" => '${PLACEHOLDER}'} } + before(:each) { ENV.store('PLACEHOLDER', secret) } + after(:each) { ENV.delete('PLACEHOLDER')} - it "should show password values via #value" do - expect(subject.password.value).to(be == secret) - end - - it "should correctly copy password types" do - clone = subject.class.new(subject.params) - expect(clone.password.value).to(be == secret) - end - - it "should obfuscate original_params" do - expect(subject.original_params['password']).to(be_a(LogStash::Util::Password)) + before(:each) do + # Ensure the shared examples are actually running with an + # environment variable placeholder. + # If this assertion fails, setup for the spec is invalid. + expect(instance_params['password']).to eq('${PLACEHOLDER}') + end + end end end From 659ef33f7205d5e111fb1db7e1f26b3dcf6bc28a Mon Sep 17 00:00:00 2001 From: Colin Surprenant Date: Wed, 10 Jun 2020 22:12:12 -0400 Subject: [PATCH 0520/1126] Backport #12009 to 7.x branch, bugfix in pipeline reload fix Settings equality test which broke the PipelineConfig equality --- .../main/java/org/logstash/config/ir/PipelineConfig.java | 2 +- .../java/org/logstash/config/ir/PipelineConfigTest.java | 6 +++++- 2 files changed, 6 insertions(+), 2 deletions(-) diff --git a/logstash-core/src/main/java/org/logstash/config/ir/PipelineConfig.java b/logstash-core/src/main/java/org/logstash/config/ir/PipelineConfig.java index c5ab1b00d..a9a8035d9 100644 --- a/logstash-core/src/main/java/org/logstash/config/ir/PipelineConfig.java +++ b/logstash-core/src/main/java/org/logstash/config/ir/PipelineConfig.java @@ -126,7 +126,7 @@ public final class PipelineConfig { PipelineConfig cother = (PipelineConfig) other; return configHash().equals(cother.configHash()) && this.pipelineId.equals(cother.pipelineId) && - this.settings.eql(cother.settings); + this.settings.equals(cother.settings); } @Override diff --git a/logstash-core/src/test/java/org/logstash/config/ir/PipelineConfigTest.java b/logstash-core/src/test/java/org/logstash/config/ir/PipelineConfigTest.java index 841042a43..fe37facec 100644 --- a/logstash-core/src/test/java/org/logstash/config/ir/PipelineConfigTest.java +++ b/logstash-core/src/test/java/org/logstash/config/ir/PipelineConfigTest.java @@ -44,7 +44,7 @@ public class PipelineConfigTest extends RubyEnvTestCase { private final static RubyObject SETTINGS = (RubyObject) RubyUtil.RUBY.evalScriptlet( "require 'logstash/environment'\n" + // this is needed to register "pipeline.system" setting "require 'logstash/settings'\n" + - "LogStash::SETTINGS");; + "LogStash::SETTINGS"); private PipelineConfig sut; private SourceWithMetadata[] orderedConfigParts; public static final String PIPELINE_CONFIG_PART_2 = @@ -101,6 +101,10 @@ public class PipelineConfigTest extends RubyEnvTestCase { PipelineConfig anotherExactPipeline = new PipelineConfig(source, pipelineIdSym, toRubyArray(orderedConfigParts), SETTINGS); assertEquals(anotherExactPipeline, sut); + final RubyObject CLONED_SETTINGS = (RubyObject)SETTINGS.callMethod("clone"); + PipelineConfig anotherExactPipelineWithClonedSettings = new PipelineConfig(source, pipelineIdSym, toRubyArray(orderedConfigParts), CLONED_SETTINGS); + assertEquals(anotherExactPipelineWithClonedSettings, sut); + PipelineConfig notMatchingPipeline = new PipelineConfig(source, pipelineIdSym, RubyArray.newEmptyArray(RubyUtil.RUBY), SETTINGS); assertNotEquals(notMatchingPipeline, sut); From 734ec041865ee7a2fcabaa29a3c4d7c4da8f65cd Mon Sep 17 00:00:00 2001 From: vijairaj Date: Fri, 26 Jun 2020 18:42:57 +0530 Subject: [PATCH 0521/1126] Ensure line codec can be found in example ruby filter (#12042) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Fixes elastic/logstash#12041 Co-authored-by: João Duarte --- .../templates/codec-plugin/lib/logstash/codecs/example.rb.erb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/pluginmanager/templates/codec-plugin/lib/logstash/codecs/example.rb.erb b/lib/pluginmanager/templates/codec-plugin/lib/logstash/codecs/example.rb.erb index 5fb97fec1..1a49d73b9 100644 --- a/lib/pluginmanager/templates/codec-plugin/lib/logstash/codecs/example.rb.erb +++ b/lib/pluginmanager/templates/codec-plugin/lib/logstash/codecs/example.rb.erb @@ -25,7 +25,7 @@ class LogStash::Codecs::<%= classify(plugin_name) %> < LogStash::Codecs::Base config :append, :validate => :string, :default => ', Hello World!' def register - @lines = LogStash::Codecs::Line.new + @lines = LogStash::Plugin.lookup("codec", "line").new @lines.charset = "UTF-8" end # def register From fe105710b56ee21eff5dafe8748db7a25c93f4e3 Mon Sep 17 00:00:00 2001 From: andsel Date: Mon, 4 May 2020 15:03:20 +0200 Subject: [PATCH 0522/1126] Fix: missed 'equal' part in time comparison test In time comparison of LocalDateTime the isBefore is strict, so in case two instants has the same millisecond, it fails in test (happens in Windows tests) Close: 11862 Backport of #11862 to 7.x --- .../config/ir/PipelineConfigTest.java | 27 ++++++++++++++++++- 1 file changed, 26 insertions(+), 1 deletion(-) diff --git a/logstash-core/src/test/java/org/logstash/config/ir/PipelineConfigTest.java b/logstash-core/src/test/java/org/logstash/config/ir/PipelineConfigTest.java index fe37facec..2fcb3776c 100644 --- a/logstash-core/src/test/java/org/logstash/config/ir/PipelineConfigTest.java +++ b/logstash-core/src/test/java/org/logstash/config/ir/PipelineConfigTest.java @@ -19,6 +19,8 @@ package org.logstash.config.ir; +import org.hamcrest.Description; +import org.hamcrest.TypeSafeMatcher; import org.jruby.*; import org.jruby.runtime.builtin.IRubyObject; import org.junit.Before; @@ -35,6 +37,25 @@ import static org.junit.Assert.*; public class PipelineConfigTest extends RubyEnvTestCase { + private static class IsBeforeOrSameMatcher extends TypeSafeMatcher { + + private LocalDateTime after; + + IsBeforeOrSameMatcher(LocalDateTime after) { + this.after = after; + } + + @Override + protected boolean matchesSafely(LocalDateTime item) { + return item.isBefore(after) || item.isEqual(after); + } + + @Override + public void describeTo(Description description) { + description.appendText(" is before " + after); + } + } + public static final String PIPELINE_ID = "main"; private RubyClass source; private RubySymbol pipelineIdSym; @@ -87,7 +108,11 @@ public class PipelineConfigTest extends RubyEnvTestCase { assertEquals("returns the pipeline id", PIPELINE_ID, sut.getPipelineId()); assertNotNull("returns the config_hash", sut.configHash()); assertEquals("returns the merged `ConfigPart#config_string`", configMerged, sut.configString()); - assertTrue("records when the config was read", sut.getReadAt().isBefore(LocalDateTime.now())); + assertThat("records when the config was read", sut.getReadAt(), isBeforeOrSame(LocalDateTime.now())); + } + + private static IsBeforeOrSameMatcher isBeforeOrSame(LocalDateTime after) { + return new IsBeforeOrSameMatcher(after); } @SuppressWarnings("rawtypes") From 27117a345a96d2decf3929f3b30e1d8fb0646dc9 Mon Sep 17 00:00:00 2001 From: Karen Metts Date: Mon, 8 Jun 2020 22:29:58 -0400 Subject: [PATCH 0523/1126] =?UTF-8?q?Doc:Add=20info=20on=20using=20api=20k?= =?UTF-8?q?eys=20for=20access=20Co-authored-by:=20Jo=C3=A3o=20Duarte=20?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- docs/static/security/api-keys.asciidoc | 183 ++++++++++++++++++++++++- 1 file changed, 182 insertions(+), 1 deletion(-) diff --git a/docs/static/security/api-keys.asciidoc b/docs/static/security/api-keys.asciidoc index 370633f00..b5718dce7 100644 --- a/docs/static/security/api-keys.asciidoc +++ b/docs/static/security/api-keys.asciidoc @@ -2,8 +2,189 @@ [[ls-api-keys]] ==== Grant access using API keys - Instead of using usernames and passwords, you can use API keys to grant access to {es} resources. You can set API keys to expire at a certain time, and you can explicitly invalidate them. Any user with the `manage_api_key` or `manage_own_api_key` cluster privilege can create API keys. + +Note that API keys are tied to the cluster they are created in. If you are +sending output to different clusters, be sure to create the correct kind of API +key. + +NOTE: For security reasons, we recommend using a unique API key per {ls} instance. +You can create as many API keys per user as necessary. + + +[float] +[[ls-create-api-key]] +===== Create an API key + +You can create API keys using either the +{ref}/security-api-create-api-key.html[Create API key API] or the +{kibana-ref}/api-keys.html[Kibana UI]. This section walks you through creating +an API key using the {ref}/security-api-create-api-key.html[Create API key API]. +The privileges needed are the same for either approach. + +Here is an example that shows how to create an API key for publishing to {es} +using the <>. + + +[source,console,subs="attributes,callouts"] +------------------------------------------------------------ +POST /_security/api_key +{ + "name": "logstash_host001", <1> + "role_descriptors": { + "logstash_writer": { <2> + "cluster": ["monitor", "manage_ilm", "read_ilm"], + "index": [ + { + "names": ["logstash-*"], + "privileges": ["view_index_metadata", "create_doc"] + } + ] + } + } +} +------------------------------------------------------------ +<1> Name of the API key +<2> Granted privileges + +The return value should look similar to this: + +[source,console-result,subs="attributes,callouts"] +-------------------------------------------------- +{ + "id":"TiNAGG4BaaMdaH1tRfuU", <1> + "name":"logstash_host001", + "api_key":"KnR6yE41RrSowb0kQ0HWoA" <2> +} +-------------------------------------------------- +<1> Unique id for this API key +<2> Generated API key + + +[float] +[[ls-api-key-publish]] +====== Create an API key for publishing + +You're in luck! The example we used in the <> section creates +an API key for publishing to {es} using the +<>. + +///// +Work in Progress + +The API key for the Elasticsearch output plugin configuration requires these +cluster privileges: + +* `monitor` +* `manage_ilm` +* `read_ilm` + +It requires these index privileges: + +* `view_index_metadata` +* `create_doc` +///// + +Here's an example using the API key in your +<> configuration. + +["source","ruby"] +----- +output { + elasticsearch { + api_key => "TiNAGG4BaaMdaH1tRfuU:KnR6yE41RrSowb0kQ0HWoA" <1> + } +} +----- +<1> Format is `id:api_key` (as returned by +{ref}/security-api-create-api-key.html[Create API key]) + +[float] +[[ls-api-key-input]] +====== Create an API key for reading + +Creating an API key to use for reading data from {es} is similar to creating an +API key for publishing described earlier. You can use the example in the +<> section, granting the appropriate privileges. + +///// +Work in Progress +The API key for the <> +configuration requires these cluster privileges: + +* `monitor` +* `read_ilm` + +It requires these index privileges: + +* `view_index_metadata` +* `create_doc` +///// + +Here's an example using the API key in your +<> configuration. + +["source","ruby"] +----- +input { + elasticsearch { + "api_key" => "TiNAGG4BaaMdaH1tRfuU:KnR6yE41RrSowb0kQ0HWoA" <1> + } +} +----- +<1> Format is `id:api_key` (as returned by +{ref}/security-api-create-api-key.html[Create API key])s + + +[float] +[[ls-api-key-filter]] +====== Create an API key for filtering + +Creating an API key to use for processing data from {es} is similar to creating +an API key for publishing described earlier. You can use the example in the +<> section, granting the appropriate privileges. + +///// +Work in Progress + +The API key for the <> +configuration requires these cluster privileges: + +* `monitor` +* `read_ilm` + +It requires these index privileges: + +* `view_index_metadata` +* `create_doc` +///// + +Here's an example using the API key in your +<> configuration. + +["source","ruby"] +----- +filter { + elasticsearch { + api_key => "TiNAGG4BaaMdaH1tRfuU:KnR6yE41RrSowb0kQ0HWoA" <1> + } +} +----- +<1> Format is `id:api_key` (as returned by {ref}/security-api-create-api-key.html[Create API key]) + + +[float] +[[learn-more-api-keys]] +===== Learn more about API keys + +See the {es} API key documentation for more information: + +* {ref}/security-api-create-api-key.html[Create API key] +* {ref}/security-api-get-api-key.html[Get API key information] +* {ref}/security-api-invalidate-api-key.html[Invalidate API key] + +See {kibana-ref}/api-keys.html[API Keys] for info on managing API keys +through {kib}. From 838c54879b206bbc43a83921f24e1fae0e469e90 Mon Sep 17 00:00:00 2001 From: Joao Duarte Date: Fri, 26 Jun 2020 16:41:41 +0100 Subject: [PATCH 0524/1126] improve test for cache difference --- .../config/ir/CompiledPipelineTest.java | 12 +++++------ .../logstash/config/ir/cache/pipeline1.conf | 13 ++++-------- .../logstash/config/ir/cache/pipeline2.conf | 20 ++++++------------- 3 files changed, 16 insertions(+), 29 deletions(-) diff --git a/logstash-core/src/test/java/org/logstash/config/ir/CompiledPipelineTest.java b/logstash-core/src/test/java/org/logstash/config/ir/CompiledPipelineTest.java index 0b63c0042..11417de37 100644 --- a/logstash-core/src/test/java/org/logstash/config/ir/CompiledPipelineTest.java +++ b/logstash-core/src/test/java/org/logstash/config/ir/CompiledPipelineTest.java @@ -570,7 +570,7 @@ public final class CompiledPipelineTest extends RubyEnvTestCase { @Test @SuppressWarnings({"unchecked"}) - public void testCompilerCacheCompiledClasses() throws IOException, InvalidIRException { + public void testCacheCompiledClassesWithDifferentId() throws IOException, InvalidIRException { final FixedPluginFactory pluginFactory = new FixedPluginFactory( () -> null, () -> IDENTITY_FILTER, @@ -582,20 +582,20 @@ public final class CompiledPipelineTest extends RubyEnvTestCase { false); final CompiledPipeline cBaselinePipeline = new CompiledPipeline(baselinePipeline, pluginFactory); - final PipelineIR pipelineWithExtraFilter = ConfigCompiler.configToPipelineIR( + final PipelineIR pipelineWithDifferentId = ConfigCompiler.configToPipelineIR( IRHelpers.toSourceWithMetadataFromPath("org/logstash/config/ir/cache/pipeline2.conf"), false); - final CompiledPipeline cPipelineWithExtraFilter = new CompiledPipeline(pipelineWithExtraFilter, pluginFactory); + final CompiledPipeline cPipelineWithDifferentId = new CompiledPipeline(pipelineWithDifferentId, pluginFactory); // actual test: compiling a pipeline with an extra filter should only create 1 extra class ComputeStepSyntaxElement.cleanClassCache(); cBaselinePipeline.buildExecution(); final int cachedBefore = ComputeStepSyntaxElement.classCacheSize(); - cPipelineWithExtraFilter.buildExecution(); + cPipelineWithDifferentId.buildExecution(); final int cachedAfter = ComputeStepSyntaxElement.classCacheSize(); - + final String message = String.format("unexpected cache size, cachedAfter: %d, cachedBefore: %d", cachedAfter, cachedBefore); - assertEquals(message, 1, cachedAfter - cachedBefore); + assertEquals(message, 0, cachedAfter - cachedBefore); } @Test diff --git a/logstash-core/src/test/resources/org/logstash/config/ir/cache/pipeline1.conf b/logstash-core/src/test/resources/org/logstash/config/ir/cache/pipeline1.conf index e26727ecc..768365c28 100644 --- a/logstash-core/src/test/resources/org/logstash/config/ir/cache/pipeline1.conf +++ b/logstash-core/src/test/resources/org/logstash/config/ir/cache/pipeline1.conf @@ -1,19 +1,14 @@ input { - stdin {} + stdin { id => "stdin_id_1" } } filter { mutate { - id => "ppl1_1" + id => "mutate_id_1" rename => ["a_field", "into_another"] } - - mutate { - id => "ppl1_2" - rename => ["a_field", "into_another"] - } } output { - stdout {} -} \ No newline at end of file + stdout { id => "stdout_id_1" } +} diff --git a/logstash-core/src/test/resources/org/logstash/config/ir/cache/pipeline2.conf b/logstash-core/src/test/resources/org/logstash/config/ir/cache/pipeline2.conf index fbe969dac..1ae8670c8 100644 --- a/logstash-core/src/test/resources/org/logstash/config/ir/cache/pipeline2.conf +++ b/logstash-core/src/test/resources/org/logstash/config/ir/cache/pipeline2.conf @@ -1,24 +1,16 @@ +# pipeline similar to pipeline 1 but with different ids +# no extra classes should be generated because of this input { - stdin {} + stdin { id => "stdin_id_1" } } filter { mutate { - id => "ppl2_1" + id => "mutate_id_1" rename => ["a_field", "into_another"] } - - mutate { - id => "ppl2_2" - rename => ["a_field", "into_another"] - } - - mutate { - id => "ppl2_3" - rename => ["a_field", "into_another"] - } } output { - stdout {} -} \ No newline at end of file + stdout { id => "stdout_id_1" } +} From 0efbc0488adba207ee309e690164a572a2e1ecf0 Mon Sep 17 00:00:00 2001 From: Ry Biesemeyer Date: Wed, 24 Jun 2020 22:43:01 +0000 Subject: [PATCH 0525/1126] plugin config: support space-deliminated URIs on list-type params Since whitespace is illegal in URIs, we can safely use it as a delimiter when validating `list`-type `URI` params, enabling the expansion of an arbitrary list of URIs from a single Environment- or Keystore-variable. Resolves: https://github.com/elastic/logstash/issues/8157 Resolves: https://github.com/elastic/logstash/issues/6366 Backport of #12051 to 7.x --- logstash-core/lib/logstash/config/mixin.rb | 11 ++++ logstash-core/lib/logstash/util/safe_uri.rb | 11 ++++ .../spec/logstash/config/mixin_spec.rb | 64 ++++++++++++++++--- 3 files changed, 78 insertions(+), 8 deletions(-) diff --git a/logstash-core/lib/logstash/config/mixin.rb b/logstash-core/lib/logstash/config/mixin.rb index 57de589bc..a8febea0b 100644 --- a/logstash-core/lib/logstash/config/mixin.rb +++ b/logstash-core/lib/logstash/config/mixin.rb @@ -342,6 +342,8 @@ module LogStash::Config::Mixin # Empty lists are converted to nils return true, [] if value.empty? + return validate_value(value, :uri_list) if config_val == :uri + validated_items = value.map {|v| validate_value(v, config_val)} is_valid = validated_items.all? {|sr| sr[0] } processed_value = validated_items.map {|sr| sr[1]} @@ -528,6 +530,15 @@ module LogStash::Config::Mixin end result = value.first.is_a?(::LogStash::Util::SafeURI) ? value.first : ::LogStash::Util::SafeURI.new(value.first) + when :uri_list + # expand entries that have space-delimited URIs in strings. + # This validator is considered private, and can be accessed + # by specifying `:validate => :uri` and `:list => true` + result = value.flat_map do |entry| + entry.kind_of?(String) ? entry.split(' ') : entry + end.map do |expanded_entry| + ::LogStash::Util::SafeURI.from(expanded_entry) + end when :path if value.size > 1 # Only 1 value wanted return false, "Expected path (one value), got #{value.size} values?" diff --git a/logstash-core/lib/logstash/util/safe_uri.rb b/logstash-core/lib/logstash/util/safe_uri.rb index f2f095432..c73a0a468 100644 --- a/logstash-core/lib/logstash/util/safe_uri.rb +++ b/logstash-core/lib/logstash/util/safe_uri.rb @@ -45,6 +45,17 @@ class LogStash::Util::SafeURI raise ArgumentError, "URI is not valid - host is not specified" if @uri.host.nil? end + ## + # Attempts to efficiently return an instance of `SafeURI` from the given object. + # @param object [Object]: an object that may or may not already be a `SafeURI`. + # @return [SafeURI]: if the given `object` was a `SafeURI`, returns it unmodified. + # otherwise, a new `SafeURI` is initialized using the `object`. + def self.from(object) + return object if object.kind_of?(self) + + new(object) + end + def to_s sanitized.to_s end diff --git a/logstash-core/spec/logstash/config/mixin_spec.rb b/logstash-core/spec/logstash/config/mixin_spec.rb index 2cddf4f7d..3fa8f0965 100644 --- a/logstash-core/spec/logstash/config/mixin_spec.rb +++ b/logstash-core/spec/logstash/config/mixin_spec.rb @@ -115,28 +115,76 @@ describe LogStash::Config::Mixin do context "when validating lists of items" do let(:klass) do Class.new(LogStash::Filters::Base) do - config_name "multiuri" - config :uris, :validate => :uri, :list => true + config_name "list_validator_spec" config :strings, :validate => :string, :list => true config :required_strings, :validate => :string, :list => true, :required => true end end - let(:uris) { ["http://example.net/1", "http://example.net/2"] } - let(:safe_uris) { uris.map {|str| ::LogStash::Util::SafeURI.new(str) } } let(:strings) { ["I am a", "modern major general"] } let(:required_strings) { ["required", "strings"] } - subject { klass.new("uris" => uris, "strings" => strings, "required_strings" => required_strings) } - - it "a URI list should return an array of URIs" do - expect(subject.uris).to match_array(safe_uris) + let(:config) do + {"strings" => strings, "required_strings" => required_strings} end + subject(:instance) { klass.new(config) } + it "a string list should return an array of strings" do expect(subject.strings).to match_array(strings) end + context 'URI lists' do + let(:klass) do + Class.new(LogStash::Filters::Base) do + config_name 'list_uri_validator_spec' + config :uris, :validate => :uri, :list => true + end + end + subject(:instance) { klass.new(config) } + + let(:uri_1) { "http://example.net/1" } + let(:uri_2) { "http://example.net/2" } + let(:uri_3) { "http://example.net:9201/3" } + + let(:uris) { [uri_1, uri_2, uri_3] } + let(:config) { Hash["uris" => uris_parameter] } + + let(:safe_uris) { uris.map {|str| ::LogStash::Util::SafeURI.new(str) } } + + shared_examples ':validate => :uri_list' do + it 'should normalize to a flat list containing all extracted URIs from the input' do + expect(instance.uris).to match_array(safe_uris) + end + end + + context 'when given a single string containing exactly one uri' do + let(:uris_parameter) { "#{uri_1}" } + let(:uris) { [uri_1] } + include_examples ':validate => :uri_list' + end + + context 'when given an array of strings, each containing exactly one uri' do + let(:uris_parameter) { uris } + include_examples ':validate => :uri_list' + end + + context 'when given a single string containing multiple whitespace-delimited uris' do + let(:uris_parameter) { "#{uri_1} #{uri_2} #{uri_3}" } + include_examples ':validate => :uri_list' + end + + context 'when given an array containing a single entry that has multiple whitespace-delimited uris' do + let(:uris_parameter) { ["#{uri_1} #{uri_2} #{uri_3}"] } + include_examples ':validate => :uri_list' + end + + context 'when given an array containing multiple entries, one of which has multiple whitespace-delimited uris' do + let(:uris_parameter) { ["#{uri_1} #{uri_2}", "#{uri_3}"] } + include_examples ':validate => :uri_list' + end + end + context "with a scalar value" do let(:strings) { "foo" } From 4951f4e751d41c3590b3e298a2b20be8afd44dac Mon Sep 17 00:00:00 2001 From: Karen Metts Date: Fri, 26 Jun 2020 14:27:13 -0400 Subject: [PATCH 0526/1126] Doc: Create section for cross-plugin functionality and add space delimiters Backport of #12051 to 7.x --- docs/static/cross-plugin-concepts.asciidoc | 17 +++++++++++++++++ docs/static/plugin-manager.asciidoc | 2 ++ 2 files changed, 19 insertions(+) create mode 100644 docs/static/cross-plugin-concepts.asciidoc diff --git a/docs/static/cross-plugin-concepts.asciidoc b/docs/static/cross-plugin-concepts.asciidoc new file mode 100644 index 000000000..3c3db2556 --- /dev/null +++ b/docs/static/cross-plugin-concepts.asciidoc @@ -0,0 +1,17 @@ +[[plugin-concepts]] +=== Cross-plugin concepts and features + +New section for concepts, features, and behaviors that apply to multiple plugins. + +[[space-delimited-uris-in-list-params]] +==== Space-deliminated URIs in list-type params + +List-type URI parameters will automatically expand strings that contain multiple +whitespace-delimited URIs into separate entries. This behaviour enables the expansion +of an arbitrary list of URIs from a single Environment- or Keystore-variable. + +Examples of plugins and options that support this functionality: + +* <> +* <> +* <> diff --git a/docs/static/plugin-manager.asciidoc b/docs/static/plugin-manager.asciidoc index d32ec3d51..50703b44e 100644 --- a/docs/static/plugin-manager.asciidoc +++ b/docs/static/plugin-manager.asciidoc @@ -153,6 +153,8 @@ bin/logstash-plugin install logstash-output-kafka Once set, plugin commands install, update can be used through this proxy. +include::cross-plugin-concepts.asciidoc[] + include::plugin-generator.asciidoc[] include::offline-plugins.asciidoc[] From a63e534481da6ffe7b659be6b300d4bfdbcb5405 Mon Sep 17 00:00:00 2001 From: Ry Biesemeyer Date: Fri, 26 Jun 2020 14:08:17 -0700 Subject: [PATCH 0527/1126] Standardize on en-GB "behavioUr" for this doc Backport of #12051 to 7.x --- docs/static/cross-plugin-concepts.asciidoc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/static/cross-plugin-concepts.asciidoc b/docs/static/cross-plugin-concepts.asciidoc index 3c3db2556..c6765397f 100644 --- a/docs/static/cross-plugin-concepts.asciidoc +++ b/docs/static/cross-plugin-concepts.asciidoc @@ -1,7 +1,7 @@ [[plugin-concepts]] === Cross-plugin concepts and features -New section for concepts, features, and behaviors that apply to multiple plugins. +New section for concepts, features, and behaviours that apply to multiple plugins. [[space-delimited-uris-in-list-params]] ==== Space-deliminated URIs in list-type params From 8eddbd608b8fc70965cbabcac11612889c1e5fcb Mon Sep 17 00:00:00 2001 From: Karen Metts Date: Tue, 23 Jun 2020 13:30:54 -0400 Subject: [PATCH 0528/1126] Doc:Add deprecation notice to legacy collection Resolves: #11979 --- docs/static/monitoring/monitoring-internal-legacy.asciidoc | 4 +++- docs/static/monitoring/monitoring-overview.asciidoc | 2 +- 2 files changed, 4 insertions(+), 2 deletions(-) diff --git a/docs/static/monitoring/monitoring-internal-legacy.asciidoc b/docs/static/monitoring/monitoring-internal-legacy.asciidoc index fb26404aa..2e3e5a977 100644 --- a/docs/static/monitoring/monitoring-internal-legacy.asciidoc +++ b/docs/static/monitoring/monitoring-internal-legacy.asciidoc @@ -2,9 +2,11 @@ [[monitoring-internal-collection-legacy]] === Collect {ls} monitoring data using legacy collectors ++++ -Legacy collection +Legacy collection (deprecated) ++++ +deprecated[7.9.0] + ==== Components for legacy collection Monitoring {ls} with legacy collection uses these components: diff --git a/docs/static/monitoring/monitoring-overview.asciidoc b/docs/static/monitoring/monitoring-overview.asciidoc index e71ef4daa..5ae274d37 100644 --- a/docs/static/monitoring/monitoring-overview.asciidoc +++ b/docs/static/monitoring/monitoring-overview.asciidoc @@ -21,7 +21,7 @@ monitoring data from your {ls} instance and sends it directly to your monitoring cluster. The benefit of Metricbeat collection is that the monitoring agent remains active even if the {ls} instance does not. -* <>. +* <>. Legacy collectors send monitoring data to your production cluster. include::monitoring-mb.asciidoc[] From c2e4e4f185cc03e2ef29083ae7b2dd9cbca62272 Mon Sep 17 00:00:00 2001 From: Colin Surprenant Date: Tue, 16 Jun 2020 16:53:49 -0400 Subject: [PATCH 0529/1126] release queue dir lock upon exceptions while opening queue --- .../java/org/logstash/ackedqueue/Queue.java | 263 ++++++++++-------- .../org/logstash/ackedqueue/QueueTest.java | 21 ++ 2 files changed, 161 insertions(+), 123 deletions(-) diff --git a/logstash-core/src/main/java/org/logstash/ackedqueue/Queue.java b/logstash-core/src/main/java/org/logstash/ackedqueue/Queue.java index 4e39e7586..3c7232e15 100644 --- a/logstash-core/src/main/java/org/logstash/ackedqueue/Queue.java +++ b/logstash-core/src/main/java/org/logstash/ackedqueue/Queue.java @@ -158,134 +158,148 @@ public final class Queue implements Closeable { * @throws IOException if an IO error occurs */ public void open() throws IOException { - final int headPageNum; - if (!this.closed.get()) { throw new IOException("queue already opened"); } lock.lock(); try { - // verify exclusive access to the dirPath - this.dirLock = FileLockFactory.obtainLock(this.dirPath, LOCK_NAME); - - // Upgrade to serialization format V2 - QueueUpgrade.upgradeQueueDirectoryToV2(dirPath); - - Checkpoint headCheckpoint; try { - headCheckpoint = this.checkpointIO.read(checkpointIO.headFileName()); - } catch (NoSuchFileException e) { - // if there is no head checkpoint, create a new headpage and checkpoint it and exit method + // verify exclusive access to the dirPath + this.dirLock = FileLockFactory.obtainLock(this.dirPath, LOCK_NAME); + } catch (LockException e) { + throw new LockException("The queue failed to obtain exclusive access, cause: " + e.getMessage()); + } - logger.debug("No head checkpoint found at: {}, creating new head page", checkpointIO.headFileName()); - - this.ensureDiskAvailable(this.maxBytes, 0); - - this.seqNum = 0; - headPageNum = 0; - - newCheckpointedHeadpage(headPageNum); + try { + openPages(); this.closed.set(false); - - return; + } catch (IOException e) { + // upon any exception while opening the queue and after dirlock has been obtained + // we need to make sure to release the dirlock. Calling the close method on a partially + // open queue has no effect because the closed flag is still true. + releaseLockAndSwallow(); + throw(e); } - - // at this point we have a head checkpoint to figure queue recovery - - // as we load pages, compute actually disk needed substracting existing pages size to the required maxBytes - long pqSizeBytes = 0; - - // reconstruct all tail pages state upto but excluding the head page - for (int pageNum = headCheckpoint.getFirstUnackedPageNum(); pageNum < headCheckpoint.getPageNum(); pageNum++) { - final String cpFileName = checkpointIO.tailFileName(pageNum); - if (!dirPath.resolve(cpFileName).toFile().exists()) { - continue; - } - final Checkpoint cp = this.checkpointIO.read(cpFileName); - - logger.debug("opening tail page: {}, in: {}, with checkpoint: {}", pageNum, this.dirPath, cp.toString()); - - PageIO pageIO = new MmapPageIOV2(pageNum, this.pageCapacity, this.dirPath); - // important to NOT pageIO.open() just yet, we must first verify if it is fully acked in which case - // we can purge it and we don't care about its integrity for example if it is of zero-byte file size. - if (cp.isFullyAcked()) { - purgeTailPage(cp, pageIO); - } else { - pageIO.open(cp.getMinSeqNum(), cp.getElementCount()); - addTailPage(PageFactory.newTailPage(cp, this, pageIO)); - pqSizeBytes += pageIO.getCapacity(); - } - - // track the seqNum as we rebuild tail pages, prevent empty pages with a minSeqNum of 0 to reset seqNum - if (cp.maxSeqNum() > this.seqNum) { - this.seqNum = cp.maxSeqNum(); - } - } - - // transform the head page into a tail page only if the headpage is non-empty - // in both cases it will be checkpointed to track any changes in the firstUnackedPageNum when reconstructing the tail pages - - logger.debug("opening head page: {}, in: {}, with checkpoint: {}", headCheckpoint.getPageNum(), this.dirPath, headCheckpoint.toString()); - - PageIO pageIO = new MmapPageIOV2(headCheckpoint.getPageNum(), this.pageCapacity, this.dirPath); - pageIO.recover(); // optimistically recovers the head page data file and set minSeqNum and elementCount to the actual read/recovered data - - pqSizeBytes += (long)pageIO.getHead(); - ensureDiskAvailable(this.maxBytes, pqSizeBytes); - - if (pageIO.getMinSeqNum() != headCheckpoint.getMinSeqNum() || pageIO.getElementCount() != headCheckpoint.getElementCount()) { - // the recovered page IO shows different minSeqNum or elementCount than the checkpoint, use the page IO attributes - - logger.warn("recovered head data page {} is different than checkpoint, using recovered page information", headCheckpoint.getPageNum()); - logger.debug("head checkpoint minSeqNum={} or elementCount={} is different than head pageIO minSeqNum={} or elementCount={}", headCheckpoint.getMinSeqNum(), headCheckpoint.getElementCount(), pageIO.getMinSeqNum(), pageIO.getElementCount()); - - long firstUnackedSeqNum = headCheckpoint.getFirstUnackedSeqNum(); - if (firstUnackedSeqNum < pageIO.getMinSeqNum()) { - logger.debug("head checkpoint firstUnackedSeqNum={} is < head pageIO minSeqNum={}, using pageIO minSeqNum", firstUnackedSeqNum, pageIO.getMinSeqNum()); - firstUnackedSeqNum = pageIO.getMinSeqNum(); - } - headCheckpoint = new Checkpoint(headCheckpoint.getPageNum(), headCheckpoint.getFirstUnackedPageNum(), firstUnackedSeqNum, pageIO.getMinSeqNum(), pageIO.getElementCount()); - } - this.headPage = PageFactory.newHeadPage(headCheckpoint, this, pageIO); - - if (this.headPage.getMinSeqNum() <= 0 && this.headPage.getElementCount() <= 0) { - // head page is empty, let's keep it as-is - // but checkpoint it to update the firstUnackedPageNum if it changed - this.headPage.checkpoint(); - } else { - // head page is non-empty, transform it into a tail page - this.headPage.behead(); - - if (headCheckpoint.isFullyAcked()) { - purgeTailPage(headCheckpoint, pageIO); - } else { - addTailPage(this.headPage); - } - - // track the seqNum as we add this new tail page, prevent empty tailPage with a minSeqNum of 0 to reset seqNum - if (headCheckpoint.maxSeqNum() > this.seqNum) { - this.seqNum = headCheckpoint.maxSeqNum(); - } - - // create a new empty head page - headPageNum = headCheckpoint.getPageNum() + 1; - newCheckpointedHeadpage(headPageNum); - } - - // only activate the first tail page - if (tailPages.size() > 0) { - this.tailPages.get(0).getPageIO().activate(); - } - - // TODO: here do directory traversal and cleanup lingering pages? could be a background operations to not delay queue start? - - this.closed.set(false); - } catch (LockException e) { - throw new LockException("The queue failed to obtain exclusive access, cause: " + e.getMessage()); } finally { lock.unlock(); } } + private void openPages() throws IOException { + final int headPageNum; + + // Upgrade to serialization format V2 + QueueUpgrade.upgradeQueueDirectoryToV2(dirPath); + + Checkpoint headCheckpoint; + try { + headCheckpoint = this.checkpointIO.read(checkpointIO.headFileName()); + } catch (NoSuchFileException e) { + // if there is no head checkpoint, create a new headpage and checkpoint it and exit method + + logger.debug("No head checkpoint found at: {}, creating new head page", checkpointIO.headFileName()); + + this.ensureDiskAvailable(this.maxBytes, 0); + + this.seqNum = 0; + headPageNum = 0; + + newCheckpointedHeadpage(headPageNum); + this.closed.set(false); + + return; + } + + // at this point we have a head checkpoint to figure queue recovery + + // as we load pages, compute actually disk needed substracting existing pages size to the required maxBytes + long pqSizeBytes = 0; + + // reconstruct all tail pages state upto but excluding the head page + for (int pageNum = headCheckpoint.getFirstUnackedPageNum(); pageNum < headCheckpoint.getPageNum(); pageNum++) { + final String cpFileName = checkpointIO.tailFileName(pageNum); + if (!dirPath.resolve(cpFileName).toFile().exists()) { + continue; + } + final Checkpoint cp = this.checkpointIO.read(cpFileName); + + logger.debug("opening tail page: {}, in: {}, with checkpoint: {}", pageNum, this.dirPath, cp.toString()); + + PageIO pageIO = new MmapPageIOV2(pageNum, this.pageCapacity, this.dirPath); + // important to NOT pageIO.open() just yet, we must first verify if it is fully acked in which case + // we can purge it and we don't care about its integrity for example if it is of zero-byte file size. + if (cp.isFullyAcked()) { + purgeTailPage(cp, pageIO); + } else { + pageIO.open(cp.getMinSeqNum(), cp.getElementCount()); + addTailPage(PageFactory.newTailPage(cp, this, pageIO)); + pqSizeBytes += pageIO.getCapacity(); + } + + // track the seqNum as we rebuild tail pages, prevent empty pages with a minSeqNum of 0 to reset seqNum + if (cp.maxSeqNum() > this.seqNum) { + this.seqNum = cp.maxSeqNum(); + } + } + + // transform the head page into a tail page only if the headpage is non-empty + // in both cases it will be checkpointed to track any changes in the firstUnackedPageNum when reconstructing the tail pages + + logger.debug("opening head page: {}, in: {}, with checkpoint: {}", headCheckpoint.getPageNum(), this.dirPath, headCheckpoint.toString()); + + PageIO pageIO = new MmapPageIOV2(headCheckpoint.getPageNum(), this.pageCapacity, this.dirPath); + pageIO.recover(); // optimistically recovers the head page data file and set minSeqNum and elementCount to the actual read/recovered data + + pqSizeBytes += (long) pageIO.getHead(); + ensureDiskAvailable(this.maxBytes, pqSizeBytes); + + if (pageIO.getMinSeqNum() != headCheckpoint.getMinSeqNum() || pageIO.getElementCount() != headCheckpoint.getElementCount()) { + // the recovered page IO shows different minSeqNum or elementCount than the checkpoint, use the page IO attributes + + logger.warn("recovered head data page {} is different than checkpoint, using recovered page information", headCheckpoint.getPageNum()); + logger.debug("head checkpoint minSeqNum={} or elementCount={} is different than head pageIO minSeqNum={} or elementCount={}", headCheckpoint.getMinSeqNum(), headCheckpoint.getElementCount(), pageIO.getMinSeqNum(), pageIO.getElementCount()); + + long firstUnackedSeqNum = headCheckpoint.getFirstUnackedSeqNum(); + if (firstUnackedSeqNum < pageIO.getMinSeqNum()) { + logger.debug("head checkpoint firstUnackedSeqNum={} is < head pageIO minSeqNum={}, using pageIO minSeqNum", firstUnackedSeqNum, pageIO.getMinSeqNum()); + firstUnackedSeqNum = pageIO.getMinSeqNum(); + } + headCheckpoint = new Checkpoint(headCheckpoint.getPageNum(), headCheckpoint.getFirstUnackedPageNum(), firstUnackedSeqNum, pageIO.getMinSeqNum(), pageIO.getElementCount()); + } + this.headPage = PageFactory.newHeadPage(headCheckpoint, this, pageIO); + + if (this.headPage.getMinSeqNum() <= 0 && this.headPage.getElementCount() <= 0) { + // head page is empty, let's keep it as-is + // but checkpoint it to update the firstUnackedPageNum if it changed + this.headPage.checkpoint(); + } else { + // head page is non-empty, transform it into a tail page + this.headPage.behead(); + + if (headCheckpoint.isFullyAcked()) { + purgeTailPage(headCheckpoint, pageIO); + } else { + addTailPage(this.headPage); + } + + // track the seqNum as we add this new tail page, prevent empty tailPage with a minSeqNum of 0 to reset seqNum + if (headCheckpoint.maxSeqNum() > this.seqNum) { + this.seqNum = headCheckpoint.maxSeqNum(); + } + + // create a new empty head page + headPageNum = headCheckpoint.getPageNum() + 1; + newCheckpointedHeadpage(headPageNum); + } + + // only activate the first tail page + if (tailPages.size() > 0) { + this.tailPages.get(0).getPageIO().activate(); + } + + // TODO: here do directory traversal and cleanup lingering pages? could be a background operations to not delay queue start? + } + + /** * delete files for the given page * @@ -713,18 +727,21 @@ public final class Queue implements Closeable { notFull.signalAll(); } finally { - try { - FileLockFactory.releaseLock(this.dirLock); - } catch (IOException e) { - // log error and ignore - logger.error("Queue close releaseLock failed, error={}", e.getMessage()); - } finally { - lock.unlock(); - } + releaseLockAndSwallow(); + lock.unlock(); } } } + private void releaseLockAndSwallow() { + try { + FileLockFactory.releaseLock(this.dirLock); + } catch (IOException e) { + // log error and ignore + logger.error("Queue close releaseLock failed, error={}", e.getMessage()); + } + } + /** * return the {@link Page} for the next read operation. * @return {@link Page} will be either a read-only tail page or the head page. diff --git a/logstash-core/src/test/java/org/logstash/ackedqueue/QueueTest.java b/logstash-core/src/test/java/org/logstash/ackedqueue/QueueTest.java index 8c7e0ed0f..f5f4b892b 100644 --- a/logstash-core/src/test/java/org/logstash/ackedqueue/QueueTest.java +++ b/logstash-core/src/test/java/org/logstash/ackedqueue/QueueTest.java @@ -38,6 +38,8 @@ import java.util.concurrent.Future; import java.util.concurrent.TimeUnit; import java.util.concurrent.TimeoutException; import java.util.concurrent.atomic.AtomicInteger; + +import org.hamcrest.CoreMatchers; import org.junit.After; import org.junit.Before; import org.junit.Rule; @@ -1043,4 +1045,23 @@ public class QueueTest { queue.open(); } } + + @Test + public void lockIsReleasedUponOpenException() throws Exception { + Settings settings = SettingsImpl.builder(TestSettings.persistedQueueSettings(100, dataPath)) + .queueMaxBytes(Long.MAX_VALUE) + .build(); + try { + Queue queue = new Queue(settings); + queue.open(); + fail("expected queue.open() to throws when not enough disk free"); + } catch (IOException e) { + assertThat(e.getMessage(), CoreMatchers.containsString("Unable to allocate")); + } + + // at this point the Queue lock should be released and Queue.open should not throw a LockException + try (Queue queue = new Queue(TestSettings.persistedQueueSettings(10, dataPath))) { + queue.open(); + } + } } From 40a807d4e627795d5293180fbfa2ed43796cc628 Mon Sep 17 00:00:00 2001 From: Colin Surprenant Date: Wed, 17 Jun 2020 17:22:30 -0400 Subject: [PATCH 0530/1126] do not call agent.converge_state_and_update before agent.execute --- logstash-core/lib/logstash/agent.rb | 12 ++++++++++++ x-pack/lib/monitoring/internal_pipeline_source.rb | 4 ++-- 2 files changed, 14 insertions(+), 2 deletions(-) diff --git a/logstash-core/lib/logstash/agent.rb b/logstash-core/lib/logstash/agent.rb index d8725146f..3042f58a8 100644 --- a/logstash-core/lib/logstash/agent.rb +++ b/logstash-core/lib/logstash/agent.rb @@ -162,6 +162,18 @@ class LogStash::Agent @running.false? end + # Only call converge_state_and_update if agent is running + # to avoid a double call to converge_state_and_update since + # agent.execute will call converge_state_and_update itself + def converge_state_and_update_if_running + converge_state_and_update if running? + end + + # Trigger convergence of pipelines + # NOTE that there is no point of calling this method before + # Agent#execute has been called since it will itself call + # converge_state_and_update and will result in a double + # convergence. def converge_state_and_update results = @source_loader.fetch diff --git a/x-pack/lib/monitoring/internal_pipeline_source.rb b/x-pack/lib/monitoring/internal_pipeline_source.rb index 256e1c07d..3c24b1423 100644 --- a/x-pack/lib/monitoring/internal_pipeline_source.rb +++ b/x-pack/lib/monitoring/internal_pipeline_source.rb @@ -35,7 +35,7 @@ module LogStash module Monitoring super(xpack_info) if xpack_info if valid_basic_license? logger.info("Validated license for monitoring. Enabling monitoring pipeline.") - enable_monitoring() + enable_monitoring end end @@ -45,7 +45,7 @@ module LogStash module Monitoring end def enable_monitoring - @agent.converge_state_and_update + @agent.converge_state_and_update_if_running end def populate_license_state(xpack_info) From e01c66c9bdd874296937144535b5f3c5167311b2 Mon Sep 17 00:00:00 2001 From: Ry Biesemeyer Date: Wed, 24 Jun 2020 00:15:09 +0000 Subject: [PATCH 0531/1126] JEE: nix global compiler lock by normalizing to Dataset interface Generated implementations of `Dataset` often have fields referencing other specifically-generated `Dataset`, despite only using public methods (`compute` and `clear`) defined on the `Dataset` interface. By allowing the code generation to reference the interface instead of the specific implementation, we eliminate the need for the compiler to chain parent class loaders indefinitely, thereby eliminating the need for a global mutual exclusion when compiling. This change moves the locking semantics from the compiler to the non-evicting cache itself, relying on tried-and-true `ConcurrentHashMap#computeIfAbsent` to minimize synchronization and cache-priming stampedes. This also vastly reduces the scope of `Dataset` implementations that we need to generate, because datasets will no longer need to reference the specific implementation details of all "downstream" datasets and will therefore be more likely to match an implementation that has already been compiled and cached. --- .../ir/compiler/ComputeStepSyntaxElement.java | 63 +++++++++---------- .../ir/compiler/VariableDefinition.java | 2 + 2 files changed, 33 insertions(+), 32 deletions(-) diff --git a/logstash-core/src/main/java/org/logstash/config/ir/compiler/ComputeStepSyntaxElement.java b/logstash-core/src/main/java/org/logstash/config/ir/compiler/ComputeStepSyntaxElement.java index 58353aa25..298d711b3 100644 --- a/logstash-core/src/main/java/org/logstash/config/ir/compiler/ComputeStepSyntaxElement.java +++ b/logstash-core/src/main/java/org/logstash/config/ir/compiler/ComputeStepSyntaxElement.java @@ -32,6 +32,8 @@ import java.nio.file.Paths; import java.util.Arrays; import java.util.HashMap; import java.util.Map; +import java.util.concurrent.ConcurrentHashMap; +import java.util.concurrent.atomic.AtomicLong; import java.util.regex.Pattern; import java.util.stream.Collectors; import java.util.stream.StreamSupport; @@ -50,14 +52,16 @@ public final class ComputeStepSyntaxElement { private static final Path SOURCE_DIR = debugDir(); - private static final ISimpleCompiler COMPILER = new SimpleCompiler(); + private static final ThreadLocal COMPILER = ThreadLocal.withInitial(SimpleCompiler::new); /** * Global cache of runtime compiled classes to prevent duplicate classes being compiled. * across pipelines and workers. */ - private static final Map, Class> CLASS_CACHE - = new HashMap<>(5000); + private static final ConcurrentHashMap, Class> CLASS_CACHE + = new ConcurrentHashMap<>(500); + + private static final AtomicLong DATASET_CLASS_INDEX = new AtomicLong(0); /** * Pattern to remove redundant {@code ;} from formatted code since {@link Formatter} does not @@ -125,39 +129,34 @@ public final class ComputeStepSyntaxElement { } } - /** - * This method is NOT thread-safe, and must have exclusive access to `COMPILER` - * so that the resulting `ClassLoader` after each `SimpleCompiler#cook()` operation - * can be teed up as the parent for the next cook operation. - * Also note that synchronizing on `COMPILER` also protects the global CLASS_CACHE. - */ - @SuppressWarnings("unchecked") + /* + * Returns a {@link Class} for this {@link ComputeStepSyntaxElement}, reusing an existing + * equivalent implementation from the global class cache when one is available, or otherwise compiling one. + * + * This method _is_ thread-safe, and uses the locking semantics of {@link ConcurrentHashMap#computeIfAbsent}. + * To do so, it relies on {@link #hashCode()} and {@link #equals(Object)}. + */ private Class compile() { - try { - synchronized (COMPILER) { - Class clazz = CLASS_CACHE.get(this); - if (clazz == null) { - final String name = String.format("CompiledDataset%d", CLASS_CACHE.size()); - final String code = CLASS_NAME_PLACEHOLDER_REGEX.matcher(normalizedSource).replaceAll(name); - if (SOURCE_DIR != null) { - final Path sourceFile = SOURCE_DIR.resolve(String.format("%s.java", name)); - Files.write(sourceFile, code.getBytes(StandardCharsets.UTF_8)); - COMPILER.cookFile(sourceFile.toFile()); - } else { - COMPILER.cook(code); - } - COMPILER.setParentClassLoader(COMPILER.getClassLoader()); - clazz = (Class) COMPILER.getClassLoader().loadClass( - String.format("org.logstash.generated.%s", name) - ); - CLASS_CACHE.put(this, clazz); + return CLASS_CACHE.computeIfAbsent(this, (__)->{ + try { + final ISimpleCompiler compiler = COMPILER.get(); + final String name = String.format("CompiledDataset%d", DATASET_CLASS_INDEX.incrementAndGet()); + final String code = CLASS_NAME_PLACEHOLDER_REGEX.matcher(normalizedSource).replaceAll(name); + if (SOURCE_DIR != null) { + final Path sourceFile = SOURCE_DIR.resolve(String.format("%s.java", name)); + Files.write(sourceFile, code.getBytes(StandardCharsets.UTF_8)); + compiler.cookFile(sourceFile.toFile()); + } else { + compiler.cook(code); } - return clazz; + return (Class) compiler.getClassLoader().loadClass( + String.format("org.logstash.generated.%s", name) + ); + } catch (final CompileException | ClassNotFoundException | IOException ex) { + throw new IllegalStateException(ex); } - } catch (final CompileException | ClassNotFoundException | IOException ex) { - throw new IllegalStateException(ex); - } + }); } @Override diff --git a/logstash-core/src/main/java/org/logstash/config/ir/compiler/VariableDefinition.java b/logstash-core/src/main/java/org/logstash/config/ir/compiler/VariableDefinition.java index e6644cca6..4219ac8e4 100644 --- a/logstash-core/src/main/java/org/logstash/config/ir/compiler/VariableDefinition.java +++ b/logstash-core/src/main/java/org/logstash/config/ir/compiler/VariableDefinition.java @@ -72,6 +72,8 @@ final class VariableDefinition implements SyntaxElement { safe = EventCondition.class; } else if (DynamicMethod.class.isAssignableFrom(clazz)) { safe = DynamicMethod.class; + } else if (Dataset.class.isAssignableFrom(clazz)) { + safe = Dataset.class; } else { safe = clazz; } From 1413c62c48ff792b528df04ce5c907d0414fcccc Mon Sep 17 00:00:00 2001 From: Joao Duarte Date: Tue, 30 Jun 2020 11:57:55 +0100 Subject: [PATCH 0532/1126] reduce Compiler Cache size to 100 The reduction from 500 to 100 is based on observations where 06d7f01fd reduced the number of generated classes by about an order of magnitude especially on very large pipelines (e.g. from ~600 to ~30). --- .../logstash/config/ir/compiler/ComputeStepSyntaxElement.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/logstash-core/src/main/java/org/logstash/config/ir/compiler/ComputeStepSyntaxElement.java b/logstash-core/src/main/java/org/logstash/config/ir/compiler/ComputeStepSyntaxElement.java index 298d711b3..9de1b8d18 100644 --- a/logstash-core/src/main/java/org/logstash/config/ir/compiler/ComputeStepSyntaxElement.java +++ b/logstash-core/src/main/java/org/logstash/config/ir/compiler/ComputeStepSyntaxElement.java @@ -59,7 +59,7 @@ public final class ComputeStepSyntaxElement { * across pipelines and workers. */ private static final ConcurrentHashMap, Class> CLASS_CACHE - = new ConcurrentHashMap<>(500); + = new ConcurrentHashMap<>(100); private static final AtomicLong DATASET_CLASS_INDEX = new AtomicLong(0); From 3a5f6860a705fcb5e17dd2c8ba219e41ed00b769 Mon Sep 17 00:00:00 2001 From: Joao Duarte Date: Tue, 30 Jun 2020 12:06:40 +0100 Subject: [PATCH 0533/1126] fix tests related to compiler cache due to reduced class generation --- .../logstash/config/ir/compiler/ComputeStepSyntaxElement.java | 1 - .../java/org/logstash/config/ir/CompiledPipelineTest.java | 4 ++-- 2 files changed, 2 insertions(+), 3 deletions(-) diff --git a/logstash-core/src/main/java/org/logstash/config/ir/compiler/ComputeStepSyntaxElement.java b/logstash-core/src/main/java/org/logstash/config/ir/compiler/ComputeStepSyntaxElement.java index 9de1b8d18..42541f2a5 100644 --- a/logstash-core/src/main/java/org/logstash/config/ir/compiler/ComputeStepSyntaxElement.java +++ b/logstash-core/src/main/java/org/logstash/config/ir/compiler/ComputeStepSyntaxElement.java @@ -101,7 +101,6 @@ public final class ComputeStepSyntaxElement { public static void cleanClassCache() { synchronized (COMPILER) { CLASS_CACHE.clear(); - COMPILER.setParentClassLoader(null); } } diff --git a/logstash-core/src/test/java/org/logstash/config/ir/CompiledPipelineTest.java b/logstash-core/src/test/java/org/logstash/config/ir/CompiledPipelineTest.java index 11417de37..d4851926f 100644 --- a/logstash-core/src/test/java/org/logstash/config/ir/CompiledPipelineTest.java +++ b/logstash-core/src/test/java/org/logstash/config/ir/CompiledPipelineTest.java @@ -615,12 +615,12 @@ public final class CompiledPipelineTest extends RubyEnvTestCase { final CompiledPipeline testCompiledPipeline = new CompiledPipeline(testPipelineIR, pluginFactory); - final long compilationBaseline = time(ChronoUnit.SECONDS, () -> { + final long compilationBaseline = time(ChronoUnit.MILLIS, () -> { final CompiledPipeline.CompiledExecution compiledExecution = baselineCompiledPipeline.buildExecution(); compiledExecution.compute(RubyUtil.RUBY.newArray(testEvent), false, false); }); - final long compilationTest = time(ChronoUnit.SECONDS, () -> { + final long compilationTest = time(ChronoUnit.MILLIS, () -> { final CompiledPipeline.CompiledExecution compiledExecution = testCompiledPipeline.buildExecution(); compiledExecution.compute(RubyUtil.RUBY.newArray(testEvent), false, false); }); From bf7041fa28212c68452bec86676ff1a7d0033992 Mon Sep 17 00:00:00 2001 From: Joao Duarte Date: Tue, 30 Jun 2020 12:15:04 +0100 Subject: [PATCH 0534/1126] test improved cache reuse during generation --- .../config/ir/CompiledPipelineTest.java | 37 +++++++- .../ir/cache/pipeline_reuse_baseline.conf | 31 +++++++ .../config/ir/cache/pipeline_reuse_test.conf | 84 +++++++++++++++++++ 3 files changed, 151 insertions(+), 1 deletion(-) create mode 100644 logstash-core/src/test/resources/org/logstash/config/ir/cache/pipeline_reuse_baseline.conf create mode 100644 logstash-core/src/test/resources/org/logstash/config/ir/cache/pipeline_reuse_test.conf diff --git a/logstash-core/src/test/java/org/logstash/config/ir/CompiledPipelineTest.java b/logstash-core/src/test/java/org/logstash/config/ir/CompiledPipelineTest.java index d4851926f..0ac719527 100644 --- a/logstash-core/src/test/java/org/logstash/config/ir/CompiledPipelineTest.java +++ b/logstash-core/src/test/java/org/logstash/config/ir/CompiledPipelineTest.java @@ -586,7 +586,7 @@ public final class CompiledPipelineTest extends RubyEnvTestCase { IRHelpers.toSourceWithMetadataFromPath("org/logstash/config/ir/cache/pipeline2.conf"), false); final CompiledPipeline cPipelineWithDifferentId = new CompiledPipeline(pipelineWithDifferentId, pluginFactory); - + // actual test: compiling a pipeline with an extra filter should only create 1 extra class ComputeStepSyntaxElement.cleanClassCache(); cBaselinePipeline.buildExecution(); @@ -598,6 +598,41 @@ public final class CompiledPipelineTest extends RubyEnvTestCase { assertEquals(message, 0, cachedAfter - cachedBefore); } + @Test + @SuppressWarnings({"unchecked"}) + public void testReuseCompiledClasses() throws IOException, InvalidIRException { + final FixedPluginFactory pluginFactory = new FixedPluginFactory( + () -> null, + () -> IDENTITY_FILTER, + mockOutputSupplier() + ); + + // this pipeline generates 10 classes + // - 7 for the filters for the nested and leaf Datasets + // - 3 for the sequence of outputs with a conditional + final PipelineIR baselinePipeline = ConfigCompiler.configToPipelineIR( + IRHelpers.toSourceWithMetadataFromPath("org/logstash/config/ir/cache/pipeline_reuse_baseline.conf"), + false); + final CompiledPipeline cBaselinePipeline = new CompiledPipeline(baselinePipeline, pluginFactory); + + // this pipeline is much bigger than the baseline + // but is carefully crafted to reuse the same classes as the baseline pipeline + final PipelineIR pipelineTwiceAsBig = ConfigCompiler.configToPipelineIR( + IRHelpers.toSourceWithMetadataFromPath("org/logstash/config/ir/cache/pipeline_reuse_test.conf"), + false); + final CompiledPipeline cPipelineTwiceAsBig = new CompiledPipeline(pipelineTwiceAsBig, pluginFactory); + + // test: compiling a much bigger pipeline and asserting no additional classes are generated + ComputeStepSyntaxElement.cleanClassCache(); + cBaselinePipeline.buildExecution(); + final int cachedBefore = ComputeStepSyntaxElement.classCacheSize(); + cPipelineTwiceAsBig.buildExecution(); + final int cachedAfter = ComputeStepSyntaxElement.classCacheSize(); + + final String message = String.format("unexpected cache size, cachedAfter: %d, cachedBefore: %d", cachedAfter, cachedBefore); + assertEquals(message, 0, cachedAfter - cachedBefore); + } + @Test @SuppressWarnings({"unchecked", "rawtypes"}) public void compilerBenchmark() throws Exception { diff --git a/logstash-core/src/test/resources/org/logstash/config/ir/cache/pipeline_reuse_baseline.conf b/logstash-core/src/test/resources/org/logstash/config/ir/cache/pipeline_reuse_baseline.conf new file mode 100644 index 000000000..4aa09f7dc --- /dev/null +++ b/logstash-core/src/test/resources/org/logstash/config/ir/cache/pipeline_reuse_baseline.conf @@ -0,0 +1,31 @@ +input { + stdin { } +} + +filter { + if [a] { + noop {} + if [a] { noop {} } + } + if [a] { + if [a] { + noop {} + if [a] { noop {} } + if [a] { noop {} } + } + } + if [a] { + if [a] { + if [a] { + noop {} + if [a] { noop {} } + } + } + } +} +output { + if [a] { noop {} } + stdout {} + stdout {} + stdout {} +} diff --git a/logstash-core/src/test/resources/org/logstash/config/ir/cache/pipeline_reuse_test.conf b/logstash-core/src/test/resources/org/logstash/config/ir/cache/pipeline_reuse_test.conf new file mode 100644 index 000000000..e4477feb8 --- /dev/null +++ b/logstash-core/src/test/resources/org/logstash/config/ir/cache/pipeline_reuse_test.conf @@ -0,0 +1,84 @@ +input { + stdin { } + stdin { } + stdin { } + stdin { } + stdin { } +} + +filter { + if [a] { + noop {} + if [a] { noop {} } + if [a] { noop {} } + if [a] { noop {} } + if [a] { noop {} } + if [a] { noop {} } + } + if [a] { + noop {} + noop {} + noop {} + if [a] { noop {} } + if [a] { noop {} } + if [a] { noop {} } + if [a] { noop {} } + } + if [a] { + noop {} + if [a] { noop {} } + } + if [a] { + if [a] { + noop {} + if [a] { noop {} } + } + } + if [a] { + if [a] { + noop {} + if [a] { noop {} } + } + } + if [a] { + if [a] { + noop {} + if [a] { noop {} } + } + if [a] { + noop {} + if [a] { noop {} } + } + } + if [a] { + if [a] { + noop {} + if [a] { noop {} } + if [a] { noop {} } + if [a] { noop {} } + } + } + if [a] { + if [a] { + if [a] { + noop {} + if [a] { noop {} } + if [a] { noop {} } + if [a] { noop {} } + } + } + } +} +output { + if [a] { + noop {} + } else { + noop {} + } + if [a] { + noop {} + } else { + noop {} + } +} + From 29d7dcef941ad11822bcc64d21d656e4618d2aed Mon Sep 17 00:00:00 2001 From: Joao Duarte Date: Fri, 5 Jun 2020 15:50:54 +0100 Subject: [PATCH 0535/1126] remove need for extra ShutdownWatcher thread The creation of a Ruby thread from Java seems to be a trigger for jruby/jruby#6207. Pipeline#shutdown now blocks on the ShutdownWatcher#start, which will wait for pipeline.finished_execution? to be true. This removes the need for the pattern: `pipeline.shutdown { block } && pipeline.thread.join` And can be replaced with just `pipeline.shutdown` To avoid having `shutdown` blocked waiting for ready? when pipeline crashes too quickly, this method returns immediately if finished_execution? is true. Most uses of pipeline#run have also been replaced by pipeline#start since the latter will block until the pipeline is ready, again avoiding the pattern: `pipeline.run && sleep 0.1 until pipeline.ready?` Pipeline tests have been changed according to these two changes. Co-authored-by: Ry Biesemeyer --- logstash-core/lib/logstash/java_pipeline.rb | 19 ++-- logstash-core/lib/logstash/pipeline.rb | 22 ++--- .../lib/logstash/pipeline_action/reload.rb | 3 +- .../lib/logstash/pipeline_action/stop.rb | 3 +- .../spec/logstash/java_pipeline_spec.rb | 87 +++++-------------- .../spec/logstash/pipeline_dlq_commit_spec.rb | 6 +- .../spec/logstash/pipeline_pq_file_spec.rb | 10 +-- .../spec/logstash/pipeline_reporter_spec.rb | 17 ++-- logstash-core/spec/logstash/pipeline_spec.rb | 37 +++----- .../spec/logstash/shutdown_watcher_spec.rb | 2 +- .../execution/ShutdownWatcherExt.java | 15 +--- .../execution/ShutdownWatcherExtTest.java | 3 + 12 files changed, 67 insertions(+), 157 deletions(-) diff --git a/logstash-core/lib/logstash/java_pipeline.rb b/logstash-core/lib/logstash/java_pipeline.rb index a0b4f582c..c44a81f72 100644 --- a/logstash-core/lib/logstash/java_pipeline.rb +++ b/logstash-core/lib/logstash/java_pipeline.rb @@ -378,30 +378,23 @@ module LogStash; class JavaPipeline < JavaBasePipeline # initiate the pipeline shutdown sequence # this method is intended to be called from outside the pipeline thread - # @param before_stop [Proc] code block called before performing stop operation on input plugins - def shutdown(&before_stop) + # and will block until the pipeline has successfully shut down. + def shutdown + return if finished_execution? # shutdown can only start once the pipeline has completed its startup. # avoid potential race condition between the startup sequence and this # shutdown method which can be called from another thread at any time sleep(0.1) while !ready? # TODO: should we also check against calling shutdown multiple times concurrently? - - before_stop.call if block_given? - stop_inputs - - # We make this call blocking, so we know for sure when the method return the shutdown is - # stopped - wait_for_workers + wait_for_shutdown clear_pipeline_metrics @logger.info("Pipeline terminated", "pipeline.id" => pipeline_id) end # def shutdown - def wait_for_workers - @logger.debug("Closing inputs", default_logging_keys) - @worker_threads.map(&:join) - @logger.debug("Worker closed", default_logging_keys) + def wait_for_shutdown + ShutdownWatcher.new(self).start end def stop_inputs diff --git a/logstash-core/lib/logstash/pipeline.rb b/logstash-core/lib/logstash/pipeline.rb index 3afc80677..30d1663d1 100644 --- a/logstash-core/lib/logstash/pipeline.rb +++ b/logstash-core/lib/logstash/pipeline.rb @@ -501,30 +501,22 @@ module LogStash; class Pipeline < BasePipeline # initiate the pipeline shutdown sequence # this method is intended to be called from outside the pipeline thread - # @param before_stop [Proc] code block called before performing stop operation on input plugins - def shutdown(&before_stop) + # and will block until the pipeline has successfully shut down. + def shutdown + return if finished_execution? + # shutdown can only start once the pipeline has completed its startup. # avoid potential race condition between the startup sequence and this # shutdown method which can be called from another thread at any time sleep(0.1) while !ready? - # TODO: should we also check against calling shutdown multiple times concurrently? - - before_stop.call if block_given? - stop_inputs - - # We make this call blocking, so we know for sure when the method return the shutdown is - # stopped - wait_for_workers + wait_for_shutdown clear_pipeline_metrics end # def shutdown - def wait_for_workers - @worker_threads.each do |t| - t.join - @logger.debug("Worker terminated", default_logging_keys(:thread => t.inspect)) - end + def wait_for_shutdown + ShutdownWatcher.new(self).start end def stop_inputs diff --git a/logstash-core/lib/logstash/pipeline_action/reload.rb b/logstash-core/lib/logstash/pipeline_action/reload.rb index 4dc9bc77c..56e430914 100644 --- a/logstash-core/lib/logstash/pipeline_action/reload.rb +++ b/logstash-core/lib/logstash/pipeline_action/reload.rb @@ -66,8 +66,7 @@ module LogStash module PipelineAction # the block must emit a success boolean value # First shutdown old pipeline - old_pipeline.shutdown { LogStash::ShutdownWatcher.start(old_pipeline) } - old_pipeline.thread.join + old_pipeline.shutdown # Then create a new pipeline new_pipeline = java_exec ? LogStash::JavaPipeline.new(@pipeline_config, @metric, agent) : LogStash::Pipeline.new(@pipeline_config, @metric, agent) diff --git a/logstash-core/lib/logstash/pipeline_action/stop.rb b/logstash-core/lib/logstash/pipeline_action/stop.rb index 50d6367fa..be631e54c 100644 --- a/logstash-core/lib/logstash/pipeline_action/stop.rb +++ b/logstash-core/lib/logstash/pipeline_action/stop.rb @@ -27,8 +27,7 @@ module LogStash module PipelineAction def execute(agent, pipelines_registry) pipelines_registry.terminate_pipeline(pipeline_id) do |pipeline| - pipeline.shutdown { LogStash::ShutdownWatcher.start(pipeline) } - pipeline.thread.join + pipeline.shutdown end LogStash::ConvergeResult::SuccessfulAction.new diff --git a/logstash-core/spec/logstash/java_pipeline_spec.rb b/logstash-core/spec/logstash/java_pipeline_spec.rb index a82a63460..430d51a65 100644 --- a/logstash-core/spec/logstash/java_pipeline_spec.rb +++ b/logstash-core/spec/logstash/java_pipeline_spec.rb @@ -212,22 +212,15 @@ describe LogStash::JavaPipeline do Thread.abort_on_exception = true pipeline = mock_java_pipeline_from_string(config, pipeline_settings_obj) - t = Thread.new { pipeline.run } Timeout.timeout(timeout) do - sleep(0.1) until pipeline.ready? - end - Stud.try(max_retry.times, [StandardError, RSpec::Expectations::ExpectationNotMetError]) do - wait(3).for do - # give us a bit of time to flush the events - # puts("*****" + output.events.map{|e| e.message}.to_s) - output.events.map{|e| e.get("message")}.include?("END") - end.to be_truthy + pipeline.start + sleep 0.01 until pipeline.stopped? end + pipeline.shutdown + expect(output.events.map{|e| e.get("message")}).to include("END") expect(output.events.size).to eq(2) expect(output.events[0].get("tags")).to eq(["notdropped"]) expect(output.events[1].get("tags")).to eq(["notdropped"]) - pipeline.shutdown - t.join Thread.abort_on_exception = abort_on_exception_state end @@ -289,7 +282,7 @@ describe LogStash::JavaPipeline do pipeline = mock_java_pipeline_from_string(test_config_with_filters) expect(pipeline.logger).to receive(:warn).with(msg, hash_including({:count_was=>worker_thread_count, :filters=>["dummyfilter"]})) - pipeline.run + pipeline.start expect(pipeline.worker_threads.size).to eq(safe_thread_count) pipeline.shutdown end @@ -302,7 +295,7 @@ describe LogStash::JavaPipeline do " not work with multiple worker threads" pipeline = mock_java_pipeline_from_string(test_config_with_filters, pipeline_settings_obj) expect(pipeline.logger).to receive(:warn).with(msg, hash_including({:worker_threads=> override_thread_count, :filters=>["dummyfilter"]})) - pipeline.run + pipeline.start expect(pipeline.worker_threads.size).to eq(override_thread_count) pipeline.shutdown end @@ -329,7 +322,7 @@ describe LogStash::JavaPipeline do it "starts multiple filter threads" do skip("This test has been failing periodically since November 2016. Tracked as https://github.com/elastic/logstash/issues/6245") pipeline = mock_java_pipeline_from_string(test_config_with_filters) - pipeline.run + pipeline.start expect(pipeline.worker_threads.size).to eq(worker_thread_count) pipeline.shutdown end @@ -374,18 +367,10 @@ describe LogStash::JavaPipeline do let(:pipeline) { mock_java_pipeline_from_string(test_config_without_output_workers) } let(:output) { pipeline.outputs.first } - before do - allow(output).to receive(:do_close) - end - - after do - pipeline.shutdown - end - it "should call close of output without output-workers" do - pipeline.run - - expect(output).to have_received(:do_close).once + expect(output).to receive(:do_close).once + pipeline.start + pipeline.shutdown end end end @@ -433,7 +418,7 @@ describe LogStash::JavaPipeline do expect(pipeline).to receive(:transition_to_running).ordered.and_call_original expect(pipeline).to receive(:start_flusher).ordered.and_call_original - pipeline.run + pipeline.start pipeline.shutdown end end @@ -604,15 +589,10 @@ describe LogStash::JavaPipeline do allow(LogStash::Plugin).to receive(:lookup).with("output", "dummyoutput").and_return(::LogStash::Outputs::DummyOutput) allow(logger).to receive(:warn) - # pipeline must be first called outside the thread context because it lazily initialize and will create a - # race condition if called in the thread - p = pipeline - t = Thread.new { p.run } - Timeout.timeout(timeout) do - sleep(0.1) until pipeline.ready? - end + pipeline.start + # the only input auto-closes, so the pipeline will automatically stop. + sleep(0.01) until pipeline.stopped? pipeline.shutdown - t.join end it "should not raise a max inflight warning if the max_inflight count isn't exceeded" do @@ -778,9 +758,8 @@ describe LogStash::JavaPipeline do it "flush periodically" do Thread.abort_on_exception = true pipeline = mock_java_pipeline_from_string(config, pipeline_settings_obj) - t = Thread.new { pipeline.run } Timeout.timeout(timeout) do - sleep(0.1) until pipeline.ready? + pipeline.start end Stud.try(max_retry.times, [StandardError, RSpec::Expectations::ExpectationNotMetError]) do wait(10).for do @@ -792,8 +771,6 @@ describe LogStash::JavaPipeline do expect(output.events.any? {|e| e.get("message") == "dummy_flush"}).to eq(true) pipeline.shutdown - - t.join end end @@ -824,9 +801,8 @@ describe LogStash::JavaPipeline do it "flush periodically without error on nil flush return" do Thread.abort_on_exception = true pipeline = mock_java_pipeline_from_string(config, pipeline_settings_obj) - t = Thread.new { pipeline.run } Timeout.timeout(timeout) do - sleep(0.1) until pipeline.ready? + pipeline.start end Stud.try(max_retry.times, [StandardError, RSpec::Expectations::ExpectationNotMetError]) do wait(10).for do @@ -838,8 +814,6 @@ describe LogStash::JavaPipeline do expect(output.events.any? {|e| e.get("message") == "dummy_flush"}).to eq(true) pipeline.shutdown - - t.join end end @@ -877,9 +851,8 @@ describe LogStash::JavaPipeline do it "flush periodically" do Thread.abort_on_exception = true pipeline = mock_java_pipeline_from_string(config, pipeline_settings_obj) - t = Thread.new { pipeline.run } Timeout.timeout(timeout) do - sleep(0.1) until pipeline.ready? + pipeline.start end Stud.try(max_retry.times, [StandardError, RSpec::Expectations::ExpectationNotMetError]) do wait(11).for do @@ -891,8 +864,6 @@ describe LogStash::JavaPipeline do expect(output.events.any? {|e| e.get("message") == "dummy_flush"}).to eq(true) pipeline.shutdown - - t.join end end @@ -931,7 +902,7 @@ describe LogStash::JavaPipeline do it "correctly distributes events" do pipeline = mock_java_pipeline_from_string(config, pipeline_settings_obj) - pipeline.run + pipeline.start pipeline.shutdown expect(output.events.size).to eq(60) expect(output.events.count {|e| e.get("cloned") == "cloned"}).to eq(30) @@ -961,7 +932,7 @@ describe LogStash::JavaPipeline do end it "return when the pipeline started working" do - subject.run + subject.start expect(subject.started_at).to be < Time.now subject.shutdown end @@ -989,18 +960,12 @@ describe LogStash::JavaPipeline do context "when the pipeline is started" do it "return the duration in milliseconds" do - # subject must be first call outside the thread context because of lazy initialization - s = subject - t = Thread.new { s.run } Timeout.timeout(timeout) do - sleep(0.1) until subject.ready? - end - Timeout.timeout(timeout) do - sleep(0.1) + subject.start end + sleep(0.1) expect(subject.uptime).to be > 0 subject.shutdown - t.join end end end @@ -1042,12 +1007,6 @@ describe LogStash::JavaPipeline do end let(:dummyoutput) { ::LogStash::Outputs::DummyOutput.new({ "id" => dummy_output_id }) } let(:metric_store) { subject.metric.collector.snapshot_metric.metric_store } - let(:pipeline_thread) do - # subject has to be called for the first time outside the thread because it will create a race condition - # with the subject.ready? call since subject is lazily initialized - s = subject - Thread.new { s.run } - end before :each do allow(::LogStash::Outputs::DummyOutput).to receive(:new).with(any_args).and_return(dummyoutput) @@ -1056,9 +1015,8 @@ describe LogStash::JavaPipeline do allow(LogStash::Plugin).to receive(:lookup).with("filter", "dummyfilter").and_return(LogStash::Filters::DummyFilter) allow(LogStash::Plugin).to receive(:lookup).with("output", "dummyoutput").and_return(::LogStash::Outputs::DummyOutput) - pipeline_thread Timeout.timeout(timeout) do - sleep(0.1) until subject.ready? + subject.start end # make sure we have received all the generated events @@ -1072,7 +1030,6 @@ describe LogStash::JavaPipeline do after :each do subject.shutdown - pipeline_thread.join end context "global metric" do diff --git a/logstash-core/spec/logstash/pipeline_dlq_commit_spec.rb b/logstash-core/spec/logstash/pipeline_dlq_commit_spec.rb index 03fdaeabc..15ae5459b 100644 --- a/logstash-core/spec/logstash/pipeline_dlq_commit_spec.rb +++ b/logstash-core/spec/logstash/pipeline_dlq_commit_spec.rb @@ -92,13 +92,13 @@ describe LogStash::Pipeline do it "retrieves proper pipeline-level DLQ writer" do expect_any_instance_of(org.logstash.common.io.DeadLetterQueueWriter).to receive(:close).and_call_original - subject.run + subject.start + subject.shutdown dlq_path = java.nio.file.Paths.get(pipeline_settings_obj.get("path.dead_letter_queue"), pipeline_id) dlq_reader = org.logstash.common.io.DeadLetterQueueReader.new(dlq_path) entry = dlq_reader.pollEntry(40) expect(entry).to_not be_nil expect(entry.reason).to eq("my reason") - subject.shutdown end end @@ -109,7 +109,7 @@ describe LogStash::Pipeline do it "does not write to the DLQ" do expect(LogStash::Util::DummyDeadLetterQueueWriter).to receive(:new).and_call_original expect_any_instance_of(LogStash::Util::DummyDeadLetterQueueWriter).to receive(:close).and_call_original - subject.run + subject.start dlq_path = java.nio.file.Paths.get(pipeline_settings_obj.get("path.dead_letter_queue"), pipeline_id) expect(java.nio.file.Files.exists(dlq_path)).to eq(false) subject.shutdown diff --git a/logstash-core/spec/logstash/pipeline_pq_file_spec.rb b/logstash-core/spec/logstash/pipeline_pq_file_spec.rb index 3c18176cc..e82da96fb 100644 --- a/logstash-core/spec/logstash/pipeline_pq_file_spec.rb +++ b/logstash-core/spec/logstash/pipeline_pq_file_spec.rb @@ -100,13 +100,6 @@ describe LogStash::Pipeline do let(:max_bytes) { 1024 * 1024 * 1024 } # 1 gb let(:times) { [] } - let(:pipeline_thread) do - # subject has to be called for the first time outside the thread because it will create a race condition - # with the subject.ready? call since subject is lazily initialized - s = subject - Thread.new { s.run } - end - let(:collected_metric) { metric_store.get_with_path("stats/pipelines/") } before :each do @@ -126,7 +119,7 @@ describe LogStash::Pipeline do pipeline_settings_obj.set("queue.max_bytes", max_bytes) times.push(Time.now.to_f) - pipeline_thread + subject.start sleep(0.1) until subject.ready? # make sure we have received all the generated events @@ -139,7 +132,6 @@ describe LogStash::Pipeline do after :each do subject.shutdown - pipeline_thread.join # Dir.rm_rf(this_queue_folder) end diff --git a/logstash-core/spec/logstash/pipeline_reporter_spec.rb b/logstash-core/spec/logstash/pipeline_reporter_spec.rb index 54a865d59..e2590a94d 100644 --- a/logstash-core/spec/logstash/pipeline_reporter_spec.rb +++ b/logstash-core/spec/logstash/pipeline_reporter_spec.rb @@ -37,12 +37,11 @@ shared_examples "a pipeline reporter" do |pipeline_setup| @pre_snapshot = reporter.snapshot - pipeline.run - @post_snapshot = reporter.snapshot - end - - after do + pipeline.start + # wait for stopped? so the input can produce all events + sleep 0.01 until pipeline.stopped? pipeline.shutdown + @post_snapshot = reporter.snapshot end describe "stalling threads info" do @@ -87,6 +86,10 @@ shared_examples "a pipeline reporter" do |pipeline_setup| end describe LogStash::PipelineReporter do - it_behaves_like "a pipeline reporter", :mock_pipeline_from_string - it_behaves_like "a pipeline reporter", :mock_java_pipeline_from_string + context "with ruby execution" do + it_behaves_like "a pipeline reporter", :mock_pipeline_from_string + end + context "with java execution" do + it_behaves_like "a pipeline reporter", :mock_java_pipeline_from_string + end end diff --git a/logstash-core/spec/logstash/pipeline_spec.rb b/logstash-core/spec/logstash/pipeline_spec.rb index d1058e762..2187b68a2 100644 --- a/logstash-core/spec/logstash/pipeline_spec.rb +++ b/logstash-core/spec/logstash/pipeline_spec.rb @@ -210,7 +210,7 @@ describe LogStash::Pipeline do Thread.abort_on_exception = true pipeline = mock_pipeline_from_string(config, pipeline_settings_obj) - t = Thread.new { pipeline.run } + pipeline.start Timeout.timeout(timeout) do sleep(0.1) until pipeline.ready? end @@ -225,7 +225,6 @@ describe LogStash::Pipeline do expect(output.events[0].get("tags")).to eq(["notdropped"]) expect(output.events[1].get("tags")).to eq(["notdropped"]) pipeline.shutdown - t.join Thread.abort_on_exception = abort_on_exception_state end @@ -305,7 +304,7 @@ describe LogStash::Pipeline do pipeline = mock_pipeline_from_string(test_config_with_filters) expect(pipeline.logger).to receive(:warn).with(msg, hash_including({:count_was=>worker_thread_count, :filters=>["dummyfilter"]})) - pipeline.run + pipeline.start expect(pipeline.worker_threads.size).to eq(safe_thread_count) pipeline.shutdown end @@ -318,7 +317,7 @@ describe LogStash::Pipeline do " not work with multiple worker threads" pipeline = mock_pipeline_from_string(test_config_with_filters, pipeline_settings_obj) expect(pipeline.logger).to receive(:warn).with(msg, hash_including({:worker_threads=> override_thread_count, :filters=>["dummyfilter"]})) - pipeline.run + pipeline.start expect(pipeline.worker_threads.size).to eq(override_thread_count) pipeline.shutdown end @@ -345,7 +344,7 @@ describe LogStash::Pipeline do it "starts multiple filter threads" do skip("This test has been failing periodically since November 2016. Tracked as https://github.com/elastic/logstash/issues/6245") pipeline = mock_pipeline_from_string(test_config_with_filters) - pipeline.run + pipeline.start expect(pipeline.worker_threads.size).to eq(worker_thread_count) pipeline.shutdown end @@ -399,7 +398,7 @@ describe LogStash::Pipeline do end it "should call close of output without output-workers" do - pipeline.run + pipeline.start expect(output).to have_received(:do_close).once end @@ -446,7 +445,7 @@ describe LogStash::Pipeline do expect(pipeline).to receive(:transition_to_running).ordered.and_call_original expect(pipeline).to receive(:start_flusher).ordered.and_call_original - pipeline.run + pipeline.start pipeline.shutdown end end @@ -493,13 +492,11 @@ describe LogStash::Pipeline do # pipeline must be first called outside the thread context because it lazily initialize and will create a # race condition if called in the thread - p = pipeline - t = Thread.new { p.run } + pipeline.start Timeout.timeout(timeout) do sleep(0.1) until pipeline.ready? end pipeline.shutdown - t.join end it "should not raise a max inflight warning if the max_inflight count isn't exceeded" do @@ -694,7 +691,7 @@ describe LogStash::Pipeline do it "flush periodically" do Thread.abort_on_exception = true pipeline = mock_pipeline_from_string(config, pipeline_settings_obj) - t = Thread.new { pipeline.run } + pipeline.start Timeout.timeout(timeout) do sleep(0.1) until pipeline.ready? end @@ -708,8 +705,6 @@ describe LogStash::Pipeline do expect(output.events.any? {|e| e.get("message") == "dummy_flush"}).to eq(true) pipeline.shutdown - - t.join end end @@ -772,7 +767,7 @@ describe LogStash::Pipeline do end it "return when the pipeline started working" do - subject.run + subject.start expect(subject.started_at).to be < Time.now subject.shutdown end @@ -800,9 +795,7 @@ describe LogStash::Pipeline do context "when the pipeline is started" do it "return the duration in milliseconds" do - # subject must be first call outside the thread context because of lazy initialization - s = subject - t = Thread.new { s.run } + subject.start Timeout.timeout(timeout) do sleep(0.1) until subject.ready? end @@ -811,7 +804,6 @@ describe LogStash::Pipeline do end expect(subject.uptime).to be > 0 subject.shutdown - t.join end end end @@ -853,12 +845,6 @@ describe LogStash::Pipeline do end let(:dummyoutput) { ::LogStash::Outputs::DummyOutput.new({ "id" => dummy_output_id }) } let(:metric_store) { subject.metric.collector.snapshot_metric.metric_store } - let(:pipeline_thread) do - # subject has to be called for the first time outside the thread because it will create a race condition - # with the subject.ready? call since subject is lazily initialized - s = subject - Thread.new { s.run } - end before :each do allow(::LogStash::Outputs::DummyOutput).to receive(:new).with(any_args).and_return(dummyoutput) @@ -867,7 +853,7 @@ describe LogStash::Pipeline do allow(LogStash::Plugin).to receive(:lookup).with("filter", "dummyfilter").and_return(LogStash::Filters::DummyFilter) allow(LogStash::Plugin).to receive(:lookup).with("output", "dummyoutput").and_return(::LogStash::Outputs::DummyOutput) - pipeline_thread + subject.start Timeout.timeout(timeout) do sleep(0.1) until subject.ready? end @@ -883,7 +869,6 @@ describe LogStash::Pipeline do after :each do subject.shutdown - pipeline_thread.join end context "global metric" do diff --git a/logstash-core/spec/logstash/shutdown_watcher_spec.rb b/logstash-core/spec/logstash/shutdown_watcher_spec.rb index b563a798e..3196117f5 100644 --- a/logstash-core/spec/logstash/shutdown_watcher_spec.rb +++ b/logstash-core/spec/logstash/shutdown_watcher_spec.rb @@ -27,7 +27,7 @@ describe LogStash::ShutdownWatcher do before :each do allow(pipeline).to receive(:reporter).and_return(reporter) - allow(pipeline).to receive(:thread).and_return(Thread.current) + allow(pipeline).to receive(:finished_execution?).and_return(false) allow(reporter).to receive(:snapshot).and_return(reporter_snapshot) allow(reporter_snapshot).to receive(:o_simple_hash).and_return({}) end diff --git a/logstash-core/src/main/java/org/logstash/execution/ShutdownWatcherExt.java b/logstash-core/src/main/java/org/logstash/execution/ShutdownWatcherExt.java index adbafc4aa..12930b51a 100644 --- a/logstash-core/src/main/java/org/logstash/execution/ShutdownWatcherExt.java +++ b/logstash-core/src/main/java/org/logstash/execution/ShutdownWatcherExt.java @@ -60,18 +60,6 @@ public final class ShutdownWatcherExt extends RubyBasicObject { private IRubyObject pipeline; - @JRubyMethod(meta = true, required = 1, optional = 3) - public static RubyThread start(final ThreadContext context, final IRubyObject recv, final IRubyObject[] args) { - return new RubyThread(context.runtime, context.runtime.getThread(), () -> { - try { - new ShutdownWatcherExt(context.runtime, RubyUtil.SHUTDOWN_WATCHER_CLASS) - .initialize(context, args).start(context); - } catch (final InterruptedException ex) { - throw new IllegalStateException(ex); - } - }); - } - @JRubyMethod(name = "unsafe_shutdown?", meta = true) public static IRubyObject isUnsafeShutdown(final ThreadContext context, final IRubyObject recv) { @@ -164,8 +152,7 @@ public final class ShutdownWatcherExt extends RubyBasicObject { TimeUnit.SECONDS.sleep(cyclePeriod); attemptsCount.incrementAndGet(); if (stopped(context).isTrue() || - !pipeline.callMethod(context, "thread") - .callMethod(context, "alive?").isTrue()) { + pipeline.callMethod(context, "finished_execution?").isTrue()) { break; } reports.add(pipelineReportSnapshot(context)); diff --git a/logstash-core/src/test/java/org/logstash/execution/ShutdownWatcherExtTest.java b/logstash-core/src/test/java/org/logstash/execution/ShutdownWatcherExtTest.java index a48c8a8cb..8a22820b0 100644 --- a/logstash-core/src/test/java/org/logstash/execution/ShutdownWatcherExtTest.java +++ b/logstash-core/src/test/java/org/logstash/execution/ShutdownWatcherExtTest.java @@ -70,6 +70,9 @@ public final class ShutdownWatcherExtTest { "pipeline.define_singleton_method(:thread) do", "Thread.current", "end", + "pipeline.define_singleton_method(:finished_execution?) do", + "false", + "end", "pipeline.define_singleton_method(:reporter) do", "reporter", "end", From c4834e55ee2926ae899f8da7a778b1a8652bc5c4 Mon Sep 17 00:00:00 2001 From: Joao Duarte Date: Thu, 2 Jul 2020 09:47:22 +0100 Subject: [PATCH 0536/1126] ensure pipeline terminates execution before doing assertion This test relies on the generator input sending 10 events and observing the output. Calling shutdown immediately after start can cause the plugin to abort earily. This change waits for the execution to finish before performing the test assertions. --- logstash-core/spec/logstash/java_pipeline_spec.rb | 1 + 1 file changed, 1 insertion(+) diff --git a/logstash-core/spec/logstash/java_pipeline_spec.rb b/logstash-core/spec/logstash/java_pipeline_spec.rb index 430d51a65..68ad5c91a 100644 --- a/logstash-core/spec/logstash/java_pipeline_spec.rb +++ b/logstash-core/spec/logstash/java_pipeline_spec.rb @@ -903,6 +903,7 @@ describe LogStash::JavaPipeline do it "correctly distributes events" do pipeline = mock_java_pipeline_from_string(config, pipeline_settings_obj) pipeline.start + sleep 0.01 until pipeline.finished_execution? pipeline.shutdown expect(output.events.size).to eq(60) expect(output.events.count {|e| e.get("cloned") == "cloned"}).to eq(30) From 6f30d81c9d57ed1d8bd78c7168079665d3a32091 Mon Sep 17 00:00:00 2001 From: Joao Duarte Date: Thu, 2 Jul 2020 09:37:13 +0100 Subject: [PATCH 0537/1126] fix pipeline spec that didn't wait for pipeline to terminate this test only called "pipeline.start" and expected an output to receive the "do_close" method call. Therefore it relies on a race condition that the pipeline shuts down quickly enough, which could fail. This change ensures the pipeline fully terminated before making the assertion This commit also removes an unused let from the time when logstash output plugins had workers. --- logstash-core/spec/logstash/pipeline_spec.rb | 20 +------------------- 1 file changed, 1 insertion(+), 19 deletions(-) diff --git a/logstash-core/spec/logstash/pipeline_spec.rb b/logstash-core/spec/logstash/pipeline_spec.rb index 2187b68a2..a4561e237 100644 --- a/logstash-core/spec/logstash/pipeline_spec.rb +++ b/logstash-core/spec/logstash/pipeline_spec.rb @@ -371,20 +371,6 @@ describe LogStash::Pipeline do eos } - let(:test_config_with_output_workers) { - <<-eos - input { - dummyinput {} - } - - output { - dummyoutput { - workers => 2 - } - } - eos - } - context "output close" do let(:pipeline) { mock_pipeline_from_string(test_config_without_output_workers) } let(:output) { pipeline.outputs.first } @@ -393,13 +379,9 @@ describe LogStash::Pipeline do allow(output).to receive(:do_close) end - after do - pipeline.shutdown - end - it "should call close of output without output-workers" do pipeline.start - + pipeline.shutdown expect(output).to have_received(:do_close).once end end From 5a20843c8c580b527aefa691676593f4538951d9 Mon Sep 17 00:00:00 2001 From: Rob Bavey Date: Thu, 2 Jul 2020 11:35:45 -0400 Subject: [PATCH 0538/1126] [7x backport] Add wait functionality to `stop_es` integration test helper function (#12067) Integration tests may fail during elasticsearch teardown, as currently the stop_es function sends a `SIGTERM` to Elasticsearch, but does not wait for the process to exit. That can lead to issues when deleting data directories from a still running process. This commit adds wait functionality to `stop_es` to wait for a short period of time, sending a `SIGKILL` if Elasticsearch does not terminate in time. Clean backport of #12061 --- qa/integration/services/elasticsearch_teardown.sh | 15 ++++++++++++--- 1 file changed, 12 insertions(+), 3 deletions(-) diff --git a/qa/integration/services/elasticsearch_teardown.sh b/qa/integration/services/elasticsearch_teardown.sh index 516db893a..f14f44f18 100755 --- a/qa/integration/services/elasticsearch_teardown.sh +++ b/qa/integration/services/elasticsearch_teardown.sh @@ -7,9 +7,18 @@ source "$current_dir/helpers.sh" ES_HOME="$current_dir/../../../build/elasticsearch" stop_es() { - pid=$(cat $ES_HOME/elasticsearch.pid) - [ "x$pid" != "x" ] && [ "$pid" -gt 0 ] - kill -SIGTERM $pid + local count=10 + [ ! -f $ES_HOME/elasticsearch.pid ] && return 0 + pid=$(cat $ES_HOME/elasticsearch.pid) 2>/dev/null + if [ "x$pid" != "x" ] && [ "$pid" -gt 0 ] + then + while kill -SIGTERM "$pid" 2>/dev/null && [ $count -ne 0 ]; do + echo "waiting for elasticsearch to stop" + count=$(( $count - 1 )) + [[ $count -eq 0 ]] && echo "killing elasticsearch" && kill -9 $pid 2>/dev/null || true + sleep 0.5 + done + fi } stop_es From 482727650ba607de7d0bf8843bf8d836b50f8356 Mon Sep 17 00:00:00 2001 From: Joao Duarte Date: Thu, 2 Jul 2020 12:57:44 +0100 Subject: [PATCH 0539/1126] make PQ and DLQ tests use less disk space Many DLQ and PQ tests were run with default settings for their size, or otherwise set to values such as 1GB. This meant that the container/machine the test ran on needed a lot of disk space (i.e. 1GB for the test + 1GB for OS and Logstash + some more free space). This commit drops the disk space requirement overall by a factor of 10 (e.g. 1GB to 100MB) --- logstash-core/spec/logstash/agent_spec.rb | 3 ++- .../spec/logstash/pipeline_pq_file_spec.rb | 6 +++--- .../spec/logstash/queue_factory_spec.rb | 4 ++-- .../common/io/DeadLetterQueueReaderTest.java | 19 ++++++++++--------- .../common/io/DeadLetterQueueWriterTest.java | 12 ++++++------ 5 files changed, 23 insertions(+), 21 deletions(-) diff --git a/logstash-core/spec/logstash/agent_spec.rb b/logstash-core/spec/logstash/agent_spec.rb index f49cb7c5a..cd1411de7 100644 --- a/logstash-core/spec/logstash/agent_spec.rb +++ b/logstash-core/spec/logstash/agent_spec.rb @@ -545,7 +545,8 @@ describe LogStash::Agent do describe "using persisted queue" do it_behaves_like "all Agent tests" do - let(:agent_settings) { mock_settings("queue.type" => "persisted", "queue.drain" => true) } + let(:agent_settings) { mock_settings("queue.type" => "persisted", "queue.drain" => true, + "queue.page_capacity" => "8mb", "queue.max_bytes" => "64mb") } end end end diff --git a/logstash-core/spec/logstash/pipeline_pq_file_spec.rb b/logstash-core/spec/logstash/pipeline_pq_file_spec.rb index e82da96fb..df0b313ac 100644 --- a/logstash-core/spec/logstash/pipeline_pq_file_spec.rb +++ b/logstash-core/spec/logstash/pipeline_pq_file_spec.rb @@ -95,9 +95,9 @@ describe LogStash::Pipeline do let(:this_queue_folder) { File.join(base_queue_path, SecureRandom.hex(8)) } let(:worker_thread_count) { 8 } # 1 4 8 - let(:number_of_events) { 100_000 } - let(:page_capacity) { 1 * 1024 * 512 } # 1 128 - let(:max_bytes) { 1024 * 1024 * 1024 } # 1 gb + let(:number_of_events) { 10_000 } + let(:page_capacity) { 1 * 1024 * 1024 } # 1 mb + let(:max_bytes) { 64 * 1024 * 1024 } # 64 mb let(:times) { [] } let(:collected_metric) { metric_store.get_with_path("stats/pipelines/") } diff --git a/logstash-core/spec/logstash/queue_factory_spec.rb b/logstash-core/spec/logstash/queue_factory_spec.rb index 56fdf1384..5e40619fb 100644 --- a/logstash-core/spec/logstash/queue_factory_spec.rb +++ b/logstash-core/spec/logstash/queue_factory_spec.rb @@ -24,8 +24,8 @@ describe LogStash::QueueFactory do [ LogStash::Setting::WritableDirectory.new("path.queue", Stud::Temporary.pathname), LogStash::Setting::String.new("queue.type", "memory", true, ["persisted", "memory"]), - LogStash::Setting::Bytes.new("queue.page_capacity", "64mb"), - LogStash::Setting::Bytes.new("queue.max_bytes", "1024mb"), + LogStash::Setting::Bytes.new("queue.page_capacity", "8mb"), + LogStash::Setting::Bytes.new("queue.max_bytes", "64mb"), LogStash::Setting::Numeric.new("queue.max_events", 0), LogStash::Setting::Numeric.new("queue.checkpoint.acks", 1024), LogStash::Setting::Numeric.new("queue.checkpoint.writes", 1024), diff --git a/logstash-core/src/test/java/org/logstash/common/io/DeadLetterQueueReaderTest.java b/logstash-core/src/test/java/org/logstash/common/io/DeadLetterQueueReaderTest.java index 2281e08d1..cea76f1e4 100644 --- a/logstash-core/src/test/java/org/logstash/common/io/DeadLetterQueueReaderTest.java +++ b/logstash-core/src/test/java/org/logstash/common/io/DeadLetterQueueReaderTest.java @@ -64,6 +64,7 @@ import static org.logstash.common.io.RecordIOWriter.VERSION_SIZE; public class DeadLetterQueueReaderTest { private Path dir; + private int defaultDlqSize = 100_000_000; // 100mb @Rule public TemporaryFolder temporaryFolder = new TemporaryFolder(); @@ -147,7 +148,7 @@ public class DeadLetterQueueReaderTest { event.setField("message", generateMessageContent(32500)); long startTime = System.currentTimeMillis(); int messageSize = 0; - try(DeadLetterQueueWriter writeManager = new DeadLetterQueueWriter(dir, 10 * 1024 * 1024, 1_000_000_000)) { + try(DeadLetterQueueWriter writeManager = new DeadLetterQueueWriter(dir, 10 * 1024 * 1024, defaultDlqSize)) { for (int i = 0; i < 2; i++) { DLQEntry entry = new DLQEntry(event, "", "", "", new Timestamp(startTime++)); messageSize += entry.serialize().length; @@ -197,7 +198,7 @@ public class DeadLetterQueueReaderTest { int size = templateEntry.serialize().length + RecordIOWriter.RECORD_HEADER_SIZE + VERSION_SIZE; DeadLetterQueueWriter writeManager = null; try { - writeManager = new DeadLetterQueueWriter(dir, size, 10000000); + writeManager = new DeadLetterQueueWriter(dir, size, defaultDlqSize); for (int i = 1; i <= count; i++) { writeManager.writeEntry(new DLQEntry(event, "1", "1", String.valueOf(i))); } @@ -236,7 +237,7 @@ public class DeadLetterQueueReaderTest { event.setField("T", new String(field)); Timestamp timestamp = new Timestamp(); - try(DeadLetterQueueWriter writeManager = new DeadLetterQueueWriter(dir, 10 * 1024 * 1024, 1_000_000_000)) { + try(DeadLetterQueueWriter writeManager = new DeadLetterQueueWriter(dir, 10 * 1024 * 1024, defaultDlqSize)) { for (int i = 0; i < 2; i++) { DLQEntry entry = new DLQEntry(event, "", "", "", timestamp); assertThat(entry.serialize().length + RecordIOWriter.RECORD_HEADER_SIZE, is(BLOCK_SIZE)); @@ -259,7 +260,7 @@ public class DeadLetterQueueReaderTest { event.setField("message", new String(field)); long startTime = System.currentTimeMillis(); int messageSize = 0; - try(DeadLetterQueueWriter writeManager = new DeadLetterQueueWriter(dir, 10 * 1024 * 1024, 1_000_000_000)) { + try(DeadLetterQueueWriter writeManager = new DeadLetterQueueWriter(dir, 10 * 1024 * 1024, defaultDlqSize)) { for (int i = 1; i <= 5; i++) { DLQEntry entry = new DLQEntry(event, "", "", "", new Timestamp(startTime++)); messageSize += entry.serialize().length; @@ -284,7 +285,7 @@ public class DeadLetterQueueReaderTest { event.setField("T", generateMessageContent(PAD_FOR_BLOCK_SIZE_EVENT)); Timestamp timestamp = new Timestamp(); - try(DeadLetterQueueWriter writeManager = new DeadLetterQueueWriter(dir, BLOCK_SIZE, 1_000_000_000)) { + try(DeadLetterQueueWriter writeManager = new DeadLetterQueueWriter(dir, BLOCK_SIZE, defaultDlqSize)) { for (int i = 0; i < 2; i++) { DLQEntry entry = new DLQEntry(event, "", "", "", timestamp); assertThat(entry.serialize().length + RecordIOWriter.RECORD_HEADER_SIZE, is(BLOCK_SIZE)); @@ -301,11 +302,11 @@ public class DeadLetterQueueReaderTest { @Test public void testWriteReadRandomEventSize() throws Exception { Event event = new Event(Collections.emptyMap()); - int eventCount = 3000; - int maxEventSize = BLOCK_SIZE * 2; + int maxEventSize = BLOCK_SIZE * 2; // 64kb + int eventCount = 1024; // max = 1000 * 64kb = 64mb long startTime = System.currentTimeMillis(); - try(DeadLetterQueueWriter writeManager = new DeadLetterQueueWriter(dir, 10 * 1024 * 1024, 1_000_000_000L)) { + try(DeadLetterQueueWriter writeManager = new DeadLetterQueueWriter(dir, 10 * 1024 * 1024, defaultDlqSize)) { for (int i = 0; i < eventCount; i++) { event.setField("message", generateMessageContent((int)(Math.random() * (maxEventSize)))); DLQEntry entry = new DLQEntry(event, "", "", String.valueOf(i), new Timestamp(startTime++)); @@ -377,7 +378,7 @@ public class DeadLetterQueueReaderTest { } private void writeEntries(final Event event, int offset, final int numberOfEvents, long startTime) throws IOException { - try (DeadLetterQueueWriter writeManager = new DeadLetterQueueWriter(dir, 10 * 1024 * 1024, 10_000_000)) { + try (DeadLetterQueueWriter writeManager = new DeadLetterQueueWriter(dir, 10 * 1024 * 1024, defaultDlqSize)) { for (int i = offset; i <= offset + numberOfEvents; i++) { DLQEntry entry = new DLQEntry(event, "foo", "bar", String.valueOf(i), new Timestamp(startTime++)); writeManager.writeEntry(entry); diff --git a/logstash-core/src/test/java/org/logstash/common/io/DeadLetterQueueWriterTest.java b/logstash-core/src/test/java/org/logstash/common/io/DeadLetterQueueWriterTest.java index 016919493..ff352749c 100644 --- a/logstash-core/src/test/java/org/logstash/common/io/DeadLetterQueueWriterTest.java +++ b/logstash-core/src/test/java/org/logstash/common/io/DeadLetterQueueWriterTest.java @@ -79,7 +79,7 @@ public class DeadLetterQueueWriterTest { @Test public void testLockFileManagement() throws Exception { Path lockFile = dir.resolve(".lock"); - DeadLetterQueueWriter writer = new DeadLetterQueueWriter(dir, 1000, 1000000); + DeadLetterQueueWriter writer = new DeadLetterQueueWriter(dir, 1000, 100000); assertTrue(Files.exists(lockFile)); writer.close(); assertFalse(Files.exists(lockFile)); @@ -87,9 +87,9 @@ public class DeadLetterQueueWriterTest { @Test public void testFileLocking() throws Exception { - DeadLetterQueueWriter writer = new DeadLetterQueueWriter(dir, 1000, 1000000); + DeadLetterQueueWriter writer = new DeadLetterQueueWriter(dir, 1000, 100000); try { - new DeadLetterQueueWriter(dir, 1000, 100000); + new DeadLetterQueueWriter(dir, 100, 1000); fail(); } catch (LockException e) { } finally { @@ -101,7 +101,7 @@ public class DeadLetterQueueWriterTest { public void testUncleanCloseOfPreviousWriter() throws Exception { Path lockFilePath = dir.resolve(".lock"); boolean created = lockFilePath.toFile().createNewFile(); - DeadLetterQueueWriter writer = new DeadLetterQueueWriter(dir, 1000, 1000000); + DeadLetterQueueWriter writer = new DeadLetterQueueWriter(dir, 1000, 100000); FileChannel channel = FileChannel.open(lockFilePath, StandardOpenOption.WRITE); try { @@ -116,7 +116,7 @@ public class DeadLetterQueueWriterTest { @Test public void testWrite() throws Exception { - DeadLetterQueueWriter writer = new DeadLetterQueueWriter(dir, 1000, 1000000); + DeadLetterQueueWriter writer = new DeadLetterQueueWriter(dir, 1000, 100000); DLQEntry entry = new DLQEntry(new Event(), "type", "id", "reason"); writer.writeEntry(entry); writer.close(); @@ -129,7 +129,7 @@ public class DeadLetterQueueWriterTest { DLQEntry entry = new DLQEntry(new Event(), "type", "id", "reason"); DLQEntry dlqEntry = new DLQEntry(dlqEvent, "type", "id", "reason"); - try (DeadLetterQueueWriter writer = new DeadLetterQueueWriter(dir, 1000, 1000000);) { + try (DeadLetterQueueWriter writer = new DeadLetterQueueWriter(dir, 1000, 100000);) { writer.writeEntry(entry); long dlqLengthAfterEvent = dlqLength(); From 9fdef56b1003ebbd3aaf7ac2ea5d6704167e5917 Mon Sep 17 00:00:00 2001 From: Joao Duarte Date: Fri, 3 Jul 2020 10:36:46 +0100 Subject: [PATCH 0540/1126] update benchmark-cli dependencies Updated elasticsearch only to 5.6.16 as 6.x introduced a deprecation in the performRequest method and needs further refactor --- tools/benchmark-cli/build.gradle | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/tools/benchmark-cli/build.gradle b/tools/benchmark-cli/build.gradle index bffded863..63a0c52fc 100644 --- a/tools/benchmark-cli/build.gradle +++ b/tools/benchmark-cli/build.gradle @@ -45,7 +45,7 @@ buildscript { ext { jmh = '1.23' - elasticsearch = '5.5.3' + elasticsearch = '5.6.16' } dependencies { @@ -55,12 +55,12 @@ dependencies { implementation group: 'org.apache.commons', name: 'commons-lang3', version: '3.10' implementation group: 'commons-codec', name: 'commons-codec', version: '1.14' - implementation group: 'commons-io', name: 'commons-io', version: '2.6' + implementation group: 'commons-io', name: 'commons-io', version: '2.7' implementation "com.fasterxml.jackson.core:jackson-core:${jacksonVersion}" api "com.fasterxml.jackson.core:jackson-databind:${jacksonDatabindVersion}" - implementation group: 'org.elasticsearch.client', name: 'rest', version: elasticsearch + implementation group: 'org.elasticsearch.client', name: 'elasticsearch-rest-client', version: elasticsearch implementation "org.openjdk.jmh:jmh-core:$jmh" - testImplementation group: 'com.github.tomakehurst', name: 'wiremock-standalone', version: '2.6.0' + testImplementation group: 'com.github.tomakehurst', name: 'wiremock-standalone', version: '2.27.0' testImplementation "junit:junit:4.12" } From 8da85f4384cc951c0ca5ebebd6f73644f91112e2 Mon Sep 17 00:00:00 2001 From: Joao Duarte Date: Mon, 6 Jul 2020 11:21:35 +0100 Subject: [PATCH 0541/1126] ensure 'starting logstash' log entry happens first --- logstash-core/lib/logstash/runner.rb | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/logstash-core/lib/logstash/runner.rb b/logstash-core/lib/logstash/runner.rb index 1959c09bc..0b5304e53 100644 --- a/logstash-core/lib/logstash/runner.rb +++ b/logstash-core/lib/logstash/runner.rb @@ -301,6 +301,8 @@ class LogStash::Runner < Clamp::StrictCommand return 0 end + logger.info("Starting Logstash", "logstash.version" => LOGSTASH_VERSION, "jruby.version" => RUBY_DESCRIPTION) + # Add local modules to the registry before everything else LogStash::Modules::Util.register_local_modules(LogStash::Environment::LOGSTASH_HOME) @@ -381,8 +383,6 @@ class LogStash::Runner < Clamp::StrictCommand # lock path.data before starting the agent @data_path_lock = FileLockFactory.obtainLock(java.nio.file.Paths.get(setting("path.data")).to_absolute_path, ".lock") - logger.info("Starting Logstash", "logstash.version" => LOGSTASH_VERSION, "jruby.version" => RUBY_DESCRIPTION) - @dispatcher.fire(:before_agent) @agent = create_agent(@settings, @source_loader) @dispatcher.fire(:after_agent) From d99ac24c7f7ece64b341090558ae183513869805 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jo=C3=A3o=20Duarte?= Date: Mon, 6 Jul 2020 15:02:36 +0100 Subject: [PATCH 0542/1126] bump gradle to 6.5.1 (#12085) --- gradle/wrapper/gradle-wrapper.jar | Bin 56172 -> 58910 bytes gradle/wrapper/gradle-wrapper.properties | 3 +-- gradlew | 31 ++++++++++------------- gradlew.bat | 4 +++ 4 files changed, 19 insertions(+), 19 deletions(-) diff --git a/gradle/wrapper/gradle-wrapper.jar b/gradle/wrapper/gradle-wrapper.jar index 28861d273a5d270fd8f65dd74570c17c9c507736..62d4c053550b91381bbd28b1afc82d634bf73a8a 100644 GIT binary patch delta 50702 zcmZ6yV{m3sw=Eo}W81cE+qU_{RwsEnww-ir+qR94Z5tikzVEqp&iTF{yK3!Sd###P zYt+P;V_vp^=S+b^D$9XGz$WbiFcNUl&|pD8e*6Fd0TBVQuNM>${d|0+7`U;x61mPSx4+EH8tni?TgTdo1Rm41x71SjRFZ8)}t+tFb_0gG94CbJThlZdIA;$;hd1s{hz zxPaRfmI*?u25R)dQD=vDm7NK8wRtK!DKd*fEbnXB(Oq?$MfU|>i`HB>YGKL8@`<7|DFdtKGtc!KYPMxf<1-`b6l|U<^)D&ZA02P2lojHzcKVcu zW#;w33$!G2Z;_R9mmvP9JLVxWyO7&@>N-Kd8FP|Z5`3}%|2j~q z`MdDZ{zjDIci;MsLJGn>Dnp&;aEIMq5GQ~i<5icnk%w*N`SSF8k!dNH-YO~9ep?pZA4(bs0;`iQ?q8BW(@TlBm<~@(>mig zNtJ`gnPuUe%}sST|4TsY7tAxoDr@s%nnwvR>EMyCQ%1(Lt8Z$pap&p9fa_cE^ONOQ z;j4@!2pX&5AS4WySb8!ug&FS6#H~mQGnt8|Bz&5={>V?(<9Hy(Xje2crn!E1Jb1*#Im1&DHM_CowY{-|D_$-6!A|+s%lh|GY3t})7!SiOoh{j)U#WSQ3So_ zCNL_~rA6lUB*SzyJZ;f-@iGI{!C0srMwvFu51eayJxE}vcF?csH256P1;RLTPcAA4 z`{JA~>B=>=!BUx?D3_F8fx_xGQ&cw>&ic#~x>$z{3z*h2Ubzk(<>tr?qvIAlBVYlA zd-b?-G=noN;Qh%8@^Sc~Lt&2LXN7zB?8mcB~*RXYG-qP#FKkPr4c(hQ^$bp_owPzhsm z&~JjV*>mEeM4iBP0-Of5V3*BTv6@ylP<2C90}^PoD+g(`XM0}cv%nUraa_;?+tY7M zpkIy49;FTsdZ-7vvlkF}bN8#{5+lrRH$0H&mTYj2j+XgRuoeioZ_!3Lx&&lP>XOT) z8Z1~hC{gBQFOS?koohPIA4hC2OKMdG{4!&hQb^blZ*aCQ9m%@j)ksp$O;8WHOPyHa zBLk`)Dtc63-l{(MNR#VPx!DTDPgqPJQx0cUIW}~Zo>)h4Sg9c=LGB_)ES*MAc(m^8JMEO@M0)|$iOcqnLrehOH5os zkpG3gjuRYcSrhxt^F-^>U%mMT5BTlK{{EvMK^o{lnoOoDHRD+Z+a9TCO0D5$p9lOo z_5EX`@Qc=`;OjP)cEBvanz$>eh>XX`ORFVv%dFoz-WyZu)NgjV?3?MaMlAL(P%K&G z*K=o{+G&w1lgL&W;$wcUKX)`)EWAXm>IauIGDT#!===^D0?K9)mM{aiGoQFe`cJt7 zW=PyV+Ss{isg{{}qyn=;1&RqgZbe{M*5QG|@4Vn{4Y`z2KAA3-0`a;ln7QeAX!V;;UN=zBm4KQB)4)`q?|q4qWK z({VoW3<~2udxdeI2>iwfJBl#?;V9V3+}Y~o)XO&U!lf|JEMT;vu}Pc69nPXqRy6!B zCs447L?s|dXxO0q5YG^!Ke)%uH+#61&cMz0Z#>mPzW*zV{ zTq$8v-{g;^Z74XfX4<3+C?X)vF#=N0i{Z^ES|6?$)Ce;%xz$hCj7=n(1zcflL(lqe5|XJZHGQ50+i^Uq3R&K-Ne0c}`F`v(PF*i10TTPlHcZL8 z#o}Zgh4e3g^a-)sZMK6p1Xezlf3W`?w>~PiO#u7X{}_q-&n^)V;!>7UzJH0pD)hg% z|7+zBa&Zew6L&keq>d>LIpGMD|zV42`vK#<+y{;*I z-C(&1lE<XWLIc{7=jr2|ph01VCnY8PJ@&l;bde$D1lgM$7D*0|^u}xMQ&J;`?yQ zd2ILbLvfj-QNVS;nKHunkH#`^%HksMC5yQoji>q`!4Ke3M(NT*X6F)KK3qC39}>wH z!-dt7nRrThc-BmuZF`x9MS0 zgr=H*(Hb2Bv>?vp(AuX?%cjP6ixc7d=3eVENOT|dVQ~*bfO?3>WetV!$39LtEV4g_ zZOwf1Q=LU!-2dqHPZsQ2@KBUd{i)N9(%7MzEEGtZvAu0cn~90jXNnBzd)7CdmrP;M zB*;vZ+EmxK@f6#I+|((>*(hqOVTChH@oi`^$1#XoWCCTl9F>5pUbW3fxWatS9~@A5 zM62`%uhmW$2KEn_;Mbpad$05rg~+9|GBYsLs_L}nPuD2{2x$F$3eKUPyH=THhj74a zb-W1D7`g%`p|;J(KH_TB7P7n!8nq-6Di+_d52o`dEW*}3ef3U@buSnP>(_~C*m0S9 ziMMNDTd7$E^x&jlX>p4Ey> zVNu3&j}i?4e4(?nKPKKWo|DE`u@9dU!zb>{S$s2?_(`q#DM<_EAqnk6_^V#34rR=7 zt|IKykYjX;JjQbrd32xa6J5Dm-)X~@pM6#URs59;f5&8$&s<|Hjmld&2rHeoIt8bP zp#A;HP0T~}sF5zt=kdyjE1IrI;a0J4&yH}OOU%1iQ=519MF1%%3{kC%tCSaeIIF&7 zRL0V~kL^$Pp6j;nX?_bWd7CDC#GPPEeh-jUr;3uH%GHb+cPL8JkYQ;~k^#_`^IC%& zp1^A(Bx7wMH+NA|)148-r8HgRWpj0LXV!E#Mha9~e;F4(p^pwc;9Yi%PhjSwNjK~5d92e78P%CsoWP-OVj`b#Q~hWa>7WYN`#ZkI>XfyBr5 zlH+>a?#kBd59EWmMOGq^H(n9JZR9*wP4{%dgQKA@sWWf!#HT-~34-9qqvO10iSGST zAlz#%?G?fhY7UfGfgC)tL5^t6-Xh4~zRQj$by8ei0ps1t@I$RacKH@B@{ib_Cx&Bl@V(Kv1G=oC5igUnWxCCeZjr|t z^``)RVzN+)TIJ6%A!i}fbs|LCjkejk-5B~VT}}hNpA^8*cDP^gGbNX0nc7J5HyKIl z^RLomK{5+%eQ1N`Y8RUI7JvPAFegTW*duSxP`@b^+u)hU6JwUy6^|^^my*MFWFy0)i>;}n>0qUL)DvKHh$DgcGs^!Xgo#Wc?Dk7v%ettd$!btasC%s z;-|<-F1a&1akfw@r7@J6-`Po%uAh-zTkR%G-VMj(rGqJN$yVeYTN`FtOW6}x%|Jf_ z_+-id3RnM$R>@>HQ}ak5AiTsNASC}6J;47eK&y3NyzoZd{o_FD<(#~KBvOks&}&l- zFDAMtHkc+9kV|)o$0w8MB&PKx21A(c4U2}MZ6u(rIh($PXUhQ+ITbGOTgWI-s54}e zn<5t4q*dy&MyKPt_QHj?)2+C<_!m z{F$orb{!qq=6#KBKboz-M&$U;95Md#h4}9l4?n&b>WY8w7N?yN4L>4DJSfqAHl`UC0aZ?o zh97psA8rb~71+P`iqlTrnLdG3pJ~=#onSuSQpMj-3vs8Tu%F_^0H$TOl%&^6iVE{% zRwlnt1KQ4R{TV`OV+m#S5RDMJuBMEh>IN*O8uXYFmlQ8eI2jJuKLd7##JIWEn30wV z)|gQxitKXeh81;2M;3(DUMp+#S@?+-Qa{r8iqjJ!)4mqyM;eq z)e{%!hD_2=w2sQ{BKdN#Tt4j)SsD%~thyLIYI`xXj;e2rDO{CZ5=YeoBle>29x0w> znLmGK&*t@21LDO*^9B`&fYfKpaFQku@Td1hthfJ(@I+o zwk^V%COyl_jQTQwQne+gF6_x`UAaA}yur-+X1gW;Eq^zGkrJ^Z{5+z(1DNNyBdkU3 zR^TdR-YGt0Y+z;N=%{r<%>El2{@Lvb0U_rU#={d@%piRYZ2-9c)GYrMP_y+@mX+Ci z|9CZhb@bk05!aTW@zHwITEOgVyvU^4V^T)D!g#Y%30vOqF%*FggAGl-d7S6Vnvvo} z^E$|Uc1D}j^2YSMEO#`peLG8Tjd|+un!S*@p@c7$*=G@rER>@xZU|uy$W|~K=1xaB zf;evfh?Bf6G|RhppafI}P>(U_EKNwD$a9Z?w46 ztzucW1c7wSc$R!X2^11HMw1JxC_6@DniT|#(dVIeD@6NpFu zlzPrFi<%B~4YOLv(3U2I!~sGEfX+1B6jJ;!zD#0l{uE4rCbN{?CwRMN-n)UrC)rr% z9mr4Ja*Qw|EPWV++a0uBJ}=<|i-O&HWiF>moVMCEu!Z|F=U$Tf)-)v`6|!p>^3HyJ zB8H3PBz+)4xNr*oSS6Wu7CAELi*21jH;)LzF4p&HzM^~CTWyc ziR+hS7=jhDH_d8?yE8iKBsgQ%IWqbd3>= zruVVXWjDo?4LHY8Vc+Schh_BmvK}1H0DkaUxYU`USg#J!_D1mEZ_-KMT$OmvTR~7wz9DK01|i8 z+WF9(chp(3`{Pl*lFakdcio4db{nvtG|~}M zkOhKsGY2J#%3LSI8mk!R%7+P~14E35B^LrqDdvc{e&w3#&_ZcJEqI6IW2zS^Tj|zA z6ZAcs$IPAL8vJ<$6Dqko_+a$Xw(Ec-JzyX}jpgtU+=&_b4XT45+juK~@N%1^IDl1S zkYuEi4Y?-5hUXxqM6yKdt8!5K3V3z2c5;01h{@fvih6aC!%FQlD*2U{1GMMiLvh53 zpeSJY>895@OM!qdcw5Eak3~+>HFCJTDs@9SRZtrSGQ4?yQBom~H}Z)S9J!N5nDV@Migy2NVJ|R!@;{w~B`h+Re6M zFajsiv_!YTDgdjSw1IKY8~C=aezC5e=WkzO@U@{lxBTkuPqbSFu>kRMc;i8L3_c&z z_PLosCjx!%be-I>XZ&8w1RY|WOl{0mb#YyAixjJOoN-Cv<~&Z8dbaz$L7=N|0NZ$n ze_B_A8Ukua-#j~>^wW?_hKB7u_v!Dk0#1wTDTyg$+AmT;nnKyKWgr7`V@=I8!5tfx ziOS&*P{1l!jSn#6TZI7DeN!?&V+&R5bKL z+tw_%jbFru!I@_wr1tfgD>x=&@ zOqyjY#SZGkMVv>t3D91pW4xSpxAE53LEpD~LUmZrgC65I4-Z`J<0n|yeJVY@NT@%I zrnbg8Zge--7koP$P5T4*je`g8G7lnPpd_TxArl($$J&uqReDU3>TXcpW7Bu41Vrne z2B9sfGaJQr$B;Q#LDtUF=N8ZFhSeS4pPRQ=4L)Ex`&6#HH!wXuwo-UkEWugqS8?E% zKbwWs&rcAi($Xkj<$1nj&LI|(3g6n|IEAryw|fPO8-3Z^?-qIOD-qDMyQM1MvGz0R z73~OL(y|c$q@ia!dvuXPAY;~pDHv6RzVlGEUy$%I`j63L!-{K~`s35z93iU5T_p_N z%lN-hvxsJZ2V(vcQjIQoK)gl$3dZuB6qeoxd;Q0W{o*`!=iyIxxFZoiU4C)IOG+vtHva80vES7u`>USwjJ-|x>9|c zSt7^DY>}KsO9oPGIQnZt1|_#I|A}#IOMba21an@K+Yzt2_-dhKT4&rlYvssZm#S5d z^5;ph0ULOBSGu#v zfuVC|{VUq!suFyt%sLub5vcP=QefvS7O9>chsR(6?U;m+NaO7_DtlVhi&QLR^JPEfr zYcg?UJ3W{Eb)QxAcap8C{*Cg9!^(OQuBlf61-8`M)hn^(wZ+mpYxTrq2l0`0=~#=h z{8Lg-0YDOoykFby44G3~ax-T;#?8Nm1QhBWnLJ|4f+i|{vVQ455Ha5db#fDMQLQsUfE`t7-c}ppbM)YNYT9T7MB!f^QWHYRaC*a4n5>X+_Uw-Zq zYT4QaY`gHq7wfsumt2|c1f<-EL;rD-ya?t5$)tvuhbeQOgja+rAES` z-HMfG2aiz&i0uq%ai=_Q;f9<Q1}Y(fd@*1(48yx00g%(|oZfTwZTre}beX@AjXO9RoexF-c7~q4WKZvcio?aEGEgb$MmZG9m*h{HHM5vlw?dBz zi{Rx5_vQT-9$5YK)>Jx@)v2^z`_2{9s5$qg%_G6|oS!lGJqE7_4xLhX$_rNQV`n?M zXO>>59M)-sR|?7LC-v(A^-~y1;X!O1?k9|#3UY@jy; zg)5;1>4!TJe;qo0EeM$YuAzdF_$R(hp92ESpxW=XjZXbs^tvNi9RbLE&1Tw6L zo*wGY$Vw#BN4m$#Iu);ZHh%~$VUzp@X^u)fopyk2$|u;+C>GbBqkH`!1j5r zK(vNYERl^3w*rtnPc;)rV!S!pM-_trA5d#zL5(FF~BG-VIDbrC;sQdUizy- zJC{(!bL-&~`7hePm_A4GjTpZGW)?V~u}dGFzW@W-vl1mAx$YRQbWYsi-?v60nBG9x z|K^mEf~PQ&9UE$M;7I6bMLg(iRRMP;0{#PYdUpKxbjS(%lzOp*gLfs7uRN zp8_QtX(x*RNAXDR_eiW>TD%)W_9|Yj$FL2?=%!kxs2+7|%bc>YS3VLv+m(DJxmW08 z`4saY9y|~<&TlUS2b;OKk&dT_LSEo`&9&!Yt9R$+>aWuG=O+;eet)eSf25Ue-hoat zaLUF@Q3~B?$w^TPf3|EeZRxrz6mHtf&|X2}x0;*?gG9450#+7FZ3`SPukqQEhs>ZU zn;n77aE`c)6k%+KvwQO0k)@ZcQ8A7`m{NX)8G4#K{hloRdFj>A9YpFK27=M@El0rf z-FSXI9NF959-Nw$l;r&^tXr%RD^r#ZaKr7mQLV>{=iw8qTC7IxPGK~c<*EYR`mQ?B zt@2A;LiiBUBiUeMhOg(5F{_1i1e$*IJ`QGx_09JsTG(xjLAB0))8(+-2B7G(c>J3o zMWEGqovp;G+%+5f35(ulJhpS&*JGP4s%47N+p?X$`|>s=(4bm7?I_%0vR_mLs7Z@f zVm2ce7dtZji5%Ld>x_}a|zsFdUy+wWRPlKf-*EI8ft%<{w zh9d^HA(amE&Jc-!Es{d9?hwdD=OP0bc;-ln6zcYEK1$0%ELzq^QI7YoI3cj<3B$6Y z!g{}j`_qg{eVZ5g($my|SFx5b;EG-Lnwyln?$!p!q8=$WEYhKZ1O2#5yGm-<&DB%i zquV!2N-)h1J-uT3k+A&W9}Zu!K`stoIbo|e^R?D+ssZbXOi%gVbCs8&J~szjlvuw4 z)=)$@*J8AXgTXT)fI%^bWyTVM zKT25qfWNE;oEi&@!%*0ZKr92MYU0cu=?wsQZAhrUu`y~XBw-gGJtXONVgS*;6qJ8- zF18o06?>P%E^txth0YKBmd$N#8)%7haQnJwQ^C7>RwlVchE^9v)k7q z&?bV?9g~I`5neZ+17}&Papx_so#Jj*8H0#4qoLnyT%A$A?E(jm5Na6rR4&k;Nb++JH>YKmu zM?UGLI`{15Sbnnz;W-9G#0!n@;OyO4KZG#DCE7ilx8gAIfqjVlQ*oHY1d)4-ukx?O z$muBkia3!@-`s+7jF}N1I4n(I`wG1&wn?#fgOQ|c8(|DT(`!IsgcX^6T@nExP-9STHl$GJ3}?<(Qq2<2AvUGH&y;+ z>W?*C-C>+55xCDD*9Tv_P+W*xqPoPTrP8Oc=nIv?R0LgS#KpZ?a(1&xZP{!qEV!*1 z-@ONB^CS2z5r|LXD&pdvPJ(4QhssYrXmL({$;%TEKw)lCVtgz6nMPVlI3secj3wBM zXE3@)T-!&eSeF$)#9m3nUJ)VxD9|P9=0Fi$f{{_~2;lADUG4|(2i8bkq%%r?(HwU* z0{miD5@|%&YKTfbmf1eYjZg@T4+jlm(up&oO-P2TxH3+w^%acuW1eId&q8<6&5z~`RToL&S7kW!BWEw`}P$d(qd{0iJHun{D zfLrjf)fky=J)Z|XS}Ix)S`^ApRM^++Trj)9+%mzq&~gMGL^$Zx9fxf`M_u|ls-@Lk z8Vlhm{Gf2T69HblQ_Z2qpO=e}XcEl-)aU+Wz*sq%d%}kLcqnCk)gB@Ru`S~EA&^*T zZdbfkB5Z(KpBM7B19o=e?Hc>}_QCsP9}Ub@N`XO0fQf17;>Po0e-QfbSoa?WJpMA6 z-uqwwB=leZLlevA!^^Hb8^WEO_|=wO}DFAFmZXRhWXBLyZPV`=n>wjNn9I?ItAD4~W_4c+ie-5eD{M2ShdYn-OpFxhHvcY7~GOD*z{2d$Z zh>6HG<-#mEKnLaBWBezC7N_+bqivUUC^JST(x296ew5i+2|!*nBC83bbiGJ~YFOzN z!~^wIB0T@fFz=XK9_g8`b_aqhwsRHtTyC=_am^xLvtH?i#7cJo9A7uaczBiet8I0- zBDf9Q0a@SB*9P5qFW*3o-o*Q2m5&-~P0t%!E9lQhBSTz#F#tBVwPA zw4jO(iUvjnzsQPTyd#Vz))>D~D~LiKmC_dhdQk7HKyM%%Dx=CMGo502pUVl9!ZXxE zfr6*>bdHzicfkcT=>Tr0Np;%3weiat@PAsHYeYdEvH;` zxbg7Tj%Txamxq>?yd7*-;}*ydIs0+|>EES{I#cO|Vt6?!_u*9@_)~pJc0^Y{K8i{0 z&ZSGVpH5@SZM;_X&SsO&*BdK4U%@bTb^cEBqv(sSS7{$k6;D-M7AVpKwivAk^P{qWK(HrhOczL1;&N5#IQlz`DoZtXx!_a3M5fdE>T)kuJWCXZv|}bh!r|NDUT2xiOd(i zAX6Aq*(+&J(f;IXWMFN@YHTgc)cNYh0wzGHp|;fTCSm3}`%0?A^Tosc2K9%y;%Vtq zNm~xS^?7}@wu^C4-x5%hEu-P7sM{#66d^!){JG_MJGDmorygP{<79)Ck=9SgSl-%S zx((%~X7o6XTyV)Dc+YUJy3_u$l@UXUBQZ;jEFf1w|m1Em6u9J6cmCsRJUsw8e>!1j#W8ys@e)HC zip-$HdTVQxZJ^6B7V^&-3j0sH8N&PEdsO?hHQYaH<($BSS5CI4(Fe^&jnJ0 zXbCIEWW{^br+?ySe*xwFYgmyB;(GZOz ziN3vQgG3PL0_m*{n#FdCMZM`xH6p;FT!^L*{sN%P^$fbFYPQMZR2L^EQ))QwF zxSJUY+{c|9%$|a?O%T@TPX+Gnxa^q0eiiOHe`w_slMJCtBm)MhCNNa;VI*ENl(@J> z9+$inFBPb+vs}WL{oHMW7WJB)L|5iT`P0sGd;?7@)BS|nbA{D9Kyd~3An12 zSAbL`D{pholk&j@b~2-n$tV>@zblMX;={H^6|q(H(9|TF(X|T00hwhOpb|>}Q{IIt zb}qr)%=7@;$n^3E9aBy=RR|0gDKu9K=bR}dQHa`~)WuV8^brTF_xgoLe2Od6UYq=l zOx~>HgR257M3^CXl#9u-Kqe$0qJ$L^3=hU&wDRB zVtW=IthA*zRWoxYYERyK^Xfah4DXHK`+cGU#;b2vrq9}))b<6kEu(OD+2R^AVkVGl zbIR;k>DLsJ+k6WiQB~LhPAm|9bx!-&a(G_Ei0Gc8t;kh0fczwzlMpDZr}PD5FW}Ci zO_W8F$7^VxA*6d1op%jpvXayUn6Wgurqb2vel_LkR)gASJ&a)&gl~q< zHxj<*$$7E0sE*H1E81`2=;H4KUQ(Rsm=8bT((QRAy2I5B`K(U(Dm~{|XUBdP z9uVO42JiS0R$AGr^ik_-`7GzgUom5l}_O|uL!q=4(mthT-f-ZWq}Htu_@-q z<0F^&oE55^#@z0`b44t04;e57)WxcRjj5iV-|{I%`#ox^MrT;h+4Y2n_hDGz&l zZtEZTdTw`xJ_vX}0B#?$xPb1l-9_woTDPrT&e&>$PE>?N%{Mw8!E0BIMIP#7)*!|I#6lL+cERh-J8NihOOZY&Mnkm3D z^yj1$vzFp9hZZAV|A!?<8E34ih*6yjdZ5{EiLf;`SDdMd(VS4UUTD2FdK63(dC*_y z##XYv`W!>V#W^T-Ga5@1oMSVd6=O)=`o!(7lvwTQlWAS-HUz7BLM1V_>k-M{R?&>c za5Z_$&Rg*pg!lv5ioi?BH-27uPfgMwvX4wrn6z*=Y>R(Yr5irkA3|~z2_XajWPPYu zHhidT!CxZO$?nj#v0*r)4@>(Hil|p$Pf=w3PUHkUV3fUY&tsB2vQ;z-th_Ghdp#q< zgUq;6b;*KLiK)j4BLu1n!@umy#Gq5>d;v@HSg@EWzaHF|Sb(xAOg&Y7&1+2+rXQ*8 z-;9_Pe`321D_lOnL|1vjQ|Wi;rS{-c9~>p}XzEyl^up>Zuxt2`95fMQYv<`V3*EAp zI=S*J>v)4WaH^(vTL_ShZOqXx-cu0|o-5Jk@mJ&fN8XwBP{Ff&)9Tx6tLm*F^g^9S zHF(R8NbE4$uz}+h%bd~AQHU-GNmc}$^LhmEz>LBTR4C|=3X=(lG7|!&dH$R{=E3%e zb$8`iMJS!~?XkXPryaoWy{cHg*?s)xn<5RXJ97VNvx@dgrDG!o-=7#&KjBkguVLM3 z&?_dStX6gfsgQm_#spNrw`@h7IUMqwjpeCT2m~^ojqo>gDZi*y1@KHYJ9{!Zxy)hc zLa~IIz7|YJ>f~am2}E9r*XEa*TvEr*jPtjh)BiT6m8&WJM*2@um$c1zhW+1lQ|=$;tgUk#)5NuUeLqFB~hx^}Kid$hrWqM|JJsKg|} z5JlOSh*>0!Y!{dG0Y1w1)l%ITDL%Q{62+@_qVpr~!nWOx^P1IC0vANjY7%~qmRxIF z^fWBFvtKiwpWE*}FYgL7pC|cYpj87x$0p$P4vCvx@pxHT=v=YDXv`uC`~;MN@ZdsL z^CEATXsOn)TheQzDLSUT<1?-!~Vifi!Rh!(?qRFFNABD zy=M8p9ms~W4co*AFVBT`S9CU%2O$Cn5^ANZ)%!_V&c>xA2xxAIBB@N;+vy3eHvLVIJaaKjPe8 zVU>8V@DdOUDEc)*YWPy8+G{()J=F5~T99u(2&H0xh@KTPX%Yjamd}Idz z0h6vXZe$&qta!5G*U)2u+vCYsd%`0)v? zVq<(@Cqyc`n46w1muY6TG1$M%J-8A552dYkzm-=Hc&^4RGbM&^Y}V|5r}X{rOqA_ z#fNl%T*d{}Yk6=k%`1<8{w}|N`L33ieE$LPwK;I7?rVosF&(f7KW*YMK;*sI5SNfg zb;}3St91+gq0*o9niME>z$C5@mL6QDNoPM)p)gslnALhQZX=s#Gg_d?4intL!C{fX zK>k$gyW6{W1Di8Y)VBb*aW7SnQnFSPUDI+4&b~Z6YNVh8FpWg_r8EXg?*5gNpVtS@ zH5Nxrc$n}i&u17~d$QB&r)EDS+N$KFr5ftf}3{&?i3` z<*-VdD1E*cF7QsvoQrI9`pap&MwyZ@l8I{JIiiYrJcR8+?V>wpNXtc@Fu^+Uv zf#Z2&=h@bn(&J4n_Kq^k2)oQNqme4C+$>%5_=2pDQaqk}W9LY)da_yR@}9|rBdIS7 zMif;|w1V36cBUy({uRW+NR2*aL9wK?qlLPo(cPlh>a4H_p5O9npUk(CY2^;IKEw9Z zzH5V90dulqN?+?E=qY243^o}qRnVI(vCr%TT=9h2bxCJud1zB}a&&c!nT7Q25eHMh z(CoZuKQ_?IPWpz|{PbvyO1Bau6#c8dS6MN>Gm9Z!kPy10p5~EkleOd4`5Tn04m8G< z#W>IHjZuT3+b8jxaN_5}bnqXbPm9G1#cE>Qs~n9t4>il?JEt0axcZkV$j&tnZn`oBfZN{AFg?>f;fM^ zTi<<$(s_^xVill)!6&x3!65d;Iqv9gCEWYyZY>=22yz)5^eA!_Uf3fLL?w04(k5sK zscMK}Npl`oMi{yS#B(U~RHR=CY@JM?M-RnVz~Wvf`0oXwxDM3AjOaCyR6Ca%Yr0YU zuS|H%*u~B?O+Orc&d8@H9QD|O3`__nAG|0^CvU4k2+TNAaf9XZMQzbf44mKye?Tr( z)4ibd7uxMR=i;VNfQ12YQi_GY5@xbg-uf==Q%A)VOv_S+u9h@#1ipr{0KTGo+E&|l z6$mwZM{@a6WU!Ie=mkcnySa4&+XOKXz}BW{jGpD~)}41^QAVL%R1}&V9ONcHn^{%h z<-YEA^{ti=oE_u=LAX1XV zN0u8;7I&^1=kG9;pyl8jj^NVf(|n|NKXyFwu2GmBvf%rJ;2S=eEh?CuQkbnc)E*+T zDFK->f7~lm7za$?g>%$uC}KTd7?o1ziB31&&YvFs)|pE9zx?aqlUPUG7J8X3HG3p?wIc!`_7MxHGSc2 zX)d-xcZ66kyC6E3gNp^IOnoAWE`$g*hadoO^n#aX2QnpKSR7A))gr)mOuZsyt9dH9(xPzWbWi4y> zQOuQ?DMHst(hNsUT8TpUt|^QQk|a}_T0pmrxT>Fpzli=9!}O0}T7^#}_x;Cy;y{6b z{XhECZ{`P3#=+Ii#LiC4+QQ8CzXZW4$p-&dQy#hlXf^2A5@qlwF7TDpqt%1WL>|VL ziKdibVph0y&<<^=`y6wq{33H~n-edXAChDGP#Ixsl+%+%U{{!(TFZXnxmnBD5&{B0 zz?28bz?}~*v=x=9$8Lp7=y)St^f}^%WkzvbgHi0HhzC$~%lK^cdd@cSG zIOt91jht1?p4rMKQnV^3?{1r`CjL^xVhx|R$bMgq7rjmQR>Tm$s)df*7X9n@0jt$1 zL-mshgjyR&$|@v6N6rwdkmL|U+~xTe+;?^Js>`L}3lDoGFUPl>N_`HyYt6QkG5#)K z*`FEt3;&H48k5zroExX~^E)cVEr5VU`b`kLb%m&)xUx^TQ@SvwcxK?=_FzfiZZeI`-v+JsU z?yMFItAHi}y|IQZ@D@@MN{9W_2o-%Gn+d7KfbhZ)`t`ZCm3Bt~85&v}!=PBG+nG}$#?_J7iHr6Et9FTBTDSq?=O z#+y1A{nB=vssV&yX7i+=AKsk5nB8NM+akuG#0D5GRB%VjKBWEM&~IqIq~v|1m5bVTyc-O)xYSPcIKLu<_f6XNY)SB z>ql*AA$AIZ@Ck=(sf7LP8VFvRV^IlLt1?Ej2LivbEh)l=T+@4rDcL@e?CQKgqrive zD zkv=#h+|T95E+U?dug_SRg1xsBRLgXVKe^o`CfIE($|!YqjxV|O%{R((miZ+Yy+<{~E#ft#%$+ROA(@`IbBmruyrqq)wD59| z-=4HBdiV_lsZBX)7x9Pw1JR}_c`p9fT~wQ>h}4j1_u;TzTo3F+@ocTaxp8CztV^JeugJ_Q-sa6f?M)FCB~6QF6cNmz7cXS0cNsCW%bq(m*sUT}4e_i&}|`+10yVrda? zhL7Y#I=1CI&fUUIL%Rm5IR2oDQYLkS*22M3PtH`?-*0}`G&{B=iywS>G=g{FKH{F6D5BYEGEe%&gg=|}A*-kIP>%^u6 z#vNu4tJM>GJ{f1%PyWlgpmDJ&-IATMYNkSQ(mF0vLm+j2%U)L_#s--U{3;^Hi`}G& zZQ6s(PCJb-O``*$vl5DQM7MCjyJjPpp`HDogmCN9KB^=!L2mjfp-g9S#gZ~9E4nS; zywc@B88`rAd}4$aA$8d-e?#L9*S)QqloVyq5j3usX3dpB$sxIKsYbhEqq_kQ9|?_W zFXn%A zp;2y}g@`atILukTcP{FH1rR`s0zToJWpIdwW&XOc*^2CPZ;RPyAtK zO%mtO8r#aB72^=f8e2F2QiStM`yifKzI&;e1pn6`jIB&5AnoJ$1)u7LS}%a~ft!JY zLlBhsA0sVGip^@NwgXc~-=Uz^Wc)9zcnx-m6zm{`bNEOsI8Jx7z6W>9APPR4{mev@ zI{lj4(eP!t@H!M)>KT0l7LA5vnz*qQleopdU`5jk*vjCk&f{VeHmvGGF`T}g(;S<2 znxui{!P4b89;2$YX9B{oQj~y80_niNjNz#!(Lw~Itl-LyOx#%~q119WtZE!9XSmZY@BU5sQt8{#R4MbtL)fa%EZifmQTL zFj)5^1o6e7Y4P203}KTcl6Xm-?M&yERaH7*ZOD`4!+;$1I?sQv#V=V6>|ZB*<#| zLD%t!`;&|txyuY$is}JTP>oS8>C2<4%&b`({4#Wooz(Bqt(?g;(Id52LP>%Jx0Jxk ztzw>r3Z*7GTKk#(Tjs9$5KZ1_>3qt}#&b%gIc-++B&7wBNy2z8Az8rr`$q{iUOZml(_iw((&yyuy-OO<-mKC#@u{j2v$!$AAEBN z@*&-QG7RQVeIM!-H0LDU-jIH2mHFe$o#ON$z~*Tz(pyidSV6R^Jnp= zp-r3uYW;Wt!pDqvzumrA49o6?zhGSAeX$E~HQm2(0Q$$Ge&I8_e;s99%Vxq~C33C{ zF*6u=6vuIA=+OsYqmp3bm<0vnfXf!q>h6W|N5X}G>t*ar$O`&^l4+glcsCx)z zclGPh_S_qo2H7R&x)C&{TJ6&{m_@qBov#Er@lL%npni~x;FM@2-5w~iWCIOtlz}sn zuLiN#i{1&n!_BvcIML^DvgsD?h@Dd)$M3J{3VCIl?*0LUORt+u)Sj0Kjg$+eF1}pz zdmQXr#(jW4m#$F{r@gm$nCU{=yMmPAU-MBkm-Vh3<{ZF~B1}i>jAFESmx*FzW1iWVgoYE(x7wIRuRC(t z?W~)B7@+pPDTz0Fz58dlACXQg){rx@` zeWD(g&${(+iJ$`C$@wqmma>SP(m;Ni=+ahlGHXOnSET0lSDCT^R7=pkkW`AU0 zWSiiJG;*`j^~WSRkDn5bunK6_PWU8SkLcnBxH>24DjYd&teBJgWFPDfB`(9+JOG$) znFo})TNoD6+EmnXfQl~|tgRBtvii3i#FaoiGoPd`DSxNL^!QAY0`%$gkGFY3XcLbBIydz6_&p z!Q{akd)+9EB=h;WJdL?p zXnOIOe8%Qrb|!phrVJeFLL}8azl*MukLF~Kda061*_tZM(v-UHNeEyS&E+xa1W#M` zsUS0sJHt`7Bfv5fAR}8l1-Kwrb3x#-E2?(n9&XM+lu-Pg*-swnTRp>#4@nlgW{NdhkJe5#nxa z50JzYrW~(KfqXDqcZpws1)H~q*FEK88_05xh~rKTTNBISd07T+SLlvz*q09Soi|Lu zVRf)*Z{n)1>U!w~)ACj`k&fvC|~bbj6dm#tQ)UllZz}(^^>oKC~+p*}Dc=u5Jlg-g`j8cD?x9;Y?zkt&0&#R}%n6w*54lM9&3C`mKRnuj@ zNHe}t6)GCC(6LFo7h;aIvW^fl7E7ErMoj^kg|=G!F@%gV>f@ZkS&7D3kpob3{0^*8 z4`KazXe5A9lj1r+8Wt#-aSqcs8_CN*vIkDp5{TI+Wr2Ux3r?30aJ@w`6H_B776=mW*H zLEU^}AApK*7bokT0G#o{%$s^-l|Z^R>{3M13?tZE%y zR`^PlieGZa%d8SOqAKFQ{;D)QxQ64aCD`@k*SACb_IGAjfWw4%%G2p-WBN z@j#&i*UYe~U9YDKlg8QRHQ!M9XIOK63uGy3V7W(FXC37Zer_ERZ)SgX-dixOGjW9U zq_l62xI?y`YV`nyFGpTAh8xJ$bIsG{w< zvRm@) zDn|)5%Pr(1F4g&aC>U3( z@IMpjviSXP(}(sZ`@R5w@;A{njv0QToxxzWB^864IN-|lA^Bjn&HdiIGaWwg^S_Tl zJ}-E+hP!-1$K2k2pm$s@N`t^Uf>HonU5L{Uj8_M|e0k6%wb-s6?A9F++_(4B9Qx(J z@CvG8bUSwwax|-}vZI`_c$0m5c}VNhK@UiS235Qg&qvj0w+j@+&<0Jb;AULBU418E z!EQ;T2uVTxHAPJPFpf~D`YNkVpPc}*{XQp5d2wIDYJRBq?f9H~EGhypuwH=ta)36y zQ41zSVCh%FPOehW{WQ|?`B-5?a1vD z=osl6^x!Y*>J{-OA$RN*JsI6oYbD=?o!1A|H*7ywc&ogEydpBq9QTGjkLj{Q=C(h1kJL>^FomaN#%Z%xKa z8Pfj*?!&Av=C&tmV&fC&oT77G*y?ZNNXN+ZUO{>teRxlBhc_|e5s31P9r5Lw{xfXx z$!#7}fe_w|!y{k(TWu<83|Pb`mjdN*{F?SuJ$?Ww=~^SLib*#@@)$rdyP=J~hH#uh zEu=A}10sfypxL^THFnJH779uHf+F=BKAKH)_*u68V^Zq{eQ2fXW|%S20uWkrg{~t4 z7?Ut!E;krX#{`*C-AsXWJqo^Cl?hDM7OXDbr4oz)K^?ny%q*XG^j^s_N}}w=ERhW< zt8W)ucnn@59~K@Gz5@(54qhbUQw05{0`*{~wAhC%mrAKhhzDCbFLMYPSPXW9-XF8U zX66tY2X0iR5A9k=g?WWMQHiX`4QA_)tj$e$>gz91953u%z*cfB0J>}V&CoaFD9jUW z_XsyYsUmkZ$k5Da+eZ-)d%}qIi7Q|FEnMr5Kk^D0^Q_1d{ss8GBm50g1_)k7BG+n% zM@B$>5FpE*Tocu-|NXS*O`p5kpor~Dd%+UF1HSl;jL`|yxtw>x?&Zf~6C-F!FYUK# z8T*U>lf8RU9}yeuVRdh^0G5R48=<0W0v*EoyL232 zA(r}#t<9{b4ILtpuGn|kS?wUr$X%SQz1yra&7pAtB_!Z)&4G2nIkPNXO=_yCBO;vU zihs)x9J$CEabPe$GTWQt1~v{Jy}6`^We%QE&|(fyEs2Jj!1(M{wR?D%M* zV9U6H&}4>Qj)IoI`qZCU50oUqs?^?eWe&$Ls%PA+S**P<5+#K*h9xxo{TTL9qyhz9m%u$$oIl0g0oIZ{TZjxzR# z9C`gyw&(iarO%mJ_~bPOY=H8n%%Bhwe^zm9%`L{YCpe)EI_NN`cmjqn6%AETkNswe zL#*_AX%wKu2-)uj^n=RTLwBf>sAp;_BZJk|;`#FPAG#3mq;@e=PGB&$y@mc%rrQVI~V3a-A}>lAJLvlN*F0sdAGsU3y{q&3{_U!5#Z8 zN?@K*oLM5^lze|S%HH7NRc!^s=HUJH$qZGGvgfzno^_j+BeG$I7c!3Q#;YN!yrWroiG>a4X&6y@e;b#7W9qWtJ1 zy5J?=8qFY~^_9Zq{mH)J(sob!CLBGC1aT@Ytq`=OTZNl#;Yf#&%r!dL222AYAG|C` zy5|blM!g*6g$!0zUMaN@^9C0wDyD?$Hs^51m~Ls;zZ81DLuu@c7uKj_l2*%j(n<9* z{v-SNfAq5EV>d6(A0}8L0uT_z|M_gFfK-iB0PZq6zo{&aH=jY_8Z?K8QnrwpbZaJ% zd{%nO8cSqfqrT%3w2{PuSgu$ma}$||wXF4`$a7k)^{I$vM>Iw;T3hjC+m}3j?+!0( znjJCbOaAkfZ^!kP>u=BF&-Y8tT@WXj?<6O|6<#J7`2lskWGR|kr6XZX75G9Tth89874tkl?E6Wuo2 zEqAUUqcIfY%}rqhW5kOImSK_;njyjgZS{vb!H=BC(DD?Q!~o_Xi_V`m#xeXBA9{EA zIen;xsfTa`@#TgdnGu$Y$@DN4prX@cr#i{qYHJXNiA_D~Z|^`NB}yMC43grCJUeK^IE#(hwYgF}s#y>9LNc)W_mI@9b#$ga-1 zbwyR}vinvmx@Ev;D{Fj{R%f0WeTAR*tyUwxm-H`Q(}x2ZFuk!34jR%7bsA5V6VV`e z(BqK8BGVZBqHg2|WR2e`AgPtuh~a7Gq8m|A*UZ3eYC(KhhceRSMEbd0B2>FVPd|G~N>EWX=~ww|%)i#^N8OX?Ccbue&p4vM?_LzMOKay7G$cuOKWv{sLY{ zaU+Y}YjUdIMe=tE@XqKn^3oEqJN82FPr3iha>S&FDUju_G(>3jfsBq_x2MSR6|)Nd z@aJM8BqMVv3VT~4TJ92FBV8!fdKnDQP8k>k0=E-3&cW8)eKk*1HB6O8%zZGfR<&P( z{nubak->Nj>yy1pR!Hw(dF;)Xs+it}%}qOoHwOpU6Z@+i0L#t*ekE!z^+Jw&Ibs|p zo9fW6`A0A+dmun%-6b?TQUzUto%ZZx)$IV{_R^k<^>=6G(Ivlbw0}jOSNwB2!l*lSi0Lg5rTV-X#v)kvV%7KLiF0TNd?b$SafJRrR*yYs02_qlE zb2DFW=i=@*fJDYR%4J+BqQi<>bIDv4)v5S#+EGkyr<-Eyd+|?KZIW|uf_I^x%Qw*F z=G(xQVAmC9M6AmXlBmt~%f?w=e~yD$qw-Jl=r-yA?yfF}+q zp;s&l$Zd@uLRmCHv6g#JcT6TvJj%KiL%(DPYrHjs?_Yn>Dh!*;=;Iht|Dx3s9pxxq z#^JFh*PKT`Ej1<*5=G}{f5?TtIw4pq!d)*qml+=^nBzdGMF4{oVSi9R+kqnyGllz5 zx+(x7ln5$J7@`=_n`Q9HKF{4QUehCr=eeN+e0pXo`TQjkRpHH{Uu-*L6Ss(ZAS{9c zgO(hDlO|p$zD_5Ejn)9pR2+&ldbfYjbS@7YY=SrBdov~Ylu?CIOqy3^=x&EpE%O{G zA!$cJHTUr}UMX1}F{H`st8$A|jFY_Thz+E}#>5kt-2e-~*Hz2~46iqp-n zo02h_4nJCS&G_TRcU}lexIl?0kn!4oK-_2>mL%)>{fdNA?tCsN_>C;5hH@#YzNP7W z4eJ`!p35&0nMF*i?UuNU*hzk#Tcdjp7$jfKl*0La3#NT{`30%}z;^%{;rQ&$GoBud zR))GxR(7=GI%vkHEsX$~TT8N1?;pVj;f+luX#NwM{vd>1NOgnVA%e9A7tKf`{HYw6 z$KATqWjiNJKnDQG$cd&r4{NulU1Cgl?QSF}btKNPdoSl!Rb(X6p39SMq%0mrxCiXT zG}-*U)g*-ZE-tp`hchi)?q!iLsAfM^lv}hC8~D*kjRXI(^Pxqh^GFhg?azmA^fswz zuQ~dkA*h8|A0Yg1(El!J2mwr=5Bv;s`TfkzF#Yd?mO+aU@E_`?eo{R#9sL{#`~pTa z{T^#gl$uI?8bstBxiHmZ5rc6SUC4I(ddj}$r~gIrf!wc~>3;0djJG5N7SmD9@8XSy zuPX|8vf>s*?w>BO|M8Y9;CLtN^LUk}U1 zj5VM%Hv@kwqvOR^*x0bqL3G^Ep(xtid(l{#=RC5DMjf4NO3svSn?{Kvb1z$Yb>mAG z7sV{rOqm*lPoNrbt&IhzF|Tj67m=@E?;R;8DAiX6Ot=Sjv?sE$Q(CeD9!~WH?|lN> zQ=3qI0*m7)-TaioD!qWqz%!p#GL{;t0ktJ0ktu!iHfYez`~}l2IRz&0=QIl}w}~{L z7*@MgJ_43JBVj$W>l%MbWVuPZD>p&(l{Z^2W~NgdJWA>9Q+sB*!#oTu>5FJMjAV=} z#{QCOC)AL@N(w6s!`oH1N2Wy4`_aw4Upxm}((2y9(Y%Nam%YdhAGeq6!}?Y118Dtf z_Hq4a=d`>%yg?>#sPnHVZIifv%8L5s=T935oidLuy`~~1N*Z)kAk`ls7 z$MrSvuYP4wA@_)FOiXA>T&3i}({&bo|1xsqA-+ zx9hDr7fE|JJM5IHnnN2S;xl7gSXDOfYoKP@L7c!VZC42vCCsddUB6 zivKpJh!#9-c!L7{(Hfok&-X^|@o4W8xu>VI^JZR&w;R?xBjc0x6V!X@7IQ6(XFpYD z&KH22!`i9z+jCy%q2OrHn~g{a|GMKCiH=?=>dL38DQ$G}B>9e4 z-$u$Q7+;h!x;F}qHzLjU$IgTKjO}xqjA*Fbp=-)Hy$M+bm6%%=D?omhzR@Qu1JK9) zA+l75JLA$QJ{g*5cc z6|X7%CDlL=ZWyuw{_H#cjU*2vLCD;q*^i|TE)Y5i1761;@SPO&78hQw>U2ve$7fW! zx}9cd66UPg`SCw=FqQlji1j~-px{qt@t^6{fH@pMY_k22SPN;?vfyFkKt?tX%ntNw$T&hTg(6fg z```TlrOODwQJO8}%F_zO3hVYG`_(2~qq1Ujr+if$dmHt0_i;aQu!v`+{}}B(?BfhG z=w+2FihLo}Su7)OEowE>31g}!){sFnVtsBcckO4b>sEa?V%I#(v%~fM3c@pv zmzy8NKb=im9r<{|X1nv~QAGv2*^Stb=+<|@xU~nL0$oIw!$$vGNwTGk`Rj$Xp#u(s z{uS{`HX99(&X?WRKii4d$|I3en>rgeH_f{kDqfOD5B-;j-KOHAvx9Zl6aQzDO0hw4 zak{h1xHiXLx05SLbxc0lGUj}!RjimF6xvbsThFhU+2g(C-VGi7I`!w)^W~cE)htIq z6@-~ldVjh|$KD&TV+&UC49i36D}i4TU(daO#9Y@^7ClJL= zUDCj}Cf=JBiNvoEjJN6=?!Ef~Op!bgiDOCLpep?-)(6h%yuK;BZ|b2byAQNxCWR2^ zJ6|e7aorH$X732&;)4V@i)f}WL7{wr6Ovvy?g_R;+YkkYPbGZ1pwPF6038Du=6;~- ztvwdzKKjK~k%Q|S+5;>a|CB=hkpfo%mU|>L+I;ui2lnTVU&~z375jZdls*T0>e+nM| zFI|@WC`Uy9Il=Lg35=Kl&j8e8?C)Iq*TVxX76>~yZQs;jSz@MMlIk%P7ab-d===*T>O>fA^$I{h2}#Z$HrT{L(cQ!*AebkG;J(LgH^e zlqmo)nuLgZsCu??-ZjU)&*e^>4GR zgRm^6-u}7ciev47awFcJiNiW-sRNW?0}ZBNZE($-Mg|YLF0C<-W~Pn9tZ^uTuxqd%TlBP{qauKx~UnwZ(YbE zy3Sjt!yqv2AK$r8{SP0 z&(4OWD>bU!Uo?h=PRkGGlty>9Sa9k0(;9Z#$cCf1!lsEDTa z;GK-@l6o0|zOL#8*g!dPR2p5-Oxhd|dOBC>mh|X_8TGt-=rBZrQMr++VxJOW#2OtS zXwLCSO!~W+>Le~CkNNS~91QXWQ|^Tv^~|q>+`E2}&TL^ocB_!2%n#2dBYB_zcU`qt z#W}|QlO6OMqF4Qv*Wi;tvO>9JGSeyyoq{kg^cSi2R-ANQ8K)=TuXynf;bFpCN_4=H z9M-7vPaXAE^Fw}QSN#L@JEgvEHYNff7N5;>5jh6^Ya-H1psXy0SyWLnrn-)r(kBiGVqb&QmYH0IXSW8X28fE3B$I*N{$j8DxWfUi|*}I{n zqqgAKO{MA6H?*yjC-QRFlK6?%I zi`UG)3=~5UTV~hkQT(YmIg7eO$QW*;v^;n?mC)kD%7r{BRe2W?^a!eyg<^Bb>)bNg zP7b-3UcgRlW9xLaU!LQ|U7{CYnf5TTInaTz8y^KD+K~B0JXHh`X|d`v*plpAovVe( zvg(~}GL(2nnDqz0}R;lnk3FYSTo6WJ8+kyBoP zKF0)U?S-H|*x>X?2jU8aFk5JWan~GhUNCY-I%=?d+LG}nSf1ri4k#b{nxgAABnTXbt(w6lZfFv0a(_9-h_``Od&SK{N;3q$=HvbU_^c1$i~9AZLO} zFznFL`y1)$FW=QLEZTR7lX1Y4tTR-2sBGEkkAH>6g_LwPmuMv*MD};#nIM>oe1Ebs z`C_j|W|7-O9bfEEAjDK<^oLev&!vAWyw(B0AcUenCM~&ak+S_A~i_Dk`vNS z_yIjHcZV7$HsbOKv(La6z?o!FEf2L&WtBF5#W~L)R7N`VtGav~bRUicZ11KN+pY(J z9Ak$qnm+v4>A4=D<&ZPnIx%%dj{c@336sKN+fo&jrR`3T0RuQ`XUU@=(QR}=*bE;B zeSR3xwX6^J=VcT+J@_LJ)|_UxjQOv&aOqI3rbLO3NZL3_UD1_vTK-UPg_Oii_tb)` zj*BU#8LUXkTU2e9c>iTg$~EF4v#`VTp@f_H~@7;SwNpyApVAMU1d0 z6j7=Oh6yPErG7DJh}tDl%Ny}}F40cRP?c(PB}#gk{?xG*CR&Rawp?hFw`M-E6FfV7 z;OUAjRI5TAU;KtvHj0l94Y@O`aUc_#oU*4^gr9R59ar=}uk@r-CbnVx*m%CmfA?K&xM|tpIgWXU`lmhgvgga5Ngfs*m&$&J{C{sUHtL^u zmM+F-cINb+F2+ty<}UP3#xBP8=59ZC4nJ4dpD9@5T`pjfYwSb;x|%;8CtnII<9$s3P@ts>(Ce2%iic!nTcnj`Dq_Q;OM}*M zc;&*FkSzA6!1fehu5^0dbqovLYC7I7zHfzpxBXIJKti#eVA1A2zWDXDbIkkhad*C} z2mrp}=uu{hc{caUH-ftNYcDba_C%-KC!iEOta^u8c#-NK9eXeWKu_|g55o{@blyaQ z5DHw1v_b}Z^+nFU)Ki$|oc|#1MMp5<`ctekcJP7)QS?m{FfO|K=YBKOoBru)v*to< zo+fb?!PZ@kvduJg=@?1rvR^cB&uGXIDg0~oT9`N&ZDHcS_=qR}tbyNY#+7T`4*Rr| zYw_>TI{4-WW$7Ln02=~ELjT06YN7qD7oGia(|K*t6Yy(Zt>-YvZb_UVq$Z( zrhcDO8F(yHhG0QzHBZq+#_&**hKz*bJldZmd0``Kn1xzrKzk|rY+rFRVBI%tz{gX!I)2Gk1WnWTueBa@vRVN zWxhFIVZOz5P>DB5`EE}$F0U90KjqguJ}62iZ5D6X6?st&UDyWzU9&SuCI^;LvfAvj zu?Y8Bj-XWwUh-=tdK@rfS?@+SOB27*dCwKM+_oAew>row*7v1OK`R6H891A*x5KBWg#ZRH@Ck z{d`$MBEyk{KEe9MXdI<*2sKi*QVBI=6XhQRID9Mr6qCxjJrY*=c-TF8Ae#PzCD;~p z1(QPhz(i-r8#Hl)k74Z`xX10+R*X!&q$|8@M}+r60P0Ng9?$f5^bHYy`T}L?Hp}Z1PYgfwOcBmGv;xa}4o5#4$L5pG5BiVio#_EB+9>XcKi} zYAbfXd4$t8q0F>{)-$t5|Au->D(imjI^({-g`}MLH53rD-kXrHXWDD}g1FH^4Wt~j z$GH_`hsMsunQIAV0uLON3;{GNR;@bvQtdhOQ^7I@We_X%1V4K}554f!-mB zwFquYbAHX14#Tj)+zLh%)S{UjWN8Ldh7U#)n&E$mDr_hi+CBUoW&;YWd@zhknPkm(~^>cqs9vE%>~!> z`N6J&a*fvZ%6}KHy50sGhl@CzOCo_ZSyh1N5tMxkvLf__v@0%BVjWmU;_BmtVe{o9 znV@E|@5VIkDaNy>sE`7iZ#mkm2_2h}ITdSB#n`N>DjNpYlH+FW(TD>_uA+bR^feng z5+al7xr>*BC??K%uhKtld2>tJWke3DRg6tsH(|KcE*{IK?@yr3^iFyTTejK zu-hQ?1}zV3*ZI1F`q5|;eL?2}(Be5x#j$PhS@ZO|&D&XXrf2O0)kHf3@gHNb#6TyF zCd*aoCh8qS(ai2;U-<0E>he%i23<0^QQPu`-b6e6%0HAR%>`Ay`?xBqe*P?n9wUN# zWoJi^UbN#ICf1>a{bN413h|ikq(uPjLLwW1x_>N-ItBR_+LLNs1$Qbn$jWhPC?M}% z?)b$y2%278D$yMcaN^kK%!5phFQ{{9*Ouq@w{fM|CApkzc~OOnfi8y5+^6Syp_+=R zxSs84jJP)2R$Wm(B>1Ga-+}+;d}io$tS^fhbSgU~Y?bn9*5Yx=eytB!x6}hfXkl7S z!(*~w9E{t7^i57i5x}qaT7#aMi~fT8Q57_Gz_AFZ+%O9m&rjs5`UEydvJ(Xbb$bc- zlL@FNh-II4DftgF&~Sw=!aSuSOk9&A3Jit>&EAH#zn28n-LwSp4m`|QmXr_NuK%Oe z$@~(x-Hmyar-ZRw}w~ zv#LMojg!wSptqEnvx|!A-|FZK?*(?)&$nxfwrX#ftYYgh(2h;6QIJ0jkA9z9R@*(XB=r(FxgfbFBa5YC1FT() z24*}287c9~uaYt`!!FV)@xs>D573XxO^>i7jV(fWMJQ7uBvt^IV16DDrydi>E@LgE zdtUr8tv*TT=Gq${+xfn%cxAn*IP3a7h6628C|=G(4TjR z8kdYnRc#6l>#JKqs#@$Xd|)c;#J(U3W+<~6V<#k$R7}7vc?%=@j3vk*tOUM|`{S^E zB*WC&cFkbIwsH@k9~hs>iJ$9C$3t@9zlrf|A~E6<4w8VvC6_{^CWE7tAu@>d(H|7a zB&!06a~ml*6b@eqv|^n#98EbNLl(s6u~p%dKVXGFA>vU-a>>LYuSa$0=gAnwc-rwy z2!2Mg>$nD2-9O9fDRl3MfW+T{*ocQ2(?)a|2)#f`m~RDK;}S8vAo0>5Z{iIVk5(FE zDl32ylIWn`qFn3U6pRy8JS~TxR0g(-MNGOA&-ggM`f~g9R{myn_t7>vUg_LY|K(jW zW1e{DQx~E48HELJn8OSB%}Ls#x$MMwJuR4EnbFs zwk`d=Ov#@{dq`oxS9_tScxLIHyp*ZZavMRy1?xbQhbgobEbmF$bL*u z{Hd8-O!RP*(_`p`Y4jHmP_Q~?c!7NuK=$^3EC!MPuNN^Hx`nUok8f~qa)GZLfWMwz zNeSsX0=##(Bme&_uTt z3*|d|aw^-ghnttx*Z=G54!w^^gN%)IK}u9j1eOHF1na>B>X|Ey`wDit94wAG4ifJG zr7Jy!XpeZ5G>#e~{#Aw^tPpM+AiX^%?h=+gO`9lZ5KHz@L$5tap)RkT78_(TH14Cf ztmc|z+`78{;Rq|6P2UjxT*KUs>Z4(7g&b6pQ`2n1m%Qkm)J*;ulWmv`uYM6N(w0Bz z%%thLAT9;5+f_;}LBfa$1EU?wxdtH9I&wdn7~Wu_Qz6z^Jln;$I@F(FS? zg%2z1$)be^%00_--wh7Baibsr^ zkLY-MxTUN(-sDo7Lda9AN*#B&3!Obr3&ypG{I5EVX2O|gUlM>KC<90Pw>$G*Q+{Ez z{|WuWxut)vm1c8gu&f*7oMNJfYja)EIwst&5Lzsl>!K_EOMR=d2JMqIy0dk>E;|Bz zvU4K*^#hbzpp~dM0Kzy{Z89hBBYrp07MmiNVBaJ3)s5v+=M8*r$=9_NFOVT(Vkz<1 z(|o%pko70f&ZAO#YtNUc_+qZO#+((ZksWf49rPt#D3ESLIhZ}Aq#A`2?6#P2wZr0s zIB+;}AO658u{G!#BN!K-f8e? zZivay0eKNxxv#K`A|5dVg=%oxnNEF^)NW?sxp&3su{csjh_ zueK2aSvYS7#3_SX$G9i6)fQP1MM{IJ*1O4_ryGx{b@}8(+l(V~3@VK$vsY07yq8;Q zqRzDx|Jbc9m;A~D4_m^QME_ zB@y=3ut58jrptiIZoB+DuADvw;K)SQUR`mxfr0JAhb(-OZhm4rFwZT zMo;@BD)~4plr@`D$rKIOXw#l6&IyOliFIUpYP;WZvlEG+$?3J06vbQyIIzHIW1401 zu7)s6=bBk(og(OEKe>+;R1ceP#pS=~fpPYSBjjO!16ZY75q{Zr*gK!z|64u_#y7lU z@oc*kH3(pVdC)68g)fm5dPI}fpZhT-E(vdzEVgE|lxu~Yrt=pz`K<=u&Gtkh%$rvf zT{CEeJCbh7z@9W^2qwzzXKVWFc5Y zh>F|tBwLL>vLsUr)6YWyq6My>bF&9_C03F?mR^wR36LfBVXj_RTH4nvp88c;ps|Lr zFcn#B(>x}ToUIvZh~WJ^E;+22G0b1T4T@bW&LY>sMGXf&T3SpifQ7(<1MOi@k_95y zL76imaK|Hhzh3p&)Uhxuo@tLQ3XYD5Uf&quz;GY2}*9F5*cX-XN?ZV$#8)gYB z)%H1iDM)r~Hs;$sWocDpkw^6MH4c@n#82`CWPe%UYR(Ypb$g8gYwl%hRGjuKRBiIA zZL5_w-L=UZg^XifnxbgdTD(e^A_|staG+`0Zfcv(L^9}G#N#`kYucFuW@>oHY`p8S}YekNhf8NBB+HMf6bgecmeB8Snz3M|N zMHWYu*AGvj2B2C1t*(;4F8uZ4NCszc$7#QjEVj2``Erm4tFex-_Pe)C6QVT+SEww- zL=Zer9I%3u+c6J)yr|s(<+0Me`gAy6rLUki z$y(&{Ur6C)|+VJuy4E73NAlb5M^O4rs}T~{_FBSXcnxdzml7J>MhwxX!NC01bv^-4ICl9LX>)!VfWVv1`(;}u zd6ZWxNfB2zRKKGte)gz5URiqj=<`$BBv|!By!M{BUv`SI35yD(g0lyyv_aoC=Gui> zoJ`U5)D?#WK&62N-5Ma-IV0umad`Bek4)fF@z;QNYATS{krucpRA{S4rj;;o5#miR z`JWP;xoEz;59T#L^#%a`eD{{i;*ZjpEb+oCPY#nHD|cC=iwP~cFm=gy>NX=TRFfqM z5+_KNdLVxUJ^^=$9!NWn9L`Q{>770GGdI2#aPsoriT&F({QT9l>A-YgYZ#o4%q+0r7QHd+c^zN%s zr!xphnqdYrJ|WSUNEU1AIP$xKqA2Z>{x*^YV~ti$8^qF;h|-sc`(KTH1ymf%7A--7 zySux)Lx5nx-7R=@( z?9wZ2u%8d=*z#Wqsd^6%1VCz46j@-tN%2*NEf_kWsUnTC{P2$5HrBs0Za0=kw3wU( z+&n!OOG+azwRNo);`|}Vi0hC~-kt6-n)h>;x$Ypr4U^aV&wlXdi_J$XO@Vio`r@G- zhDkl}B=R>+6c2k0@pDL%Fe-5=@JfFmoZYx(5g2koEe z%C+S{Bi#isH&_AiOXNq;?Xgy|QF$~ZoGet$LIlg5wJ5MePBv{WrXcVxm+)lEHF?Z7 z4AB456~UZxZ|HqXjC-{^asK+FxYdr>;lvuqJI+hqTo~|jiP}ZQ1z)2?YdFThyT&;x zh%ZCcZk=yt+&@4^+F9t0X@kx-Iy`Q}?Y#{fZofrIZ6JKYLeb>rRG13EHOts^#$Z(~;-Q znfr*TwZXmK?6<c79Pvrp zrKcbVOn{S?<^Z)2ueT#F+Mw>4V1-*-t>PZ1UHn(5WRD99Fxi~3xX2*OS~KS)V-M4B zkf~?QjYH#v={~n9^{FYP)+k>wJ@~}^JGyg;S*;jLWwpj_@z@=T*{ZH5c5n%FdtDAv z<*2Oq_IGBC&jI9TFMbzn1QDMT6^1IWFCf3~c81bWoxL-JK2VMiA*h^t)w1ND3Te+} zg#;Rp?{FFV?pHMD*HLzy$xAQ~|;W z0OOj+ptU)Smv*l4g4tIxadhGiZ;#@g{R8;bt;8!niC1FLGa(GeA{DT^n9T&>pSOmF zODWllIbaJYS8RE%A-@D4-gCS2oV2q83v9qGzwagAZLGQ7eWL_C-F#~V)4mFd^jxFN zf8{3ABq>45m4NfuL9k@*GXEDx=i)Dw`B(*hy5AGe{U8*R&#Aw*rpAX+r-brcwC@3LD0_8Gz0X zZGK@d9>Lt$+hn5?Zp()J)d=bt16q_@N*D${#8L&ZCCn>=8n7^GGFJassSyGVCl}aB z^v~6z%n*=i5nuRTWvdY`C|fqv)mhbZReUbcBcGo!0&Z`he#m(Tgl(_R|O+cSp7OlsB-7$CfeC zR~0^RtZrR^;W$DgII4Zao5f@Gsig9Fx!!@pprV`{PFl95p8eQz45zD;eX$Xo8qAev z`dw|m9z8`o^ontPMbU8GIy%U#Rq#PQSrt`NTi7_Y9@ygb@nDaEw$iStmmLsI6Qa!L zRXQfaJEA*EICb_}q?ATXpNBo$;~0p2MnX@~Mq(5ahz;fY_;RT0aB8ZrpJc5!GRmf} z?V&X>3Rl%@X-^Vzr)|k!WngD-Sbk%l#!HBy8YS@T&c4&R|+fRraJ4W zrm>n=o>poW-8u#Y)R8?P3nzXr1dE>iREHO#KW?R*?F7s&(;9E`+j)s99z7~@e6`EdrL%>3TV!g&SdNqiZ882SQv=O;1KWi zb3txrDlMtb&;nYSb2rqT2rw0tXeuS_?=7%Yr$a3i3M=AH6LR9{a3|=hHfM_x?TWh| zEbqRvTef3r3smt>?3mIgDI=e!9Lv%k4VOyno5Bb-3|XcMG`9l$b|WUs+Khb4;-ryr z2b*F{m1!OV?hMp?#D2inP~n%$I;Eo2hsKR>pGfzmu2H?7@jJNm3V55g;p*xm=Br&Z ziypR?FG5;dZbL8lX<~~bojuH}dIGYZ>Q!jp0(9lJbs;0K-V)o7laKE@dGL+~WpT^g z`=(37i!&N$b8cJ#X)YV`PAIAh&P?5yFthJ=fg~EJCe+XOwE68^bkTVfo(P4{lBj$E zbrz>EJ<|i^v3YWmC}9)ShTn~1B=IZZNngEZ9_b@e4PRtcX!FObMaB+&)+F2Ln-8q- zIgGTjXWYuvRN2ndTtvI*TS@YyUf_OvN7%$Pb)+R-NK=JC{LK;PMJ5r zdq&&dsAhSjnRsC03LY8zmhoi8m)t*~q!!@PXK_xtqj{pGB(~w_jvdeQCap6@+X2O9 zN6a}qMgYFd=U5Bgvj%PvXj^_vAUX^Mf9wsx2VukQz5*d5mBkTUFUgus83S};3D+7_ zT%XhzI-D{AP@2_$-*Hln5L4{O&NA#b$AHm4+lEW@`|1o^@OfrJD(=k+_3~06u6%%F zB-tzSZe*xzeT%(Sly3PNJ4q#O5w*>@Lo8>C2zbE0mV~lZi+3H=*DSnVj}0TSqc;Ok zhvorwHTH@F!(WbU38-78PX+jNX)Xn^zV)RI*iUx@058|e3`E5lBiotj-Q{OSK`@`s zw>kkcwE~B8>U9J=JO|-+DCnCis(>!R9m&Yh>>8P;NTnB~}L zx7bLuio5%bFseyJqrR=2xO0suUx(0_GW#j{&GxYlHqd^yB#1w_`?~8%zYG640#fvK zBtv9L@iB6I{tH+@ZicShOM9p`34I{~xxSyq$8$c`)+$wy*cDaBnz!1EpHyb_>Q2` zM=v2K^090}uRC549vJ$4BIlDO3ges48n5hU9lR{64!gUhebhnyuBe>M*1PARi}O{j zn38*ZFli-znw*Qh4EHrCXgPWHwQ~j=OAIRnCIe1WsLbngLxE`V;O{?@LX93Mo=pKM zf*ugKRGy6=jZScSVev9+)}Eneo-OT`i{Mm7vfOo?J25MZXa$00naxd(&Jqjm@C2nl z;89qHmcULAvsfxfMN9$cCT~%Ov3OL?3-& z?uG|V!F#!ES^8+DscA*8O(R3Lyo>^*p^6B0LvpkE9c3GGhh3v_brF>?4Um-*cE7xw z%_j0c20%WZ>_&F6bQOxIG+~Jn#hY?iED!JMJSAj!P{uO%{7NEx9rkS+ItZ29lm+$E3*uxdN|D+bwN zr->qgOLv5_fL3l@X5|fSyFD$YIA$&hlsKIo{vhORU)2Iqkis^+`}QjexX^drV8lTw za_jMQB21Xf8=0x~hmq!HAam|`0aNU2=Rq4PonoPLTU7OoEFCh|4T^?^0@7i~($kcL z8mo&ab-M%yZgZrsRRIziR!xSI2$Y!TpsG2?0;X%=6q@bFS5An>(8T7vESsBCiH?wT zA9G@lOh+5q_z{qAx-SjCU%`o)%$F+FNgpp+aF!Rj50oQbBP0-f0lgHwCzk)Dd&j|RYpc*-^(gkHstui>2s zL9ZLX1l3V9w03a($RHgP*P~j)EJ)(H4K^l5p@^pN>crNwACR0qEsm=FmSXpasXQt# zgL9BZ8RfiqY*|`D8kP_|n=(5Uqk?DqUbDL`SVvQ_ro;$#6v4?qwW94(w$==Gk-o9a zH^rzXS*L8>EQJq1bm-e&;;&sy%WH9aps=J8JPatU3}{6#?sm#bx0!Spb3|^*fW`AZ z!K zgDO`5#i&uJw`KS=uJ$CvS>_xJ>LC=u<5+}=jH+t(eZWwNSO-mi_cfuwv{)7m(+*lc zE))6g&1p_`6x~TSDpi?~_A>X|P11H~Qx$DC(bT~W^5&5HBD*r;RXci4wc)NJ6ysUK zmVUAIylOA$#9KJg{1^;6eVAp}8FC)Ua(PRNBM&aLyp(8q)bB6Ttm2_OmFyIb`Fasc z|Fuw-Lb)~83bN=jkVSL<_50)!_!=N)XYIt6;+45AJj5aqdOne-+{ zeI}gF1rNXaK7acT?X~IIDo89@qLjPVq08Fh1{2dvVID@p56F(q|noOO?Tdhw8 z)rxEZ*ON)y&TOML#ygO2Tv={v@21og}o+q2`U;j24Vy`HmVRF*q4r(GB{YrNL ztHJWJ3KZT(&t}9aAfbrOAFoliosj z+_Dd~5U@#VHM?Tp1!Pui30VrTg+Qm|EC~==$8(Uj%C&k~UXHdd#98690O4HI*7#;3gJ5sk@k&m>dH7%n;$j2&< z!@P8Rv*yHGz}p#AiRK%g<5ihN)TD{3%6H$8jo2(#)HQ#oK2&|?7=LS$YBD;g{$YoP zD=&MfB)Oy{73sC;onE$*-WhIzh^7>0$UxSJ&SQVys|J`Gg$II#JF5I_(Oy+{E1uXD zH2ITCdI$2nw?{l5bn>0oQqr1GWFF;AVpKcEBHBklTEA;CHy-Mpkq zo@3HmKh5SI4_A-a6kLxvZ4J;Hz3vC&56nNldqX3vKdp85?$*8MZdMo7$m^OW@PqZ0c;uQ{3a3z8C4%ZBGF?%7}AcQ6|b3&&+ras_dib8<70>AVy*Bo)drEjjh?#1e2g&8L58YUlW(V~ae2aqko2A>2o1mHI8QKH2=gA86+d z+=-Wi`mqM6e;;0f`Y|B#(rb|GqqUKfQ=;mNJSaZw$F1l72uOkl@~skT#3#v7rM_$u zJS*8q7%H0AFFIApj_&PN=ScZ6JLvb!6yRZ0LVgzoAjuFEYoI7_;(Tnv`(}LX{Q2SL znc5GednPU{o7wj%nj>74v5+Ny7moq4o{s|~hz6cDxyNRkzk0hW*b9IFOSFJfH@f;n z-Y9UsSn-+1`FRCgOkpZ?y{mXU?@Q|ysE_GbuU=QyG*_e-nK#1GboDVeE$%oDw7V}l z43+gCZ+9VT5w*jecOQ+yiBwCiffYM}-*oE`eCwz<6*QqR~crY|%6s8~*X2HW(U# zc~aHQ&DV4pe}A?D#gy~_$I(2@_-MD`?5$FjfUwMV;uCM{bgjJ);}WdRVKaR&%UUoC zxhR6}n}Ii2A4LT?So{!JnG+Eh4C9RU0BgnkRT?g$5HU3-TYP{492{PQ?v&s`ghHn) zv!SP6gY`An)BA+uA*(zuf3xky09wqp88e8j(wpIv68fL*X z{OXw!pr7<6trQ19_2|xyK;DEflquD_Cr_blp)hMv7*>G9khYm)282HP9#BgRilL7~ z`@p=6%LqNy`Tpxs&c$3eQ$ICDF_C{i$8fL3PJ_E{Vdrbp>q-e?Dynnw2tV<1d)YK- z7T1_^D>7W_*m${u$dV@sdiTWZGVtXLCL+;ge!}QYwl!H7&@oYzeL-mk= zQYOkxL8V+~s>imHN91PcXxbwBBj6JI-WYh_2z3MG*>er3zG45_W0{LM)Fpt-+Z|-y z|4uxAnl~08Q+4vEO8pNr*VQ0Xc+6Zn?Kc%u$|kfVfe9#5=ADV| zC*4=n=S_cSv!`iXs{};raXiX((gL%T+BMXynpct0-KqgifYt|lk9FIKlvj~^7Ba~-7j`ZHkXOb0=XbMz68p=lF)Rv|lYQ=;wD&7if;CosyK2O`Q6DIS@+ z_HO}XVJHOdzEV85*OG6RRRuAkG!*(A1kMr%_`O2Z$r;?t;nWZ#P@4{G3hNRwI`s{Q zp5fDSJ8il3P#X%6z5w3O!r2UhL~T9qPVrUWReLdZ8riHmev;K__3#+-^H1=nWUz7{ zt62sbi$ki*~2FU zvo#E40ABZn2#e(k)TjxB+m(v+pAIEEZ!#}3R)74sxxw~>_+(?ER39hC z7&FLq;{M)fQ1oN0*S0jXr}Pj<+8|^-exz>Che_c1_IH!5GUWGL0H>lE_~0I4tdZF( z4oit*eJPqYY&vH(VKh|gh>HSewMA^Bqw7&uW<_K3ioPMY%-jp!bwf5(#{zx|mv5>b zA&P0C%n-@sn1nu&ZEw&P@Y~t1q#ZPmsjk0SR$E*cbI?o6YC)SMK z@@V>=1+MIDS8>Qh2biaXTDX^WZk&+4t{>@CM|!9;Ji_#|2Ye(CVXPfL|KWEPMF_zq z?8GNciLt~?1=djRH~da9I*iU5JswE|H?2i&*gNF=H@tCe+4{IQXlYBWL7XV)RlD-C z-q`6G)N8G(i{Zu{)%2_HX!8T>3TQ7B;Ir#Fi;TxHl9fH{l0EC({X!hHI0uA#Rh7PV$RI8?yLdC(EO-znzg!!JCsUTc35ni|}5#Iow+ji}US<_XaNHkE9 zlxfX*bG32uxTDyP>H^T|18oS`$k`V=KNVcdr5#m2T${S}Q94SwD8C7>pYzq{Q|Zaj zo!~c*0P^D`M7Kl;@CS%ht~E-Tq)`biL+@pWh~_+c_@uZ|9W&cu+Qb4qO)i`KaQv!| zldypWIv7$6!a!z|iFjAm#*^kEy@LGPr&sERM=bS|DkZzrQYIUpKlQ;=QfRqY<{X%52s#b8>}?w5Ll6+n)3TNsU8}3I#Kj6Vgtn5G(wMb2h20 zR94<^<(Jcwx)rR|x8?yU`ZuT2fS!>B$aHBg73(6XUfpkJ5=-Jbh9XT4_{j_|e zs<2Zr?0%g)0X+r|()|Vw?4;pY{mnVfNdo4y+l!z1P@_ZbgsSxg5#6CCj7i=cfET1K zi|vh*Uf%K5XhRr~n3ip6U5_|y5exBX$(5{2^^3nq1Z2Ctsei+(OO~}v`q>p_1t6A? z;n`Kf8gU=ydR1Ok=$@EJHS=-X&ngpx!UuIU(roaSv;o=WTle6ks?!I(etX_2-e7wF z3D(Gaz8ktAjw?D2Vl#Yk=MD=s66zEz^4X`xS?T`EME-jVY6SQB`a-E=|^)|$pB-VzSeH9@vTp6yU+BoDf zP0x4iU&rXIARbF`)LI-})}f_{jk)?kB! zzRw%!(_=@tVNZ%~3T|pHYA*AO^9t33UbiTITGy&Xd{?y}egHH$I~QxQvMugEA~6e1 zU(x<3ae81!d@0^m_ExWh#}vxP(c1hSm z@5HE0b|}NG<^fQZP~|{o6zpYHq=mgxh`31b7GMT0ZIw^~UFM`}sftfh=v6pU%Z51! zZ%kXFwRz=~CZ-DB4!-vkdFL`$nutd`TcA7WNO@_Kx|a;+DNZ;4F43TDo{3$}sfDS2 z4}mkSayY}gA_=cEqjXr8Go!en;@hZq;T?D^!VI^1 zSh2QRulS2_bD}>{uPJ7{gU*L0-I*`g=i8w5! z)^yuYz;*y?SKWg)Gn|V0bjZp*;cY0ycbra^>d#q=y2iogI>kD zb{?aP4J^Ca~Si;s40WZoDZM z@Dv#~zQ(ey6Tn)&SW#}U-t@V)%BX*V)8)%TrRFMt2BzW!K_9K+Tt2X8p0$2`O|6|O zB}YB(dw`OX&T^rkG;aP(34VZH!LSwFXUTxDa~ww9xaO9wAGk;oE9Ew?ZZyP=&*sl+ z4Xu_cY+*yn2v^mE$cidYpTrY*`EZaV-M9i>Q!AreAx9oq7rX~N98AYJFbP?|EM6-L zG%;EOX2Lq4a;0c$rDAoIN1VPgL^Pzm1Dww-wHv47>J-C31(oM9c3(aiG8Fjo1GC;r zhQ=3r2emZRmsT{&L_wM-S>svTSvEjMRC3B8QSLP&JQeUVy$_Y9cm13)Jhe=gq7yHn zHhH5Qj%>%@tGskoVR#!WA&-x7n6Sf6UKwcvAd(gQNRk%Gv9E~zjgn%@I&XFu-{p1! zkq*{)UDgQ0*_8gmk<9k>306MPMNKR{*>b6A%3h02|U6?)`uRiXA}ym$|GLcP@``5gqpoM zT(YQ`kEC=O$Wj||=^x|z0u#>;WjRs_*PqzYygE*l*GJiH&&~ZUE$*%Cv%b-tcxo)~ zc$&KI^m$;oxCUaXeH)3ZCQl~qPQ@OFB|yTAMsB~&=poSOJbH_%d(K+8MdJDs!$WV@SQnB z>af#b+pIay;m|)*`a1-f+hTw^{07T&5-OT)H2KwLYx$};xJeh!Y-Lf z(tXmu$W5PX!dsCC4eh>`E>m_ySPR!dSo6b2T&s}S>^^&2;?Fn%JHX!*Ma3BWDco|) zt4Tpo0OJ%XzWWnvf!s>-N9U5@MqR*o>|&IaOK}rF=d!JorYjCwTnVY3BP%N9<0V2E zY%fc3-ArttGdx|$8f*KdD!!iRQf0-O^L7v8e(-5R6KQL~V64nOn;26vJq#gb#BL!{ ze@_{kSO=*FU7j7DW1_B{`=^EZI_-X&rXaOQc8%u3vPg&Q*Sf?IF3N?)!6j?4`R06XTfW9jkwo@lyr}4ulwsr z8%N!=G@H8$!lSU+CS3H!I6SHXW<#{F5Cy0ctS%JCGlSPC-Ke9SYuM}7tzE!lw0LE= zmt%0mI;ihVQk1bHpu8~H*eL*X;fQS?0W2nsy3Bs0UVHjt9n5zYj@ka)`_RE_+5K7I zR$@eo+Xtyc*+j#keE6>rzvt>&4}H8wxl6SroQ}Z}zuI}X=O z@YCBu(X%>33N$$kXdRu1e9JbGYl(PvMlLx4)JV#3w_r5Fes(%@Ror{5s>QwHU;(-q z%WL*TB&F^mqjwC^5M{qPY^sFG+REVp*}&$8)5{VU&0Aq+!9{LX-H) zePQ}Dy$&qu%4;|&0@7sxY_FMLGDsu7OYM_-A(OWg8AGFqp za|^z{b&X0T%SvvUaZrKiL?-4Do?Y2?P}S`@ieBp*$w=!$uMO`C>D5r0Y|jwqoq(Cxl<*OM-s{KCxgk%Mc&q>{+8nau zl!0x>z-nWmSf;T)pv_BXEo?q7-g6PnH4yHQ1D&fS&YAxIrgJV~USp>h#Cxc^}vj@w6peCz-L+VFzI1RVHYHJXEp|Xy}R#I7eKI=+E07{4TixNMH1+GjxRZlUlB`dqPNj>+H z?2R4;H^qL`J7Cd|WsxBZ&fVOU>CFe6u zGD$zYGr#~*)#hkz$n)LzL2d!e{HZl=i}ynP?hkQ`Ysl@*r(AkrsZD-oG8d2N2U+dRcQ-Zzgnx8|wn~wP< zaKOirxEP|H$C6u~%(P2p2k6CGyMTT9Z3hEQR~`@`jU}SirBhRb4Ycy+GDW2g$E?Jf z0)N_X9@-I1lr;xhhW9&{iGR7`E5N|Nd{A}WG*Sg-?l$gHP7&FJh!c^j+hcdRaR885z{$g}8C+H8*QBQ)c<E*P+oS)r~&xJuzKcKo{pV zZWT~?*ONCG-^np0iSCxT-{NGy7ujBTwUq@I6tO`d7^$?7Au*2NmDsZ6jOUgf0DT2O zaSk(P^?e&H@Zs~g_BW?Z0dv)G4ccQ;NAIJ{2g~K+rBPnulRd4|-J$Y2+EgEcvw@gY z2lPF1fq-ll?&6Whds@!%e&b>1#uDFw>D>%1zW`&J#n|HQ4~UO3hS9;S{q^RN!U1T} z(Ro>w!FrM<(?$$@V-`hNW(e2=>8r?0Vng|9cI2^9HCVZ_YQ;m78>})`D=rVf%s3Oc)rrck_7>bD+QhS< zQ%A%%v_5x)o5*LyeH0p-=nl4Ok9^!z`)U-OQ#yc3FFEsy3dGlCD7;nuI9iU^hJACZm8QjxZyRwD4L+717$z)ueeiVWABIbjt7g1M&-zH+lgFRNzS?`|z zeqQ(J;N9z|AamkA-nAgQIr>^=^3C{mXzlHH^6uasuiB9h59l6JBVk;60Ts$z^k?35 zcnoJ$rE&S0>U(Nk>OLrlocaSH?=1<&W)k0PRklrqaALK7{yvNubm);axN@NTd5Xf~ zq@NFuqngZe@;gUis6}&!{YRSw?vHKDyHcNUV>ZWl+P1<}5%fofl#dby-C!btAcDM#Fk%yPBvIYk;c*hKRgR>)|4NznZ62RLi z>aXe;y6Ni>s^9VZ((+%WtpzXcQ?`*-@5p&%y1Nx8E|JrE@t#qRI1EaL&P=jFyD7J3 z?_x)8AhRGcJ95T&Wdl#1>!CUmw0tT8rS;C##D+<|X6 zy&sOibljMdf!!@IXb`Zc=Y!*fv2t>PUZ;}fGq5q}YburU2G5kQ@WxJ-oyxQu40Go` z(4rK)}T{AT@2f`Y%VwGC6-khGxPtOz8sA$|lK6f@)Sw}sPh)JAl6pTFh# z#E8wt$vIVqxb;T?o=Ys%=dWJ{;?XfI$#n8jsTIBHGd|ugm3lwvrOugP<Kp&FB$gF}T&p6ir@Y<|i){S!&Sbg(0pE;9#dH#=5_{xJN!Tt1_!b zl5gg@o33c=&iKT?JZgP7Ve&)aDH+~L{lGja?OoN(a8BbGW-(i&Ctt3$uj7l{J&2_P}?Xl}) zYO^PWCWN{>6w`N@j5>kOOt*qWnQfU(k)4C}of*%Vr=23h^{@7y|7&dtFJfP47!=wEh6YlIzywzHpaOkcU;vhG_~w|t601YkeGw;= zu0T~eW1XaZoOrM+<;LjrSe^!zoq+*bM%jw63e^Rg{5bT+1SUm`paWo`)ASd4f> zN6n7zZT`*sf$W@&jFdwka|)S-CRWMAv9-GipX|GhLniiz!FJ&vxLvQFm;zi==&n)k z4HrnmBIqh$0ss?vBuowA?;%~H&6G z4$yk+T++nhUneQCI5y9@2B~!S8 zcJZy?<^A-hs9N0*J!3Er?X%~f*;Vc1)Ff#_BQegrr`4yFKw2-XKsnqb5^fcqq*}O7 z$`j$Ex>o-@Z25DlsRNRdDKCP0QG&VYxJ-DewzQ1T@(&G%BwwqgGoKIIyR4 zVo?A#-@6$v$SUBCN;Isc+H4HKp=BXAz_e{X%3e%O+LD!FtlvJC@!Bj&a?2%HlzP&c zzjKRni~w^zDouEsF<&ok4F8~2)ops{L3kz;DE!69>*e}IxMx1YL7T6-+zi|!XLfNY zQtJ~|q%rRFtqtepW6&%f(k>kAI>~X9zNQHv!s=-7M;bK2cf5@l2t1^1zW`{itZ1#I z4l3^6h?|4R7=7o5tWKW=g*cv2gq5$18+yzZ)Slk5>+_*= z2-EnfGWbhV+4k$K=}V-lg?OD_g4TRjro;p`A7#t*$N}PHV_p^YPio&3hZQ5GCo(M^ z>F;VvA$Xfhh<1_UK1J7CGG+#QpV({;L!7{rroSk%bR{BR?4~j5>l5!iOcinJw6*;}IRSVG zM~aMy`LQ7htA5y!S__VEg4lerxwj*G!z#tWKc$$7%{gmU6L1tQ#|< zU@B*;+9IRlBh?BAGSq_|X-hCP1_Bg+K$V`X)J%;jO~Sn(IALyd7oPTWijLmP;>iO) zw@Ga8wQ#_I6}3j?Q-@vt+{ENnCIaBQ$Pe_TAl%d7C_#5jW5!aMkcK7ffl1+~YW~m8LkTB)E+^;Gx zH^o%Ni$z;5$cpmz^_-g`0SOWri%h%JC0AD)8Aq)_OBp%o&H|^spV_KWElEapSdT5! z>vK;H*mrR$GXjb?A-GNv`9+q1cmB^fSq{KEu8UV9jNP~D9LnaUaoR-ybn6_+DiWNg zhL#_8FP|OdS18KOmr&|WJfg+w=?*f^64E#E0fV^H62!7qK6$&j_!H(F1);vO5B;mcAetYOJ;rc6UyvyMe zuq~JJvahQT<6MnBd&VoN-r%ULg*4-*&!m|{>sCmWtGj9#p+(s(8;WaSn3U#$*>}1fQYw;?MqnYXOs5ceuXEuPxxo7v?saQu zV0oETPN%P==3EFsge9Iw%u8!Nx(T~_oW$Rcoo)$UQ7Z(xNRD@MhgiA6RYW`bT7?`_^Tc6zn2LY0ddIWv!?Qa38N7efd&b-2b z`!^W!c}X}A6ErPA2fc{FfEO#IAkjQn)O|X-ar)sgxzE3==dn?OK!2;}8CzTaKa}%c zfnz|x0kw@sz{n9e^q)zkgU-pP2zWM&R&%p6mSk++XGW9fJJxTK_tJ0#APK zn85Jg1xciwEoufi3F3mB1eyPVgWe1L310!b#xa3%uP`_$SpV`a`){)4D~57nkgpB} zsGb@BAd^GU9~p5$PuXQbe2zadghTp=3v7kP`JYS^ z$S=mGk-@DY-DXMW?^b<^+&z^+a&f}!R_-wZGj1t2FV}U zx{CZtW_$weXYscue%7;w`mgVZWfA`8-uP``8jkoEtA<6!=a<2Ut3llfOI9aJ+kf8eb@{EdeO z3L7E;FaONvPm$375DWYVoj{VIbbog-qCbT~|2Yc$sh$7r`2OFrq5tWPa4G&u;%7Hw z4@%-^U-fr?1nNKk?URr{-~zLze;Qu4GqBbg7byGz?|<&zfAmJd!1(_u8R)&hpUw?L z5(LGn{MF;i&5%MA_^$$|X9~!fhCjt=#FW4*T~!{uTUy|0~MuA4Y+HYUD3`=N!rJ_(X?MAn1w$I^=Ej|Kj@!@8p-^HzXbkoCVxh7 z{7#z8`J40_xVwP)`_=sE0RKB@Gyh+X)FRgJoIgFRf9I?f{>uURTeJP&JF!1KSbwK4 zmHbA>|2@k;eFlH$43>j9yuV}rbsGZ>hCk;H{~QJW_*KB#C5hj$|Ltb;AFNs}C|xq( zn`QXl@&8#m`R@i&-3!d@Apy#BY9Xo@wkCkx{R002 zeFt%Y-YY*F{ii8l=*pYlbNq8s_D}hKT0+PSXo^PlcPAzHb3XRZQQ*G}nm+u0&CV2M Wpg=YziJeUL-T&R)yZ1v^oe$kr-BqWa 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 Date: Tue, 7 Jul 2020 15:27:57 +0100 Subject: [PATCH 0543/1126] update jruby to 9.2.12.0 Also tweak the documentation since most of the add-opens are no longer needed, except: java.io due to colinsurprenant/jruby-stdin-channel#1 java.security due to jruby-openssl java.nio.channels, sun.nio.ch, sun.management and java.io from jruby: https://github.com/jruby/jruby/blob/9.2.12.0/bin/.jruby.module_opts Co-authored-by: Ry Biesemeyer --- docs/static/troubleshooting.asciidoc | 22 +++++++--------------- rubyUtils.gradle | 2 +- versions.yml | 4 ++-- 3 files changed, 10 insertions(+), 18 deletions(-) diff --git a/docs/static/troubleshooting.asciidoc b/docs/static/troubleshooting.asciidoc index cb48217de..124eaa600 100644 --- a/docs/static/troubleshooting.asciidoc +++ b/docs/static/troubleshooting.asciidoc @@ -59,8 +59,8 @@ Running Logstash with Java 11 results in warnings similar to these: [source,sh] ----- WARNING: An illegal reflective access operation has occurred -WARNING: Illegal reflective access by org.jruby.util.SecurityHelper (file:/Users/chrisuser/logstash-6.7.0/logstash-core/lib/jars/jruby-complete-9.2.6.0.jar) to field java.lang.reflect.Field.modifiers -WARNING: Please consider reporting this to the maintainers of org.jruby.util.SecurityHelper +WARNING: Illegal reflective access by org.jruby.ext.openssl.SecurityHelper (file:/{...}/jruby{...}jopenssl.jar) to field java.security.MessageDigest.provider +WARNING: Please consider reporting this to the maintainers of org.jruby.ext.openssl.SecurityHelper WARNING: Use --illegal-access=warn to enable warnings of further illegal reflective access operations WARNING: All illegal access operations will be denied in a future release ----- @@ -73,18 +73,11 @@ Try adding these values to the `jvm.options` file. [source,sh] ----- ---add-opens=java.base/java.lang=ALL-UNNAMED ---add-opens=java.base/java.security=ALL-UNNAMED ---add-opens=java.base/java.util=ALL-UNNAMED ---add-opens=java.base/java.security.cert=ALL-UNNAMED ---add-opens=java.base/java.util.zip=ALL-UNNAMED ---add-opens=java.base/java.lang.reflect=ALL-UNNAMED ---add-opens=java.base/java.util.regex=ALL-UNNAMED ---add-opens=java.base/java.net=ALL-UNNAMED ---add-opens=java.base/java.io=ALL-UNNAMED ---add-opens=java.base/java.lang=ALL-UNNAMED ---add-opens=java.base/javax.crypto=ALL-UNNAMED ---add-opens=java.management/sun.management=ALL-UNNAMED +--add-opens=java.base/java.security=ALL-UNNAMED +--add-opens=java.base/java.io=ALL-UNNAMED +--add-opens=java.base/java.nio.channels=org.jruby.dist +--add-opens=java.base/sun.nio.ch=org.jruby.dist +--add-opens=java.management/sun.management=org.jruby.dist ----- *Notes:* @@ -338,4 +331,3 @@ Coming soon - diff --git a/rubyUtils.gradle b/rubyUtils.gradle index b6ff3f11f..b9c4f7125 100644 --- a/rubyUtils.gradle +++ b/rubyUtils.gradle @@ -25,7 +25,7 @@ buildscript { dependencies { classpath 'org.yaml:snakeyaml:1.23' classpath "de.undercouch:gradle-download-task:4.0.4" - classpath "org.jruby:jruby-complete:9.2.11.1" + classpath "org.jruby:jruby-complete:9.2.12.0" } } diff --git a/versions.yml b/versions.yml index 3f13ba807..85ec616b8 100644 --- a/versions.yml +++ b/versions.yml @@ -7,8 +7,8 @@ logstash-core-plugin-api: 2.1.16 # jruby must reference a *released* version of jruby which can be downloaded from the official download url # *and* for which jars artifacts are published for compile-time jruby: - version: 9.2.11.1 - sha1: cceb81635fe3cd39f895c7632428e94b503e8e3d + version: 9.2.12.0 + sha1: bccc2034e773cb1aba2cc4b8b40921265f6e857f # jruby-runtime-override, if specified, will override the jruby version installed in vendor/jruby for logstash runtime only, # not for the compile-time jars From 40f99249e664ba3f877c8fa2643a39e2c61b24ce Mon Sep 17 00:00:00 2001 From: Rob Bavey Date: Mon, 6 Jul 2020 16:45:37 -0400 Subject: [PATCH 0544/1126] Clear `JAVA_HOME` to use bundled JDK for Elasticsearch This commit clears the `JAVA_HOME` variable when starting Elasticsearch to force it to use the bundled version of the JDK, rather than the default `JAVA_HOME` from the machine Logstash integration tests are being run on, and removes the likelihood of tests failing to run due to `JAVA_HOME` being set to a non-compliant JDK. --- qa/integration/services/elasticsearch_setup.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/qa/integration/services/elasticsearch_setup.sh b/qa/integration/services/elasticsearch_setup.sh index c5cebcf1e..0af88f0d9 100755 --- a/qa/integration/services/elasticsearch_setup.sh +++ b/qa/integration/services/elasticsearch_setup.sh @@ -8,7 +8,7 @@ ES_HOME="$current_dir/../../../build/elasticsearch" start_es() { es_args=$@ - $ES_HOME/bin/elasticsearch -Epath.data=/tmp/ls_integration/es-data -Epath.logs=/tmp/ls_integration/es-logs $es_args -p $ES_HOME/elasticsearch.pid > /tmp/elasticsearch.log 2>/dev/null & + JAVA_HOME= $ES_HOME/bin/elasticsearch -Epath.data=/tmp/ls_integration/es-data -Epath.logs=/tmp/ls_integration/es-logs $es_args -p $ES_HOME/elasticsearch.pid > /tmp/elasticsearch.log 2>/dev/null & count=120 echo "Waiting for elasticsearch to respond..." while ! curl --silent localhost:9200 && [[ $count -ne 0 ]]; do From 16b2ce735075375edbe9f87d90758ea7a4922bee Mon Sep 17 00:00:00 2001 From: DeDe Morton Date: Tue, 30 Jun 2020 18:00:43 -0700 Subject: [PATCH 0545/1126] Change links to refactored Beats getting started docs --- docs/static/advanced-pipeline.asciidoc | 4 ++-- docs/static/fb-ls-kafka-example.asciidoc | 4 ++-- docs/static/monitoring/monitoring-mb.asciidoc | 2 +- 3 files changed, 5 insertions(+), 5 deletions(-) diff --git a/docs/static/advanced-pipeline.asciidoc b/docs/static/advanced-pipeline.asciidoc index 63668aa0e..1e3e274ee 100644 --- a/docs/static/advanced-pipeline.asciidoc +++ b/docs/static/advanced-pipeline.asciidoc @@ -31,7 +31,7 @@ input plugin enables Logstash to receive events from the Elastic Beats framework to work with the Beats framework, such as Packetbeat and Metricbeat, can also send event data to Logstash. To install Filebeat on your data source machine, download the appropriate package from the Filebeat https://www.elastic.co/downloads/beats/filebeat[product page]. You can also refer to -{filebeat-ref}/filebeat-getting-started.html[Getting Started with Filebeat] in the Beats documentation for additional +{filebeat-ref}/filebeat-installation-configuration.html[Filebeat quick start] for additional installation instructions. After installing Filebeat, you need to configure it. Open the `filebeat.yml` file located in your Filebeat installation @@ -654,7 +654,7 @@ If you are using Kibana to visualize your data, you can also explore the Filebea image::static/images/kibana-filebeat-data.png[Discovering Filebeat data in Kibana] -See the {filebeat-ref}/filebeat-getting-started.html[Filebeat getting started docs] for info about loading the Kibana +See the {filebeat-ref}/filebeat-installation-configuration.html[Filebeat quick start docs] for info about loading the Kibana index pattern for Filebeat. You've successfully created a pipeline that uses Filebeat to take Apache web logs as input, parses those logs to diff --git a/docs/static/fb-ls-kafka-example.asciidoc b/docs/static/fb-ls-kafka-example.asciidoc index 86b428f9b..6764d43b1 100644 --- a/docs/static/fb-ls-kafka-example.asciidoc +++ b/docs/static/fb-ls-kafka-example.asciidoc @@ -28,8 +28,8 @@ The `-e` flag is optional and sends output to standard error instead of syslog. A connection to {es} and {kib} is required for this one-time setup step because {filebeat} needs to create the index template in {es} and load the sample dashboards into {kib}. For more information about configuring -the connection to {es}, see the Filebeat modules -{filebeat-ref}/filebeat-modules-quickstart.html[quick start]. +the connection to {es}, see the Filebeat +{filebeat-ref}/filebeat-installation-configuration.html[quick start]. + After the template and dashboards are loaded, you'll see the message `INFO {kib} dashboards successfully loaded. Loaded dashboards`. diff --git a/docs/static/monitoring/monitoring-mb.asciidoc b/docs/static/monitoring/monitoring-mb.asciidoc index a6bd60edc..116a11304 100644 --- a/docs/static/monitoring/monitoring-mb.asciidoc +++ b/docs/static/monitoring/monitoring-mb.asciidoc @@ -52,7 +52,7 @@ monitoring.cluster_uuid: PRODUCTION_ES_CLUSTER_UUID [[configure-metricbeat]] ==== Install and configure {metricbeat} -. {metricbeat-ref}/metricbeat-installation.html[Install {metricbeat}] on the +. {metricbeat-ref}/metricbeat-installation-configuration.html[Install {metricbeat}] on the same server as {ls}. . Enable the `logstash-xpack` module in {metricbeat}. + From b02978fd41377e3527a97af21d9c98039ba88631 Mon Sep 17 00:00:00 2001 From: Joao Duarte Date: Wed, 8 Jul 2020 19:01:16 +0100 Subject: [PATCH 0546/1126] add dependency notice for amazing_print --- .../src/main/resources/licenseMapping.csv | 1 + .../notices/amazing_print-NOTICE.txt | 22 +++++++++++++++++++ 2 files changed, 23 insertions(+) create mode 100644 tools/dependencies-report/src/main/resources/notices/amazing_print-NOTICE.txt diff --git a/tools/dependencies-report/src/main/resources/licenseMapping.csv b/tools/dependencies-report/src/main/resources/licenseMapping.csv index 043d5a9ba..36fcada45 100644 --- a/tools/dependencies-report/src/main/resources/licenseMapping.csv +++ b/tools/dependencies-report/src/main/resources/licenseMapping.csv @@ -3,6 +3,7 @@ dependency,dependencyUrl,licenseOverride "atomic:",http://github.com/ruby-concurrency/atomic,Apache-2.0 "avl_tree:",https://github.com/nahi/avl_tree,BSD-2-Clause-FreeBSD "avro:",https://github.com/apache/avro/tree/master/lang/ruby,Apache-2.0 +"amazing_print:",https://github.com/amazing-print/amazing_print,MIT "awesome_print:",https://github.com/awesome-print/awesome_print,MIT "aws-eventstream:",https://github.com/aws/aws-sdk-ruby/tree/master/gems/aws-eventstream,Apache-2.0 "aws-sdk-core:",http://github.com/aws/aws-sdk-ruby,Apache-2.0 diff --git a/tools/dependencies-report/src/main/resources/notices/amazing_print-NOTICE.txt b/tools/dependencies-report/src/main/resources/notices/amazing_print-NOTICE.txt new file mode 100644 index 000000000..d5ab3a384 --- /dev/null +++ b/tools/dependencies-report/src/main/resources/notices/amazing_print-NOTICE.txt @@ -0,0 +1,22 @@ +MIT License + +Copyright (c) 2010-2019 Michael Dvorkin +Copyright (c) 2020 AmazingPrint + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. From 6719163863a24d40bd8a9e5d8126ea34f012a038 Mon Sep 17 00:00:00 2001 From: Karen Metts Date: Mon, 6 Jul 2020 17:59:57 -0400 Subject: [PATCH 0547/1126] Doc:Replace outdated pipeline viewer screenshot --- .../monitoring/images/pipeline-tree.png | Bin 149305 -> 107838 bytes 1 file changed, 0 insertions(+), 0 deletions(-) diff --git a/docs/static/monitoring/images/pipeline-tree.png b/docs/static/monitoring/images/pipeline-tree.png index 2643c755a4f8d6892ee615703b57adf2d2fa8be0..5df4d3545e9a212a2a74fafee6be3a759fb14f20 100644 GIT binary patch literal 107838 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

bU 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 z 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 F0syqlcB=pY literal 149305 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 Bf}{Wd From efbdd8d27ce27c926094453452166480a179e1b9 Mon Sep 17 00:00:00 2001 From: Rob Bavey Date: Mon, 13 Jul 2020 09:09:17 -0400 Subject: [PATCH 0548/1126] Fix gradle typo Inadvertent extra character causes aarch64 builds to fail. --- build.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/build.gradle b/build.gradle index 53df9822c..784544059 100644 --- a/build.gradle +++ b/build.gradle @@ -131,7 +131,7 @@ tasks.register("configureArchitecture") { String esArch = arch // For aarch64 architectures, beats and elasticsearch name their artifacts differently - if (arch == "aarch64") {i + if (arch == "aarch64") { beatsArch="arm64" esArch="aarch64" } else if (arch == "amd64") { From 7a4b81363bfb1f4930e5d3ed8aeb918c5c1bc1bd Mon Sep 17 00:00:00 2001 From: Rob Bavey Date: Tue, 16 Jun 2020 12:54:02 -0400 Subject: [PATCH 0549/1126] Fix kafka setup scripts This commit updates the kafka setup scripts to ensure that the kafka setup is clean between builds, by setting an explicit zookeeper data directory to be cleaned each time, and correctly overriding `log.dirs` instead of `log.dir` to ensure that the kafka logs are written and wiped in a consistent place each time, which helps when using the non-immutable images used in arm64 tests. --- qa/integration/services/kafka_setup.sh | 11 +++++++---- qa/integration/specs/kafka_input_spec.rb | 21 +++++++++++---------- 2 files changed, 18 insertions(+), 14 deletions(-) diff --git a/qa/integration/services/kafka_setup.sh b/qa/integration/services/kafka_setup.sh index e874883af..08d36e357 100755 --- a/qa/integration/services/kafka_setup.sh +++ b/qa/integration/services/kafka_setup.sh @@ -17,6 +17,7 @@ KAFKA_HOME=$INSTALL_DIR/kafka KAFKA_TOPIC=logstash_topic_plain KAFKA_MESSAGES=37 KAFKA_LOGS_DIR=/tmp/ls_integration/kafka-logs +ZOOKEEPER_DATA_DIR=/tmp/ls_integration/zookeeper setup_kafka() { local version=$1 @@ -25,17 +26,19 @@ setup_kafka() { curl -s -o $INSTALL_DIR/kafka.tgz "https://mirrors.ocf.berkeley.edu/apache/kafka/$version/kafka_2.11-$version.tgz" mkdir $KAFKA_HOME && tar xzf $INSTALL_DIR/kafka.tgz -C $KAFKA_HOME --strip-components 1 rm $INSTALL_DIR/kafka.tgz + echo "dataDir=$ZOOKEEPER_DATA_DIR" >> $KAFKA_HOME/config/zookeeper.properties fi } start_kafka() { echo "Starting ZooKeeper" - $KAFKA_HOME/bin/zookeeper-server-start.sh -daemon $KAFKA_HOME/config/zookeeper.properties - wait_for_port 2181 - echo "Starting Kafka broker" rm -rf ${KAFKA_LOGS_DIR} mkdir -p ${KAFKA_LOGS_DIR} - $KAFKA_HOME/bin/kafka-server-start.sh -daemon $KAFKA_HOME/config/server.properties --override delete.topic.enable=true --override advertised.host.name=127.0.0.1 --override log.dir=${KAFKA_LOGS_DIR} --override log.flush.interval.ms=200 + rm -rf ${ZOOKEEPER_DATA_DIR} + mkdir -p ${ZOOKEEPER_DATA_DIR} + $KAFKA_HOME/bin/zookeeper-server-start.sh -daemon $KAFKA_HOME/config/zookeeper.properties + wait_for_port 2181 + $KAFKA_HOME/bin/kafka-server-start.sh -daemon $KAFKA_HOME/config/server.properties --override delete.topic.enable=true --override advertised.host.name=127.0.0.1 --override log.dir=${KAFKA_LOGS_DIR} --override log.dirs=${KAFKA_LOGS_DIR} --override log.flush.interval.ms=200 wait_for_port 9092 } diff --git a/qa/integration/specs/kafka_input_spec.rb b/qa/integration/specs/kafka_input_spec.rb index 6e9ac5a0f..315b45efa 100644 --- a/qa/integration/specs/kafka_input_spec.rb +++ b/qa/integration/specs/kafka_input_spec.rb @@ -30,21 +30,22 @@ describe "Test Kafka Input" do } after(:all) { - @fixture.teardown + @fixture.teardown unless @fixture.nil? } it "can ingest 37 apache log lines from Kafka broker" do - logstash_service = @fixture.get_service("logstash") - logstash_service.start_background(@fixture.config) + unless @fixture.nil? + logstash_service = @fixture.get_service("logstash") + logstash_service.start_background(@fixture.config) - try(num_retries) do - expect(@fixture.output_exists?).to be true - end + try(num_retries) do + expect(@fixture.output_exists?).to be true + end - try(num_retries) do - count = File.foreach(@fixture.actual_output).inject(0) {|c, _| c+1} - expect(count).to eq(num_events) + try(num_retries) do + count = File.foreach(@fixture.actual_output).inject(0) {|c, _| c+1} + expect(count).to eq(num_events) + end end end - end From 8e750ccd08a27e3c17163f4e993b69d901b16f55 Mon Sep 17 00:00:00 2001 From: Karen Metts Date: Thu, 9 Jul 2020 16:32:43 -0400 Subject: [PATCH 0550/1126] Doc:Add info on reserved fields in events Co-authored-by: Ry Biesemeyer Fixes: 11946 --- docs/static/processing-info.asciidoc | 2 ++ docs/static/reserved-fields.asciidoc | 39 ++++++++++++++++++++++++++++ 2 files changed, 41 insertions(+) create mode 100644 docs/static/reserved-fields.asciidoc diff --git a/docs/static/processing-info.asciidoc b/docs/static/processing-info.asciidoc index 6466c9af0..fe9904109 100644 --- a/docs/static/processing-info.asciidoc +++ b/docs/static/processing-info.asciidoc @@ -44,3 +44,5 @@ processing cost required to preserve order. The Java pipeline initialization time appears in the startup logs at INFO level. Initialization time is the time it takes to compile the pipeline config and instantiate the compiled execution for all workers. + +include::reserved-fields.asciidoc[] diff --git a/docs/static/reserved-fields.asciidoc b/docs/static/reserved-fields.asciidoc new file mode 100644 index 000000000..d05fe9b73 --- /dev/null +++ b/docs/static/reserved-fields.asciidoc @@ -0,0 +1,39 @@ +[float] +[[reserved-fields]] +==== Reserved fields in {ls} events + +Some fields in {ls} events are reserved, or are required to adhere to a certain +shape. Using these fields can cause runtime exceptions when the event API or +plugins encounter incompatible values. + +[cols="<,<",options="header",] +|======================================================================= +| | +| <> |A key/value map. + +Ruby-based Plugin API: value is an +https://javadoc.io/static/org.jruby/jruby-core/9.2.5.0/org/jruby/RubyHash.html[org.jruby.RubyHash]. + +Java-based Plugin API: value is an +https://github.com/elastic/logstash/blob/master/logstash-core/src/main/java/org/logstash/ConvertedMap.java[org.logstash.ConvertedMap]. + +In serialized form (such as JSON): a key/value map where the keys must be +strings and the values are not constrained to a particular type. + +| `@timestamp` |An object holding representation of a specific moment in time. + +Ruby-based Plugin API: value is an +https://javadoc.io/static/org.jruby/jruby-core/9.2.5.0/org/jruby/RubyTime.html[org.jruby.RubyTime]. + +Java-based Plugin API: value is a +https://docs.oracle.com/en/java/javase/11/docs/api/java.base/java/time/Instant.html[java.time.Instant]. + +In serialized form (such as JSON) or when setting with Event#set: an +ISO8601-compliant String value is acceptable. + +| `@version` |A string, holding an integer value. +| `tags` |An array of distinct strings +|======================================================================= + + + From b2c652bf9dbdb6da5fb6a132736e79adad53e6aa Mon Sep 17 00:00:00 2001 From: Rob Bavey Date: Mon, 13 Jul 2020 14:41:38 -0400 Subject: [PATCH 0551/1126] Ensure more gradle tasks using task avoidance API Release Manager builds were failing as `downloadEs` task was being needlessly run during `rake artifact:all` task. When run with `RELEASE=1`. this was causing build failures due to the non-availability of Elasticsearch release artifacts. This commit aims to avoid running the `downloadES` task when it is not needed, continuing the work done in #11914 This commit also removes code that was repeated in different parts of the build script. --- build.gradle | 21 ++++++++------------- x-pack/build.gradle | 1 + 2 files changed, 9 insertions(+), 13 deletions(-) diff --git a/build.gradle b/build.gradle index 784544059..cb047e880 100644 --- a/build.gradle +++ b/build.gradle @@ -450,12 +450,9 @@ tasks.register("runIntegrationTests"){ dependsOn tasks.getByPath(":logstash-integration-tests:integrationTests") dependsOn copyEs dependsOn copyFilebeat + shouldRunAfter ":logstash-core:test" } -bootstrap.dependsOn assemblyDeps - -runIntegrationTests.shouldRunAfter tasks.getByPath(":logstash-core:test") -check.dependsOn runIntegrationTests tasks.register("generateLicenseReport", JavaExec) { @@ -506,11 +503,8 @@ tasks.register("generatePluginsVersion") { } bootstrap.dependsOn assemblyDeps - -runIntegrationTests.shouldRunAfter tasks.getByPath(":logstash-core:test") check.dependsOn runIntegrationTests - Boolean oss = System.getenv('OSS').equals('true') if (!oss) { @@ -520,11 +514,12 @@ if (!oss) { dependsOn installTestGems } } - tasks.getByPath(":logstash-xpack:rubyIntegrationTests").configure { - dependsOn copyEs - } } - - task runXPackUnitTests(dependsOn: [tasks.getByPath(":logstash-xpack:rubyTests")]) {} - task runXPackIntegrationTests(dependsOn: [tasks.getByPath(":logstash-xpack:rubyIntegrationTests")]) {} } + + tasks.register("runXPackUnitTests"){ + dependsOn ":logstash-xpack:rubyTests" + } + tasks.register("runXPackIntegrationTests"){ + dependsOn ":logstash-xpack:rubyIntegrationTests" + } diff --git a/x-pack/build.gradle b/x-pack/build.gradle index 5f78f0388..5c978f556 100644 --- a/x-pack/build.gradle +++ b/x-pack/build.gradle @@ -35,6 +35,7 @@ tasks.register("rubyTests", Test) { } tasks.register("rubyIntegrationTests", Test) { + dependsOn (":copyEs") inputs.files fileTree("${projectDir}/qa") inputs.files fileTree("${projectDir}/lib") inputs.files fileTree("${projectDir}/modules") From 9f7cc64ee81dae34b6a2632e8f378c4db2bc1e33 Mon Sep 17 00:00:00 2001 From: Colin Surprenant Date: Thu, 2 Jul 2020 14:49:14 -0400 Subject: [PATCH 0552/1126] monitor worker threads exceptions to not crash logstash, just the failed pipeline The worker threads were not correctly monitored for a worker loop exception resulting in a complete logstash crash upon any exception even when multiple pipelines are running. Now only the failed pipeline is terminated. If pipeline reloading is enabled, it is possible to edit the config and have that failed pipeline reloaded. --- logstash-core/lib/logstash/agent.rb | 4 +- logstash-core/lib/logstash/java_pipeline.rb | 73 +++++++++++++------ logstash-core/lib/logstash/pipeline.rb | 6 +- .../spec/logstash/java_pipeline_spec.rb | 42 +++++++++++ .../org/logstash/execution/WorkerLoop.java | 4 - 5 files changed, 100 insertions(+), 29 deletions(-) diff --git a/logstash-core/lib/logstash/agent.rb b/logstash-core/lib/logstash/agent.rb index 3042f58a8..f05a3b9f7 100644 --- a/logstash-core/lib/logstash/agent.rb +++ b/logstash-core/lib/logstash/agent.rb @@ -200,7 +200,9 @@ class LogStash::Agent converge_result rescue => e - logger.error("An exception happened when converging configuration", :exception => e.class, :message => e.message, :backtrace => e.backtrace) + attributes = {:exception => e.class, :message => e.message} + attributes.merge!({:backtrace => e.backtrace}) if logger.debug? + logger.error("An exception happened when converging configuration", attributes) end # Calculate the Logstash uptime in milliseconds diff --git a/logstash-core/lib/logstash/java_pipeline.rb b/logstash-core/lib/logstash/java_pipeline.rb index c44a81f72..7e7ba3016 100644 --- a/logstash-core/lib/logstash/java_pipeline.rb +++ b/logstash-core/lib/logstash/java_pipeline.rb @@ -17,6 +17,7 @@ require "thread" require "concurrent" +require "thwait" require "logstash/filters/base" require "logstash/inputs/base" require "logstash/outputs/base" @@ -119,19 +120,31 @@ module LogStash; class JavaPipeline < JavaBasePipeline @finished_run.make_false @thread = Thread.new do + error_log_params = ->(e) { + default_logging_keys( + :exception => e, + :backtrace => e.backtrace, + "pipeline.sources" => pipeline_source_details + ) + } + begin LogStash::Util.set_thread_name("pipeline.#{pipeline_id}") ThreadContext.put("pipeline.id", pipeline_id) run @finished_run.make_true rescue => e - close - pipeline_log_params = default_logging_keys( - :exception => e, - :backtrace => e.backtrace, - "pipeline.sources" => pipeline_source_details) - logger.error("Pipeline aborted due to error", pipeline_log_params) + # no need to log at ERROR level since this log will be redundant to the log in + # the worker loop thread global rescue clause + logger.debug("Pipeline terminated by worker error", error_log_params.call(e)) ensure + # we must trap any exception here to make sure the following @finished_execution + # is always set to true regardless of any exception before in the close method call + begin + close + rescue => e + logger.error("Pipeline close error, ignoring", error_log_params.call(e)) + end @finished_execution.make_true end end @@ -176,21 +189,18 @@ module LogStash; class JavaPipeline < JavaBasePipeline transition_to_running start_flusher # Launches a non-blocking thread for flush events - wait_inputs - transition_to_stopped + begin + monitor_inputs_and_workers + ensure + transition_to_stopped - @logger.debug("Input plugins stopped! Will shutdown filter/output workers.", default_logging_keys) - - shutdown_flusher - shutdown_workers - - close + shutdown_flusher + shutdown_workers + close + end @logger.debug("Pipeline has been shutdown", default_logging_keys) - - # exit code - return 0 - end # def run + end def transition_to_running @running.make_true @@ -279,7 +289,16 @@ module LogStash; class JavaPipeline < JavaBasePipeline thread = Thread.new do Util.set_thread_name("[#{pipeline_id}]>worker#{t}") ThreadContext.put("pipeline.id", pipeline_id) - worker_loop.run + begin + worker_loop.run + rescue => e + # WorkerLoop.run() catches all Java Exception class and re-throws as IllegalStateException with the + # original exception as the cause + @logger.error( + "Pipeline worker error, the pipeline will be stopped", + default_logging_keys(:error => e.cause.message, :exception => e.cause.class, :backtrace => e.cause.backtrace) + ) + end end @worker_threads << thread end @@ -309,10 +328,20 @@ module LogStash; class JavaPipeline < JavaBasePipeline end.to_a.compact end - def wait_inputs - @input_threads.each do |thread| - thread.join # Thread or java.lang.Thread (both have #join) + def monitor_inputs_and_workers + twait = ThreadsWait.new(*(@input_threads + @worker_threads)) + + while !@input_threads.empty? + terminated_thread = twait.next_wait + if @input_threads.delete(terminated_thread).nil? + # this is a worker thread termination + # delete it from @worker_threads so that wait_for_workers does not wait for it + @worker_threads.delete(terminated_thread) + raise("Worker thread terminated in pipeline.id: #{pipeline_id}") + end end + + @logger.debug("Input plugins stopped! Will shutdown filter/output workers.", default_logging_keys) end def start_inputs diff --git a/logstash-core/lib/logstash/pipeline.rb b/logstash-core/lib/logstash/pipeline.rb index 30d1663d1..ccec00bab 100644 --- a/logstash-core/lib/logstash/pipeline.rb +++ b/logstash-core/lib/logstash/pipeline.rb @@ -402,8 +402,10 @@ module LogStash; class Pipeline < BasePipeline # # Users need to check their configuration or see if there is a bug in the # plugin. - @logger.error("Exception in pipelineworker, the pipeline stopped processing new events, please check your filter configuration and restart Logstash.", - default_logging_keys("exception" => e.message, "backtrace" => e.backtrace)) + @logger.error( + "Pipeline worker error, the pipeline will be stopped", + default_logging_keys("exception" => e.message, "backtrace" => e.backtrace) + ) raise e end diff --git a/logstash-core/spec/logstash/java_pipeline_spec.rb b/logstash-core/spec/logstash/java_pipeline_spec.rb index 68ad5c91a..69f5ceab9 100644 --- a/logstash-core/spec/logstash/java_pipeline_spec.rb +++ b/logstash-core/spec/logstash/java_pipeline_spec.rb @@ -88,6 +88,17 @@ class DummyFilter < LogStash::Filters::Base def close() end end +class DummyCrashingFilter < LogStash::Filters::Base + config_name "dummycrashingfilter" + milestone 2 + + def register; end + + def filter(event) + raise("crashing filter") + end +end + class DummySafeFilter < LogStash::Filters::Base config_name "dummysafefilter" milestone 2 @@ -226,6 +237,37 @@ describe LogStash::JavaPipeline do end end + context "a crashing worker" do + subject { mock_java_pipeline_from_string(config, pipeline_settings_obj) } + + let(:pipeline_settings) { { "pipeline.batch.size" => 1, "pipeline.workers" => 1 } } + let(:config) do + <<-EOS + input { generator {} } + filter { dummycrashingfilter {} } + output { dummyoutput {} } + EOS + end + let(:dummyoutput) { ::LogStash::Outputs::DummyOutput.new } + + before :each do + allow(::LogStash::Outputs::DummyOutput).to receive(:new).with(any_args).and_return(dummyoutput) + allow(LogStash::Plugin).to receive(:lookup).with("input", "generator").and_return(LogStash::Inputs::Generator) + allow(LogStash::Plugin).to receive(:lookup).with("codec", "plain").and_return(LogStash::Codecs::Plain) + allow(LogStash::Plugin).to receive(:lookup).with("filter", "dummycrashingfilter").and_return(DummyCrashingFilter) + allow(LogStash::Plugin).to receive(:lookup).with("output", "dummyoutput").and_return(::LogStash::Outputs::DummyOutput) + end + + after :each do + subject.shutdown + end + + it "does not raise in the main thread, terminates the run thread and finishes execution" do + expect { subject.start && subject.thread.join }.to_not raise_error + expect(subject.finished_execution?).to be_truthy + end + end + describe "defaulting the pipeline workers based on thread safety" do before(:each) do allow(LogStash::Plugin).to receive(:lookup).with("input", "dummyinput").and_return(DummyInput) diff --git a/logstash-core/src/main/java/org/logstash/execution/WorkerLoop.java b/logstash-core/src/main/java/org/logstash/execution/WorkerLoop.java index 843f67fe7..b0e974d3d 100644 --- a/logstash-core/src/main/java/org/logstash/execution/WorkerLoop.java +++ b/logstash-core/src/main/java/org/logstash/execution/WorkerLoop.java @@ -98,10 +98,6 @@ public final class WorkerLoop implements Runnable { execution.compute(batch, true, true); readClient.closeBatch(batch); } catch (final Exception ex) { - LOGGER.error( - "Exception in pipelineworker, the pipeline stopped processing new events, please check your filter configuration and restart Logstash.", - ex - ); throw new IllegalStateException(ex); } } From 05dbba780f97f0ef9a4565085aac6fa1470f9d68 Mon Sep 17 00:00:00 2001 From: Colin Surprenant Date: Thu, 2 Jul 2020 14:53:01 -0400 Subject: [PATCH 0553/1126] fix PipelineRegistry to avoid re-creating a pipeline in the process of being created A pipeline in the process of being created was not marked as such in the pipeline registry resulting in a situation where a slow to initialize pipeline could be recreated on state convergence resulting in a PQ LockException because that pipeline was already existing and held the PQ lock. Replace native Java concurency with Ruby Mutex for simpler and straighforward implementation. --- .../lib/logstash/pipelines_registry.rb | 160 ++++++++++++------ .../spec/logstash/pipelines_registry_spec.rb | 41 +++++ logstash-core/spec/support/matchers.rb | 2 +- 3 files changed, 154 insertions(+), 49 deletions(-) diff --git a/logstash-core/lib/logstash/pipelines_registry.rb b/logstash-core/lib/logstash/pipelines_registry.rb index cb9e37527..6143f3ee3 100644 --- a/logstash-core/lib/logstash/pipelines_registry.rb +++ b/logstash-core/lib/logstash/pipelines_registry.rb @@ -17,40 +17,100 @@ module LogStash class PipelineState - attr_reader :pipeline_id, :pipeline + attr_reader :pipeline_id def initialize(pipeline_id, pipeline) @pipeline_id = pipeline_id @pipeline = pipeline - @reloading = Concurrent::AtomicBoolean.new(false) + @loading = Concurrent::AtomicBoolean.new(false) + + # this class uses a lock to ensure thread safe visibility. + @lock = Mutex.new end def terminated? - # a reloading pipeline is never considered terminated - @reloading.false? && @pipeline.finished_execution? + @lock.synchronize do + # a loading pipeline is never considered terminated + @loading.false? && @pipeline.finished_execution? + end end - def set_reloading(is_reloading) - @reloading.value = is_reloading + def set_loading(is_loading) + @lock.synchronize do + @loading.value = is_loading + end end def set_pipeline(pipeline) - raise(ArgumentError, "invalid nil pipeline") if pipeline.nil? - @pipeline = pipeline + @lock.synchronize do + raise(ArgumentError, "invalid nil pipeline") if pipeline.nil? + @pipeline = pipeline + end + end + + def pipeline + @lock.synchronize { @pipeline } end end + class PipelineStates + + def initialize + @states = {} + @locks = {} + @lock = Mutex.new + end + + def get(pipeline_id) + @lock.synchronize do + @states[pipeline_id] + end + end + + def put(pipeline_id, state) + @lock.synchronize do + @states[pipeline_id] = state + end + end + + def remove(pipeline_id) + @lock.synchronize do + @states.delete(pipeline_id) + @locks.delete(pipeline_id) + end + end + + def size + @lock.synchronize do + @states.size + end + end + + def empty? + @lock.synchronize do + @states.empty? + end + end + + def each_with_object(init, &block) + states = @lock.synchronize { @states.dup } + states.each_with_object(init, &block) + end + + def get_lock(pipeline_id) + @lock.synchronize do + @locks[pipeline_id] ||= Mutex.new + end + end + end + + class PipelinesRegistry attr_reader :states include LogStash::Util::Loggable def initialize - # we leverage the semantic of the Java ConcurrentHashMap for the - # compute() method which is atomic; calling compute() concurrently - # will block until the other compute finishes so no mutex is necessary - # for synchronizing compute calls - @states = java.util.concurrent.ConcurrentHashMap.new - @locks = java.util.concurrent.ConcurrentHashMap.new + @states = PipelineStates.new end # Execute the passed creation logic block and create a new state upon success @@ -62,23 +122,35 @@ module LogStash # # @return [Boolean] new pipeline creation success def create_pipeline(pipeline_id, pipeline, &create_block) - lock = get_lock(pipeline_id) + lock = @states.get_lock(pipeline_id) lock.lock - success = false state = @states.get(pipeline_id) - if state - if state.terminated? - success = yield - state.set_pipeline(pipeline) - else - logger.error("Attempted to create a pipeline that already exists", :pipeline_id => pipeline_id) - end + + if state && !state.terminated? + logger.error("Attempted to create a pipeline that already exists", :pipeline_id => pipeline_id) + return false + end + + if state.nil? + state = PipelineState.new(pipeline_id, pipeline) + state.set_loading(true) @states.put(pipeline_id, state) + begin + success = yield + ensure + state.set_loading(false) + @states.remove(pipeline_id) unless success + end else - success = yield - @states.put(pipeline_id, PipelineState.new(pipeline_id, pipeline)) if success + state.set_loading(true) + state.set_pipeline(pipeline) + begin + success = yield + ensure + state.set_loading(false) + end end success @@ -92,22 +164,20 @@ module LogStash # # @yieldparam [Pipeline] the pipeline to terminate def terminate_pipeline(pipeline_id, &stop_block) - lock = get_lock(pipeline_id) + lock = @states.get_lock(pipeline_id) lock.lock state = @states.get(pipeline_id) if state.nil? logger.error("Attempted to terminate a pipeline that does not exists", :pipeline_id => pipeline_id) - @states.remove(pipeline_id) else yield(state.pipeline) - @states.put(pipeline_id, state) end ensure lock.unlock end - # Execute the passed reloading logic block in the context of the reloading state and set new pipeline in state + # Execute the passed reloading logic block in the context of the loading state and set new pipeline in state # @param pipeline_id [String, Symbol] the pipeline id # @param reload_block [Block] the reloading execution logic # @@ -115,26 +185,26 @@ module LogStash # # @return [Boolean] new pipeline creation success def reload_pipeline(pipeline_id, &reload_block) - lock = get_lock(pipeline_id) + lock = @states.get_lock(pipeline_id) lock.lock success = false state = @states.get(pipeline_id) + if state.nil? logger.error("Attempted to reload a pipeline that does not exists", :pipeline_id => pipeline_id) - @states.remove(pipeline_id) - else - state.set_reloading(true) - begin - success, new_pipeline = yield - state.set_pipeline(new_pipeline) - ensure - state.set_reloading(false) - end - @states.put(pipeline_id, state) + return false end - success + state.set_loading(true) + begin + success, new_pipeline = yield + state.set_pipeline(new_pipeline) + ensure + state.set_loading(false) + end + + success ensure lock.unlock end @@ -153,7 +223,7 @@ module LogStash # @return [Boolean] true if the states collection is empty. def empty? - @states.isEmpty + @states.empty? end # @return [Hash{String=>Pipeline}] @@ -189,11 +259,5 @@ module LogStash end end end - - def get_lock(pipeline_id) - @locks.compute_if_absent(pipeline_id) do |k| - java.util.concurrent.locks.ReentrantLock.new - end - end end end diff --git a/logstash-core/spec/logstash/pipelines_registry_spec.rb b/logstash-core/spec/logstash/pipelines_registry_spec.rb index 5a36b6332..3af1ff78a 100644 --- a/logstash-core/spec/logstash/pipelines_registry_spec.rb +++ b/logstash-core/spec/logstash/pipelines_registry_spec.rb @@ -101,6 +101,47 @@ describe LogStash::PipelinesRegistry do end end end + + context "when pipeline is initializing" do + let (:wait_start_create_block) { Queue.new } + let (:wait_before_exiting_create_block) { Queue.new } + let (:slow_initializing_pipeline) { double("slow_initializing_pipeline") } + let (:pipeline2) { double("pipeline2") } + + it "should create a loading state before calling the create block" do + + # create a thread which calls create_pipeline and wait in the create + # block so we can controle the pipeline initialization phase + t = Thread.new do + subject.create_pipeline(pipeline_id, slow_initializing_pipeline) do + # signal that we entered the create block + wait_start_create_block << "ping" + + # stall here until wait_before_exiting_create_block receives a message + wait_before_exiting_create_block.pop + + true + end + end + + # stall here until subject.create_pipeline has been called in the above thread + # and it entered the create block + wait_start_create_block.pop + + # finished_execution? should not be called in the below tests using terminated? + # because the loading state is true. This is to make sure the state is used and not + # the pipeline termination status + expect(slow_initializing_pipeline).not_to receive(:finished_execution?) + + expect(subject.states.get(pipeline_id).terminated?).to be_falsey + expect(subject.get_pipeline(pipeline_id)).to eq(slow_initializing_pipeline) + expect(subject.empty?).to be_falsey + + # signal termination of create block + wait_before_exiting_create_block << "ping" + t.join + end + end end context "terminating a pipeline" do diff --git a/logstash-core/spec/support/matchers.rb b/logstash-core/spec/support/matchers.rb index 71a37cd00..0a6c08f38 100644 --- a/logstash-core/spec/support/matchers.rb +++ b/logstash-core/spec/support/matchers.rb @@ -92,9 +92,9 @@ RSpec::Matchers.define :have_running_pipeline? do |pipeline_config| try(30) do pipeline = agent.get_pipeline(pipeline_config.pipeline_id) expect(pipeline).to_not be_nil + expect(pipeline.running?).to be_truthy end expect(pipeline.config_str).to eq(pipeline_config.config_string) - expect(pipeline.running?).to be_truthy expect(agent.running_pipelines.keys.map(&:to_s)).to include(pipeline_config.pipeline_id.to_s) end From 556865ee88b90fea2beced0abdf20dcecb3718e8 Mon Sep 17 00:00:00 2001 From: Colin Surprenant Date: Wed, 8 Jul 2020 13:12:05 -0400 Subject: [PATCH 0554/1126] ignore default username when no password is set fixes a regression introduced with the api_key support for xpack monitoring and management in #11864 which disabled the possibility to not use any authentication by relying on the default options and only enabling monitoring for example. It now ignores the default username option when no password is explicitly set. --- x-pack/lib/helpers/elasticsearch_options.rb | 16 +++++---------- .../elasticsearch_source_spec.rb | 8 ++++++-- .../helpers/elasticsearch_options_spec.rb | 20 +++++++++---------- 3 files changed, 20 insertions(+), 24 deletions(-) diff --git a/x-pack/lib/helpers/elasticsearch_options.rb b/x-pack/lib/helpers/elasticsearch_options.rb index 26bd6d82a..397632a06 100644 --- a/x-pack/lib/helpers/elasticsearch_options.rb +++ b/x-pack/lib/helpers/elasticsearch_options.rb @@ -67,9 +67,12 @@ module LogStash module Helpers opts['ssl'] = true end - # the username setting has a default value and should not be included when using another authentication + # the username setting has a default value and should not be included when using another authentication such as cloud_auth or api_key. + # it should also not be included when no password is set. # it is safe to silently remove here since all authentication verifications have been validated at this point. - if settings.set?("#{prefix}#{feature}.elasticsearch.cloud_auth") || settings.set?("#{prefix}#{feature}.elasticsearch.api_key") + if settings.set?("#{prefix}#{feature}.elasticsearch.cloud_auth") || + settings.set?("#{prefix}#{feature}.elasticsearch.api_key") || + (!settings.set?("#{prefix}#{feature}.elasticsearch.password") && !settings.set?("#{prefix}#{feature}.elasticsearch.username")) opts.delete('user') end @@ -201,15 +204,6 @@ module LogStash module Helpers authentication_count += 1 if provided_password authentication_count += 1 if provided_api_key - if authentication_count == 0 - # when no explicit authentication is set it is relying on default username - # but without and explicit password set - raise(ArgumentError, - "With the default #{prefix}#{feature}.elasticsearch.username, " + - "#{prefix}#{feature}.elasticsearch.password must be set" - ) - end - if authentication_count > 1 raise(ArgumentError, "Multiple authentication options are specified, please only use one of #{prefix}#{feature}.elasticsearch.username/password, #{prefix}#{feature}.elasticsearch.cloud_auth or #{prefix}#{feature}.elasticsearch.api_key") end diff --git a/x-pack/spec/config_management/elasticsearch_source_spec.rb b/x-pack/spec/config_management/elasticsearch_source_spec.rb index 7eb385dd1..927d853b2 100644 --- a/x-pack/spec/config_management/elasticsearch_source_spec.rb +++ b/x-pack/spec/config_management/elasticsearch_source_spec.rb @@ -151,8 +151,12 @@ describe LogStash::ConfigManagement::ElasticsearchSource do } end - it "should raise an ArgumentError" do - expect { described_class.new(system_settings) }.to raise_error(ArgumentError) + it "will rely on username and password settings" do + # since cloud_id and cloud_auth are simply containers for host and username/password + # both could be set independently and if cloud_auth is not set then authn will be done + # using the provided username/password settings, which can be set or not if not auth is + # required. + expect { described_class.new(system_settings) }.to_not raise_error end end end diff --git a/x-pack/spec/helpers/elasticsearch_options_spec.rb b/x-pack/spec/helpers/elasticsearch_options_spec.rb index 3fb5b4922..edc0d7eea 100644 --- a/x-pack/spec/helpers/elasticsearch_options_spec.rb +++ b/x-pack/spec/helpers/elasticsearch_options_spec.rb @@ -107,10 +107,11 @@ describe LogStash::Helpers::ElasticsearchOptions do } end - it "fails without password" do - expect { - test_class.es_options_from_settings_or_modules('monitoring', system_settings) - }.to raise_error(ArgumentError, /password must be set/) + it "ignores the implicit default username when no password is set" do + # when no explicit password is set then the default/implicit username should be ignored + es_options = test_class.es_options_from_settings_or_modules('monitoring', system_settings) + expect(es_options).to_not include("user") + expect(es_options).to_not include("password") end context "with cloud_auth" do @@ -296,13 +297,10 @@ describe LogStash::Helpers::ElasticsearchOptions do end context "when cloud_auth is not set" do - - it "raises for invalid configuration" do - # if not other authn is provided it will assume basic auth using the default username - # but the password is missing. - expect { - test_class.es_options_from_settings_or_modules('monitoring', system_settings) - }.to raise_error(ArgumentError, /With the default.*?username,.*?password must be set/) + it "does not use authentication and ignores the default username" do + es_options = test_class.es_options_from_settings_or_modules('monitoring', system_settings) + expect(es_options).to include("cloud_id") + expect(es_options.keys).to_not include("hosts", "user", "password") end context 'username and password set' do From 8ec9d4e6d064e5bff22660c19d9264b14035e8cc Mon Sep 17 00:00:00 2001 From: Karen Metts <35154725+karenzone@users.noreply.github.com> Date: Tue, 14 Jul 2020 17:57:10 -0400 Subject: [PATCH 0555/1126] [Doc]Release notes for 7.8 (#12033) (#12037) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-authored-by: João Duarte --- docs/static/releasenotes.asciidoc | 199 +++++++++++++++++++++++++++++- 1 file changed, 198 insertions(+), 1 deletion(-) diff --git a/docs/static/releasenotes.asciidoc b/docs/static/releasenotes.asciidoc index 0e59ae361..de9801151 100644 --- a/docs/static/releasenotes.asciidoc +++ b/docs/static/releasenotes.asciidoc @@ -3,6 +3,7 @@ This section summarizes the changes in the following releases: +* <> * <> * <> * <> @@ -29,6 +30,170 @@ This section summarizes the changes in the following releases: * <> * <> +[[logstash-7-8-0]] +=== Logstash 7.8.0 Release Notes + +==== New features and improvements + +===== Expanded JDK ecosystem + +We have improved test scripts infrastructure to accept a specific Java +Development Kit (JDK) present in the host. The changes include exporting the +path to a JDK home into an environment variable named BUILD_JAVA_HOME and its +use by shell scripts to launch test and integration scripts. This work and other +JDK14 fixes pave the way for Logstash to support both AdoptOpenJDK 11 and 14 in +the near future . https://github.com/elastic/logstash/pull/11786[#11786], +https://github.com/elastic/logstash/pull/11839[#11839], +https://github.com/elastic/logstash/pull/11935[#11935] + +===== Expanded JDK platform support + +{ls} runs on many different operating platforms and various flavors of the Java +Development Kit (JDK), and we’ve expanded this coverage in 7.8.0. {ls} has +introduced support for running on CentOS/RHEL 8.x and Ubuntu 20.04. +We’ve added new JDK support for Zulu 11, AdoptOpenJDK 11, and +Oracle/OpenJDK/AdoptOpenJDK 14. + +===== {es} API key support + +Support for API keys was added to {es} in 6.7.0. With 7.8.0 {ls} introduces +support for {es} API keys in the {es} output plugin +https://github.com/logstash-plugins/logstash-output-elasticsearch/pull/934[#934]. + +Authentication in {es} can be done in different ways, from LDAP to SAML and +others. User/password authentication makes sense for discrete users accessing +{es}. For machine-to-machine communication, API key access is more common. Check out <> for more information about using API keys with {ls} +and {es}. + +Support for API keys in the {es} input and filter plugins, and the monitoring +and management features will be added in upcoming releases. + + +===== Proxy support for monitoring and centralized management + +Many of our users deploy {ls} and the Elastic Stack in segmented networks where +one component may not be able to directly reach out to another or to the +Internet. {ls} plugins, such as the elasticsearch, http and SNS outputs, support +the configuration of proxy servers. Version 7.8.0 brings proxy support to +monitoring and central management +https://github.com/elastic/logstash/pull/11799[#11799]. + +Configure the proxy's URL in your `logstash.yml` file using +"xpack.monitoring.elasticsearch.proxy" (for monitoring) or +"xpack.management.elasticsearch.proxy" (for central management). + + +==== Performance improvements and notable issues fixed + +* Performance: Share a single secret store https://github.com/elastic/logstash/pull/10794[#10794] +* Performance: Improve event.clone memory usage https://github.com/elastic/logstash/pull/11794[#11794] +* Refactor: Avoid array in case of single event https://github.com/elastic/logstash/pull/11732[#11732] +* Debugging: Print RUBY_DESCRIPTION at startup to facilitate debugging https://github.com/elastic/logstash/pull/11852[#11852] +* Fix: Avoid gsub (frame dependent) usage from Java https://github.com/elastic/logstash/pull/11874[#11874] + +==== Announcement: Azure and Netflow module deprecation + +Azure and Netflow modules in Logstash have been deprecated and replaced by +the Azure modules in {filebeat-ref}/filebeat-module-azure.html[{filebeat}] and +{metricbeat-ref}/metricbeat-module-azure.html[{metricbeat}], and the Netflow +module in {filebeat-ref}/filebeat-module-netflow.html[{filebeat}]. The +{filebeat} and {metricbeat} modules are compliant with the +{ecs-ref}/index.html[Elastic Common Schema (ECS)]. + +==== Known issue + +*Performance regression.* A potential performance regression may affect +some users. This issue can cause a slowdown on pipeline compilation when +multiple large pipelines are in use. We believe the issue was introduced in 7.7.0. +This issue is currently being tracked and investigated in +https://github.com/elastic/logstash/issues/12031[#12031] + +This issue seems to be affecting only big pipeline installations (that is, big +pipeline definitions when multiple pipelines are defined). Symptoms include +increased startup time and the appearance that Logstash is not responding to +input events. + +If you believe this issue is affecting you, we recommended that you downgrade to +7.6.2 while we continue to investigate and provide a resolution. + +==== Plugins + +*Cef Codec - 6.1.1* + +* Improved encoding performance, especially when encoding many extension fields https://github.com/logstash-plugins/logstash-codec-cef/pull/81[#81] +* Fixed CEF short to long name translation for ahost/agentHostName field, according to documentation https://github.com/logstash-plugins/logstash-codec-cef/pull/75[#75] +* Fixed support for deep dot notation https://github.com/logstash-plugins/logstash-codec-cef/pull/73[#73] +* Removed obsolete `sev` and `deprecated_v1_fields` fields +* Fixed minor doc inconsistencies (added reverse_mapping to options table, moved it to alpha order in option descriptions, fixed typo) https://github.com/logstash-plugins/logstash-codec-cef/pull/60[#60] +* Added reverse_mapping option, which can be used to make encoder compliant to spec https://github.com/logstash-plugins/logstash-codec-cef/pull/51[#51] +* Fix handling of malformed inputs that have illegal unescaped-equals characters in extension field values (restores behaviour from <= v5.0.3 in some edge-cases) https://github.com/logstash-plugins/logstash-codec-cef/issues/56[#56] +* Fix bug in parsing headers where certain legal escape sequences could cause non-escaped pipe characters to be ignored. +* Fix bug in parsing extension values where a legal unescaped space in a field's value could be interpreted as a field separator https://github.com/logstash-plugins/logstash-codec-cef/pull/54[#54] +* Add explicit handling for extension key names that use array-like syntax that isn't legal with the strict-mode field-reference parser (e.g., `fieldname[0]` becomes `[fieldname][0]`). +* Fix handling of higher-plane UTF-8 characters in message body +* move `sev` and `deprecated_v1_fields` fields from deprecated to obsolete +* added mapping for outcome = eventOutcome from CEF whitepaper (ref:p26/39) +* changed rt from receiptTime to deviceReceiptTime (ref:p27/39) +* changed tokenizer to include additional fields (ad.fieldname) +* Add `delimiter` setting. This allows the decoder to be used with inputs like the TCP input where event delimiters are used. +* Implements the dictionary translation for abbreviated CEF field names from chapter Chapter 2: ArcSight Extension Dictionary page 3 of 39 of the CEF specification. +* add `_cefparsefailure` tag on failed decode +* breaking: Updated plugin to use new Java Event APIs +* Switch in-place sub! to sub when extracting `cef_version`. new Logstash Java Event does not support in-place String changes. +* Depend on logstash-core-plugin-api instead of logstash-core, removing the need to mass update plugins on major releases of logstash +* New dependency requirements for logstash-core for the 5.0 release +* Implements `encode` with escaping according to the CEF specification +* Config option `sev` is deprecated, use `severity` instead. +* Plugins were updated to follow the new shutdown semantic. This allows Logstash to instruct input plugins to terminate gracefully, + instead of using Thread.raise on the plugins' threads. https://github.com/elastic/logstash/pull/3895[#3895] +* Dependency on logstash-core update to 2.0 + +*Elasticsearch Filter - 3.7.1* + +* Fix: solves an issue where non-ascii unicode values in a template were not handled correctly https://github.com/logstash-plugins/logstash-filter-elasticsearch/pull/128[#128] + +*File Input - 4.1.18* + +* Fix: release watched files on completion (in read-mode) https://github.com/logstash-plugins/logstash-input-file/pull/271[#271] +* Added configuration setting `check_archive_validity` settings to enable + gzipped files verification. Fixes: https://github.com/logstash-plugins/logstash-input-file/issues/261[#261] +* [DOC] Added clarification for settings available with `read` mode https://github.com/logstash-plugins/logstash-input-file/pull/235[#235] +* [DOC] Rearranged text and fixed formatting for `mode` setting https://github.com/logstash-plugins/logstash-input-file/pull/266[#266] + +*Syslog Input - 3.4.2* + +* Remove (deprecated) dependency on thread_safe gem. +* CI: upgrade testing https://github.com/logstash-plugins/logstash-input-syslog/pull/58[#58] +* [DOC] Correct example for `timezone` option https://github.com/logstash-plugins/logstash-input-syslog/pull/53[#53] + +*Tcp Input - 6.0.5* + +* Fix potential startup crash that could occur when multiple instances of this plugin were started simultaneously https://github.com/logstash-plugins/logstash-input-tcp/pull/155[#155] + +*Kafka Integration - 10.2.0* + +* Changed: config defaults to be aligned with Kafka client defaults https://github.com/logstash-plugins/logstash-integration-kafka/pull/30[#30] + +* updated kafka client (and its dependencies) to version 2.4.1 https://github.com/logstash-plugins/logstash-integration-kafka/pull/16[#16] +* added the input `client_rack` parameter to enable support for follower fetching +* added the output `partitioner` parameter for tuning partitioning strategy +* Refactor: normalized error logging a bit - make sure exception type is logged +* Fix: properly handle empty ssl_endpoint_identification_algorithm https://github.com/logstash-plugins/logstash-integration-kafka/pull/8[#8] +* Refactor : made `partition_assignment_strategy` option easier to configure by accepting simple values from an enumerated set instead of requiring lengthy class paths https://github.com/logstash-plugins/logstash-integration-kafka/pull/25[#25] + +*Elasticsearch Output - 10.5.1* + +* [DOC] Removed outdated compatibility notices, reworked cloud notice, and fixed formatting for `hosts` examples https://github.com/logstash-plugins/logstash-output-elasticsearch/pull/938[#938] +* Added api_key support https://github.com/logstash-plugins/logstash-output-elasticsearch/pull/934[#934] +* [DOC] Added note about `_type` setting change from `doc` to `_doc` https://github.com/logstash-plugins/logstash-output-elasticsearch/pull/884[#884] +* Fixed default index value https://github.com/logstash-plugins/logstash-output-elasticsearch/pull/927[#927] + +*File Output - 4.3.0* + +* Made `stale_cleanup_interval` configurable https://github.com/logstash-plugins/logstash-output-file/pull/84[#84] +* CI: upgrade testing https://github.com/logstash-plugins/logstash-output-file/pull/83[#83] + + [[logstash-7-7-1]] === Logstash 7.7.1 Release Notes @@ -43,6 +208,22 @@ https://github.com/elastic/logstash/pull/11772[#11772] * Fixed: when x-pack Monitoring is configured with `cloud_id`, the monitoring pipeline now correctly resolves the hosts. https://github.com/elastic/logstash/pull/11800[#11800] +==== Known issue + +*Performance regression.* A potential performance regression may affects +some users. This issue can cause a slowdown on pipeline compilation when +multiple pipelines are in use. We believe the issue was introduced in 7.7.0. +This issue is currently being tracked and investigated in +https://github.com/elastic/logstash/issues/12031[#12031] + +This issue seems to be affecting only big pipeline installations (that is, big +pipeline definitions when multiple pipelines are defined). Symptoms include +increased startup time and the appearance that Logstash is not responding to +input events. + +If you believe this issue is affecting you, we recommended that you downgrade to +7.6.2 while we continue to investigate and provide a resolution. + ==== Plugins *Elasticsearch Output - 10.4.2* @@ -112,6 +293,22 @@ https://github.com/elastic/logstash/pull/11592[#11592] * Fixed: Change Javadoc to conform to updated requirements for JDK13 https://github.com/elastic/logstash/pull/11642[#11642] +==== Known issue + +*Performance regression.* A potential performance regression may affects +some users. This issue can cause a slowdown on pipeline compilation when +multiple pipelines are in use. We believe the issue was introduced in 7.7.0. +This issue is currently being tracked and investigated in +https://github.com/elastic/logstash/issues/12031[#12031] + +This issue seems to be affecting only big pipeline installations (that is, big +pipeline definitions when multiple pipelines are defined). Symptoms include +increased startup time and the appearance that Logstash is not responding to +input events. + +If you believe this issue is affecting you, we recommended that you downgrade to +7.6.2 while we continue to investigate and provide a resolution. + ==== Logstash Plugin changes *Grok Filter* @@ -1312,4 +1509,4 @@ Here are the plugin changes. - Tweaked logging statements to reduce verbosity - Fixed numerous issues relating to builds on Travis https://github.com/logstash-plugins/logstash-output-elasticsearch/pull/799[#799] * logstash-output-s3 - - Fixed issue where on restart, 0 byte files could erroneously be uploaded to s3 https://github.com/logstash-plugins/logstash-output-s3/issues/195[#195] \ No newline at end of file + - Fixed issue where on restart, 0 byte files could erroneously be uploaded to s3 https://github.com/logstash-plugins/logstash-output-s3/issues/195[#195] From c05ccd739fcd6ea55963a8f73044fb973b2a1cb3 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jo=C3=A3o=20Duarte?= Date: Wed, 15 Jul 2020 10:05:11 +0100 Subject: [PATCH 0556/1126] bump version to 7.10.0 (#12111) --- README.md | 16 ++++++++-------- versions.yml | 4 ++-- 2 files changed, 10 insertions(+), 10 deletions(-) diff --git a/README.md b/README.md index cc75a3553..023c531dc 100644 --- a/README.md +++ b/README.md @@ -28,14 +28,14 @@ These builds are created nightly and have undergone no formal QA, so they should | [deb-complete][] | [deb-oss][] | | [rpm-complete][] | [rpm-oss][] | -[tar-complete]: https://snapshots.elastic.co/downloads/logstash/logstash-7.9.0-SNAPSHOT.tar.gz -[zip-complete]: https://snapshots.elastic.co/downloads/logstash/logstash-7.9.0-SNAPSHOT.zip -[deb-complete]: https://snapshots.elastic.co/downloads/logstash/logstash-7.9.0-SNAPSHOT.deb -[rpm-complete]: https://snapshots.elastic.co/downloads/logstash/logstash-7.9.0-SNAPSHOT.rpm -[tar-oss]: https://snapshots.elastic.co/downloads/logstash/logstash-oss-7.9.0-SNAPSHOT.tar.gz -[zip-oss]: https://snapshots.elastic.co/downloads/logstash/logstash-oss-7.9.0-SNAPSHOT.zip -[deb-oss]: https://snapshots.elastic.co/downloads/logstash/logstash-oss-7.9.0-SNAPSHOT.deb -[rpm-oss]: https://snapshots.elastic.co/downloads/logstash/logstash-oss-7.9.0-SNAPSHOT.rpm +[tar-complete]: https://snapshots.elastic.co/downloads/logstash/logstash-7.10.0-SNAPSHOT.tar.gz +[zip-complete]: https://snapshots.elastic.co/downloads/logstash/logstash-7.10.0-SNAPSHOT.zip +[deb-complete]: https://snapshots.elastic.co/downloads/logstash/logstash-7.10.0-SNAPSHOT.deb +[rpm-complete]: https://snapshots.elastic.co/downloads/logstash/logstash-7.10.0-SNAPSHOT.rpm +[tar-oss]: https://snapshots.elastic.co/downloads/logstash/logstash-oss-7.10.0-SNAPSHOT.tar.gz +[zip-oss]: https://snapshots.elastic.co/downloads/logstash/logstash-oss-7.10.0-SNAPSHOT.zip +[deb-oss]: https://snapshots.elastic.co/downloads/logstash/logstash-oss-7.10.0-SNAPSHOT.deb +[rpm-oss]: https://snapshots.elastic.co/downloads/logstash/logstash-oss-7.10.0-SNAPSHOT.rpm ## Need Help? diff --git a/versions.yml b/versions.yml index 85ec616b8..a54cf09c6 100644 --- a/versions.yml +++ b/versions.yml @@ -1,7 +1,7 @@ --- # alpha and beta qualifiers are now added via VERSION_QUALIFIER environment var -logstash: 7.9.0 -logstash-core: 7.9.0 +logstash: 7.10.0 +logstash-core: 7.10.0 logstash-core-plugin-api: 2.1.16 # jruby must reference a *released* version of jruby which can be downloaded from the official download url From 51b5217826f29ef40395d77749584d7b7b6f924a Mon Sep 17 00:00:00 2001 From: Joao Duarte Date: Wed, 15 Jul 2020 10:29:07 +0100 Subject: [PATCH 0557/1126] don't call runIntegrationTests from check gradle task This is a temporary fix. Currently the check task depends on the integrationt tests task, which means all dependant tasks will be resolved even if they're just registered instead of created. This resolution is a problem because the downloadES task will fail if, for the version we're building, Elasticsearch doesn't yet have a build we can download. So for now we'll remove this to unblock builds, but finding a way to compartimentalize failures is needed going forward --- build.gradle | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/build.gradle b/build.gradle index cb047e880..1281cd959 100644 --- a/build.gradle +++ b/build.gradle @@ -503,7 +503,13 @@ tasks.register("generatePluginsVersion") { } bootstrap.dependsOn assemblyDeps -check.dependsOn runIntegrationTests +// FIXME: adding the integration tests task to check will mean +// that any registered task will be evaluated. This creates an issue +// where the downloadES task may throw an error on versions where +// Elasticsearch doesn't yet have a build we can fetch +// So for now we'll remove this to unblock builds, but finding a way +// to compartimentalize failures is needed going forward +//check.dependsOn runIntegrationTests Boolean oss = System.getenv('OSS').equals('true') From dc412713efaad97c479b367b6479b367fabc018d Mon Sep 17 00:00:00 2001 From: Joao Duarte Date: Wed, 15 Jul 2020 17:05:41 +0100 Subject: [PATCH 0558/1126] add ci script setup dependencies This script can be useful for preparing the environment for services like code scanners. --- ci/bootstrap_dependencies.sh | 3 +++ 1 file changed, 3 insertions(+) create mode 100644 ci/bootstrap_dependencies.sh diff --git a/ci/bootstrap_dependencies.sh b/ci/bootstrap_dependencies.sh new file mode 100644 index 000000000..9b4e972e0 --- /dev/null +++ b/ci/bootstrap_dependencies.sh @@ -0,0 +1,3 @@ +#!/bin/bash + +./gradlew installDefaultGems From 6546bb3ba572ec8926231d049d8dbdb0a0475be8 Mon Sep 17 00:00:00 2001 From: Karen Metts <35154725+karenzone@users.noreply.github.com> Date: Fri, 17 Jul 2020 20:31:43 -0400 Subject: [PATCH 0559/1126] Doc:Fine tune 7.8 release notes (#12122) Forwardport 7.8.0 release notes updates from #12050 to 7.x branch --- docs/static/releasenotes.asciidoc | 27 +++++++++++++-------------- 1 file changed, 13 insertions(+), 14 deletions(-) diff --git a/docs/static/releasenotes.asciidoc b/docs/static/releasenotes.asciidoc index de9801151..fe2ada230 100644 --- a/docs/static/releasenotes.asciidoc +++ b/docs/static/releasenotes.asciidoc @@ -35,25 +35,24 @@ This section summarizes the changes in the following releases: ==== New features and improvements -===== Expanded JDK ecosystem +===== Expanded JDK ecosystem and platform support -We have improved test scripts infrastructure to accept a specific Java -Development Kit (JDK) present in the host. The changes include exporting the -path to a JDK home into an environment variable named BUILD_JAVA_HOME and its -use by shell scripts to launch test and integration scripts. This work and other -JDK14 fixes pave the way for Logstash to support both AdoptOpenJDK 11 and 14 in -the near future . https://github.com/elastic/logstash/pull/11786[#11786], -https://github.com/elastic/logstash/pull/11839[#11839], -https://github.com/elastic/logstash/pull/11935[#11935] +We can be more flexible and responsive in supporting new JDKs and deprecating +old ones, thanks to recent improvements to our test scripts infrastructure. This +work and other JDK14 fixes pave the way for {ls} to support both AdoptOpenJDK 11 +and 14 in the near future. -===== Expanded JDK platform support - -{ls} runs on many different operating platforms and various flavors of the Java -Development Kit (JDK), and we’ve expanded this coverage in 7.8.0. {ls} has -introduced support for running on CentOS/RHEL 8.x and Ubuntu 20.04. +{ls} has introduced support for running on CentOS/RHEL 8.x and Ubuntu 20.04. We’ve added new JDK support for Zulu 11, AdoptOpenJDK 11, and Oracle/OpenJDK/AdoptOpenJDK 14. + +<> is covered in <>. +The complete list of supported operating systems and JVMs is available in the +https://www.elastic.co/support/matrix[support matrix]. + + + ===== {es} API key support Support for API keys was added to {es} in 6.7.0. With 7.8.0 {ls} introduces From 31358315382da1aea2a2983308306dfb51bbed32 Mon Sep 17 00:00:00 2001 From: Karen Metts Date: Mon, 11 May 2020 21:00:34 -0400 Subject: [PATCH 0560/1126] Doc:Create a new header for integration plugins Integration plugins need a different header. For example, the plugin docs should to point to the integration repo rather than the input, output, filter, or codec repo. The new header also includes boilerplate text to indicate that the individual plugin is part of an integration rather than stand-alone. This work implements needed changes. --- .../plugin_header-integration.asciidoc | 39 +++++++++++++++++++ 1 file changed, 39 insertions(+) create mode 100644 docs/include/plugin_header-integration.asciidoc diff --git a/docs/include/plugin_header-integration.asciidoc b/docs/include/plugin_header-integration.asciidoc new file mode 100644 index 000000000..c12cbbb23 --- /dev/null +++ b/docs/include/plugin_header-integration.asciidoc @@ -0,0 +1,39 @@ +ifeval::["{versioned_docs}"!="true"] +[subs="attributes"] +++++ +{plugin} +++++ +endif::[] +ifeval::["{versioned_docs}"=="true"] +[subs="attributes"] +++++ +{version} +++++ +endif::[] + +* A component of the <> +* Integration version: {version} +* Released on: {release_date} +* {changelog_url}[Changelog] + +ifeval::["{versioned_docs}"!="true"] + +For other versions, see the +{lsplugindocs}/{type}-{plugin}-index.html[Versioned plugin docs]. + +endif::[] + +ifeval::["{versioned_docs}"=="true"] + +For other versions, see the <>. + +To learn more about Logstash, see the {logstash-ref}/index.html[Logstash Reference]. + +endif::[] + +==== Getting Help + +For questions about the plugin, open a topic in the http://discuss.elastic.co[Discuss] forums. +For bugs or feature requests, open an issue in https://github.com/logstash-plugins/logstash-integration-{plugin}[Github]. +For the list of Elastic supported plugins, please consult the https://www.elastic.co/support/matrix#matrix_logstash_plugins[Elastic Support Matrix]. + From d78635ca4f758933bb5b28bc8d3b56b8c906aab8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jo=C3=A3o=20Duarte?= Date: Wed, 22 Jul 2020 16:39:33 +0100 Subject: [PATCH 0561/1126] Document use of keystore values in pipelines.yml --- docs/static/settings-file.asciidoc | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/docs/static/settings-file.asciidoc b/docs/static/settings-file.asciidoc index 57379e04c..5075e84a6 100644 --- a/docs/static/settings-file.asciidoc +++ b/docs/static/settings-file.asciidoc @@ -27,8 +27,8 @@ pipeline.batch.size: 125 pipeline.batch.delay: 50 ------------------------------------------------------------------------------------- -The `logstash.yml` file also supports bash-style interpolation of environment variables in -setting values. +The `logstash.yml` file also supports bash-style interpolation of environment variables and +keystore secrets in setting values. [source,yaml] ------------------------------------------------------------------------------------- From e7db1ae16cbbd06676cfdea347613158c8bb7a20 Mon Sep 17 00:00:00 2001 From: Joao Duarte Date: Mon, 20 Jul 2020 16:26:30 +0100 Subject: [PATCH 0562/1126] initial introduction of .fossa.yml Although fossa has a fossa init tool to auto discover dependencies, it doesn't work well for Logstash. The mix of JRuby and Java allows for correct gradle detection but for Ruby we tell FOSSA to look at the lockfile, which we generate using ci/bootstrap_dependencies.sh This is a work in progress and covers 99% of our dependencies. As we get comfortable we'll have to uncomment a few ruby subprojects contained in the logstash source tree. --- .fossa.yml | 59 ++++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 59 insertions(+) create mode 100755 .fossa.yml diff --git a/.fossa.yml b/.fossa.yml new file mode 100755 index 000000000..55e69801b --- /dev/null +++ b/.fossa.yml @@ -0,0 +1,59 @@ +# Generated by FOSSA CLI (https://github.com/fossas/fossa-cli) +# Visit https://fossa.com to learn more + +version: 2 +cli: + server: https://app.fossa.com + fetcher: custom + project: git@github.com:elastic/logstash.git +analyze: + modules: + - name: Logstash gems + type: bundler + strategy: lockfile + target: . + path: . + - name: benchmark-cli + type: gradle + target: 'benchmark-cli:' + path: . + - name: dependencies-report + type: gradle + target: 'dependencies-report:' + path: . + - name: ingest-converter + type: gradle + target: 'ingest-converter:' + path: . + - name: logstash-core + type: gradle + target: 'logstash-core:' + path: . + - name: logstash-core-benchmarks + type: gradle + target: 'logstash-core-benchmarks:' + path: . + - name: logstash-integration-tests + type: gradle + target: 'logstash-integration-tests:' + path: . + - name: logstash-xpack + type: gradle + target: 'logstash-xpack:' + # path: . + # - name: docker + # type: pip + # target: docker + # path: docker + # - name: Gemfile + # type: gem + # target: qa + # path: qa + # - name: Gemfile + # type: gem + # target: qa/integration + # path: qa/integration + # - name: Gemfile + # type: gem + # target: tools/paquet + # path: tools/paquet From 702f872efff08d006df4d3b430740e54f3b580ca Mon Sep 17 00:00:00 2001 From: Rob Bavey Date: Thu, 16 Jul 2020 11:14:50 -0400 Subject: [PATCH 0563/1126] Fix docker image labels Prior to this commit, the value of `org.label-schema.license` and the values in `org.opencontainers.image.*` were not set, and therefore would be inherited from the base OS image. --- docker/Makefile | 4 ++++ docker/templates/Dockerfile.j2 | 17 +++++++++++------ 2 files changed, 15 insertions(+), 6 deletions(-) diff --git a/docker/Makefile b/docker/Makefile index 673043f8b..7bb782cab 100644 --- a/docker/Makefile +++ b/docker/Makefile @@ -21,6 +21,7 @@ HTTPD ?= logstash-docker-artifact-server FIGLET := pyfiglet -w 160 -f puffy all: build-from-local-artifacts build-from-local-oss-artifacts public-dockerfiles +DATE:= $(shell date -u +'%Y-%m-%dT%H:%M:%S.%sZ') lint: venv flake8 tests @@ -70,6 +71,7 @@ docker_paths: public-dockerfiles: venv templates/Dockerfile.j2 docker_paths $(COPY_FILES) jinja2 \ + -D created_date='$(DATE)' \ -D elastic_version='$(ELASTIC_VERSION)' \ -D version_tag='$(VERSION_TAG)' \ -D image_flavor='full' \ @@ -77,6 +79,7 @@ public-dockerfiles: venv templates/Dockerfile.j2 docker_paths $(COPY_FILES) -D release='$(RELEASE)' \ templates/Dockerfile.j2 > $(ARTIFACTS_DIR)/Dockerfile-full && \ jinja2 \ + -D created_date='$(DATE)' \ -D elastic_version='$(ELASTIC_VERSION)' \ -D version_tag='$(VERSION_TAG)' \ -D image_flavor='oss' \ @@ -133,6 +136,7 @@ env2yaml: golang dockerfile: venv templates/Dockerfile.j2 $(foreach FLAVOR, $(IMAGE_FLAVORS), \ jinja2 \ + -D created_date='$(DATE)' \ -D elastic_version='$(ELASTIC_VERSION)' \ -D version_tag='$(VERSION_TAG)' \ -D image_flavor='$(FLAVOR)' \ diff --git a/docker/templates/Dockerfile.j2 b/docker/templates/Dockerfile.j2 index 44e782d2e..59ac10cdb 100644 --- a/docker/templates/Dockerfile.j2 +++ b/docker/templates/Dockerfile.j2 @@ -7,8 +7,10 @@ {% if image_flavor == 'oss' -%} {% set tarball = 'logstash-oss-%s.tar.gz' % elastic_version -%} + {% set license = 'Apache 2.0' -%} {% else -%} {% set tarball = 'logstash-%s.tar.gz' % elastic_version -%} + {% set license = 'Elastic License' -%} {% endif -%} @@ -62,17 +64,20 @@ ADD env2yaml/env2yaml /usr/local/bin/ EXPOSE 9600 5044 -LABEL org.label-schema.schema-version="1.0" \ +LABEL org.label-schema.schema-version="1.0" \ org.label-schema.vendor="Elastic" \ + org.opencontainers.image.vendor="Elastic" \ org.label-schema.name="logstash" \ + org.opencontainers.image.title="logstash" \ org.label-schema.version="{{ elastic_version }}" \ + org.opencontainers.image.version="{{ elastic_version }}" \ org.label-schema.url="https://www.elastic.co/products/logstash" \ org.label-schema.vcs-url="https://github.com/elastic/logstash" \ -{% if image_flavor == 'oss' -%} - license="Apache-2.0" -{% else -%} - license="Elastic License" -{% endif -%} + license="{{ license }}" \ + org.label-schema.license="{{ license }}" \ + org.opencontainers.image.licenses="{{ license }}" \ + org.label-schema.build-date={{ created_date }} \ + org.opencontainers.image.created={{ created_date }} ENTRYPOINT ["/usr/local/bin/docker-entrypoint"] From 69ba072ef35d01146d12db00a347f4b847307141 Mon Sep 17 00:00:00 2001 From: Karen Metts <35154725+karenzone@users.noreply.github.com> Date: Mon, 27 Jul 2020 14:47:55 -0400 Subject: [PATCH 0564/1126] Doc:Forwardport 7.8.1 release notes (#12092) to 7.x #12142 MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-authored-by: João Duarte Co-authored-by: Karen Metts <35154725+karenzone@users.noreply.github.com> Co-authored-by: Colin Surprenant --- docs/static/releasenotes.asciidoc | 76 +++++++++++++++++++++++++++++++ 1 file changed, 76 insertions(+) diff --git a/docs/static/releasenotes.asciidoc b/docs/static/releasenotes.asciidoc index fe2ada230..dca7aee28 100644 --- a/docs/static/releasenotes.asciidoc +++ b/docs/static/releasenotes.asciidoc @@ -3,6 +3,7 @@ This section summarizes the changes in the following releases: +* <> * <> * <> * <> @@ -30,6 +31,80 @@ This section summarizes the changes in the following releases: * <> * <> +[[logstash-7-8-1]] +=== Logstash 7.8.1 Release Notes + +==== Performance improvements and notable issues fixed + +===== Fixed performance regression during pipeline compilation + +A performance regression was introduced in 7.7.0, as described in the <>. +The issue was caused by an enhancement - https://github.com/elastic/logstash/pull/11078[#11078] - that included the plugin ids in log entries produced by Logstash pipelines. +The implementation of this feature has been fixed and no longer causes the performance issue. You can find more about the solution here https://github.com/elastic/logstash/pull/12038[#12038]. + +===== Multiple fixes to pipeline shutdown and reloading + +7.8.1 brings many fixes that improve the stability of the pipeline lifecycle. +In previous releases, enabling monitoring could result in Logstash crashes if pipelines from concurrent pipeline reloads (fixed in https://github.com/elastic/logstash/pull/12034[#12034]). +Also, pipelines failing to start correctly could prevent the Persistent Queue from being used afterwards (fixed in https://github.com/elastic/logstash/pull/12023[#12023]). Finally, a JRuby issue concerning threads and the Ruby/Java implementation boundary could cause crashes during pipeline reloads, and this has been fixed in https://github.com/elastic/logstash/pull/11900[#11900]. + +===== Changes in the dependencies of Beats/TCP/HTTP Input Plugins + +To avoid breaking changes and retain control on the set of ciphers exposed in these plugins, underlying dependencies (`tcnative` and `boringssl`) have been dropped in favor of using JVM supplied ciphers instead. +Overall there should be no impact but this may result in fewer ciphers being available if the JCE unlimited strength jurisdiction policy is not installed. +NOTE: This policy is installed by default on versions of the JDK from u161 onwards. +You can find more information in the release notes of the respective plugins. + +==== Plugins + +*Xml Filter - 4.1.1* + +* Fix: exceptions thrown while handling events no longer crash the pipeline https://github.com/logstash-plugins/logstash-filter-xml/pull/73[#73] + +*Beats Input - 6.0.11* + +* Updated jackson databind and Netty dependencies. Additionally, this release removes the dependency on `tcnative` and + `boringssl`, using JVM supplied ciphers instead. This may result in fewer ciphers being available if the JCE + unlimited strength jurisdiction policy is not installed. (This policy is installed by default on versions of the + JDK from u161 onwards.) https://github.com/logstash-plugins/logstash-input-beats/pull/393[#393] +* Added error handling to detect if ssl certificate or key files can't be read https://github.com/logstash-plugins/logstash-input-beats/pull/394[#394] + +*Elasticsearch Input - 4.6.2* + +* Added scroll clearing and better handling of scroll expiration https://github.com/logstash-plugins/logstash-input-elasticsearch/pull/128[#128] +* [DOC] Removed outdated compatibility notice https://github.com/logstash-plugins/logstash-input-elasticsearch/pull/124[#124] + +*Http Input - 3.3.5* + +* Updated jackson databind and Netty dependencies. Additionally, this release removes the dependency on `tcnative` and + `boringssl`, using JVM supplied ciphers instead. This may result in fewer ciphers being available if the JCE + unlimited strength jurisdiction policy is not installed. (This policy is installed by default on versions of the + JDK from u161 onwards.) https://github.com/logstash-plugins/logstash-input-http/pull/126[#126] + +*Syslog Input - 3.4.3* + +* [DOC] Added expanded descriptions and requirements for facility_labels and severity_labels. https://github.com/logstash-plugins/logstash-input-syslog/pull/52[#52] + +*Tcp Input - 6.0.6* + +* Updated Netty dependencies. Additionally, this release removes the dependency on `tcnative` and + `boringssl`, using JVM supplied ciphers instead. This may result in fewer ciphers being available if the JCE + unlimited strength jurisdiction policy is not installed. (This policy is installed by default on versions of the + JDK from u161 onwards.) https://github.com/logstash-plugins/logstash-input-tcp/pull/157[#157] + +*Jdbc Integration - 5.0.5* + +* Fixed user sequel_opts not being passed down properly https://github.com/logstash-plugins/logstash-integration-jdbc/pull/37[#37] +* Refactored jdbc_streaming to share driver loading, so the fixes from the jdbc plugin also effect jdbc_streaming +* Fixed issue where JDBC Drivers that don't correctly register with Java's DriverManager fail to load (such as Sybase) https://github.com/logstash-plugins/logstash-integration-jdbc/pull/34[#34] +* Fixed issue where a lost connection to the database can cause errors when using prepared statements with the scheduler https://github.com/logstash-plugins/logstash-integration-jdbc/pull/25[#25] +* Fixed potential resource leak by ensuring scheduler is shutdown when a pipeline encounter an error during the running https://github.com/logstash-plugins/logstash-integration-jdbc/pull/28[#28] + +*S3 Output - 4.3.2* + +* [DOC]Added note that only AWS S3 is supported. No other S3 compatible storage solutions are supported. https://github.com/logstash-plugins/logstash-output-s3/pull/223[#223] + + [[logstash-7-8-0]] === Logstash 7.8.0 Release Notes @@ -99,6 +174,7 @@ module in {filebeat-ref}/filebeat-module-netflow.html[{filebeat}]. The {filebeat} and {metricbeat} modules are compliant with the {ecs-ref}/index.html[Elastic Common Schema (ECS)]. +[[known-pipeline-slowdown]] ==== Known issue *Performance regression.* A potential performance regression may affect From dbf43f9bd9bfb603e1747ebc1389504a14a24938 Mon Sep 17 00:00:00 2001 From: Ry Biesemeyer Date: Mon, 27 Jul 2020 20:15:36 +0000 Subject: [PATCH 0565/1126] reword bin/system_install help text to be less confusing. Present OPTIONSFILE search in a way that reads first-match-wins, since that is what actually happens. Resolves: #12145 --- bin/system-install | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/bin/system-install b/bin/system-install index 5ac9a2ce2..d81c5e87b 100755 --- a/bin/system-install +++ b/bin/system-install @@ -17,8 +17,8 @@ elif [ "$1" == "-h" ] || [ "$1" == "--help" ]; then echo echo "OPTIONSFILE: Full path to a startup.options file" echo "OPTIONSFILE is required if STARTUPTYPE is specified, but otherwise looks first" - echo "in $LOGSTASH_HOME/config/startup.options and then /etc/logstash/startup.options" - echo "Last match wins" + echo "in /etc/logstash/startup.options and then " + echo "in $LOGSTASH_HOME/config/startup.options " echo echo "STARTUPTYPE: e.g. sysv, upstart, systemd, etc." echo "OPTIONSFILE is required to specify a STARTUPTYPE." From 2aa5cadd4427120436bee42cd3584d630cee3487 Mon Sep 17 00:00:00 2001 From: Karen Metts Date: Tue, 2 Jun 2020 21:09:43 -0400 Subject: [PATCH 0566/1126] Doc:Fix link to monitoring docs and tag optional features --- docs/static/security/logstash.asciidoc | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/docs/static/security/logstash.asciidoc b/docs/static/security/logstash.asciidoc index 62f7927c9..75e5ef0bb 100644 --- a/docs/static/security/logstash.asciidoc +++ b/docs/static/security/logstash.asciidoc @@ -196,10 +196,11 @@ output { Authority's certificate. [float] +[role="xpack"] [[ls-monitoring-user]] ==== Configuring Credentials for Logstash Monitoring -If you plan to ship Logstash {logstash-ref}/monitoring-logstash.html[monitoring] +If you plan to ship Logstash {logstash-ref}/configuring-logstash.html[monitoring] data to a secure cluster, you need to configure the username and password that Logstash uses to authenticate for shipping monitoring data. @@ -232,6 +233,7 @@ PUT _xpack/security/user/logstash_system/_enable // CONSOLE [float] +[role="xpack"] [[ls-pipeline-management-user]] ==== Configuring Credentials for Centralized Pipeline Management From dcca6c2c61e4bc9592e5fa93ea6a444f640ec8b7 Mon Sep 17 00:00:00 2001 From: andsel Date: Wed, 29 Jul 2020 17:19:51 +0200 Subject: [PATCH 0567/1126] Expose xpack.monitoring.elasticsearch.proxy setting as Docker env variable In PR #11799 we missed to add the exposure of proxy also as docker env variable so that uses can connect the dockerzied Logstash to a proxed monitoring cluster --- docker/data/logstash/env2yaml/env2yaml.go | 1 + 1 file changed, 1 insertion(+) diff --git a/docker/data/logstash/env2yaml/env2yaml.go b/docker/data/logstash/env2yaml/env2yaml.go index 129ad09c0..4c4f6882c 100644 --- a/docker/data/logstash/env2yaml/env2yaml.go +++ b/docker/data/logstash/env2yaml/env2yaml.go @@ -99,6 +99,7 @@ func normalizeSetting(setting string) (string, error) { "xpack.monitoring.elasticsearch.hosts", "xpack.monitoring.elasticsearch.username", "xpack.monitoring.elasticsearch.password", + "xpack.monitoring.elasticsearch.proxy", "xpack.monitoring.elasticsearch.ssl.certificate_authority", "xpack.monitoring.elasticsearch.ssl.truststore.path", "xpack.monitoring.elasticsearch.ssl.truststore.password", From 7df59fbe762d2422b2107e4f7e4d4af5d833644d Mon Sep 17 00:00:00 2001 From: andsel Date: Wed, 29 Jul 2020 17:24:11 +0200 Subject: [PATCH 0568/1126] Remove settings that was intended to direct ship monitoring data to ES monitoring cluster During the development of PR #11541 to direct ship monitoring data to an monitoring ES cluster without hopping through a production ES cluster, the settings for elasticsearch ouput was cloned into a version without the `xpack` prefix. Since that feature has been removed the settings should also be removed from the Docker image --- docker/data/logstash/env2yaml/env2yaml.go | 10 ---------- 1 file changed, 10 deletions(-) diff --git a/docker/data/logstash/env2yaml/env2yaml.go b/docker/data/logstash/env2yaml/env2yaml.go index 4c4f6882c..b66a39fed 100644 --- a/docker/data/logstash/env2yaml/env2yaml.go +++ b/docker/data/logstash/env2yaml/env2yaml.go @@ -84,16 +84,6 @@ func normalizeSetting(setting string) (string, error) { "modules", "path.logs", "path.plugins", - "monitoring.enabled", - "monitoring.collection.interval", - "monitoring.elasticsearch.hosts", - "monitoring.elasticsearch.username", - "monitoring.elasticsearch.password", - "monitoring.elasticsearch.ssl.certificate_authority", - "monitoring.elasticsearch.ssl.truststore.path", - "monitoring.elasticsearch.ssl.truststore.password", - "monitoring.elasticsearch.ssl.keystore.path", - "monitoring.elasticsearch.ssl.keystore.password", "xpack.monitoring.enabled", "xpack.monitoring.collection.interval", "xpack.monitoring.elasticsearch.hosts", From 2e7ba7b417caa7bdaf115dd617321acb15b6eb2e Mon Sep 17 00:00:00 2001 From: Karen Metts Date: Tue, 28 Jul 2020 18:08:16 -0400 Subject: [PATCH 0569/1126] Doc:Add monitoring and management to API key security content --- docs/static/security/api-keys.asciidoc | 106 +++++++++++++++++- ...configuration-management-settings.asciidoc | 1 - 2 files changed, 105 insertions(+), 2 deletions(-) diff --git a/docs/static/security/api-keys.asciidoc b/docs/static/security/api-keys.asciidoc index b5718dce7..596d31250 100644 --- a/docs/static/security/api-keys.asciidoc +++ b/docs/static/security/api-keys.asciidoc @@ -7,10 +7,20 @@ access to {es} resources. You can set API keys to expire at a certain time, and you can explicitly invalidate them. Any user with the `manage_api_key` or `manage_own_api_key` cluster privilege can create API keys. -Note that API keys are tied to the cluster they are created in. If you are +Tips for creating API keys: + +* API keys are tied to the cluster they are created in. If you are sending output to different clusters, be sure to create the correct kind of API key. +* {ls} can send both collected data and monitoring information to {es}. If you are +sending both to the same cluster, you can use the same API key. For different +clusters, you need an API key per cluster. + +* A single cluster can share a key for ingestion and monitoring purposes. + +* A production cluster and a monitoring cluster require separate keys. + NOTE: For security reasons, we recommend using a unique API key per {ls} instance. You can create as many API keys per user as necessary. @@ -176,6 +186,100 @@ filter { <1> Format is `id:api_key` (as returned by {ref}/security-api-create-api-key.html[Create API key]) +[float] +[[ls-api-key-monitor]] +====== Create an API key for monitoring + +To create an API key to use for sending monitoring data to {es}, use the +{ref}/security-api-create-api-key.html[Create API key API]. For example: + +[source,console,subs="attributes,callouts"] +------------------------------------------------------------ +POST /_security/api_key +{ + "name": "logstash_host001", <1> + "role_descriptors": { + "logstash_monitoring": { <2> + "cluster": ["monitor"], + "index": [ + { + "names": [".monitoring-ls-*"], + "privileges": ["create_index", "create"] + } + ] + } + } +} +------------------------------------------------------------ +<1> Name of the API key +<2> Granted privileges + +The return value should look similar to this: + +[source,console-result,subs="attributes,callouts"] +-------------------------------------------------- +{ + "id":"TiNAGG4BaaMdaH1tRfuU", <1> + "name":"logstash_host001", + "api_key":"KnR6yE41RrSowb0kQ0HWoA" <2> +} +-------------------------------------------------- +<1> Unique id for this API key +<2> Generated API key + +Now you can use this API key in your logstash.yml configuration file: +["source","yml",subs="attributes"] +-------------------- +xpack.monitoring.elasticsearch.api_key: TiNAGG4BaaMdaH1tRfuU:KnR6yE41RrSowb0kQ0HWoA <1> +-------------------- +<1> Format is `id:api_key` (as returned by {ref}/security-api-create-api-key.html[Create API key]) + + +[float] +[[ls-api-key-man]] +====== Create an API key for central management + +To create an API key to use for central management, use the +{ref}/security-api-create-api-key.html[Create API key API]. For example: + +[source,console,subs="attributes,callouts"] +------------------------------------------------------------ +POST /_security/api_key +{ + "name": "logstash_host001", <1> + "role_descriptors": { + "logstash_monitoring": { <2> + "cluster": ["monitor"], + "index": ["read"] + } + } +} +------------------------------------------------------------ +<1> Name of the API key +<2> Granted privileges + +The return value should look similar to this: + +[source,console-result,subs="attributes,callouts"] +-------------------------------------------------- +{ + "id":"TiNAGG4BaaMdaH1tRfuU", <1> + "name":"logstash_host001", + "api_key":"KnR6yE41RrSowb0kQ0HWoA" <2> +} +-------------------------------------------------- +<1> Unique id for this API key +<2> Generated API key + +Now you can use this API key in your logstash.yml configuration file: +["source","yml",subs="attributes"] +-------------------- +xpack.management.elasticsearch.api_key: TiNAGG4BaaMdaH1tRfuU:KnR6yE41RrSowb0kQ0HWoA <1> +-------------------- +<1> Format is `id:api_key` (as returned by +{ref}/security-api-create-api-key.html[Create API key]) + + [float] [[learn-more-api-keys]] ===== Learn more about API keys diff --git a/docs/static/settings/configuration-management-settings.asciidoc b/docs/static/settings/configuration-management-settings.asciidoc index c83863d75..893daac7c 100644 --- a/docs/static/settings/configuration-management-settings.asciidoc +++ b/docs/static/settings/configuration-management-settings.asciidoc @@ -103,6 +103,5 @@ provides access to `.logstash-*` indices for managing configurations. `xpack.management.elasticsearch.api_key`:: Authenticate using an Elasticsearch API key. Note that this option also requires using SSL. - The API key Format is `id:api_key` where `id` and `api_key` are as returned by the Elasticsearch https://www.elastic.co/guide/en/elasticsearch/reference/current/security-api-create-api-key.html[Create API key API]. From e8385738c50e491463615302af93af12550dae95 Mon Sep 17 00:00:00 2001 From: Rob Bavey Date: Mon, 3 Aug 2020 09:43:09 -0400 Subject: [PATCH 0570/1126] 7x Introduce integration tests for docker images (#12157) Clean backport of #12135 This commit adds integration tests for the Logstash docker images. Previous integration tests were removed in https://github.com/elastic/logstash/pull/10693, due to the tests being non functional. The commit adds image and container tests. The image tests check the contents and the metadata of the image; the container tests check the logstash process, and includes tests ensuring that logstash runs, and is configurable. This test also adds a ci script to allow the tests to be run on jenkins, and to split the running of these tests up based on the image type and includes updates to the rake tasks to support this. --- ci/docker_acceptance_tests.sh | 64 +++++++++ docker/Makefile | 11 +- qa/Gemfile | 1 + .../fixtures/custom_logstash_yml/logstash.yml | 1 + .../multiple_pipelines/config/pipelines.yml | 4 + .../multiple_pipelines/pipelines/basic1.cfg | 7 + .../multiple_pipelines/pipelines/basic2.cfg | 7 + qa/docker/fixtures/simple_pipeline/basic.cfg | 7 + qa/docker/shared_examples/container.rb | 76 +++++++++++ qa/docker/shared_examples/container_config.rb | 37 ++++++ .../shared_examples/container_options.rb | 59 +++++++++ qa/docker/shared_examples/image_metadata.rb | 39 ++++++ qa/docker/spec/full/container_spec.rb | 47 +++++++ qa/docker/spec/full/image_spec.rb | 6 + qa/docker/spec/oss/container_spec.rb | 10 ++ qa/docker/spec/oss/image_spec.rb | 6 + qa/docker/spec/spec_helper.rb | 122 ++++++++++++++++++ rakelib/artifacts.rake | 33 ++++- 18 files changed, 530 insertions(+), 7 deletions(-) create mode 100755 ci/docker_acceptance_tests.sh create mode 100644 qa/docker/fixtures/custom_logstash_yml/logstash.yml create mode 100644 qa/docker/fixtures/multiple_pipelines/config/pipelines.yml create mode 100644 qa/docker/fixtures/multiple_pipelines/pipelines/basic1.cfg create mode 100644 qa/docker/fixtures/multiple_pipelines/pipelines/basic2.cfg create mode 100644 qa/docker/fixtures/simple_pipeline/basic.cfg create mode 100644 qa/docker/shared_examples/container.rb create mode 100644 qa/docker/shared_examples/container_config.rb create mode 100644 qa/docker/shared_examples/container_options.rb create mode 100644 qa/docker/shared_examples/image_metadata.rb create mode 100644 qa/docker/spec/full/container_spec.rb create mode 100644 qa/docker/spec/full/image_spec.rb create mode 100644 qa/docker/spec/oss/container_spec.rb create mode 100644 qa/docker/spec/oss/image_spec.rb create mode 100644 qa/docker/spec/spec_helper.rb diff --git a/ci/docker_acceptance_tests.sh b/ci/docker_acceptance_tests.sh new file mode 100755 index 000000000..027a227bd --- /dev/null +++ b/ci/docker_acceptance_tests.sh @@ -0,0 +1,64 @@ +#!/usr/bin/env bash +set -e +set -x + +# Since we are using the system jruby, we need to make sure our jvm process +# uses at least 1g of memory, If we don't do this we can get OOM issues when +# installing gems. See https://github.com/elastic/logstash/issues/5179 +export JRUBY_OPTS="-J-Xmx1g" +export GRADLE_OPTS="-Xmx4g -Dorg.gradle.daemon=false -Dorg.gradle.logging.level=info -Dfile.encoding=UTF-8" + +# Can run either a specific flavor, or all flavors - +# eg `ci/acceptance_tests.sh oss` will run tests for open source container +# `ci/acceptance_tests.sh full` will run tests for the default container +# `ci/acceptance_tests.sh` will run tests for all containers +SELECTED_TEST_SUITE=$1 + +# The acceptance test in our CI infrastructure doesn't clear the workspace between run +# this mean the lock of the Gemfile can be sticky from a previous run, before generating any package +# we will clear them out to make sure we use the latest version of theses files +# If we don't do this we will run into gem Conflict error. +[ -f Gemfile ] && rm Gemfile +[ -f Gemfile.lock ] && rm Gemfile.lock + +LS_HOME="$PWD" +QA_DIR="$PWD/qa" + +cd $QA_DIR +bundle check || bundle install + +echo "Building Logstash artifacts" +cd $LS_HOME + +if [[ $SELECTED_TEST_SUITE == "oss" ]]; then + echo "building oss docker images" + cd $LS_HOME + rake artifact:docker_oss + echo "Acceptance: Installing dependencies" + cd $QA_DIR + bundle install + + echo "Acceptance: Running the tests" + bundle exec rspec docker/spec/oss/*_spec.rb +elif [[ $SELECTED_TEST_SUITE == "full" ]]; then + echo "building full docker images" + cd $LS_HOME + rake artifact:docker + echo "Acceptance: Installing dependencies" + cd $QA_DIR + bundle install + + echo "Acceptance: Running the tests" + bundle exec rspec docker/spec/full/*_spec.rb +else + echo "Building all docker images" + cd $LS_HOME + rake artifact:docker_only + + echo "Acceptance: Installing dependencies" + cd $QA_DIR + bundle install + + echo "Acceptance: Running the tests" + bundle exec rspec docker/spec/**/*_spec.rb +fi diff --git a/docker/Makefile b/docker/Makefile index 7bb782cab..0d215870d 100644 --- a/docker/Makefile +++ b/docker/Makefile @@ -69,7 +69,9 @@ docker_paths: mkdir -p $(ARTIFACTS_DIR)/docker/env2yaml mkdir -p $(ARTIFACTS_DIR)/docker/pipeline -public-dockerfiles: venv templates/Dockerfile.j2 docker_paths $(COPY_FILES) +public-dockerfiles: public-dockerfiles_oss public_dockerfiles_full + +public-dockerfiles_full: venv templates/Dockerfile.j2 docker_paths $(COPY_FILES) jinja2 \ -D created_date='$(DATE)' \ -D elastic_version='$(ELASTIC_VERSION)' \ @@ -78,6 +80,11 @@ public-dockerfiles: venv templates/Dockerfile.j2 docker_paths $(COPY_FILES) -D local_artifacts='false' \ -D release='$(RELEASE)' \ templates/Dockerfile.j2 > $(ARTIFACTS_DIR)/Dockerfile-full && \ + cd $(ARTIFACTS_DIR)/docker && \ + cp $(ARTIFACTS_DIR)/Dockerfile-full Dockerfile && \ + tar -zcf ../logstash-$(VERSION_TAG)-docker-build-context.tar.gz Dockerfile bin config env2yaml pipeline + +public-dockerfiles_oss: venv templates/Dockerfile.j2 docker_paths $(COPY_FILES) jinja2 \ -D created_date='$(DATE)' \ -D elastic_version='$(ELASTIC_VERSION)' \ @@ -87,8 +94,6 @@ public-dockerfiles: venv templates/Dockerfile.j2 docker_paths $(COPY_FILES) -D release='$(RELEASE)' \ templates/Dockerfile.j2 > $(ARTIFACTS_DIR)/Dockerfile-oss && \ cd $(ARTIFACTS_DIR)/docker && \ - cp $(ARTIFACTS_DIR)/Dockerfile-full Dockerfile && \ - tar -zcf ../logstash-$(VERSION_TAG)-docker-build-context.tar.gz Dockerfile bin config env2yaml pipeline && \ cp $(ARTIFACTS_DIR)/Dockerfile-oss Dockerfile && \ tar -zcf ../logstash-oss-$(VERSION_TAG)-docker-build-context.tar.gz Dockerfile bin config env2yaml pipeline diff --git a/qa/Gemfile b/qa/Gemfile index 02247c0ca..5b2806389 100644 --- a/qa/Gemfile +++ b/qa/Gemfile @@ -4,3 +4,4 @@ gem "rspec", "~> 3.1.0" gem "rake" gem "stud" gem "pry", :group => :test +gem 'docker-api' diff --git a/qa/docker/fixtures/custom_logstash_yml/logstash.yml b/qa/docker/fixtures/custom_logstash_yml/logstash.yml new file mode 100644 index 000000000..41f0994c3 --- /dev/null +++ b/qa/docker/fixtures/custom_logstash_yml/logstash.yml @@ -0,0 +1 @@ +pipeline.batch.size: 200 \ No newline at end of file diff --git a/qa/docker/fixtures/multiple_pipelines/config/pipelines.yml b/qa/docker/fixtures/multiple_pipelines/config/pipelines.yml new file mode 100644 index 000000000..12cc49864 --- /dev/null +++ b/qa/docker/fixtures/multiple_pipelines/config/pipelines.yml @@ -0,0 +1,4 @@ +- pipeline.id: pipeline_one + path.config: "/usr/share/logstash/pipeline/basic1.cfg" +- pipeline.id: pipeline_two + path.config: "/usr/share/logstash/pipeline/basic2.cfg" \ No newline at end of file diff --git a/qa/docker/fixtures/multiple_pipelines/pipelines/basic1.cfg b/qa/docker/fixtures/multiple_pipelines/pipelines/basic1.cfg new file mode 100644 index 000000000..055a40405 --- /dev/null +++ b/qa/docker/fixtures/multiple_pipelines/pipelines/basic1.cfg @@ -0,0 +1,7 @@ +input { +beats { +id => 'multi_pipeline1' +port => 5044 +} +} +output { stdout {} } \ No newline at end of file diff --git a/qa/docker/fixtures/multiple_pipelines/pipelines/basic2.cfg b/qa/docker/fixtures/multiple_pipelines/pipelines/basic2.cfg new file mode 100644 index 000000000..c4ddd6bb9 --- /dev/null +++ b/qa/docker/fixtures/multiple_pipelines/pipelines/basic2.cfg @@ -0,0 +1,7 @@ +input { +beats { +id => 'multi_pipeline2' +port => 5044 +} +} +output { stdout {} } \ No newline at end of file diff --git a/qa/docker/fixtures/simple_pipeline/basic.cfg b/qa/docker/fixtures/simple_pipeline/basic.cfg new file mode 100644 index 000000000..eba040fd1 --- /dev/null +++ b/qa/docker/fixtures/simple_pipeline/basic.cfg @@ -0,0 +1,7 @@ +input { +beats { +id => 'simple_pipeline' +port => 5044 +} +} +output { stdout {} } \ No newline at end of file diff --git a/qa/docker/shared_examples/container.rb b/qa/docker/shared_examples/container.rb new file mode 100644 index 000000000..cdd6a4a88 --- /dev/null +++ b/qa/docker/shared_examples/container.rb @@ -0,0 +1,76 @@ +shared_examples_for 'the container is configured correctly' do |flavor| + + before do + @image = find_image(flavor) + @container = create_container(@image, {}) + end + + after do + cleanup_container(@container) + end + + context 'logstash' do + it 'should run with the correct version' do + expect(exec_in_container(@container, 'logstash --version')).to match /#{version}/ + end + + it 'should be running an API server on port 9600' do + wait_for_logstash(@container) + expect(get_logstash_status(@container)).to eql 'green' + end + end + + context 'container files' do + it 'should have the correct license agreement' do + expect(exec_in_container(@container, 'cat /usr/share/logstash/LICENSE.txt')).to have_correct_license_agreement(flavor) + end + + it 'should have the correct user' do + expect(exec_in_container(@container, 'whoami').chomp).to eql 'logstash' + end + + it 'should have the correct home directory' do + expect(exec_in_container(@container, 'printenv HOME').chomp).to eql '/usr/share/logstash' + end + + it 'should link /opt/logstash to /usr/share/logstash' do + expect(exec_in_container(@container, 'readlink /opt/logstash').chomp).to eql '/usr/share/logstash' + end + + it 'should have all files owned by the logstash user' do + expect(exec_in_container(@container, 'find /usr/share/logstash ! -user logstash')).to be_nil + expect(exec_in_container(@container, 'find /usr/share/logstash -user logstash')).not_to be_nil + end + + it 'should have a logstash user with uid 1000' do + expect(exec_in_container(@container, 'id -u logstash').chomp).to eql '1000' + end + + it 'should have a logstash user with gid 1000' do + expect(exec_in_container(@container, 'id -g logstash').chomp).to eql '1000' + end + + it 'should not have a RollingFile appender' do + expect(exec_in_container(@container, 'cat /usr/share/logstash/config/log4j2.properties')).not_to match /RollingFile/ + end + end + + context 'the java process' do + it 'should be running under the logstash user' do + expect(java_process(@container, "user")).to eql 'logstash' + end + + it 'should be running under the logstash group' do + expect(java_process(@container, "group")).to eql 'logstash' + end + + it 'should have cgroup overrides set' do + expect(java_process(@container, "args")).to match /-Dls.cgroup.cpu.path.override=/ + expect(java_process(@container, "args")).to match /-Dls.cgroup.cpuacct.path.override=/ + end + + it 'should have a pid of 1' do + expect(java_process(@container, "pid")).to eql '1' + end + end +end \ No newline at end of file diff --git a/qa/docker/shared_examples/container_config.rb b/qa/docker/shared_examples/container_config.rb new file mode 100644 index 000000000..c2ae27050 --- /dev/null +++ b/qa/docker/shared_examples/container_config.rb @@ -0,0 +1,37 @@ +shared_examples_for 'it runs with different configurations' do |flavor| + + before do + @image = find_image(flavor) + @container = start_container(@image, options) + end + + after do + cleanup_container(@container) + end + + context 'when a single pipeline is configured via volume bind' do + let(:options) { {"HostConfig" => { "Binds" => ["#{FIXTURES_DIR}/simple_pipeline/:/usr/share/logstash/pipeline/"] } } } + + it 'should show the stats for that pipeline' do + expect(get_node_stats(@container)['pipelines']['main']['plugins']['inputs'][0]['id']).to eq 'simple_pipeline' + end + end + + context 'when multiple pipelines are configured via volume bind' do + let(:options) { {"HostConfig" => { "Binds" => ["#{FIXTURES_DIR}/multiple_pipelines/pipelines/:/usr/share/logstash/pipeline/", + "#{FIXTURES_DIR}/multiple_pipelines/config/pipelines.yml:/usr/share/logstash/config/pipelines.yml"] } } } + + it "should show stats for both pipelines" do + expect(get_node_stats(@container)['pipelines']['pipeline_one']['plugins']['inputs'][0]['id']).to eq 'multi_pipeline1' + expect(get_node_stats(@container)['pipelines']['pipeline_two']['plugins']['inputs'][0]['id']).to eq 'multi_pipeline2' + end + end + + context 'when a custom `logstash.yml` is configured via volume bind' do + let(:options) { {"HostConfig" => { "Binds" => ["#{FIXTURES_DIR}/custom_logstash_yml/logstash.yml:/usr/share/logstash/config/logstash.yml"] } } } + + it 'should change the value of pipeline.batch.size' do + expect(get_node_info(@container)['pipelines']['main']['batch_size']).to eq 200 + end + end +end \ No newline at end of file diff --git a/qa/docker/shared_examples/container_options.rb b/qa/docker/shared_examples/container_options.rb new file mode 100644 index 000000000..eeb4d6769 --- /dev/null +++ b/qa/docker/shared_examples/container_options.rb @@ -0,0 +1,59 @@ +shared_examples_for 'it applies settings correctly' do |flavor| + + before do + @image = find_image(flavor) + @container = start_container(@image, options) + end + + after do + cleanup_container(@container) + end + + context 'when setting pipeline workers shell style' do + let(:options) { { 'ENV' => ['PIPELINE_WORKERS=32'] } } + + it "should correctly set the number of pipeline workers" do + expect(get_node_info(@container)['pipelines']['main']['workers']).to eql 32 + end + end + + context 'when setting pipeline workers dot style' do + let(:options) { { 'ENV' => ['pipeline.workers=64'] } } + + it "should correctly set the number of pipeline workers" do + expect(get_node_info(@container)['pipelines']['main']['workers']).to eql 64 + end + end + + context 'when setting pipeline batch size' do + let(:options) { { 'ENV' => ['pipeline.batch.size=123'] } } + + it "should correctly set the batch size" do + expect(get_node_info(@container)['pipelines']['main']['batch_size']).to eql 123 + end + end + + context 'when setting pipeline batch delay' do + let(:options) { { 'ENV' => ['pipeline.batch.delay=36'] } } + + it 'should correctly set batch delay' do + expect(get_node_info(@container)['pipelines']['main']['batch_delay']).to eql 36 + end + end + + context 'when setting unsafe shutdown to true shell style' do + let(:options) { { 'ENV' => ['pipeline.unsafe_shutdown=true'] } } + + it 'should set unsafe shutdown to true' do + expect(get_settings(@container)['pipeline.unsafe_shutdown']).to be_truthy + end + end + + context 'when setting unsafe shutdown to true dot style' do + let(:options) { { 'ENV' => ['pipeline.unsafe_shutdown=true'] } } + + it 'should set unsafe shutdown to true' do + expect(get_settings(@container)['pipeline.unsafe_shutdown']).to be_truthy + end + end +end diff --git a/qa/docker/shared_examples/image_metadata.rb b/qa/docker/shared_examples/image_metadata.rb new file mode 100644 index 000000000..d19aa3f5f --- /dev/null +++ b/qa/docker/shared_examples/image_metadata.rb @@ -0,0 +1,39 @@ +shared_examples_for 'the metadata is set correctly' do |flavor| + before do + @image = find_image(flavor) + @image_config = @image.json['Config'] + @labels = @image_config['Labels'] + end + + it 'should have the correct working directory' do + expect(@image_config['WorkingDir']).to eql '/usr/share/logstash' + end + + it 'should have the correct Architecture' do + expect(@image.json['Architecture']).to have_correct_architecture_for_flavor(flavor) + end + + %w(license org.label-schema.license org.opencontainers.image.licenses).each do |label| + it "should set the license label #{label} correctly" do + expect(@labels[label]).to have_correct_license_label(flavor) + end + end + + %w(org.label-schema.name org.opencontainers.image.title).each do |label| + it "should set the name label #{label} correctly" do + expect(@labels[label]).to eql "logstash" + end + end + + %w(org.opencontainers.image.vendor).each do |label| + it "should set the vendor label #{label} correctly" do + expect(@labels[label]).to eql "Elastic" + end + end + + %w(org.label-schema.version org.opencontainers.image.version).each do |label| + it "should set the version label #{label} correctly" do + expect(@labels[label]).to eql qualified_version + end + end +end \ No newline at end of file diff --git a/qa/docker/spec/full/container_spec.rb b/qa/docker/spec/full/container_spec.rb new file mode 100644 index 000000000..63cc9dc17 --- /dev/null +++ b/qa/docker/spec/full/container_spec.rb @@ -0,0 +1,47 @@ +require_relative '../spec_helper' +require_relative '../../shared_examples/container_config' +require_relative '../../shared_examples/container_options' +require_relative '../../shared_examples/container' + +describe 'A container running the full image' do + it_behaves_like 'the container is configured correctly', 'full' + it_behaves_like 'it runs with different configurations', 'full' + it_behaves_like 'it applies settings correctly', 'full' + + context 'when configuring xpack settings' do + before do + @image = find_image('full') + @container = start_container(@image, {'ENV' => env}) + end + + after do + cleanup_container(@container) + end + + context 'when disabling xpack monitoring' do + let(:env) {['xpack.monitoring.enabled=false']} + + it 'should set monitoring to false' do + expect(get_settings(@container)['xpack.monitoring.enabled']).to be_falsey + end + end + + context 'when enabling xpack monitoring' do + let(:env) {['xpack.monitoring.enabled=true']} + + it 'should set monitoring to true' do + expect(get_settings(@container)['xpack.monitoring.enabled']).to be_truthy + end + end + + context 'when setting elasticsearch urls as an array' do + let(:env) { ['xpack.monitoring.elasticsearch.hosts=["http://node1:9200","http://node2:9200"]']} + + it 'should set set the hosts property correctly' do + expect(get_settings(@container)['xpack.monitoring.elasticsearch.hosts']).to be_an(Array) + expect(get_settings(@container)['xpack.monitoring.elasticsearch.hosts']).to include('http://node1:9200') + expect(get_settings(@container)['xpack.monitoring.elasticsearch.hosts']).to include('http://node2:9200') + end + end + end +end \ No newline at end of file diff --git a/qa/docker/spec/full/image_spec.rb b/qa/docker/spec/full/image_spec.rb new file mode 100644 index 000000000..e222d59d3 --- /dev/null +++ b/qa/docker/spec/full/image_spec.rb @@ -0,0 +1,6 @@ +require_relative '../spec_helper' +require_relative '../../shared_examples/image_metadata' + +describe 'An image with the full distribution' do + it_behaves_like 'the metadata is set correctly', 'full' +end \ No newline at end of file diff --git a/qa/docker/spec/oss/container_spec.rb b/qa/docker/spec/oss/container_spec.rb new file mode 100644 index 000000000..d3662f44b --- /dev/null +++ b/qa/docker/spec/oss/container_spec.rb @@ -0,0 +1,10 @@ +require_relative '../spec_helper' +require_relative '../../shared_examples/container_config' +require_relative '../../shared_examples/container_options' +require_relative '../../shared_examples/container' + +describe 'A container running the oss image' do + it_behaves_like 'the container is configured correctly', 'oss' + it_behaves_like 'it applies settings correctly', 'oss' + it_behaves_like 'it runs with different configurations', 'oss' +end \ No newline at end of file diff --git a/qa/docker/spec/oss/image_spec.rb b/qa/docker/spec/oss/image_spec.rb new file mode 100644 index 000000000..18e228452 --- /dev/null +++ b/qa/docker/spec/oss/image_spec.rb @@ -0,0 +1,6 @@ +require_relative '../spec_helper' +require_relative '../../shared_examples/image_metadata' + +describe 'An image with the oss distribution' do + it_behaves_like 'the metadata is set correctly', 'oss' +end \ No newline at end of file diff --git a/qa/docker/spec/spec_helper.rb b/qa/docker/spec/spec_helper.rb new file mode 100644 index 000000000..c98961d87 --- /dev/null +++ b/qa/docker/spec/spec_helper.rb @@ -0,0 +1,122 @@ +ROOT = File.expand_path(File.join(File.dirname(__FILE__), '..', '..', '..')) +$LOAD_PATH.unshift File.join(ROOT, 'logstash-core/lib') +FIXTURES_DIR = File.expand_path(File.join("..", "..", "fixtures"), __FILE__) + +require 'logstash/version' +require 'json' +require 'stud/try' +require 'docker-api' + +def version + @version ||= LOGSTASH_VERSION +end + +def qualified_version + qualifier = ENV['VERSION_QUALIFIER'] + qualified_version = qualifier ? [version, qualifier].join("-") : version + ENV["RELEASE"] == "1" ? qualified_version : [qualified_version, "SNAPSHOT"].join("-") +end + +def find_image(flavor) + Docker::Image.all.detect{ + |image| image.info['RepoTags'].detect{ + |tag| tag == "docker.elastic.co/logstash/logstash-#{flavor}:#{qualified_version}" + }} +end + +def create_container(image, options = {}) + image.run(nil, options) +end + +def start_container(image, options={}) + container = create_container(image, options) + wait_for_logstash(container) + container +end + +def wait_for_logstash(container) + Stud.try(40.times, RSpec::Expectations::ExpectationNotMetError) do + expect(container.exec(['curl', '-s', 'http://localhost:9600/_node'])[0][0]).not_to be_empty + end +end + +def cleanup_container(container) + unless container.nil? + container.kill + container.delete(:force=>true) + end +end + +def license_label_for_flavor(flavor) + flavor.match(/oss/) ? 'Apache 2.0' : 'Elastic License' +end + +def license_agreement_for_flavor(flavor) + flavor.match(/oss/) ? 'Apache License' : 'ELASTIC LICENSE AGREEMENT!' +end + +def get_logstash_status(container) + JSON.parse(container.exec(['curl', '-s', 'http://localhost:9600'])[0][0])['status'] +end + + +def get_node_info(container) + JSON.parse(container.exec(['curl', '-s', 'http://localhost:9600/_node'])[0][0]) +end + +def get_node_stats(container) + JSON.parse(container.exec(['curl', '-s', 'http://localhost:9600/_node/stats'])[0][0]) +end + +def get_settings(container) + YAML.load(container.read_file('/usr/share/logstash/config/logstash.yml')) +end + +def java_process(container, column) + exec_in_container(container, "ps -C java -o #{column}=").strip +end + +def exec_in_container(container, command) + container.exec(command.split)[0][0] +end + +def architecture_for_flavor(flavor) + flavor.match(/aarch64/) ? 'arm64' : 'amd64' +end + +RSpec::Matchers.define :have_correct_license_label do |expected| + match do |actual| + values_match? license_label_for_flavor(expected), actual + end + failure_message do |actual| + "expected License:#{actual} to eq #{license_label_for_flavor(expected)}" + end +end + +RSpec::Matchers.define :have_correct_license_agreement do |expected| + match do |actual| + values_match? /#{license_agreement_for_flavor(expected)}/, actual + true + end + failure_message do |actual| + "expected License Agreement:#{actual} to contain #{license_agreement_for_flavor(expected)}" + end +end + +RSpec::Matchers.define :have_correct_architecture_for_flavor do |expected| + match do |actual| + values_match? architecture_for_flavor(expected), actual + true + end + failure_message do |actual| + "expected Architecture: #{actual} to be #{architecture_for_flavor(expected)}" + end +end + +shared_context 'image_context' do |flavor| + before do + @image = find_image(flavor) + @image_config = @image.json['Config'] + @labels = @image_config['Labels'] + end +end diff --git a/rakelib/artifacts.rake b/rakelib/artifacts.rake index f91b2fe67..da14d613e 100644 --- a/rakelib/artifacts.rake +++ b/rakelib/artifacts.rake @@ -122,6 +122,7 @@ namespace "artifact" do desc "Generate rpm, deb, tar and zip artifacts" task "all" => ["prepare", "build"] + task "docker_only" => ["prepare", "build_docker_full", "build_docker_oss"] desc "Build a tar.gz of default logstash plugins with all dependencies" task "tar" => ["prepare", "generate_build_metadata"] do @@ -207,12 +208,26 @@ namespace "artifact" do build_docker(true) end - desc "Generate Dockerfile for default and oss images" + desc "Generate Dockerfiles for full and oss images" task "dockerfiles" => ["prepare", "generate_build_metadata"] do puts("[dockerfiles] Building Dockerfiles") - build_dockerfiles + build_dockerfile('oss') + build_dockerfile('full') end + desc "Generate Dockerfile for oss images" + task "dockerfile_oss" => ["prepare", "generate_build_metadata"] do + puts("[dockerfiles] Building oss Dockerfile") + build_dockerfile('oss') + end + + desc "Generate Dockerfile for full images" + task "dockerfile_full" => ["prepare", "generate_build_metadata"] do + puts("[dockerfiles] Building default Dockerfiles") + build_dockerfile('full') + end + + # Auxiliary tasks task "build" => [:generate_build_metadata] do Rake::Task["artifact:gems"].invoke unless SNAPSHOT_BUILD @@ -231,6 +246,16 @@ namespace "artifact" do end end + task "build_docker_full" => [:generate_build_metadata] do + Rake::Task["artifact:docker"].invoke + Rake::Task["artifact:dockerfile_full"].invoke + end + + task "build_docker_oss" => [:generate_build_metadata] do + Rake::Task["artifact:docker_oss"].invoke + Rake::Task["artifact:dockerfile_oss"].invoke + end + task "generate_build_metadata" do return if defined?(BUILD_METADATA_FILE) BUILD_METADATA_FILE = Tempfile.new('build.rb') @@ -570,14 +595,14 @@ namespace "artifact" do end end - def build_dockerfiles + def build_dockerfile(flavor) env = { "ARTIFACTS_DIR" => ::File.join(Dir.pwd, "build"), "RELEASE" => ENV["RELEASE"], "VERSION_QUALIFIER" => VERSION_QUALIFIER } Dir.chdir("docker") do |dir| - system(env, "make public-dockerfiles") + system(env, "make public-dockerfiles_#{flavor}") puts "Dockerfiles created in #{::File.join(env['ARTIFACTS_DIR'], 'docker')}" end end From 2c9cf09e882e6c3cf84f8fc59f0506590c555d97 Mon Sep 17 00:00:00 2001 From: Karen Metts Date: Wed, 29 Jul 2020 19:42:17 -0400 Subject: [PATCH 0571/1126] Doc:Fix name of monitoring settings --- docs/static/security/logstash.asciidoc | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/docs/static/security/logstash.asciidoc b/docs/static/security/logstash.asciidoc index 75e5ef0bb..8771304bd 100644 --- a/docs/static/security/logstash.asciidoc +++ b/docs/static/security/logstash.asciidoc @@ -218,8 +218,8 @@ Then configure the user and password in the `logstash.yml` configuration file: [source,yaml] ---------------------------------------------------------- -monitoring.elasticsearch.username: logstash_system -monitoring.elasticsearch.password: t0p.s3cr3t +xpack.monitoring.elasticsearch.username: logstash_system +xpack.monitoring.elasticsearch.password: t0p.s3cr3t ---------------------------------------------------------- If you initially installed an older version of {xpack} and then upgraded, the From 04a3852428339df8f6be1cafaa389e6409f46521 Mon Sep 17 00:00:00 2001 From: Ry Biesemeyer Date: Thu, 23 Jul 2020 00:45:07 +0000 Subject: [PATCH 0572/1126] specs: don't start ES connection pool when only validating config Accidentally succeeding at connecting to an HTTP resource that is not a real, live Elasticsearch (such as an Elastic Cloud instance that has been shut down and reaped) can cause client initialization to fail. --- x-pack/spec/license_checker/license_reader_spec.rb | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/x-pack/spec/license_checker/license_reader_spec.rb b/x-pack/spec/license_checker/license_reader_spec.rb index 5acdecf80..ccb0af5a4 100644 --- a/x-pack/spec/license_checker/license_reader_spec.rb +++ b/x-pack/spec/license_checker/license_reader_spec.rb @@ -38,6 +38,13 @@ describe LogStash::LicenseChecker::LicenseReader do LogStash::Helpers::ElasticsearchOptions.es_options_from_settings('monitoring', system_settings) end + before(:each) do + # We do _not_ want the client's connection pool to start on initialization, as error conditions + # from accidentally succeeding at establishing a connection to an HTTP resource that's not actually + # a live Elasticsearch (e.g., reaped cloud instance) can cause errors. + allow_any_instance_of(LogStash::Outputs::ElasticSearch::HttpClient::Pool).to receive(:start) + end + subject { described_class.new(system_settings, 'monitoring', elasticsearch_options) } describe '#fetch_xpack_info' do From f736d9c86057b75cf3be2cd5ef2408c7a393cede Mon Sep 17 00:00:00 2001 From: Joao Duarte Date: Tue, 4 Aug 2020 09:53:18 +0100 Subject: [PATCH 0573/1126] bump jruby to 9.2.13.0 --- rubyUtils.gradle | 2 +- versions.yml | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/rubyUtils.gradle b/rubyUtils.gradle index b9c4f7125..b81762d51 100644 --- a/rubyUtils.gradle +++ b/rubyUtils.gradle @@ -25,7 +25,7 @@ buildscript { dependencies { classpath 'org.yaml:snakeyaml:1.23' classpath "de.undercouch:gradle-download-task:4.0.4" - classpath "org.jruby:jruby-complete:9.2.12.0" + classpath "org.jruby:jruby-complete:9.2.13.0" } } diff --git a/versions.yml b/versions.yml index a54cf09c6..9280c3212 100644 --- a/versions.yml +++ b/versions.yml @@ -7,8 +7,8 @@ logstash-core-plugin-api: 2.1.16 # jruby must reference a *released* version of jruby which can be downloaded from the official download url # *and* for which jars artifacts are published for compile-time jruby: - version: 9.2.12.0 - sha1: bccc2034e773cb1aba2cc4b8b40921265f6e857f + version: 9.2.13.0 + sha1: 876bee4475c1d22b1acd437fcdf7f38b682f0e60 # jruby-runtime-override, if specified, will override the jruby version installed in vendor/jruby for logstash runtime only, # not for the compile-time jars From 762d48e31222976368a9c15a058aedbb89b29f6e Mon Sep 17 00:00:00 2001 From: Karen Metts Date: Tue, 4 Aug 2020 19:16:54 -0400 Subject: [PATCH 0574/1126] Doc:Adjust link for integration plugin header file --- docs/include/plugin_header-integration.asciidoc | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/docs/include/plugin_header-integration.asciidoc b/docs/include/plugin_header-integration.asciidoc index c12cbbb23..e7f5d4d6c 100644 --- a/docs/include/plugin_header-integration.asciidoc +++ b/docs/include/plugin_header-integration.asciidoc @@ -11,7 +11,7 @@ ifeval::["{versioned_docs}"=="true"] ++++ endif::[] -* A component of the <> +* A component of the <> * Integration version: {version} * Released on: {release_date} * {changelog_url}[Changelog] @@ -25,7 +25,7 @@ endif::[] ifeval::["{versioned_docs}"=="true"] -For other versions, see the <>. +For other versions, see the <<{type}-{plugin}-index,overview list>>. To learn more about Logstash, see the {logstash-ref}/index.html[Logstash Reference]. From 1013a80b383ce973aa4c7fbf471d32e4cd46a03d Mon Sep 17 00:00:00 2001 From: Joao Duarte Date: Thu, 6 Aug 2020 15:08:14 +0100 Subject: [PATCH 0575/1126] allow skipping pr creation in version bump script --- tools/release/bump_plugin_versions.rb | 19 ++++++++++++++----- 1 file changed, 14 insertions(+), 5 deletions(-) diff --git a/tools/release/bump_plugin_versions.rb b/tools/release/bump_plugin_versions.rb index 06e28d5ef..7fc351dcb 100755 --- a/tools/release/bump_plugin_versions.rb +++ b/tools/release/bump_plugin_versions.rb @@ -20,6 +20,16 @@ require 'net/http' require 'uri' require 'fileutils' require 'yaml' +require 'optparse' + +options = {pr: true} +OptionParser.new do |opts| + opts.banner = "Usage: bump_plugin_versions.rb base_branch last_release allow_for --[no-]pr" + + opts.on("--[no-]pr", "Create Pull Request") do |v| + options[:pr] = v + end +end.parse! def compute_dependecy(version, allow_for) gem_version = Gem::Version.new(version) @@ -76,14 +86,12 @@ end IO.write("Gemfile.template", gemfile) -puts "Cleaning up before running 'rake artifact:tar'" -FileUtils.rm_f("Gemfile") +puts "Cleaning up before running computing dependencies" FileUtils.rm_f("Gemfile.jruby-2.5.lock.release") -FileUtils.rm_rf("vendor") # compute new lock file -puts "Running 'rake artifact:tar'" -result = `rake artifact:tar` +puts "Running: ./gradlew clean installDefaultGems" +`./gradlew clean installDefaultGems` puts "Cleaning up generated lock file (removing injected requirements)" # remove explicit requirements from lock file @@ -102,6 +110,7 @@ FileUtils.mv("Gemfile.lock", "Gemfile.jruby-2.5.lock.release") puts `git diff Gemfile.jruby-2.5.lock.release` +exit(0) unless options[:pr] puts "Creating commit.." branch_name = "update_lock_#{Time.now.to_i}" From 6f421e56da2c9dd9ee845b2e8f5ce8bc1ee81861 Mon Sep 17 00:00:00 2001 From: Ry Biesemeyer Date: Tue, 4 Aug 2020 21:09:37 +0000 Subject: [PATCH 0576/1126] perf: fix memoization of `PipelineConfig#configString()` --- .../java/org/logstash/config/ir/PipelineConfig.java | 12 ++++++++++-- 1 file changed, 10 insertions(+), 2 deletions(-) diff --git a/logstash-core/src/main/java/org/logstash/config/ir/PipelineConfig.java b/logstash-core/src/main/java/org/logstash/config/ir/PipelineConfig.java index a9a8035d9..deecd62a0 100644 --- a/logstash-core/src/main/java/org/logstash/config/ir/PipelineConfig.java +++ b/logstash-core/src/main/java/org/logstash/config/ir/PipelineConfig.java @@ -59,7 +59,7 @@ public final class PipelineConfig { private RubyObject settings; private LocalDateTime readAt; private String configHash; - private String configString; + private volatile String configString; private List sourceRefs; @SuppressWarnings({"rawtypes", "unchecked"}) @@ -108,7 +108,15 @@ public final class PipelineConfig { } public String configString() { - this.configString = confParts.stream().map(SourceWithMetadata::getText).collect(Collectors.joining("\n")); + if (this.configString == null) { + synchronized(this) { + if (this.configString == null) { + this.configString = confParts.stream() + .map(SourceWithMetadata::getText) + .collect(Collectors.joining("\n")); + } + } + } return this.configString; } From b2961deaee42248798f0d4debd9e809e16a30ca3 Mon Sep 17 00:00:00 2001 From: Ry Biesemeyer Date: Tue, 4 Aug 2020 21:28:03 +0000 Subject: [PATCH 0577/1126] test: no-op refactor to avoid repeating implementation in test --- .../config/ir/PipelineConfigTest.java | 39 ++++++++++++++----- 1 file changed, 29 insertions(+), 10 deletions(-) diff --git a/logstash-core/src/test/java/org/logstash/config/ir/PipelineConfigTest.java b/logstash-core/src/test/java/org/logstash/config/ir/PipelineConfigTest.java index 2fcb3776c..685f9bbe8 100644 --- a/logstash-core/src/test/java/org/logstash/config/ir/PipelineConfigTest.java +++ b/logstash-core/src/test/java/org/logstash/config/ir/PipelineConfigTest.java @@ -77,23 +77,42 @@ public class PipelineConfigTest extends RubyEnvTestCase { " generator1\n" + "}"; + static class SourceCollector { + private final StringBuilder compositeSource = new StringBuilder(); + private final List orderedConfigParts = new ArrayList<>(); + + void appendSource(final String protocol, final String id, final int line, final int column, final String text) throws IncompleteSourceWithMetadataException { + orderedConfigParts.add(new SourceWithMetadata(protocol, id, line, column, text)); + compositeSource.append(text); + compositeSource.append("\n"); + } + + String compositeSource() { + return this.compositeSource.toString(); + } + + SourceWithMetadata[] orderedConfigParts() { + return this.orderedConfigParts.toArray(new SourceWithMetadata[]{}); + } + } + @Before public void setUp() throws IncompleteSourceWithMetadataException { source = RubyUtil.RUBY.getClass("LogStash::Config::Source::Local"); pipelineIdSym = RubySymbol.newSymbol(RubyUtil.RUBY, PIPELINE_ID); - orderedConfigParts = new SourceWithMetadata[]{ - new SourceWithMetadata("file", "/tmp/1", 0, 0, "input { generator1 }"), - new SourceWithMetadata("file", "/tmp/2", 0, 0, "input { generator2 }"), - new SourceWithMetadata("file", "/tmp/3", 0, 0, "input { generator3 }"), - new SourceWithMetadata("file", "/tmp/4", 0, 0, "input { generator4 }"), - new SourceWithMetadata("file", "/tmp/5", 0, 0, "input { generator5 }"), - new SourceWithMetadata("file", "/tmp/6", 0, 0, "input { generator6 }"), - new SourceWithMetadata("string", "config_string", 0, 0, "input { generator1 }"), - }; + final SourceCollector sourceCollector = new SourceCollector(); + sourceCollector.appendSource("file", "/tmp/1", 0, 0, "input { generator1 }"); + sourceCollector.appendSource("file", "/tmp/2", 0, 0, "input { generator2 }"); + sourceCollector.appendSource("file", "/tmp/3", 0, 0, "input { generator3 }"); + sourceCollector.appendSource("file", "/tmp/4", 0, 0, "input { generator4 }"); + sourceCollector.appendSource("file", "/tmp/5", 0, 0, "input { generator5 }"); + sourceCollector.appendSource("file", "/tmp/6", 0, 0, "input { generator6 }"); + sourceCollector.appendSource("string", "config_string", 0, 0, "input { generator1 }"); - configMerged = Arrays.stream(orderedConfigParts).map(SourceWithMetadata::getText).collect(Collectors.joining("\n")); + orderedConfigParts = sourceCollector.orderedConfigParts(); + configMerged = sourceCollector.compositeSource(); List unorderedList = Arrays.asList(orderedConfigParts); Collections.shuffle(unorderedList); From 854a31756e0e481b765e0da8bcce450c5fca908f Mon Sep 17 00:00:00 2001 From: Ry Biesemeyer Date: Tue, 4 Aug 2020 21:36:12 +0000 Subject: [PATCH 0578/1126] lir: inject newline delimiter only when necessary Our internal representation of the composite config file needs only to inject newline delimiters if they are missing, and to avoid doing so if they are present. This allows `PipelineConfig#sourceReferences()`, used to map back from the composite line/column to source file/column, to correctly track an offset using the source fragments `SourceWithMetadata#getLinesCount()`. Fixes: #12155 --- .../org/logstash/config/ir/PipelineConfig.java | 15 ++++++++++++--- .../logstash/config/ir/PipelineConfigTest.java | 11 +++++++---- 2 files changed, 19 insertions(+), 7 deletions(-) diff --git a/logstash-core/src/main/java/org/logstash/config/ir/PipelineConfig.java b/logstash-core/src/main/java/org/logstash/config/ir/PipelineConfig.java index deecd62a0..dba86cb70 100644 --- a/logstash-core/src/main/java/org/logstash/config/ir/PipelineConfig.java +++ b/logstash-core/src/main/java/org/logstash/config/ir/PipelineConfig.java @@ -62,6 +62,8 @@ public final class PipelineConfig { private volatile String configString; private List sourceRefs; + private static final String NEWLINE = "\n"; + @SuppressWarnings({"rawtypes", "unchecked"}) public PipelineConfig(RubyClass source, RubySymbol pipelineId, RubyObject uncastedConfigParts, RubyObject logstashSettings) { IRubyObject uncasted = uncastedConfigParts.checkArrayType(); @@ -111,9 +113,16 @@ public final class PipelineConfig { if (this.configString == null) { synchronized(this) { if (this.configString == null) { - this.configString = confParts.stream() - .map(SourceWithMetadata::getText) - .collect(Collectors.joining("\n")); + final StringBuilder compositeConfig = new StringBuilder(); + for (SourceWithMetadata confPart : confParts) { + // If our composite config ends without a trailing newline, + // append one before appending the next config part + if (compositeConfig.lastIndexOf(NEWLINE) < compositeConfig.length() - 1 ) { + compositeConfig.append(NEWLINE); + } + compositeConfig.append(confPart.getText()); + } + this.configString = compositeConfig.toString(); } } } diff --git a/logstash-core/src/test/java/org/logstash/config/ir/PipelineConfigTest.java b/logstash-core/src/test/java/org/logstash/config/ir/PipelineConfigTest.java index 685f9bbe8..b26d3656f 100644 --- a/logstash-core/src/test/java/org/logstash/config/ir/PipelineConfigTest.java +++ b/logstash-core/src/test/java/org/logstash/config/ir/PipelineConfigTest.java @@ -83,8 +83,11 @@ public class PipelineConfigTest extends RubyEnvTestCase { void appendSource(final String protocol, final String id, final int line, final int column, final String text) throws IncompleteSourceWithMetadataException { orderedConfigParts.add(new SourceWithMetadata(protocol, id, line, column, text)); + + if (compositeSource.length() > 0 && !compositeSource.toString().endsWith("\n")) { + compositeSource.append("\n"); + } compositeSource.append(text); - compositeSource.append("\n"); } String compositeSource() { @@ -103,11 +106,11 @@ public class PipelineConfigTest extends RubyEnvTestCase { pipelineIdSym = RubySymbol.newSymbol(RubyUtil.RUBY, PIPELINE_ID); final SourceCollector sourceCollector = new SourceCollector(); - sourceCollector.appendSource("file", "/tmp/1", 0, 0, "input { generator1 }"); + sourceCollector.appendSource("file", "/tmp/1", 0, 0, "input { generator1 }\n"); sourceCollector.appendSource("file", "/tmp/2", 0, 0, "input { generator2 }"); - sourceCollector.appendSource("file", "/tmp/3", 0, 0, "input { generator3 }"); + sourceCollector.appendSource("file", "/tmp/3", 0, 0, "input { generator3 }\n"); sourceCollector.appendSource("file", "/tmp/4", 0, 0, "input { generator4 }"); - sourceCollector.appendSource("file", "/tmp/5", 0, 0, "input { generator5 }"); + sourceCollector.appendSource("file", "/tmp/5", 0, 0, "input { generator5 }\n"); sourceCollector.appendSource("file", "/tmp/6", 0, 0, "input { generator6 }"); sourceCollector.appendSource("string", "config_string", 0, 0, "input { generator1 }"); From 7637fa3f37367ea37a1943b3dd09716ca30e0b93 Mon Sep 17 00:00:00 2001 From: Karen Metts <35154725+karenzone@users.noreply.github.com> Date: Tue, 18 Aug 2020 15:52:58 -0400 Subject: [PATCH 0579/1126] Release notes 7.9.0 (#12179) (#12188) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-authored-by: João Duarte --- docs/static/releasenotes.asciidoc | 166 ++++++++++++++++++++++++++++++ 1 file changed, 166 insertions(+) diff --git a/docs/static/releasenotes.asciidoc b/docs/static/releasenotes.asciidoc index dca7aee28..c771fe79a 100644 --- a/docs/static/releasenotes.asciidoc +++ b/docs/static/releasenotes.asciidoc @@ -3,6 +3,7 @@ This section summarizes the changes in the following releases: +* <> * <> * <> * <> @@ -31,6 +32,171 @@ This section summarizes the changes in the following releases: * <> * <> +[[logstash-7-9-0]] +=== Logstash 7.9.0 Release Notes + +==== New features and enhancements + +===== ECS support in Elasticsearch output plugin + +This release is the first step toward Elastic Common Schema (ECS) support in +{ls}. With 7.9, you can configure the <> to manage index templates that are compatible with the +{ecs-ref}[Elastic Common Schema (ECS)]. The +<> +in the {es} output plugin makes this possible. + +See +{logstash-ref}/plugins-outputs-elasticsearch.html#_compatibility_with_the_elastic_common_schema_ecs[Compatibility with the Elastic Common Schema (ECS)] +in the {es} output plugin docs for more information. + +===== Expanded API key support + +With this release, we've continued expanding support for {es} API keys. Support +for API keys in the <> arrived +in {ls} 7.8.0. {ls} 7.9.0 introduces support for {es} API keys in the +<>, the +<>, and {ls} +<> and <>. + +Check out <> for more information about using API keys with {ls} +and {es}. +Implementation details are in https://github.com/elastic/logstash/pull/11953[#11953]. + +===== ARM64 support (experimental) + +{ls} runs on arm machines! We have tested {ls} against arm64, and we are looking +to make docker and other images available soon. + +ARM artifacts are not yet supported for production, and we’re offering them as +"experimental" to early adopters. + +===== Improved support in App Search output + +We replaced the deprecated Java client library for the +<> with the +Ruby client library, and expanded integration testing. These changes provide a +foundation for expanding App Search integration and quality assurance in future +releases. + +===== Improvements to persistent queue (PQ) + +We've enhanced persistent queues to better manage exceptions and error handling +which could sometimes result in a `LockException` when the queue file lock was +not properly released. Under some conditions, a complex pipeline that is slower +to initialize could be recreated when it was not done initializing, causing a +`LockException`. Implementation details are in https://github.com/elastic/logstash/pull/12023[#12023]. + +These changes result in better stability of persistent queues. + +===== Improvements to pipeline workers error handling + +Worker threads were not correctly monitored for a worker loop exception +resulting in a complete logstash crash upon any exception even when multiple +pipelines are running. Now only the failed pipeline is terminated. If pipeline +reloading is enabled, you can edit the config and have the failed pipeline +reloaded. +Implementation details are in +https://github.com/elastic/logstash/pull/12019[#12019] and +https://github.com/elastic/logstash/pull/12038[#12038]. + +===== Performance improvement on startup and pipeline restarts + +This release contains several optimizations to pipeline compilation, an +essential step of the pipeline initialization process. These changes +significantly improve startup and pipeline-restart performance for complex +pipelines. +(For technical details, check out this PR: https://github.com/elastic/logstash/pull/12060[#12060].) + +From our tests in three different pipelines with eight workers each, we have +seen times decrease from 9 - 28 minutes to around 1 minute. + +To aid the development of pipelines, especially the performance impact of +compilation, Logstash now reports the time taken to compile each pipeline as a +log entry such as: + +[source,sh] +----- +[2020-08-12T14:10:29,388][INFO ][logstash.javapipeline ][main] Pipeline Java execution initialization time {"seconds"=>0.7} +----- + +==== Performance improvements and notable issues fixed + +* Support <> on list-type params https://github.com/elastic/logstash/pull/12051[#12051]. +Resolves https://github.com/elastic/logstash/issues/6366[#6366] and https://github.com/elastic/logstash/issues/8157[#8157]. +* Support using unix pipe as local config file https://github.com/elastic/logstash/pull/11109[#11109] +* Logging improvements +** Display Java pipeline initialization time to help with troubleshooting and diagnostics https://github.com/elastic/logstash/pull/11749[#11749] +** Logging framework enhancement to allow more finetuned logging https://github.com/elastic/logstash/pull/11853[#11853] +** Better logging after definition improvements and script routes in log4j https://github.com/elastic/logstash/pull/11929[#11929] and https://github.com/elastic/logstash/pull/11992[#11992] +** Improved {ls} startup logging to ensure that 'starting logstash' entry happens before any other log entries https://github.com/elastic/logstash/pull/12086[#12086] +* Fix: Add back pipelines queue.data and queue.capacity subdocuments for _node/stats https://github.com/elastic/logstash/pull/11923[#11923] +* Fix: Avoid reloading pipelines that have no changes https://github.com/elastic/logstash/pull/12009[#12009] +* Fix: Removed unnecessary calls that, under some circumstances, could cause +pipeline startup issues for pipelines that were slow to initialize +https://github.com/elastic/logstash/pull/12034[#12034] +* Fix: Allow trailing newlines in config fragments to resolve an issue in which split configs were corrupted when merged https://github.com/elastic/logstash/pull/12161[#12161] +* Fix: Resolve issue in which pipeline init fails for a slow pipeline when monitoring is enabled https://github.com/elastic/logstash/pull/12034[#12034] +* Fix: Ignore default username when no password is set for monitoring and management https://github.com/elastic/logstash/pull/12094[#12094] +* Refactor code refactor to launch ruby thread from ruby code instead of java (as a workaround for jruby bug) https://github.com/elastic/logstash/pull/11900[#11900] +* Updates to dependencies +** Update log4j dependency to 2.13.3 +** Update jruby to 9.2.12.0 + +==== Plugin releases + +*Rubydebug Codec - 3.1.0* + +* Replace stale awesome_print library with maintained fork called amazing_print https://github.com/logstash-plugins/logstash-codec-rubydebug/pull/8[#8] + +*Elasticsearch Filter - 3.9.0* + +* Add support to define a proxy with the proxy config option https://github.com/logstash-plugins/logstash-filter-elasticsearch/pull/134[#134] +* Added api_key support https://github.com/logstash-plugins/logstash-filter-elasticsearch/pull/132[#132] +* [DOC] Removed outdated compatibility notice https://github.com/logstash-plugins/logstash-filter-elasticsearch/pull/131[#131] + +*Memcached Filter - 1.1.0* + +* Added better exception handling https://github.com/logstash-plugins/logstash-filter-memcached/pull/25[#25] + +*Elasticsearch Input - 4.7.0* + +* Added api_key support https://github.com/logstash-plugins/logstash-input-elasticsearch/pull/131[#131] + +*File Input - 4.2.1* + +* Fix: Skip sincedb eviction if read mode completion deletes file during flush https://github.com/logstash-plugins/logstash-input-file/pull/273[#273] +* Fix: Watched files performance with huge filesets https://github.com/logstash-plugins/logstash-input-file/pull/268[#268] +* Updated logging to include full traces in debug (and trace) levels + +*Imap Input - 3.1.0* + +* Adds an option to recursively search the message parts for attachment and inline attachment filenames. If the save_attachments option is set to true, the content of attachments is included in the `attachments.data` field. The attachment data can then be used by the Elasticsearch Ingest Attachment Processor Plugin https://github.com/logstash-plugins/logstash-input-imap/pull/48[#48] + +*Kafka Integration - 10.4.0* + +* Added the input `isolation_level` to allow fine control of whether to return transactional messages https://github.com/logstash-plugins/logstash-integration-kafka/pull/44[#44] +* Added the input and output `client_dns_lookup` parameter to allow control of how DNS requests are made + +*Rabbitmq Integration - 7.1.0* + +* Added support in Output plugin for `sprintf` templates in values provided to `message_properties` https://github.com/logstash-plugins/logstash-integration-rabbitmq/issues/8[#8] +* Added support for _extended_ metadata including raw payload to events generated by the Input Plugin https://github.com/logstash-plugins/logstash-integration-rabbitmq/issues/13[#13] +* Fixes an issue with custom port assignment, in which the custom port was not being applied when more than one host was supplied https://github.com/logstash-plugins/logstash-integration-rabbitmq/pull/12[#12] +* Fixes bug where attempting to read from undeclared exchange resulted in infinite retry loop https://github.com/logstash-plugins/logstash-integration-rabbitmq/issues/10[#10] +* Fixes bug where failing to establish initial connection resulted in a pipeline that refused to shut down https://github.com/logstash-plugins/logstash-integration-rabbitmq/issues/11[#11] + +*Elastic_app_search Output - 1.1.0* + +* Switched AppSearch client library from Java to Ruby https://github.com/logstash-plugins/logstash-output-elastic_app_search/issues/12[#12] +* Covered with integration tests and dockerized local AppSearch server instance. + +*Elasticsearch Output - 10.6.1* + +* Fixed an issue introduced in 10.6.0 that broke Logstash Core's monitoring feature when this plugin is run in Logstash 7.7-7.8. https://github.com/logstash-plugins/logstash-output-elasticsearch/pull/953[#953] +* Added `ecs_compatiblity` mode, for managing ECS-compatable templates https://github.com/logstash-plugins/logstash-output-elasticsearch/pull/952[#952] + + [[logstash-7-8-1]] === Logstash 7.8.1 Release Notes From ef1352ef5313066a7ec03cc0a9438d5b933146d6 Mon Sep 17 00:00:00 2001 From: Rob Bavey Date: Mon, 17 Aug 2020 17:42:03 -0400 Subject: [PATCH 0580/1126] Add UBI8 docker image to artifacts This commit adds the rake docker_ubi8 rake task, and associated changes to the docker template and makefiles. This commit also refactors the acceptance tests to extract xpack tests into a helper class to allow the same tests to be used in both 'full' and 'ubi8' docker image tests --- ci/docker_acceptance_tests.sh | 10 +++++++ docker/Makefile | 29 +++++++++++++++++--- docker/templates/Dockerfile.j2 | 23 ++++++++++++---- qa/docker/shared_examples/xpack.rb | 39 +++++++++++++++++++++++++++ qa/docker/spec/full/container_spec.rb | 39 ++------------------------- qa/docker/spec/ubi8/container_spec.rb | 27 +++++++++++++++++++ qa/docker/spec/ubi8/image_spec.rb | 6 +++++ rakelib/artifacts.rake | 27 ++++++++++++------- 8 files changed, 146 insertions(+), 54 deletions(-) create mode 100644 qa/docker/shared_examples/xpack.rb create mode 100644 qa/docker/spec/ubi8/container_spec.rb create mode 100644 qa/docker/spec/ubi8/image_spec.rb diff --git a/ci/docker_acceptance_tests.sh b/ci/docker_acceptance_tests.sh index 027a227bd..5001dd08a 100755 --- a/ci/docker_acceptance_tests.sh +++ b/ci/docker_acceptance_tests.sh @@ -50,6 +50,16 @@ elif [[ $SELECTED_TEST_SUITE == "full" ]]; then echo "Acceptance: Running the tests" bundle exec rspec docker/spec/full/*_spec.rb +elif [[ $SELECTED_TEST_SUITE == "ubi8" ]]; then + echo "building full docker images" + cd $LS_HOME + rake artifact:docker_ubi8 + echo "Acceptance: Installing dependencies" + cd $QA_DIR + bundle install + + echo "Acceptance: Running the tests" + bundle exec rspec docker/spec/ubi8/*_spec.rb else echo "Building all docker images" cd $LS_HOME diff --git a/docker/Makefile b/docker/Makefile index 0d215870d..38d291476 100644 --- a/docker/Makefile +++ b/docker/Makefile @@ -12,7 +12,7 @@ else VERSION_TAG := $(ELASTIC_VERSION) endif -IMAGE_FLAVORS ?= oss full +IMAGE_FLAVORS ?= oss full ubi8 DEFAULT_IMAGE_FLAVOR ?= full IMAGE_TAG := $(ELASTIC_REGISTRY)/logstash/logstash @@ -28,7 +28,7 @@ lint: venv # Build from artifacts on the local filesystem, using an http server (running # in a container) to provide the artifacts to the Dockerfile. -build-from-local-artifacts: venv dockerfile env2yaml +build-from-local-full-artifacts: venv dockerfile env2yaml docker run --rm -d --name=$(HTTPD) \ -p 8000:8000 --expose=8000 -v $(ARTIFACTS_DIR):/mnt \ python:3 bash -c 'cd /mnt && python3 -m http.server' @@ -49,6 +49,16 @@ build-from-local-oss-artifacts: venv dockerfile env2yaml (docker kill $(HTTPD); false); -docker kill $(HTTPD) +build-from-local-ubi8-artifacts: venv dockerfile env2yaml + docker run --rm -d --name=$(HTTPD) \ + -p 8000:8000 --expose=8000 -v $(ARTIFACTS_DIR):/mnt \ + python:3 bash -c 'cd /mnt && python3 -m http.server' + timeout 120 bash -c 'until curl -s localhost:8000 > /dev/null; do sleep 1; done' + pyfiglet -f puffy -w 160 "Building: oss"; \ + docker build --network=host -t $(IMAGE_TAG)-ubi8:$(VERSION_TAG) -f $(ARTIFACTS_DIR)/Dockerfile-ubi8 data/logstash || \ + (docker kill $(HTTPD); false); + -docker kill $(HTTPD) + COPY_FILES = $(ARTIFACTS_DIR)/docker/config/pipelines.yml $(ARTIFACTS_DIR)/docker/config/logstash-oss.yml $(ARTIFACTS_DIR)/docker/config/logstash-full.yml $(ARTIFACTS_DIR)/docker/config/log4j2.properties $(ARTIFACTS_DIR)/docker/pipeline/default.conf $(ARTIFACTS_DIR)/docker/bin/docker-entrypoint $(ARTIFACTS_DIR)/docker/env2yaml/env2yaml $(ARTIFACTS_DIR)/docker/config/pipelines.yml: data/logstash/config/pipelines.yml @@ -69,7 +79,7 @@ docker_paths: mkdir -p $(ARTIFACTS_DIR)/docker/env2yaml mkdir -p $(ARTIFACTS_DIR)/docker/pipeline -public-dockerfiles: public-dockerfiles_oss public_dockerfiles_full +public-dockerfiles: public-dockerfiles_oss public_dockerfiles_full public_dockerfiles_ubi8 public-dockerfiles_full: venv templates/Dockerfile.j2 docker_paths $(COPY_FILES) jinja2 \ @@ -97,6 +107,19 @@ public-dockerfiles_oss: venv templates/Dockerfile.j2 docker_paths $(COPY_FILES) cp $(ARTIFACTS_DIR)/Dockerfile-oss Dockerfile && \ tar -zcf ../logstash-oss-$(VERSION_TAG)-docker-build-context.tar.gz Dockerfile bin config env2yaml pipeline +public-dockerfiles_ubi8: venv templates/Dockerfile.j2 docker_paths $(COPY_FILES) + jinja2 \ + -D created_date='$(DATE)' \ + -D elastic_version='$(ELASTIC_VERSION)' \ + -D version_tag='$(VERSION_TAG)' \ + -D image_flavor='ubi8' \ + -D local_artifacts='false' \ + -D release='$(RELEASE)' \ + templates/Dockerfile.j2 > $(ARTIFACTS_DIR)/Dockerfile-ubi8 && \ + cd $(ARTIFACTS_DIR)/docker && \ + cp $(ARTIFACTS_DIR)/Dockerfile-ubi8 Dockerfile && \ + tar -zcf ../logstash-$(VERSION_TAG)-docker-build-context.tar.gz Dockerfile bin config env2yaml pipeline + # Push the image to the dedicated push endpoint at "push.docker.elastic.co" push: $(foreach FLAVOR, $(IMAGE_FLAVORS), \ diff --git a/docker/templates/Dockerfile.j2 b/docker/templates/Dockerfile.j2 index 59ac10cdb..21ad1bb04 100644 --- a/docker/templates/Dockerfile.j2 +++ b/docker/templates/Dockerfile.j2 @@ -13,13 +13,21 @@ {% set license = 'Elastic License' -%} {% endif -%} +{% if image_flavor == 'ubi8' -%} + {% set base_image = 'registry.access.redhat.com/ubi8/ubi-minimal' -%} + {% set package_manager = 'microdnf' -%} +{% else -%} + {% set base_image = 'centos:7' -%} + {% set package_manager = 'yum' -%} +{% endif -%} -FROM centos:7 +FROM {{ base_image }} # Install Java and the "which" command, which is needed by Logstash's shell # scripts. -RUN yum update -y && yum install -y java-11-openjdk-devel which && \ - yum clean all +# Minimal distributions also require findutils tar gzip (procps for integration tests) +RUN {{ package_manager }} update -y && {{ package_manager }} install -y procps findutils tar gzip java-11-openjdk-devel which && \ + {{ package_manager }} clean all # Provide a non-root user to run the process. RUN groupadd --gid 1000 logstash && \ @@ -45,13 +53,18 @@ ENV PATH=/usr/share/logstash/bin:$PATH # Provide a minimal configuration, so that simple invocations will provide # a good experience. ADD config/pipelines.yml config/pipelines.yml -ADD config/logstash-{{ image_flavor }}.yml config/logstash.yml +{% if image_flavor == 'oss' -%} +ADD config/logstash-oss.yml config/logstash.yml +{% else -%} +ADD config/logstash-full.yml config/logstash.yml +{% endif -%} ADD config/log4j2.properties config/ ADD pipeline/default.conf pipeline/logstash.conf RUN chown --recursive logstash:root config/ pipeline/ # Ensure Logstash gets a UTF-8 locale by default. -ENV LANG='en_US.UTF-8' LC_ALL='en_US.UTF-8' +# Minimal distributions do not ship with en language packs. +ENV LANG='C.UTF-8' LC_ALL='C.UTF-8' # Place the startup wrapper script. ADD bin/docker-entrypoint /usr/local/bin/ diff --git a/qa/docker/shared_examples/xpack.rb b/qa/docker/shared_examples/xpack.rb new file mode 100644 index 000000000..c0e0f52f7 --- /dev/null +++ b/qa/docker/shared_examples/xpack.rb @@ -0,0 +1,39 @@ +shared_examples_for 'a container with xpack features' do |flavor| + context 'when configuring xpack settings' do + before do + @image = find_image(flavor) + @container = start_container(@image, {'ENV' => env}) + end + + after do + cleanup_container(@container) + end + + context 'when disabling xpack monitoring' do + let(:env) {['xpack.monitoring.enabled=false']} + + it 'should set monitoring to false' do + expect(get_settings(@container)['xpack.monitoring.enabled']).to be_falsey + end + end + + context 'when enabling xpack monitoring' do + let(:env) {['xpack.monitoring.enabled=true']} + + it 'should set monitoring to true' do + expect(get_settings(@container)['xpack.monitoring.enabled']).to be_truthy + end + end + + context 'when setting elasticsearch urls as an array' do + let(:env) { ['xpack.monitoring.elasticsearch.hosts=["http://node1:9200","http://node2:9200"]']} + + it 'should set set the hosts property correctly' do + expect(get_settings(@container)['xpack.monitoring.elasticsearch.hosts']).to be_an(Array) + expect(get_settings(@container)['xpack.monitoring.elasticsearch.hosts']).to include('http://node1:9200') + expect(get_settings(@container)['xpack.monitoring.elasticsearch.hosts']).to include('http://node2:9200') + end + end + end +end + diff --git a/qa/docker/spec/full/container_spec.rb b/qa/docker/spec/full/container_spec.rb index 63cc9dc17..797f1c2ba 100644 --- a/qa/docker/spec/full/container_spec.rb +++ b/qa/docker/spec/full/container_spec.rb @@ -2,46 +2,11 @@ require_relative '../spec_helper' require_relative '../../shared_examples/container_config' require_relative '../../shared_examples/container_options' require_relative '../../shared_examples/container' +require_relative '../../shared_examples/xpack' describe 'A container running the full image' do it_behaves_like 'the container is configured correctly', 'full' it_behaves_like 'it runs with different configurations', 'full' it_behaves_like 'it applies settings correctly', 'full' - - context 'when configuring xpack settings' do - before do - @image = find_image('full') - @container = start_container(@image, {'ENV' => env}) - end - - after do - cleanup_container(@container) - end - - context 'when disabling xpack monitoring' do - let(:env) {['xpack.monitoring.enabled=false']} - - it 'should set monitoring to false' do - expect(get_settings(@container)['xpack.monitoring.enabled']).to be_falsey - end - end - - context 'when enabling xpack monitoring' do - let(:env) {['xpack.monitoring.enabled=true']} - - it 'should set monitoring to true' do - expect(get_settings(@container)['xpack.monitoring.enabled']).to be_truthy - end - end - - context 'when setting elasticsearch urls as an array' do - let(:env) { ['xpack.monitoring.elasticsearch.hosts=["http://node1:9200","http://node2:9200"]']} - - it 'should set set the hosts property correctly' do - expect(get_settings(@container)['xpack.monitoring.elasticsearch.hosts']).to be_an(Array) - expect(get_settings(@container)['xpack.monitoring.elasticsearch.hosts']).to include('http://node1:9200') - expect(get_settings(@container)['xpack.monitoring.elasticsearch.hosts']).to include('http://node2:9200') - end - end - end + it_behaves_like 'a container with xpack features', 'full' end \ No newline at end of file diff --git a/qa/docker/spec/ubi8/container_spec.rb b/qa/docker/spec/ubi8/container_spec.rb new file mode 100644 index 000000000..90cd8f9d0 --- /dev/null +++ b/qa/docker/spec/ubi8/container_spec.rb @@ -0,0 +1,27 @@ +require_relative '../spec_helper' +require_relative '../../shared_examples/container_config' +require_relative '../../shared_examples/container_options' +require_relative '../../shared_examples/container' +require_relative '../../shared_examples/xpack' + +describe 'A container running the ubi8 image' do + it_behaves_like 'the container is configured correctly', 'ubi8' + it_behaves_like 'it runs with different configurations', 'ubi8' + it_behaves_like 'it applies settings correctly', 'ubi8' + it_behaves_like 'a container with xpack features', 'ubi8' + + context 'The running container' do + before do + @image = find_image('ubi8') + @container = start_container(@image, {}) + end + + after do + cleanup_container(@container) + end + + it 'should be based on Red Hat Enterprise Linux' do + expect(exec_in_container(@container, 'cat /etc/redhat-release').chomp).to match /Red Hat Enterprise Linux/ + end + end +end \ No newline at end of file diff --git a/qa/docker/spec/ubi8/image_spec.rb b/qa/docker/spec/ubi8/image_spec.rb new file mode 100644 index 000000000..562f4aef4 --- /dev/null +++ b/qa/docker/spec/ubi8/image_spec.rb @@ -0,0 +1,6 @@ +require_relative '../spec_helper' +require_relative '../../shared_examples/image_metadata' + +describe 'An image with the full distribution' do + it_behaves_like 'the metadata is set correctly', 'ubi8' +end \ No newline at end of file diff --git a/rakelib/artifacts.rake b/rakelib/artifacts.rake index da14d613e..fa085e68a 100644 --- a/rakelib/artifacts.rake +++ b/rakelib/artifacts.rake @@ -122,7 +122,7 @@ namespace "artifact" do desc "Generate rpm, deb, tar and zip artifacts" task "all" => ["prepare", "build"] - task "docker_only" => ["prepare", "build_docker_full", "build_docker_oss"] + task "docker_only" => ["prepare", "build_docker_full", "build_docker_oss", "build_docker_ubi8"] desc "Build a tar.gz of default logstash plugins with all dependencies" task "tar" => ["prepare", "generate_build_metadata"] do @@ -199,13 +199,19 @@ namespace "artifact" do desc "Build docker image" task "docker" => ["prepare", "generate_build_metadata", "tar"] do puts("[docker] Building docker image") - build_docker(false) + build_docker('full') end desc "Build OSS docker image" task "docker_oss" => ["prepare", "generate_build_metadata", "tar_oss"] do puts("[docker_oss] Building OSS docker image") - build_docker(true) + build_docker('oss') + end + + desc "Build UBI8 docker image" + task "docker_ubi8" => %w(prepare generate_build_metadata tar) do + puts("[docker_ubi8] Building UBI docker image") + build_docker('ubi8') end desc "Generate Dockerfiles for full and oss images" @@ -213,6 +219,7 @@ namespace "artifact" do puts("[dockerfiles] Building Dockerfiles") build_dockerfile('oss') build_dockerfile('full') + build_dockerfile('ubi8') end desc "Generate Dockerfile for oss images" @@ -227,6 +234,11 @@ namespace "artifact" do build_dockerfile('full') end + desc "Generate Dockerfile for full images" + task "dockerfile_ubi8" => ["prepare", "generate_build_metadata"] do + puts("[dockerfiles] Building default Dockerfiles") + build_dockerfile('ubi8') + end # Auxiliary tasks task "build" => [:generate_build_metadata] do @@ -242,6 +254,7 @@ namespace "artifact" do unless ENV['SKIP_DOCKER'] == "1" Rake::Task["artifact:docker"].invoke Rake::Task["artifact:docker_oss"].invoke + Rake::Task["artifact:docker_ubi8"].invoke Rake::Task["artifact:dockerfiles"].invoke end end @@ -580,18 +593,14 @@ namespace "artifact" do end end # def package - def build_docker(oss = false) + def build_docker(flavor) env = { "ARTIFACTS_DIR" => ::File.join(Dir.pwd, "build"), "RELEASE" => ENV["RELEASE"], "VERSION_QUALIFIER" => VERSION_QUALIFIER } Dir.chdir("docker") do |dir| - if oss - system(env, "make build-from-local-oss-artifacts") - else - system(env, "make build-from-local-artifacts") - end + system(env, "make build-from-local-#{flavor}-artifacts") end end From 0772e72fa80ec8d7eefb0ad9a38046c53dea9b68 Mon Sep 17 00:00:00 2001 From: Rob Bavey Date: Tue, 18 Aug 2020 09:29:07 -0400 Subject: [PATCH 0581/1126] Minor fixes to acceptance and docker test scripts --- ci/docker_acceptance_tests.sh | 3 ++- docker/Makefile | 2 +- 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/ci/docker_acceptance_tests.sh b/ci/docker_acceptance_tests.sh index 5001dd08a..671e5d615 100755 --- a/ci/docker_acceptance_tests.sh +++ b/ci/docker_acceptance_tests.sh @@ -11,6 +11,7 @@ export GRADLE_OPTS="-Xmx4g -Dorg.gradle.daemon=false -Dorg.gradle.logging.level= # Can run either a specific flavor, or all flavors - # eg `ci/acceptance_tests.sh oss` will run tests for open source container # `ci/acceptance_tests.sh full` will run tests for the default container +# `ci/acceptance_tests.sh ubi8` will run tests for the ubi8 based container # `ci/acceptance_tests.sh` will run tests for all containers SELECTED_TEST_SUITE=$1 @@ -51,7 +52,7 @@ elif [[ $SELECTED_TEST_SUITE == "full" ]]; then echo "Acceptance: Running the tests" bundle exec rspec docker/spec/full/*_spec.rb elif [[ $SELECTED_TEST_SUITE == "ubi8" ]]; then - echo "building full docker images" + echo "building ubi8 docker images" cd $LS_HOME rake artifact:docker_ubi8 echo "Acceptance: Installing dependencies" diff --git a/docker/Makefile b/docker/Makefile index 38d291476..a5799b8e0 100644 --- a/docker/Makefile +++ b/docker/Makefile @@ -54,7 +54,7 @@ build-from-local-ubi8-artifacts: venv dockerfile env2yaml -p 8000:8000 --expose=8000 -v $(ARTIFACTS_DIR):/mnt \ python:3 bash -c 'cd /mnt && python3 -m http.server' timeout 120 bash -c 'until curl -s localhost:8000 > /dev/null; do sleep 1; done' - pyfiglet -f puffy -w 160 "Building: oss"; \ + pyfiglet -f puffy -w 160 "Building: ubi8"; \ docker build --network=host -t $(IMAGE_TAG)-ubi8:$(VERSION_TAG) -f $(ARTIFACTS_DIR)/Dockerfile-ubi8 data/logstash || \ (docker kill $(HTTPD); false); -docker kill $(HTTPD) From 7b8335c54257582e930812a7b14f17e096547d10 Mon Sep 17 00:00:00 2001 From: Rob Bavey Date: Tue, 18 Aug 2020 16:42:52 -0400 Subject: [PATCH 0582/1126] Limit locale changes to ubi8 container --- docker/templates/Dockerfile.j2 | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/docker/templates/Dockerfile.j2 b/docker/templates/Dockerfile.j2 index 21ad1bb04..ebd961837 100644 --- a/docker/templates/Dockerfile.j2 +++ b/docker/templates/Dockerfile.j2 @@ -16,9 +16,12 @@ {% if image_flavor == 'ubi8' -%} {% set base_image = 'registry.access.redhat.com/ubi8/ubi-minimal' -%} {% set package_manager = 'microdnf' -%} + # Minimal distributions do not ship with en language packs. + {% set locale = 'C.UTF-8' -%} {% else -%} {% set base_image = 'centos:7' -%} {% set package_manager = 'yum' -%} + {% set locale = 'en_US.UTF-8' -%} {% endif -%} FROM {{ base_image }} @@ -62,9 +65,8 @@ ADD config/log4j2.properties config/ ADD pipeline/default.conf pipeline/logstash.conf RUN chown --recursive logstash:root config/ pipeline/ -# Ensure Logstash gets a UTF-8 locale by default. -# Minimal distributions do not ship with en language packs. -ENV LANG='C.UTF-8' LC_ALL='C.UTF-8' +# Ensure Logstash gets the correct locale by default. +ENV LANG={{ locale }} LC_ALL={{ locale }} # Place the startup wrapper script. ADD bin/docker-entrypoint /usr/local/bin/ From 0fd5d3a0322c942d9730e1264e0fb511deaa4fa3 Mon Sep 17 00:00:00 2001 From: Karen Metts Date: Wed, 19 Aug 2020 10:59:39 -0400 Subject: [PATCH 0583/1126] Doc:Add note that stdin input doesn't allow config reloading --- docs/static/reloading-config.asciidoc | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/docs/static/reloading-config.asciidoc b/docs/static/reloading-config.asciidoc index fdf2003c2..4661de546 100644 --- a/docs/static/reloading-config.asciidoc +++ b/docs/static/reloading-config.asciidoc @@ -54,3 +54,13 @@ a change in the config file triggers a reload (or the pipeline is restarted). In general, Logstash is not watching or monitoring any configuration files used or referenced by inputs, filters or outputs. + +[[plugins-block-reload]] +==== Plugins that prevent automatic reloading + +Input and output plugins usually interact with OS resources. In some +circumstances those resources can't be released without a restart. For this +reason some plugins can't be simply updated and this prevents pipeline reload. + +The <> plugin, for example, prevents +reloading for these reasons. From 4ef0204098da5485e643b2c8094fffde5f55a75a Mon Sep 17 00:00:00 2001 From: Drew Boswell Date: Wed, 5 Aug 2020 16:07:05 +0200 Subject: [PATCH 0584/1126] add ssl verification_mode to env2yaml --- docker/data/logstash/env2yaml/env2yaml.go | 2 ++ 1 file changed, 2 insertions(+) diff --git a/docker/data/logstash/env2yaml/env2yaml.go b/docker/data/logstash/env2yaml/env2yaml.go index b66a39fed..27c7955f6 100644 --- a/docker/data/logstash/env2yaml/env2yaml.go +++ b/docker/data/logstash/env2yaml/env2yaml.go @@ -91,6 +91,7 @@ func normalizeSetting(setting string) (string, error) { "xpack.monitoring.elasticsearch.password", "xpack.monitoring.elasticsearch.proxy", "xpack.monitoring.elasticsearch.ssl.certificate_authority", + "xpack.monitoring.elasticsearch.ssl.verification_mode", "xpack.monitoring.elasticsearch.ssl.truststore.path", "xpack.monitoring.elasticsearch.ssl.truststore.password", "xpack.monitoring.elasticsearch.ssl.keystore.path", @@ -102,6 +103,7 @@ func normalizeSetting(setting string) (string, error) { "xpack.management.elasticsearch.username", "xpack.management.elasticsearch.password", "xpack.management.elasticsearch.ssl.certificate_authority", + "xpack.management.elasticsearch.ssl.verification_mode", "xpack.management.elasticsearch.ssl.truststore.path", "xpack.management.elasticsearch.ssl.truststore.password", "xpack.management.elasticsearch.ssl.keystore.path", From 75411cfe0bd816e74e63f995d73f189d74bc9706 Mon Sep 17 00:00:00 2001 From: Colin Surprenant Date: Thu, 20 Aug 2020 14:53:51 -0400 Subject: [PATCH 0585/1126] ensure input plugin close is called upon termination or pipeline reload --- logstash-core/lib/logstash/java_pipeline.rb | 46 ++++++++++++------- logstash-core/lib/logstash/pipeline.rb | 46 ++++++++++++------- .../spec/logstash/java_pipeline_spec.rb | 6 ++- logstash-core/spec/logstash/pipeline_spec.rb | 5 +- 4 files changed, 68 insertions(+), 35 deletions(-) diff --git a/logstash-core/lib/logstash/java_pipeline.rb b/logstash-core/lib/logstash/java_pipeline.rb index 7e7ba3016..c20138e36 100644 --- a/logstash-core/lib/logstash/java_pipeline.rb +++ b/logstash-core/lib/logstash/java_pipeline.rb @@ -378,32 +378,33 @@ module LogStash; class JavaPipeline < JavaBasePipeline plugin.run(wrapped_write_client(plugin.id.to_sym)) rescue => e if plugin.stop? - @logger.debug("Input plugin raised exception during shutdown, ignoring it.", - default_logging_keys(:plugin => plugin.class.config_name, :exception => e.message, :backtrace => e.backtrace)) + @logger.debug( + "Input plugin raised exception during shutdown, ignoring it.", + default_logging_keys( + :plugin => plugin.class.config_name, + :exception => e.message, + :backtrace => e.backtrace)) return end # otherwise, report error and restart - @logger.error(I18n.t("logstash.pipeline.worker-error-debug", - default_logging_keys( - :plugin => plugin.inspect, - :error => e.message, - :exception => e.class, - :stacktrace => e.backtrace.join("\n")))) + @logger.error(I18n.t( + "logstash.pipeline.worker-error-debug", + default_logging_keys( + :plugin => plugin.inspect, + :error => e.message, + :exception => e.class, + :stacktrace => e.backtrace.join("\n")))) # Assuming the failure that caused this exception is transient, # let's sleep for a bit and execute #run again sleep(1) - begin - plugin.do_close - rescue => close_exception - @logger.debug("Input plugin raised exception while closing, ignoring", - default_logging_keys(:plugin => plugin.class.config_name, :exception => close_exception.message, - :backtrace => close_exception.backtrace)) - end + close_plugin_and_ignore(plugin) retry + ensure + close_plugin_and_ignore(plugin) end - end # def inputworker + end # initiate the pipeline shutdown sequence # this method is intended to be called from outside the pipeline thread @@ -519,6 +520,19 @@ module LogStash; class JavaPipeline < JavaBasePipeline private + def close_plugin_and_ignore(plugin) + begin + plugin.do_close + rescue => e + @logger.warn( + "plugin raised exception while closing, ignoring", + default_logging_keys( + :plugin => plugin.class.config_name, + :exception => e.message, + :backtrace => e.backtrace)) + end + end + # @return [WorkerLoop] a new WorkerLoop instance or nil upon construction exception def init_worker_loop begin diff --git a/logstash-core/lib/logstash/pipeline.rb b/logstash-core/lib/logstash/pipeline.rb index ccec00bab..54089d518 100644 --- a/logstash-core/lib/logstash/pipeline.rb +++ b/logstash-core/lib/logstash/pipeline.rb @@ -474,32 +474,33 @@ module LogStash; class Pipeline < BasePipeline plugin.run(wrapped_write_client(plugin.id.to_sym)) rescue => e if plugin.stop? - @logger.debug("Input plugin raised exception during shutdown, ignoring it.", - default_logging_keys(:plugin => plugin.class.config_name, :exception => e.message, :backtrace => e.backtrace)) + @logger.debug( + "Input plugin raised exception during shutdown, ignoring it.", + default_logging_keys( + :plugin => plugin.class.config_name, + :exception => e.message, + :backtrace => e.backtrace)) return end # otherwise, report error and restart - @logger.error(I18n.t("logstash.pipeline.worker-error-debug", - default_logging_keys( - :plugin => plugin.inspect, - :error => e.message, - :exception => e.class, - :stacktrace => e.backtrace.join("\n")))) + @logger.error(I18n.t( + "logstash.pipeline.worker-error-debug", + default_logging_keys( + :plugin => plugin.inspect, + :error => e.message, + :exception => e.class, + :stacktrace => e.backtrace.join("\n")))) # Assuming the failure that caused this exception is transient, # let's sleep for a bit and execute #run again sleep(1) - begin - plugin.do_close - rescue => close_exception - @logger.debug("Input plugin raised exception while closing, ignoring", - default_logging_keys(:plugin => plugin.class.config_name, :exception => close_exception.message, - :backtrace => close_exception.backtrace)) - end + close_plugin_and_ignore(plugin) retry + ensure + close_plugin_and_ignore(plugin) end - end # def inputworker + end # initiate the pipeline shutdown sequence # this method is intended to be called from outside the pipeline thread @@ -654,6 +655,19 @@ module LogStash; class Pipeline < BasePipeline private + def close_plugin_and_ignore(plugin) + begin + plugin.do_close + rescue => e + @logger.warn( + "plugin raised exception while closing, ignoring", + default_logging_keys( + :plugin => plugin.class.config_name, + :exception => e.message, + :backtrace => e.backtrace)) + end + end + def maybe_setup_out_plugins if @outputs_registered.make_true register_plugins(@outputs) diff --git a/logstash-core/spec/logstash/java_pipeline_spec.rb b/logstash-core/spec/logstash/java_pipeline_spec.rb index 69f5ceab9..ac7f0f209 100644 --- a/logstash-core/spec/logstash/java_pipeline_spec.rb +++ b/logstash-core/spec/logstash/java_pipeline_spec.rb @@ -405,12 +405,14 @@ describe LogStash::JavaPipeline do eos } - context "output close" do + context "input and output close" do let(:pipeline) { mock_java_pipeline_from_string(test_config_without_output_workers) } let(:output) { pipeline.outputs.first } + let(:input) { pipeline.inputs.first } - it "should call close of output without output-workers" do + it "should call close of input and output without output-workers" do expect(output).to receive(:do_close).once + expect(input).to receive(:do_close).once pipeline.start pipeline.shutdown end diff --git a/logstash-core/spec/logstash/pipeline_spec.rb b/logstash-core/spec/logstash/pipeline_spec.rb index a4561e237..01f8d411f 100644 --- a/logstash-core/spec/logstash/pipeline_spec.rb +++ b/logstash-core/spec/logstash/pipeline_spec.rb @@ -371,18 +371,21 @@ describe LogStash::Pipeline do eos } - context "output close" do + context "inputs and output close" do let(:pipeline) { mock_pipeline_from_string(test_config_without_output_workers) } let(:output) { pipeline.outputs.first } + let(:input) { pipeline.inputs.first } before do allow(output).to receive(:do_close) + allow(input).to receive(:do_close) end it "should call close of output without output-workers" do pipeline.start pipeline.shutdown expect(output).to have_received(:do_close).once + expect(input).to have_received(:do_close).once end end end From a755eb5470b1fd6cea3e717c223984ee493cbcc3 Mon Sep 17 00:00:00 2001 From: Andres Rodriguez Date: Tue, 25 Aug 2020 16:07:29 -0400 Subject: [PATCH 0586/1126] Docker: Expose xpack.management.elasticsearch.proxy (#12201) Expose the proxy xpack management proxy setting in docker (xpack.management.elasticsearch.proxy). Also surface the same proxy setting in the sample config. --- config/logstash.yml | 2 ++ docker/data/logstash/env2yaml/env2yaml.go | 1 + 2 files changed, 3 insertions(+) diff --git a/config/logstash.yml b/config/logstash.yml index d7c544e75..fb211819f 100644 --- a/config/logstash.yml +++ b/config/logstash.yml @@ -256,6 +256,7 @@ pipeline.ordered: auto #xpack.monitoring.enabled: false #xpack.monitoring.elasticsearch.username: logstash_system #xpack.monitoring.elasticsearch.password: password +#xpack.monitoring.elasticsearch.proxy: ["http://proxy:port"] #xpack.monitoring.elasticsearch.hosts: ["https://es1:9200", "https://es2:9200"] # an alternative to hosts + username/password settings is to use cloud_id/cloud_auth #xpack.monitoring.elasticsearch.cloud_id: monitoring_cluster_id:xxxxxxxxxx @@ -278,6 +279,7 @@ pipeline.ordered: auto #xpack.management.pipeline.id: ["main", "apache_logs"] #xpack.management.elasticsearch.username: logstash_admin_user #xpack.management.elasticsearch.password: password +#xpack.management.elasticsearch.proxy: ["http://proxy:port"] #xpack.management.elasticsearch.hosts: ["https://es1:9200", "https://es2:9200"] # an alternative to hosts + username/password settings is to use cloud_id/cloud_auth #xpack.management.elasticsearch.cloud_id: management_cluster_id:xxxxxxxxxx diff --git a/docker/data/logstash/env2yaml/env2yaml.go b/docker/data/logstash/env2yaml/env2yaml.go index 27c7955f6..82483aae8 100644 --- a/docker/data/logstash/env2yaml/env2yaml.go +++ b/docker/data/logstash/env2yaml/env2yaml.go @@ -102,6 +102,7 @@ func normalizeSetting(setting string) (string, error) { "xpack.management.elasticsearch.hosts", "xpack.management.elasticsearch.username", "xpack.management.elasticsearch.password", + "xpack.management.elasticsearch.proxy", "xpack.management.elasticsearch.ssl.certificate_authority", "xpack.management.elasticsearch.ssl.verification_mode", "xpack.management.elasticsearch.ssl.truststore.path", From 713fbfbf146d6b989668f9000a04e9c54102c165 Mon Sep 17 00:00:00 2001 From: Julien Mailleret <8582351+jmlrt@users.noreply.github.com> Date: Wed, 26 Aug 2020 16:26:48 +0200 Subject: [PATCH 0587/1126] fix ubi8 docker build context This commit fixes a typo in the name of the docker build context for ubi8 images. --- docker/Makefile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docker/Makefile b/docker/Makefile index a5799b8e0..7ac714e24 100644 --- a/docker/Makefile +++ b/docker/Makefile @@ -118,7 +118,7 @@ public-dockerfiles_ubi8: venv templates/Dockerfile.j2 docker_paths $(COPY_FILES) templates/Dockerfile.j2 > $(ARTIFACTS_DIR)/Dockerfile-ubi8 && \ cd $(ARTIFACTS_DIR)/docker && \ cp $(ARTIFACTS_DIR)/Dockerfile-ubi8 Dockerfile && \ - tar -zcf ../logstash-$(VERSION_TAG)-docker-build-context.tar.gz Dockerfile bin config env2yaml pipeline + tar -zcf ../logstash-ubi8-$(VERSION_TAG)-docker-build-context.tar.gz Dockerfile bin config env2yaml pipeline # Push the image to the dedicated push endpoint at "push.docker.elastic.co" push: From ad631e464ec4786d556df6ae7577095dd56a9a2c Mon Sep 17 00:00:00 2001 From: Rob Bavey Date: Thu, 20 Aug 2020 17:14:24 -0400 Subject: [PATCH 0588/1126] Add test for ordered pipeline flushing fix --- .../spec/logstash/java_pipeline_spec.rb | 66 +++++++++++-------- 1 file changed, 39 insertions(+), 27 deletions(-) diff --git a/logstash-core/spec/logstash/java_pipeline_spec.rb b/logstash-core/spec/logstash/java_pipeline_spec.rb index ac7f0f209..9181dac67 100644 --- a/logstash-core/spec/logstash/java_pipeline_spec.rb +++ b/logstash-core/spec/logstash/java_pipeline_spec.rb @@ -776,8 +776,9 @@ describe LogStash::JavaPipeline do end context "Periodic Flush" do - let(:config) do - <<-EOS + shared_examples 'it flushes correctly' do + let(:config) do + <<-EOS input { dummy_input {} } @@ -787,37 +788,48 @@ describe LogStash::JavaPipeline do output { dummy_output {} } - EOS - end - let(:output) { ::LogStash::Outputs::DummyOutput.new } - - before do - allow(::LogStash::Outputs::DummyOutput).to receive(:new).with(any_args).and_return(output) - allow(LogStash::Plugin).to receive(:lookup).with("input", "dummy_input").and_return(LogStash::Inputs::DummyBlockingInput) - allow(LogStash::Plugin).to receive(:lookup).with("filter", "dummy_flushing_filter").and_return(DummyFlushingFilterPeriodic) - allow(LogStash::Plugin).to receive(:lookup).with("output", "dummy_output").and_return(::LogStash::Outputs::DummyOutput) - allow(LogStash::Plugin).to receive(:lookup).with("codec", "plain").and_return(LogStash::Codecs::Plain) - end - - it "flush periodically" do - Thread.abort_on_exception = true - pipeline = mock_java_pipeline_from_string(config, pipeline_settings_obj) - Timeout.timeout(timeout) do - pipeline.start + EOS end - Stud.try(max_retry.times, [StandardError, RSpec::Expectations::ExpectationNotMetError]) do - wait(10).for do - # give us a bit of time to flush the events - output.events.empty? - end.to be_falsey + let(:output) { ::LogStash::Outputs::DummyOutput.new } + + before do + allow(::LogStash::Outputs::DummyOutput).to receive(:new).with(any_args).and_return(output) + allow(LogStash::Plugin).to receive(:lookup).with("input", "dummy_input").and_return(LogStash::Inputs::DummyBlockingInput) + allow(LogStash::Plugin).to receive(:lookup).with("filter", "dummy_flushing_filter").and_return(DummyFlushingFilterPeriodic) + allow(LogStash::Plugin).to receive(:lookup).with("output", "dummy_output").and_return(::LogStash::Outputs::DummyOutput) + allow(LogStash::Plugin).to receive(:lookup).with("codec", "plain").and_return(LogStash::Codecs::Plain) end - expect(output.events.any? {|e| e.get("message") == "dummy_flush"}).to eq(true) + it "flush periodically" do + Thread.abort_on_exception = true + pipeline = mock_java_pipeline_from_string(config, pipeline_settings_obj) + Timeout.timeout(timeout) do + pipeline.start + end + Stud.try(max_retry.times, [StandardError, RSpec::Expectations::ExpectationNotMetError]) do + wait(10).for do + # give us a bit of time to flush the events + output.events.empty? + end.to be_falsey + end - pipeline.shutdown + expect(output.events.any? {|e| e.get("message") == "dummy_flush"}).to eq(true) + + pipeline.shutdown + end + + end + + it_behaves_like 'it flushes correctly' + + context 'with pipeline ordered' do + before do + pipeline_settings_obj.set("pipeline.workers", 1) + pipeline_settings_obj.set("pipeline.ordered", true) + end + it_behaves_like 'it flushes correctly' end end - context "Periodic Flush that intermittently returns nil" do let(:config) do <<-EOS From c1dc4748683c411ab1b53d1960729b5da2db5af2 Mon Sep 17 00:00:00 2001 From: Colin Surprenant Date: Tue, 25 Aug 2020 12:29:36 -0400 Subject: [PATCH 0589/1126] fix flushing upon empty batches with ordered execution when running a pipeline with ordered execution, flushes on the pipeline were no longer being called when compute is called with an empty batch, causing issues with the aggregate filter, for example, not being able to push events on timeout. --- .../logstash/config/ir/CompiledPipeline.java | 30 +++++++++++++------ 1 file changed, 21 insertions(+), 9 deletions(-) diff --git a/logstash-core/src/main/java/org/logstash/config/ir/CompiledPipeline.java b/logstash-core/src/main/java/org/logstash/config/ir/CompiledPipeline.java index b351c0612..092e1c0e5 100644 --- a/logstash-core/src/main/java/org/logstash/config/ir/CompiledPipeline.java +++ b/logstash-core/src/main/java/org/logstash/config/ir/CompiledPipeline.java @@ -306,6 +306,8 @@ public final class CompiledPipeline { public final class CompiledOrderedExecution extends CompiledExecution { + @SuppressWarnings({"unchecked"}) private final RubyArray EMPTY_ARRAY = RubyUtil.RUBY.newEmptyArray(); + @Override public void compute(final QueueBatch batch, final boolean flush, final boolean shutdown) { compute(batch.events(), flush, shutdown); @@ -313,16 +315,26 @@ public final class CompiledPipeline { @Override public void compute(final Collection batch, final boolean flush, final boolean shutdown) { - @SuppressWarnings({"unchecked"}) final RubyArray outputBatch = RubyUtil.RUBY.newArray(); - // send batch one-by-one as single-element batches down the filters - @SuppressWarnings({"unchecked"}) final RubyArray filterBatch = RubyUtil.RUBY.newArray(1); - for (final RubyEvent e : batch) { - filterBatch.set(0, e); - final Collection result = compiledFilters.compute(filterBatch, flush, shutdown); - copyNonCancelledEvents(result, outputBatch); - compiledFilters.clear(); + if (!batch.isEmpty()) { + @SuppressWarnings({"unchecked"}) final RubyArray outputBatch = RubyUtil.RUBY.newArray(); + @SuppressWarnings({"unchecked"}) final RubyArray filterBatch = RubyUtil.RUBY.newArray(1); + // send batch one-by-one as single-element batches down the filters + for (final RubyEvent e : batch) { + filterBatch.set(0, e); + _compute(filterBatch, outputBatch, flush, shutdown); + } + compiledOutputs.compute(outputBatch, flush, shutdown); + } else if (flush || shutdown) { + @SuppressWarnings({"unchecked"}) final RubyArray outputBatch = RubyUtil.RUBY.newArray(); + _compute(EMPTY_ARRAY, outputBatch, flush, shutdown); + compiledOutputs.compute(outputBatch, flush, shutdown); } - compiledOutputs.compute(outputBatch, flush, shutdown); + } + + private void _compute(final RubyArray batch, final RubyArray outputBatch, final boolean flush, final boolean shutdown) { + final Collection result = compiledFilters.compute(batch, flush, shutdown); + copyNonCancelledEvents(result, outputBatch); + compiledFilters.clear(); } } From 07e8400f2761a51e369a2ad8216873dc058cd549 Mon Sep 17 00:00:00 2001 From: Karen Metts <35154725+karenzone@users.noreply.github.com> Date: Wed, 2 Sep 2020 11:49:55 -0400 Subject: [PATCH 0590/1126] Doc:Add redirect from multiline filter to multiline codec (#12208) (#12217) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Add filebeat module use case Co-authored-by: João Duarte --- docs/static/redirects.asciidoc | 24 ++++++++++++++++++++++++ 1 file changed, 24 insertions(+) diff --git a/docs/static/redirects.asciidoc b/docs/static/redirects.asciidoc index 4a517acf4..7d160ea39 100644 --- a/docs/static/redirects.asciidoc +++ b/docs/static/redirects.asciidoc @@ -3,3 +3,27 @@ The following pages have moved or been deleted. +[role="exclude",id="plugins-filters-multiline"] +=== Multiline filter plugin + +The <> replaces the multiline +filter plugin. The multiline codec is better equipped to handle multi-worker +pipelines and threading. + +Here's why. Multiline takes individual lines of text and groups them according +to some criteria. +Accomplishing this operation in the filter stage is possible only if the +pipeline has a single worker. Otherwise, chunks would end up in different +workers, and the resulting composition would not make sense. + +The <> allows input plugins to +create separate codec instances per “identity.” For example, each file or tcp +connection can have its own codec instance. + +[role="exclude",id="alt-fb"] +==== {filebeat} modules + +If your use case involves reading files that contain multiline entries, +{filebeat-ref}[{filebeat}] might be a better option. +{filebeat} offers {filebeat-ref}/filebeat-modules.html[modules] for processing logs +from many known apps, such as nginx or apache. From c0d9b025e54f1f2b6af503f33db5a6e5c2ca15b4 Mon Sep 17 00:00:00 2001 From: andsel Date: Fri, 4 Sep 2020 11:21:34 +0200 Subject: [PATCH 0591/1126] Fix to implement the blank? method that doesn't exists for String, is added by Rails framework --- logstash-core/lib/logstash/api/app_helpers.rb | 4 +++- logstash-core/lib/logstash/util.rb | 16 ++++++++++++++++ qa/integration/specs/reload_config_spec.rb | 5 +++-- 3 files changed, 22 insertions(+), 3 deletions(-) diff --git a/logstash-core/lib/logstash/api/app_helpers.rb b/logstash-core/lib/logstash/api/app_helpers.rb index 3a6aa8829..99db7d963 100644 --- a/logstash-core/lib/logstash/api/app_helpers.rb +++ b/logstash-core/lib/logstash/api/app_helpers.rb @@ -17,6 +17,7 @@ require "logstash/json" require "logstash/api/errors" +require "logstash/util" module LogStash::Api::AppHelpers # This method handle both of the normal flow *happy path* @@ -60,10 +61,11 @@ module LogStash::Api::AppHelpers def as_boolean(string) return true if string == true || string =~ (/(true|t|yes|y|1)$/i) - return false if string == false || string.blank? || string =~ (/(false|f|no|n|0)$/i) + return false if string == false || LogStash::Util.blank?(string) || string =~ (/(false|f|no|n|0)$/i) raise ArgumentError.new("invalid value for Boolean: \"#{string}\"") end + protected def default_metadata @factory.build(:default_metadata).all end diff --git a/logstash-core/lib/logstash/util.rb b/logstash-core/lib/logstash/util.rb index 091151101..66edc0608 100644 --- a/logstash-core/lib/logstash/util.rb +++ b/logstash-core/lib/logstash/util.rb @@ -219,4 +219,20 @@ module LogStash::Util Marshal.load(Marshal.dump(o)) end end + + # Returns true if the object is considered blank. + # A blank includes things like '', ' ', nil, + # and arrays and hashes that have nothing in them. + # + # This logic is mostly shared with ActiveSupport's blank? + def self.blank?(value) + if value.kind_of?(NilClass) + true + elsif value.kind_of?(String) + value !~ /\S/ + else + value.respond_to?(:empty?) ? value.empty? : !value + end + end + end # module LogStash::Util diff --git a/qa/integration/specs/reload_config_spec.rb b/qa/integration/specs/reload_config_spec.rb index 4092aa9b2..f3f3cdf9a 100644 --- a/qa/integration/specs/reload_config_spec.rb +++ b/qa/integration/specs/reload_config_spec.rb @@ -22,6 +22,7 @@ require_relative '../framework/helpers' require "logstash/devutils/rspec/spec_helper" require "socket" require "json" +require "logstash/util" describe "Test Logstash service when config reload is enabled" do before(:all) { @@ -71,7 +72,7 @@ describe "Test Logstash service when config reload is enabled" do send_data(reload_port, sample_data) Stud.try(retry_attempts.times, RSpec::Expectations::ExpectationNotMetError) do - expect(IO.read(output_file2).blank?).to be false + expect(LogStash::Util.blank?(IO.read(output_file2))).to be false end # check instance metrics. It should not be reset @@ -89,7 +90,7 @@ describe "Test Logstash service when config reload is enabled" do instance_reload_stats = logstash_service.monitoring_api.node_stats["reloads"] expect(pipeline_reload_stats["successes"]).to eq(1) expect(pipeline_reload_stats["failures"]).to eq(0) - expect(pipeline_reload_stats["last_success_timestamp"].blank?).to be false + expect(LogStash::Util.blank?(pipeline_reload_stats["last_success_timestamp"])).to be false expect(pipeline_reload_stats["last_error"]).to eq(nil) expect(instance_reload_stats["successes"]).to eq(1) From 68ac9477d5bfbafe7e64f8ad3efb2ad15f81dce3 Mon Sep 17 00:00:00 2001 From: Rob Bavey Date: Fri, 11 Sep 2020 14:26:43 -0400 Subject: [PATCH 0592/1126] [7.x backport] Fix keystore thread safety (#12235) Clean backport of #12233 This commit is intended to fix thread safety issues with the JavaKeystore implementation of the secret store. From reading the code, it appears that thread safety for the keystore was intended to be provided by a ReentrantReadWriteLock, a read lock for accessing secrets from the keystore, and a write lock for updating secrets in the keystore. In practice, this was insufficient, the act of accessing a secret from the keystore involved the mutation of a shared keyStore object - the keyStore is `load`ed every time a secret is retrieved from the store. Previous to https://github.com/elastic/logstash/pull/10794, this did not matter, each pipeline held its own instance of the secret store, effectively meaning that only a single thread would ever access a key store at any one time. This PR moved to using a shared keystore instance for substitution variables, exposing the lack of thread safety in the JavaKeystore class. This commit is intended to be the simplest change to fix the underlying issue, and does not address whether we *need* to reload the secrets every time they are read. Relates #12229 --- .../secret/store/backend/JavaKeyStore.java | 38 +++++++++---------- .../store/backend/JavaKeyStoreTest.java | 32 +++++++++++++++- 2 files changed, 48 insertions(+), 22 deletions(-) diff --git a/logstash-core/src/main/java/org/logstash/secret/store/backend/JavaKeyStore.java b/logstash-core/src/main/java/org/logstash/secret/store/backend/JavaKeyStore.java index ab40eed61..760c1b90b 100644 --- a/logstash-core/src/main/java/org/logstash/secret/store/backend/JavaKeyStore.java +++ b/logstash-core/src/main/java/org/logstash/secret/store/backend/JavaKeyStore.java @@ -47,8 +47,7 @@ import java.security.UnrecoverableKeyException; import java.security.cert.CertificateException; import java.util.*; import java.util.concurrent.locks.Lock; -import java.util.concurrent.locks.ReadWriteLock; -import java.util.concurrent.locks.ReentrantReadWriteLock; +import java.util.concurrent.locks.ReentrantLock; import static org.logstash.secret.store.SecretStoreFactory.LOGSTASH_MARKER; @@ -66,9 +65,8 @@ public final class JavaKeyStore implements SecretStore { private char[] keyStorePass; private Path keyStorePath; private ProtectionParameter protectionParameter; - private Lock readLock; + private Lock lock; private boolean useDefaultPass = false; - private Lock writeLock; //package private for testing static String filePermissions = "rw-r--r--"; private static final boolean IS_WINDOWS = System.getProperty("os.name").startsWith("Windows"); @@ -89,7 +87,7 @@ public final class JavaKeyStore implements SecretStore { } try { init(config); - writeLock.lock(); + lock.lock(); LOGGER.debug("Creating new keystore at {}.", keyStorePath.toAbsolutePath()); String keyStorePermissions = filePermissions; //create the keystore on disk with a default entry to identify this as a logstash keystore @@ -120,7 +118,7 @@ public final class JavaKeyStore implements SecretStore { } catch (Exception e) { //should never happen throw new SecretStoreException.UnknownException("Error while trying to create the Logstash keystore. ", e); } finally { - releaseLock(writeLock); + releaseLock(lock); config.clearValues(); } } @@ -129,7 +127,7 @@ public final class JavaKeyStore implements SecretStore { public void delete(SecureConfig config) { try { initLocks(); - writeLock.lock(); + lock.lock(); if (exists(config)) { Files.delete(Paths.get(new String(config.getPlainText(PATH_KEY)))); } @@ -138,7 +136,7 @@ public final class JavaKeyStore implements SecretStore { } catch (Exception e) { //should never happen throw new SecretStoreException.UnknownException("Error while trying to delete the Logstash keystore", e); } finally { - releaseLock(writeLock); + releaseLock(lock); config.clearValues(); } } @@ -234,16 +232,14 @@ public final class JavaKeyStore implements SecretStore { } private void initLocks(){ - ReadWriteLock readWriteLock = new ReentrantReadWriteLock(); - readLock = readWriteLock.readLock(); - writeLock = readWriteLock.writeLock(); + lock = new ReentrantLock(); } @Override public Collection list() { Set identifiers = new HashSet<>(); try { - readLock.lock(); + lock.lock(); loadKeyStore(); Enumeration aliases = keyStore.aliases(); while (aliases.hasMoreElements()) { @@ -253,7 +249,7 @@ public final class JavaKeyStore implements SecretStore { } catch (Exception e) { throw new SecretStoreException.ListException(e); } finally { - releaseLock(readLock); + releaseLock(lock); } return identifiers; } @@ -275,7 +271,7 @@ public final class JavaKeyStore implements SecretStore { } try { init(config); - readLock.lock(); + lock.lock(); try (final InputStream is = Files.newInputStream(keyStorePath)) { try { keyStore.load(is, this.keyStorePass); @@ -302,7 +298,7 @@ public final class JavaKeyStore implements SecretStore { } catch (Exception e) { //should never happen throw new SecretStoreException.UnknownException("Error while trying to load the Logstash keystore", e); } finally { - releaseLock(readLock); + releaseLock(lock); config.clearValues(); } } @@ -319,7 +315,7 @@ public final class JavaKeyStore implements SecretStore { @Override public void persistSecret(SecretIdentifier identifier, byte[] secret) { try { - writeLock.lock(); + lock.lock(); loadKeyStore(); SecretKeyFactory factory = SecretKeyFactory.getInstance("PBE"); //PBEKey requires an ascii password, so base64 encode it @@ -337,14 +333,14 @@ public final class JavaKeyStore implements SecretStore { } catch (Exception e) { throw new SecretStoreException.PersistException(identifier, e); } finally { - releaseLock(writeLock); + releaseLock(lock); } } @Override public void purgeSecret(SecretIdentifier identifier) { try { - writeLock.lock(); + lock.lock(); loadKeyStore(); keyStore.deleteEntry(identifier.toExternalForm()); saveKeyStore(); @@ -352,7 +348,7 @@ public final class JavaKeyStore implements SecretStore { } catch (Exception e) { throw new SecretStoreException.PurgeException(identifier, e); } finally { - releaseLock(writeLock); + releaseLock(lock); } } @@ -366,7 +362,7 @@ public final class JavaKeyStore implements SecretStore { public byte[] retrieveSecret(SecretIdentifier identifier) { if (identifier != null && identifier.getKey() != null && !identifier.getKey().isEmpty()) { try { - readLock.lock(); + lock.lock(); loadKeyStore(); SecretKeyFactory factory = SecretKeyFactory.getInstance("PBE"); KeyStore.SecretKeyEntry secretKeyEntry = (KeyStore.SecretKeyEntry) keyStore.getEntry(identifier.toExternalForm(), protectionParameter); @@ -385,7 +381,7 @@ public final class JavaKeyStore implements SecretStore { } catch (Exception e) { throw new SecretStoreException.RetrievalException(identifier, e); } finally { - releaseLock(readLock); + releaseLock(lock); } } return null; diff --git a/logstash-core/src/test/java/org/logstash/secret/store/backend/JavaKeyStoreTest.java b/logstash-core/src/test/java/org/logstash/secret/store/backend/JavaKeyStoreTest.java index 6d5931aab..021e77117 100644 --- a/logstash-core/src/test/java/org/logstash/secret/store/backend/JavaKeyStoreTest.java +++ b/logstash-core/src/test/java/org/logstash/secret/store/backend/JavaKeyStoreTest.java @@ -46,15 +46,18 @@ import java.nio.file.Paths; import java.nio.file.attribute.PosixFileAttributeView; import java.nio.file.attribute.PosixFilePermission; import java.util.*; +import java.util.concurrent.Callable; +import java.util.concurrent.ExecutionException; +import java.util.concurrent.ExecutorService; import java.util.concurrent.Executors; import java.util.concurrent.Future; +import java.util.concurrent.TimeUnit; import java.util.stream.Collectors; import java.util.stream.IntStream; import static java.nio.file.attribute.PosixFilePermission.*; import static org.assertj.core.api.Assertions.assertThat; import static org.assertj.core.api.Fail.fail; -import static org.hamcrest.CoreMatchers.isA; import static org.logstash.secret.store.SecretStoreFactory.LOGSTASH_MARKER; /** @@ -689,4 +692,31 @@ public class JavaKeyStoreTest { withDefinedPassConfig.add(SecretStoreFactory.KEYSTORE_ACCESS_KEY, "wrongpassword".toCharArray()); new JavaKeyStore().load(withDefinedPassConfig); } + + @Test(timeout = 40_000) + public void concurrentReadTest() throws Exception { + + final int KEYSTORE_COUNT = 250; + + final ExecutorService executorService = Executors.newFixedThreadPool(KEYSTORE_COUNT); + String password = "pAssW3rd!"; + keyStore.persistSecret(new SecretIdentifier("password"), password.getBytes(StandardCharsets.UTF_8)); + try{ + Callable reader = () -> keyStore.retrieveSecret(new SecretIdentifier("password")); + + List> futures = new ArrayList<>(); + for (int i = 0; i < KEYSTORE_COUNT; i++) { + futures.add(executorService.submit(reader)); + } + + for (Future future : futures) { + byte[] result = future.get(); + assertThat(result).isNotNull(); + assertThat(new String(result, StandardCharsets.UTF_8)).isEqualTo(password); + } + } finally { + executorService.shutdownNow(); + executorService.awaitTermination(Long.MAX_VALUE, TimeUnit.MILLISECONDS); + } + } } \ No newline at end of file From 1f345a26537f9864799cecc8e4c375af540f574a Mon Sep 17 00:00:00 2001 From: Karen Metts <35154725+karenzone@users.noreply.github.com> Date: Mon, 14 Sep 2020 16:45:09 -0400 Subject: [PATCH 0593/1126] Doc:Forwardport Release notes 7.9.1 to 7.x (#12240) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * Release notes for 7.9.1 (#12220) * Doc:Fix release notes formatting for consistency (#12224) Co-authored-by: João Duarte Co-authored-by: Karen Metts <35154725+karenzone@users.noreply.github.com> --- docs/static/releasenotes.asciidoc | 75 ++++++++++++++++++++++++++++++- 1 file changed, 74 insertions(+), 1 deletion(-) diff --git a/docs/static/releasenotes.asciidoc b/docs/static/releasenotes.asciidoc index c771fe79a..998f036d3 100644 --- a/docs/static/releasenotes.asciidoc +++ b/docs/static/releasenotes.asciidoc @@ -3,6 +3,7 @@ This section summarizes the changes in the following releases: +* <> * <> * <> * <> @@ -32,6 +33,78 @@ This section summarizes the changes in the following releases: * <> * <> +[[logstash-7-9-1]] +=== Logstash 7.9.1 Release Notes + +==== Notable issues fixed + +===== Fixes in Docker image configuration of Monitoring and Central Management + +As more and more users adopt our docker images, we've been getting reports on gaps where these images don't provide all the configuration knobs the other artifacts do. This release exposes more environment variables for configuring proxy support and certificate verification mode for monitoring and central management (https://github.com/elastic/logstash/pull/12151[#12151], https://github.com/elastic/logstash/pull/12201[#12201]), and for configuring verification_mode https://github.com/elastic/logstash/pull/12162[#12162]. + +===== Pipeline execution fixes to flushing and shutdown + +Since 7.2.0, a change caused terminating pipelines to not request input plugins to cleanup before shutdown, which could cause leaks in resources that weren't freed during pipeline reloads. You can find more information on the fix here: https://github.com/elastic/logstash/pull/12195[#12195] + +Logstash supports ordered execution for pipelines with a single worker. A bug was found in this mode where the flushing mechanism wasn't working, preventing plugins like the aggregate filter from working correctly. This has been fixed, and you can read the details here: https://github.com/elastic/logstash/pull/12204[#12204] + +===== Consistent Fingerprinting + +Our fingerprint filter is a popular solution to perform deduplication of data in downstream systems like Elasticsearch, by computing a hash value based on data from each event. Users reported that this filter could produced different values for events containing the same data since it didn't ensure the order in which Hash Maps/Objects/Ruby Hashes processed their key/value pairs. +This has now been fixed, and you can read more about how it was solved and all the tests we've done here: https://github.com/logstash-plugins/logstash-filter-fingerprint/pull/55[#55] + +===== Updated JRuby to 9.2.13.0 + +The new JRuby release brings greater stability to its code optimizations in multithreaded workloads and a fix to exception handling in Windows environments, both issues that could affect our users. See the https://github.com/jruby/jruby/releases/tag/9.2.13.0[JRuby release notes] for more information. + +==== Plugins + +*Avro Codec - 3.2.4* + +* [DOC] Add clarifications on partial deserialization https://github.com/logstash-plugins/logstash-codec-avro/pull/35[#35] + +*Fingerprint Filter - 3.2.2* + +* Fixed lack of consistent fingerprints on Hash/Map objects https://github.com/logstash-plugins/logstash-filter-fingerprint/pull/55[#55] + +*Kv Filter - 4.4.1* + +* Fixed issue where a `field_split_pattern` containing a literal backslash failed to match correctly https://github.com/logstash-plugins/logstash-filter-kv/issues/87[#87] + +*Elasticsearch Input - 4.7.1* + +* [DOC] Updated sliced scroll link to resolve to correct location after doc structure change https://github.com/logstash-plugins/logstash-input-elasticsearch/pull/135[#135] +* [DOC] Added usage example of docinfo metadata https://github.com/logstash-plugins/logstash-input-elasticsearch/pull/98[#98] + +*Http_poller Input - 5.0.2* + +* [DOC] Expanded url option to include Manticore keys https://github.com/logstash-plugins/logstash-input-http_poller/pull/119[#119] + +*Snmp Input - 1.2.5* + +* Updated snmp4j library to v2.8.4 https://github.com/logstash-plugins/logstash-input-snmp/pull/86[#86] +* Fixed: support SNMPv3 multiple identical security name with different credentials https://github.com/logstash-plugins/logstash-input-snmp/pull/84[#84] +* Fixed: multithreading problem when using multiple snmp inputs with multiple v3 credentials https://github.com/logstash-plugins/logstash-input-snmp/pull/80[#80] + +*Syslog Input - 3.4.4* + +* Refactor: avoid global side-effect + cleanup https://github.com/logstash-plugins/logstash-input-syslog/pull/62[#62] +* avoid setting `BasicSocket.do_not_reverse_lookup` as it has side effects for others + +*Jdbc Integration - 5.0.6* + +* [DOC] Replaced plugin_header file with plugin_header-integration file. https://github.com/logstash-plugins/logstash-integration-jdbc/pull/40[#40] + +*Rabbitmq Integration - 7.1.1* + +* [DOC] Replaced plugin_header file with plugin_header-integration file. https://github.com/logstash-plugins/logstash-integration-rabbitmq/issues/34[#34] + +*Elasticsearch Output - 10.6.2* + +* [DOC] Added clarifying info on http compression settings and behaviors https://github.com/logstash-plugins/logstash-output-elasticsearch/pull/943[#943] +* [DOC] Fixed entry for ilm_policy default value https://github.com/logstash-plugins/logstash-output-elasticsearch/pull/956[#956] + + [[logstash-7-9-0]] === Logstash 7.9.0 Release Notes @@ -268,7 +341,7 @@ You can find more information in the release notes of the respective plugins. *S3 Output - 4.3.2* -* [DOC]Added note that only AWS S3 is supported. No other S3 compatible storage solutions are supported. https://github.com/logstash-plugins/logstash-output-s3/pull/223[#223] +* [DOC] Added note that only AWS S3 is supported. No other S3 compatible storage solutions are supported. https://github.com/logstash-plugins/logstash-output-s3/pull/223[#223] [[logstash-7-8-0]] From 2fb348e053261859ff523f7c44aca746543ce448 Mon Sep 17 00:00:00 2001 From: Karen Metts <35154725+karenzone@users.noreply.github.com> Date: Tue, 15 Sep 2020 16:51:29 -0400 Subject: [PATCH 0594/1126] [DOC] Logging settings can affect performances (#12246) (#12247) Logging settings can affect performances Backports #12246 to 7.x branch Co-authored-by: Luca Belluccini --- docs/static/troubleshooting.asciidoc | 18 ++++++++++++++++++ 1 file changed, 18 insertions(+) diff --git a/docs/static/troubleshooting.asciidoc b/docs/static/troubleshooting.asciidoc index 124eaa600..1a95b0585 100644 --- a/docs/static/troubleshooting.asciidoc +++ b/docs/static/troubleshooting.asciidoc @@ -162,6 +162,24 @@ troubleshooting tips to share, please: * create an issue at https://github.com/elastic/logstash/issues, or * create a pull request with your proposed changes at https://github.com/elastic/logstash. +[float] +[[ts-pipeline-logging-level-performance]] +=== Logging level can affect performances + +*Symptoms* + +Simple filters such as `mutate` or `json` filter can take several milliseconds per event to execute. +Inputs and outputs might be affected, too. + +*Background* + +The different plugins running on Logstash can be quite verbose if the logging level is set to `debug` or `trace`. +As the logging library used in Logstash is synchronous, heavy logging can affect performances. + +*Solution* + +Reset the logging level to `info`. + [float] [[ts-kafka]] == Common Kafka support issues and solutions From 1684c8529ff188de2b9cb3a4a0160ea7234eb202 Mon Sep 17 00:00:00 2001 From: Rob Bavey Date: Wed, 16 Sep 2020 09:13:58 -0400 Subject: [PATCH 0595/1126] [7x backport]Fix docker image certification (#12248) Clean backport of #12242 This commit includes the required changes to pass RedHat docker image certification. This includes: Moving license files to /licenses folder Adding required base labels for name, description, vendor and summary Relates: https://github.com/elastic/dev/issues/1287 --- docker/templates/Dockerfile.j2 | 11 ++++++++++- qa/docker/shared_examples/container.rb | 6 +++++- qa/docker/shared_examples/image_metadata.rb | 16 ++++++++++++++-- 3 files changed, 29 insertions(+), 4 deletions(-) diff --git a/docker/templates/Dockerfile.j2 b/docker/templates/Dockerfile.j2 index ebd961837..a3f4f9763 100644 --- a/docker/templates/Dockerfile.j2 +++ b/docker/templates/Dockerfile.j2 @@ -45,9 +45,13 @@ RUN curl -Lo - {{ url_root }}/{{ tarball }} | \ chown --recursive logstash:logstash /usr/share/logstash/ && \ chown -R logstash:root /usr/share/logstash && \ chmod -R g=u /usr/share/logstash && \ + mkdir /licenses/ && \ + mv /usr/share/logstash/NOTICE.TXT /licenses/NOTICE.TXT && \ + mv /usr/share/logstash/LICENSE.txt /licenses/LICENSE.txt && \ find /usr/share/logstash -type d -exec chmod g+s {} \; && \ ln -s /usr/share/logstash /opt/logstash + WORKDIR /usr/share/logstash ENV ELASTIC_CONTAINER true @@ -92,7 +96,12 @@ LABEL org.label-schema.schema-version="1.0" \ org.label-schema.license="{{ license }}" \ org.opencontainers.image.licenses="{{ license }}" \ org.label-schema.build-date={{ created_date }} \ - org.opencontainers.image.created={{ created_date }} + org.opencontainers.image.created={{ created_date }} \ + description="Logstash is a free and open server-side data processing pipeline that ingests data from a multitude of sources, transforms it, and then sends it to your favorite 'stash.'" \ + name="logstash" \ + maintainer="info@elastic.co" \ + summary="Logstash is a free and open server-side data processing pipeline that ingests data from a multitude of sources, transforms it, and then sends it to your favorite 'stash.'" \ + vendor="Elastic" ENTRYPOINT ["/usr/local/bin/docker-entrypoint"] diff --git a/qa/docker/shared_examples/container.rb b/qa/docker/shared_examples/container.rb index cdd6a4a88..0d8f339b0 100644 --- a/qa/docker/shared_examples/container.rb +++ b/qa/docker/shared_examples/container.rb @@ -22,7 +22,11 @@ shared_examples_for 'the container is configured correctly' do |flavor| context 'container files' do it 'should have the correct license agreement' do - expect(exec_in_container(@container, 'cat /usr/share/logstash/LICENSE.txt')).to have_correct_license_agreement(flavor) + expect(exec_in_container(@container, 'cat /licenses/LICENSE.txt')).to have_correct_license_agreement(flavor) + end + + it 'should have the license notices file' do + expect(exec_in_container(@container, 'cat /licenses/NOTICE.TXT')).to match /Notice for/ end it 'should have the correct user' do diff --git a/qa/docker/shared_examples/image_metadata.rb b/qa/docker/shared_examples/image_metadata.rb index d19aa3f5f..56d1ea56d 100644 --- a/qa/docker/shared_examples/image_metadata.rb +++ b/qa/docker/shared_examples/image_metadata.rb @@ -19,13 +19,25 @@ shared_examples_for 'the metadata is set correctly' do |flavor| end end - %w(org.label-schema.name org.opencontainers.image.title).each do |label| + %w(name org.label-schema.name org.opencontainers.image.title).each do |label| it "should set the name label #{label} correctly" do expect(@labels[label]).to eql "logstash" end end - %w(org.opencontainers.image.vendor).each do |label| + %w(maintainer).each do |label| + it "should set the name label #{label} correctly" do + expect(@labels[label]).to eql "info@elastic.co" + end + end + + %w(description summary).each do |label| + it "should set the name label #{label} correctly" do + expect(@labels[label]).to eql "Logstash is a free and open server-side data processing pipeline that ingests data from a multitude of sources, transforms it, and then sends it to your favorite 'stash.'" + end + end + + %w(vendor org.opencontainers.image.vendor).each do |label| it "should set the vendor label #{label} correctly" do expect(@labels[label]).to eql "Elastic" end From d792d4dd43e788419e82a6a74080dfb92f20ac85 Mon Sep 17 00:00:00 2001 From: andsel Date: Thu, 17 Sep 2020 11:18:20 +0200 Subject: [PATCH 0596/1126] Added elastic-app-search and jwt license definition and notices --- .../src/main/resources/licenseMapping.csv | 2 ++ .../main/resources/notices/elastic-app-search-NOTICE.txt | 5 +++++ .../src/main/resources/notices/jwt-NOTICE.txt | 9 +++++++++ 3 files changed, 16 insertions(+) create mode 100644 tools/dependencies-report/src/main/resources/notices/elastic-app-search-NOTICE.txt create mode 100644 tools/dependencies-report/src/main/resources/notices/jwt-NOTICE.txt diff --git a/tools/dependencies-report/src/main/resources/licenseMapping.csv b/tools/dependencies-report/src/main/resources/licenseMapping.csv index 36fcada45..34acd7aa2 100644 --- a/tools/dependencies-report/src/main/resources/licenseMapping.csv +++ b/tools/dependencies-report/src/main/resources/licenseMapping.csv @@ -38,6 +38,7 @@ dependency,dependencyUrl,licenseOverride "domain_name:",https://github.com/knu/ruby-domain_name,BSD-2-Clause "dotenv:",https://github.com/bkeepers/dotenv,MIT "edn:",https://github.com/relevance/edn-ruby,MIT +"elastic-app-search:",https://github.com/elastic/app-search-ruby,Apache-2.0 "elasticsearch-api:",https://github.com/elastic/elasticsearch-ruby,Apache-2.0 "elasticsearch-transport:",https://github.com/elastic/elasticsearch-ruby,Apache-2.0 "elasticsearch:",https://github.com/elastic/elasticsearch-ruby,Apache-2.0 @@ -65,6 +66,7 @@ dependency,dependencyUrl,licenseOverride "jruby-jms:",https://github.com/reidmorrison/jruby-jms,Apache-2.0 "jruby-openssl:","https://github.com/jruby/jruby-openssl/",EPL-1.0 "jruby-stdin-channel:","https://github.com/colinsurprenant/jruby-stdin-channel",Apache-2.0 +"jwt:",https://github.com/jwt/ruby-jwt,MIT "json:",http://json-jruby.rubyforge.org/,Ruby "lru_redux:","https://github.com/SamSaffron/lru_redux/",MIT "mail:","https://github.com/mikel/mail/",MIT diff --git a/tools/dependencies-report/src/main/resources/notices/elastic-app-search-NOTICE.txt b/tools/dependencies-report/src/main/resources/notices/elastic-app-search-NOTICE.txt new file mode 100644 index 000000000..de1008a58 --- /dev/null +++ b/tools/dependencies-report/src/main/resources/notices/elastic-app-search-NOTICE.txt @@ -0,0 +1,5 @@ +source: https://github.com/elastic/app-search-ruby/blob/v7.8.0/NOTICE.txt + +Elastic App Search Ruby client. + +Copyright 2012-2019 Elasticsearch B.V. \ No newline at end of file diff --git a/tools/dependencies-report/src/main/resources/notices/jwt-NOTICE.txt b/tools/dependencies-report/src/main/resources/notices/jwt-NOTICE.txt new file mode 100644 index 000000000..316bf4578 --- /dev/null +++ b/tools/dependencies-report/src/main/resources/notices/jwt-NOTICE.txt @@ -0,0 +1,9 @@ +source: https://github.com/jwt/ruby-jwt/blob/v2.2.2/LICENSE + +Copyright (c) 2011 Jeff Lindsay + +Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. \ No newline at end of file From 9472d89363cc376f727943fbbcf4131ad782a9a5 Mon Sep 17 00:00:00 2001 From: Rob Bavey Date: Tue, 22 Sep 2020 14:19:48 -0400 Subject: [PATCH 0597/1126] [7x backport] Update ubi8-minimal to pull from elastic docker registry (#12258) Clean backport of #12253 --- docker/templates/Dockerfile.j2 | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docker/templates/Dockerfile.j2 b/docker/templates/Dockerfile.j2 index a3f4f9763..d6987d63c 100644 --- a/docker/templates/Dockerfile.j2 +++ b/docker/templates/Dockerfile.j2 @@ -14,7 +14,7 @@ {% endif -%} {% if image_flavor == 'ubi8' -%} - {% set base_image = 'registry.access.redhat.com/ubi8/ubi-minimal' -%} + {% set base_image = 'docker.elastic.co/ubi8/ubi-minimal' -%} {% set package_manager = 'microdnf' -%} # Minimal distributions do not ship with en language packs. {% set locale = 'C.UTF-8' -%} From b287ec72e22beef7bff3ed27be875fa652917435 Mon Sep 17 00:00:00 2001 From: Karen Metts <35154725+karenzone@users.noreply.github.com> Date: Wed, 23 Sep 2020 14:10:18 -0400 Subject: [PATCH 0598/1126] Doc:Clarify how Bulk API interacts with DLQ (#12209) (#12268) Documents both HTTP success and HTTP failure scenarios. Co-authored-by: Ry Biesemeyer Backports #12209 --- docs/static/dead-letter-queues.asciidoc | 61 +++++++++++++++---------- 1 file changed, 38 insertions(+), 23 deletions(-) diff --git a/docs/static/dead-letter-queues.asciidoc b/docs/static/dead-letter-queues.asciidoc index 4d1c283c7..e451fc4fd 100644 --- a/docs/static/dead-letter-queues.asciidoc +++ b/docs/static/dead-letter-queues.asciidoc @@ -1,37 +1,52 @@ [[dead-letter-queues]] -=== Dead Letter Queues +=== Dead Letter Queues (DLQ) -NOTE: The dead letter queue feature is currently supported for the -<> output only. Additionally, The dead -letter queue is only used where the response code is either 400 -or 404, both of which indicate an event that cannot be retried. -Support for additional outputs will be available in future releases of the -Logstash plugins. Before configuring Logstash to use this feature, refer to -the output plugin documentation to verify that the plugin supports the dead -letter queue feature. +The dead letter queue (DLQ) can provide another layer of data resilience. By default, when Logstash encounters an event that it cannot process because the data contains a mapping error or some other issue, the Logstash pipeline either hangs or drops the unsuccessful event. In order to protect against data loss in this situation, you can <> to write -unsuccessful events to a dead letter queue instead of dropping them. +unsuccessful events to a dead letter queue instead of dropping them. -Each event written to the dead letter queue includes the original event, along -with metadata that describes the reason the event could not be processed, -information about the plugin that wrote the event, and the timestamp for when -the event entered the dead letter queue. +NOTE: The dead letter queue is currently supported only for the +<>. The dead letter queue is used for +documents with response codes of 400 or 404, both of which indicate an event +that cannot be retried. -To process events in the dead letter queue, you simply create a Logstash -pipeline configuration that uses the +Each event written to the dead letter queue includes the original event, +metadata that describes the reason the event could not be processed, information +about the plugin that wrote the event, and the timestamp when the event +entered the dead letter queue. + +To process events in the dead letter queue, create a Logstash pipeline +configuration that uses the <> to read -from the queue. +from the queue. See <> for more information. image::static/images/dead_letter_queue.png[Diagram showing pipeline reading from the dead letter queue] -See <> for more information. +[[es-proc-dlq]] +==== {es} processing and the dead letter queue + +**HTTP request failure.** If the HTTP request fails (because {es} is unreachable +or because it returned an HTTP error code), the {es} output retries the entire +request indefinitely. In these scenarios, the dead letter queue has no +opportunity to intercept. + +**HTTP request success.** The {ref}/docs-bulk.html[{es} Bulk API] can perform +multiple actions using the same request. If the Bulk API request is successful, +it returns `200 OK`, even if some documents in the batch have +{ref}/docs-bulk.html#bulk-failures-ex[failed]. In this situation, the `errors` +flag for the request will be `true`. + +The response body can include metadata indicating that one or more specific +actions in the bulk request could not be performed, along with an HTTP-style +status code per entry to indicate why the action could not be performed. +If the DLQ is configured, individual indexing failures are routed there. [[configuring-dlq]] -==== Configuring Logstash to Use Dead Letter Queues +==== Configuring {ls} to use dead letter queues Dead letter queues are disabled by default. To enable dead letter queues, set the `dead_letter_queue_enable` option in the `logstash.yml` @@ -61,7 +76,7 @@ path.dead_letter_queue: "path/to/data/dead_letter_queue" NOTE: You may not use the same `dead_letter_queue` path for two different Logstash instances. -===== File Rotation +===== File rotation Dead letter queues have a built-in file rotation policy that manages the file size of the queue. When the file size reaches a preconfigured threshold, a new @@ -73,7 +88,7 @@ will be dropped if they would increase the size of the dead letter queue beyond this setting. [[processing-dlq-events]] -==== Processing Events in the Dead Letter Queue +==== Processing events in the dead letter queue When you are ready to process events in the dead letter queue, you create a pipeline that uses the @@ -131,7 +146,7 @@ will not be resubmitted to the dead letter queue if they cannot be processed correctly. [[dlq-timestamp]] -==== Reading From a Timestamp +==== Reading from a timestamp When you read from the dead letter queue, you might not want to process all the events in the queue, especially if there are a lot of old events in the queue. @@ -154,7 +169,7 @@ For this example, the pipeline starts reading all events that were delivered to the dead letter queue on or after June 6, 2017, at 23:40:37. [[dlq-example]] -==== Example: Processing Data That Has Mapping Errors +==== Example: Processing data that has mapping errors In this example, the user attempts to index a document that includes geo_ip data, but the data cannot be processed because it contains a mapping error: From 16e0f85af840009e99eccf18f6cee416581270e0 Mon Sep 17 00:00:00 2001 From: Rob Bavey Date: Thu, 24 Sep 2020 10:41:27 -0400 Subject: [PATCH 0599/1126] 7.9.2 Release Notes (#12272) * Add JDK 15 compatibility notice * Add more information to app_search missed dependency fixed issue Co-authored-by: Karen Metts <35154725+karenzone@users.noreply.github.com> --- docs/static/releasenotes.asciidoc | 33 +++++++++++++++++++++++++++++++ 1 file changed, 33 insertions(+) diff --git a/docs/static/releasenotes.asciidoc b/docs/static/releasenotes.asciidoc index 998f036d3..6aac4ada4 100644 --- a/docs/static/releasenotes.asciidoc +++ b/docs/static/releasenotes.asciidoc @@ -3,6 +3,7 @@ This section summarizes the changes in the following releases: +* <> * <> * <> * <> @@ -33,6 +34,38 @@ This section summarizes the changes in the following releases: * <> * <> +[[logstash-7-9-2]] +=== Logstash 7.9.2 Release Notes + +==== Notable issues fixed + +===== Secret store thread safety issues with multiple pipelines + +Since `7.8.0`, a change to optimise the speed of loading variables from the Logstash Secret Store could cause Logstash not to be able to start when the feature was used in conjunction with multiple pipelines. This has now been fixed, and you can read the details here: https://github.com/elastic/logstash/pull/12236[#12236] + +===== App Search output startup failure + +Since `7.9.0`, a regression was introduced which prevented pipelines using the Elastic App Search output from starting. This release fixes support for this plugin, you can read the details here: https://github.com/logstash-plugins/logstash-output-elastic_app_search/pull/18[#18], https://github.com/elastic/logstash/pull/12251[#12251] +[[jdk15-compat]] +==== Compatibility notice: {ls} and JDK 15 + +{ls} is not yet compatible with JDK 15. + +While we are working to support JDK 15, we encourage you to use supported JDK +versions (8, 11 or 14). See <> for details and the +https://www.elastic.co/support/matrix#matrix_jvm[Elastic Support Matrix] for the +official word on supported versions across products and releases. + +==== Plugins + +*Sleep Filter - 3.0.7* + +* Changed Fixnum to Integer. Fixnum was deprecated in ruby 2.4. https://github.com/logstash-plugins/logstash-filter-sleep/pull/10[#10] + +*Elastic_app_search Output - 1.1.1* + +* Added missed dependency (elastic-app-search) to the gemspec https://github.com/logstash-plugins/logstash-output-elastic_app_search/pull/18[#18]. Fixes https://github.com/logstash-plugins/logstash-output-elastic_app_search/issues/17[#17] + [[logstash-7-9-1]] === Logstash 7.9.1 Release Notes From f9f998313e70698adfe0807408ec0c1c01391042 Mon Sep 17 00:00:00 2001 From: Karen Metts <35154725+karenzone@users.noreply.github.com> Date: Tue, 29 Sep 2020 17:20:21 -0400 Subject: [PATCH 0600/1126] Doc:Increase visibility of offline plugin support (#12283) (#12284) Elevates visibility of Offline Plugin Management section so that air gapped users don't have to struggle through instructions that require an internet connection. Backports: #12283 Related: #12280 --- docs/static/offline-plugins.asciidoc | 7 +- docs/static/plugin-manager.asciidoc | 144 +++++++++++++-------------- 2 files changed, 76 insertions(+), 75 deletions(-) diff --git a/docs/static/offline-plugins.asciidoc b/docs/static/offline-plugins.asciidoc index 0fd4925b4..aba0d4627 100644 --- a/docs/static/offline-plugins.asciidoc +++ b/docs/static/offline-plugins.asciidoc @@ -9,7 +9,7 @@ This procedure requires a staging machine running Logstash that has access to a required for offline installation. [[building-offline-packs]] -[float] +[discrete] === Building Offline Plugin Packs An _offline plugin pack_ is a compressed file that contains all the plugins your offline Logstash installation requires, @@ -49,7 +49,7 @@ bin/logstash-plugin prepare-offline-pack logstash-filter-* logstash-input-beats NOTE: Downloading all dependencies for the specified plugins may take some time, depending on the plugins listed. [[installing-offline-packs]] -[float] +[discrete] === Installing Offline Plugin Packs To install an offline plugin pack: @@ -74,7 +74,8 @@ bin/logstash-plugin install file:///path/to/logstash-offline-plugins-{logstash_v This command expects a file URI, so make sure you use forward slashes and specify the full path to the pack. -[float] +[discrete] +[[updating-offline-packs]] === Updating Offline Plugins To update offline plugins, you update the plugins on the staging server and then use the same process that you followed to diff --git a/docs/static/plugin-manager.asciidoc b/docs/static/plugin-manager.asciidoc index 50703b44e..8e2c0c3fc 100644 --- a/docs/static/plugin-manager.asciidoc +++ b/docs/static/plugin-manager.asciidoc @@ -1,11 +1,6 @@ [[working-with-plugins]] == Working with plugins -Logstash has a rich collection of input, filter, codec and output plugins. Plugins are available as self-contained -packages called gems and hosted on RubyGems.org. The plugin manager accessed via `bin/logstash-plugin` script is used to manage the -lifecycle of plugins in your Logstash deployment. You can install, remove and upgrade plugins using the Command Line -Interface (CLI) invocations described below. - [IMPORTANT] .macOS Gatekeeper warnings ==== @@ -32,12 +27,36 @@ https://support.apple.com/en-us/HT202491[Safely open apps on your Mac]. ==== -[float] -[[http-proxy]] -=== Proxy configuration +Logstash has a rich collection of input, filter, codec, and output plugins. +Check out the https://www.elastic.co/support/matrix#matrix_logstash_plugins[Elastic Support Matrix] +to see which plugins are supported at various levels. -The majority of the plugin manager commands require access to the internet to reach https://rubygems.org[RubyGems.org]. -If your organization is behind a firewall you can set these environments variables to configure Logstash to use your proxy. +Plugins are available in self-contained packages called gems and hosted on +https://rubygems.org/[RubyGems.org]. Use the plugin manager +script--`bin/logstash-plugin`--to manage plugins: + +* <> +* <> +* <> +* <> +* <> +* <> + +[discrete] +[[pointer-to-offline]] +=== No internet connection? + +If you don't have an internet connection, check out <> for +information on <>, +<>, and <> +offline plugin packs. + +[discrete] +[[http-proxy]] +==== Proxy configuration + +Most plugin manager commands require access to the internet to reach https://rubygems.org[RubyGems.org]. +If your organization is behind a firewall, you can set these environments variables to configure Logstash to use your proxy. [source, shell] ---------------------------------- @@ -45,11 +64,11 @@ export http_proxy=http://localhost:3128 export https_proxy=http://localhost:3128 ---------------------------------- -[float] +[discrete] [[listing-plugins]] === Listing plugins -Logstash release packages bundle common plugins so you can use them out of the box. To list the plugins currently +Logstash release packages bundle common plugins. To list the plugins currently available in your deployment: [source,shell] @@ -59,43 +78,67 @@ bin/logstash-plugin list --verbose <2> bin/logstash-plugin list '*namefragment*' <3> bin/logstash-plugin list --group output <4> ---------------------------------- -<1> Will list all installed plugins +<1> Lists all installed plugins +<2> Lists installed plugins with version information +<3> Lists all installed plugins containing a namefragment +<4> Lists all installed plugins for a particular group (input, filter, codec, output) -<2> Will list installed plugins with version information - -<3> Will list all installed plugins containing a namefragment - -<4> Will list all installed plugins for a particular group (input, filter, codec, output) - -[float] +[discrete] [[installing-plugins]] === Adding plugins to your deployment -The most common situation when dealing with plugin installation is when you have access to internet. Using this method, -you will be able to retrieve plugins hosted on the public repository (RubyGems.org) and install on top of your Logstash -installation. +When you have access to internet, you can retrieve plugins hosted on the +https://rubygems.org/[RubyGems.org]public repository and install them on top of +your Logstash installation. [source,shell] ---------------------------------- -bin/logstash-plugin install logstash-output-kafka +bin/logstash-plugin install logstash-input-github ---------------------------------- -Once the plugin is successfully installed, you can start using it in your configuration file. +After a plugin is successfully installed, you can use it in your configuration file. +[discrete] +[[updating-plugins]] +=== Updating plugins + +Plugins have their own release cycles and are often released independently of Logstash’s core release cycle. +Using the update subcommand you can get the latest version of the plugin. + +[source,shell] +---------------------------------- +bin/logstash-plugin update <1> +bin/logstash-plugin update logstash-input-github <2> +---------------------------------- +<1> updates all installed plugins +<2> updates only the plugin you specify + +[discrete] +[[removing-plugins]] +=== Removing plugins + +If you need to remove plugins from your Logstash installation: + +[source,shell] +---------------------------------- +bin/logstash-plugin remove logstash-input-github +---------------------------------- + +[discrete] [[installing-local-plugins]] -[float] ==== Advanced: Adding a locally built plugin -In some cases, you want to install plugins which have not yet been released and not hosted on RubyGems.org. Logstash -provides you the option to install a locally built plugin which is packaged as a ruby gem. Using a file location: +In some cases, you may want to install plugins which are not yett released and +not hosted on RubyGems.org. Logstash provides you the option to install a +locally built plugin which is packaged as a ruby gem. Using a file location: [source,shell] ---------------------------------- bin/logstash-plugin install /path/to/logstash-output-kafka-1.0.0.gem ---------------------------------- +[discrete] [[installing-local-plugins-path]] -[float] ==== Advanced: Using `--path.plugins` Using the Logstash `--path.plugins` flag, you can load a plugin source code located on your file system. Typically this is used by @@ -109,49 +152,6 @@ The path needs to be in a specific directory hierarchy: `PATH/logstash/TYPE/NAM bin/logstash --path.plugins /opt/shared/lib ---------------------------------- -[[updating-plugins]] -[float] -=== Updating plugins - -Plugins have their own release cycle and are often released independent of Logstash’s core release cycle. Using the update -subcommand you can get the latest version of the plugin. - -[source,shell] ----------------------------------- -bin/logstash-plugin update <1> -bin/logstash-plugin update logstash-output-kafka <2> ----------------------------------- -<1> will update all installed plugins - -<2> will update only this plugin - -[[removing-plugins]] -[float] -=== Removing plugins - -If you need to remove plugins from your Logstash installation: - -[source,shell] ----------------------------------- -bin/logstash-plugin remove logstash-output-kafka ----------------------------------- - -[[proxy-plugins]] -[float] -=== Proxy Support - -The previous sections relied on Logstash being able to communicate with RubyGems.org. In certain environments, Forwarding -Proxy is used to handle HTTP requests. Logstash Plugins can be installed and updated through a Proxy by setting the -`HTTP_PROXY` environment variable: - -[source,shell] ----------------------------------- -export HTTP_PROXY=http://127.0.0.1:3128 - -bin/logstash-plugin install logstash-output-kafka ----------------------------------- - -Once set, plugin commands install, update can be used through this proxy. include::cross-plugin-concepts.asciidoc[] From 813e059a9da5c0b36410dd97066f2d386aa2f80f Mon Sep 17 00:00:00 2001 From: Rob Bavey Date: Thu, 20 Feb 2020 11:20:40 -0500 Subject: [PATCH 0601/1126] Bundle JDK (AdoptOpenJDK 11) in Logstash artifacts (x86_64) Create new artifacts with bundled JDK for the supported platforms on x86_64. Download JDK packages from AdoptOpenJDK site, the selected version is loaded from `versions.yml`. Changed also the launch scripts to give precedence to JAVA_HOME, then fallback on bundled JDK if present, as last resource go to the system Java. New artifacts produced with bundled JDK are: - tar.gz with JDK for Linux and Darwin - zip file for Windows - dep and rpm - Docker image All artifacts without JDK are now postfixed with '-no-jdk' while the ones with JDK included has the architecture extension. Covered with tests the touched parts Co-authored-by: Rob Bavey --- bin/logstash | 4 +- bin/logstash.lib.sh | 29 ++- bin/setup.bat | 12 +- bin/system-install | 2 +- build.gradle | 174 ++++++++++++++- docker/templates/Dockerfile.j2 | 6 +- .../spec/lib/artifact_operation_spec.rb | 2 + .../cli/logstash-plugin/list.rb | 1 + .../shared_examples/installed_with_jdk.rb | 52 +++++ qa/acceptance/spec/shared_examples/updated.rb | 2 +- qa/docker/shared_examples/container.rb | 16 +- qa/docker/spec/spec_helper.rb | 2 +- .../specs/cli/prepare_offline_pack_spec.rb | 2 +- qa/rspec/commands.rb | 7 +- qa/rspec/commands/base.rb | 18 ++ qa/rspec/commands/debian.rb | 8 +- qa/rspec/commands/redhat.rb | 8 +- qa/rspec/commands/suse.rb | 8 +- qa/rspec/commands/system_helpers.rb | 14 +- qa/rspec/matchers/be_running.rb | 6 + rakelib/artifacts.rake | 202 ++++++++++++------ versions.yml | 6 + 22 files changed, 484 insertions(+), 97 deletions(-) create mode 100644 qa/acceptance/spec/shared_examples/installed_with_jdk.rb diff --git a/bin/logstash b/bin/logstash index ae23c5163..696361964 100755 --- a/bin/logstash +++ b/bin/logstash @@ -1,7 +1,5 @@ #!/bin/bash -# Run logstash from source -# -# This is most useful when done from a git checkout. +# Run logstash # # Usage: # bin/logstash [arguments] diff --git a/bin/logstash.lib.sh b/bin/logstash.lib.sh index 33c05fbc4..3abe5fcfc 100755 --- a/bin/logstash.lib.sh +++ b/bin/logstash.lib.sh @@ -72,15 +72,38 @@ parse_jvm_options() { fi } +setup_bundled_jdk_part() { + OS_NAME="$(uname -s)" + if [ $OS_NAME = "Darwin" ]; then + BUNDLED_JDK_PART="jdk.app/Contents/Home" + else + BUNDLED_JDK_PART="jdk" + fi +} + setup_java() { # set the path to java into JAVACMD which will be picked up by JRuby to launch itself if [ -z "$JAVACMD" ]; then - if [ -x "$JAVA_HOME/bin/java" ]; then - JAVACMD="$JAVA_HOME/bin/java" - else + setup_bundled_jdk_part + JAVACMD_TEST=`command -v java` + if [ -n "$JAVA_HOME" ]; then + echo "Using JAVA_HOME defined java: ${JAVA_HOME}" + if [ -x "$JAVA_HOME/bin/java" ]; then + JAVACMD="$JAVA_HOME/bin/java" + if [ -d "${LOGSTASH_HOME}/${BUNDLED_JDK_PART}" -a -x "${LOGSTASH_HOME}/${BUNDLED_JDK_PART}/bin/java" ]; then + echo "WARNING, using JAVA_HOME while Logstash distribution comes with a bundled JDK" + fi + else + echo "Invalid JAVA_HOME, doesn't contain bin/java executable" + fi + elif [ -d "${LOGSTASH_HOME}/${BUNDLED_JDK_PART}" -a -x "${LOGSTASH_HOME}/${BUNDLED_JDK_PART}/bin/java" ]; then + echo "Using bundled JDK: ${LOGSTASH_HOME}/${BUNDLED_JDK_PART}" + JAVACMD="${LOGSTASH_HOME}/${BUNDLED_JDK_PART}/bin/java" + elif [ -n "$JAVACMD_TEST" ]; then set +e JAVACMD=`command -v java` set -e + echo "Using system java: $JAVACMD" fi fi diff --git a/bin/setup.bat b/bin/setup.bat index b846894a9..a1138e401 100644 --- a/bin/setup.bat +++ b/bin/setup.bat @@ -22,8 +22,18 @@ rem ### 2: set java if defined JAVA_HOME ( set JAVA="%JAVA_HOME%\bin\java.exe" + echo Using JAVA_HOME defined java: %JAVA_HOME% + if exist "%LS_HOME%\jdk" ( + echo WARNING, using JAVA_HOME while Logstash distribution comes with a bundled JDK + ) ) else ( - for %%I in (java.exe) do set JAVA="%%~$PATH:I" + if exist "%LS_HOME%\jdk" ( + set JAVA="%LS_HOME%\jdk\bin\java.exe" + echo "Using bundled JDK: %JAVA%"" + ) else ( + for %%I in (java.exe) do set JAVA="%%~$PATH:I" + echo "Using system java: %JAVA%" + ) ) if not exist %JAVA% ( diff --git a/bin/system-install b/bin/system-install index d81c5e87b..7a2d37300 100755 --- a/bin/system-install +++ b/bin/system-install @@ -61,7 +61,7 @@ done # bin/logstash-plugin is a short lived ruby script thus we can use aggressive "faster starting JRuby options" # see https://github.com/jruby/jruby/wiki/Improving-startup-time -export JRUBY_OPTS="$JRUBY_OPTS -J-XX:+TieredCompilation -J-XX:TieredStopAtLevel=1 -J-noverify -X-C -Xcompile.invokedynamic=false" +export JRUBY_OPTS="$JRUBY_OPTS $OPEN_JAVA_MODULES -J-XX:+TieredCompilation -J-XX:TieredStopAtLevel=1 -J-noverify -X-C -Xcompile.invokedynamic=false" tempfile=$(mktemp) if [ "x${PRESTART}" == "x" ]; then diff --git a/build.gradle b/build.gradle index 1281cd959..572fa7735 100644 --- a/build.gradle +++ b/build.gradle @@ -25,18 +25,20 @@ buildscript { } } dependencies { + classpath 'org.yaml:snakeyaml:1.17' classpath "gradle.plugin.com.github.jk1:gradle-license-report:0.7.1" } } plugins { id "de.undercouch.download" version "4.0.4" + id "com.dorongold.task-tree" version "1.5" } apply plugin: 'de.undercouch.download' apply from: "rubyUtils.gradle" - +import org.yaml.snakeyaml.Yaml import de.undercouch.gradle.tasks.download.Download import groovy.json.JsonSlurper @@ -242,7 +244,7 @@ tasks.register("assembleTarDistribution") { inputs.files fileTree("${projectDir}/x-pack") outputs.files file("${buildDir}/logstash-${project.version}-SNAPSHOT.tar.gz") doLast { - rake(projectDir, buildDir, 'artifact:tar') + rake(projectDir, buildDir, 'artifact:no_bundle_jdk_tar') } } @@ -257,7 +259,7 @@ tasks.register("assembleOssTarDistribution") { inputs.files fileTree("${projectDir}/logstash-core/lib") inputs.files fileTree("${projectDir}/logstash-core/src") doLast { - rake(projectDir, buildDir, 'artifact:tar_oss') + rake(projectDir, buildDir, 'artifact:archives_oss') } } @@ -274,7 +276,7 @@ tasks.register("assembleZipDistribution") { inputs.files fileTree("${projectDir}/x-pack") outputs.files file("${buildDir}/logstash-${project.version}.zip") doLast { - rake(projectDir, buildDir, 'artifact:zip') + rake(projectDir, buildDir, 'artifact:archives') } } @@ -290,7 +292,7 @@ tasks.register("assembleOssZipDistribution") { inputs.files fileTree("${projectDir}/logstash-core/src") outputs.files file("${buildDir}/logstash-${project.version}.zip") doLast { - rake(projectDir, buildDir, 'artifact:zip_oss') + rake(projectDir, buildDir, 'artifact:archives_oss') } } @@ -422,7 +424,7 @@ tasks.register("deleteLocalEs", Delete) { delete ('./build/elasticsearch') } -tasks.register("copyEs", Copy){ +tasks.register("copyEs", Copy) { dependsOn = [downloadEs, deleteLocalEs] from tarTree(resources.gzip(project.ext.elasticsearchDownloadLocation)) into "./build/" @@ -509,11 +511,165 @@ bootstrap.dependsOn assemblyDeps // Elasticsearch doesn't yet have a build we can fetch // So for now we'll remove this to unblock builds, but finding a way // to compartimentalize failures is needed going forward -//check.dependsOn runIntegrationTests +//check.dependsOn runIntegrationTest -Boolean oss = System.getenv('OSS').equals('true') +runIntegrationTests.shouldRunAfter tasks.getByPath(":logstash-core:test") -if (!oss) { +def selectOsType() { + if (project.ext.has("jdk_bundle_os")) { + return project.ext.jdk_bundle_os + } + String osName = System.properties['os.name'] + switch (osName.toLowerCase()) { + case ~/mac os x/: + return "darwin" + case ~/windows.*/: + return "windows" + case ~/linux/: + return "linux" + default: + throw new IllegalArgumentException("Can't determine OS type from name: $osName") + } +} + +class JDKDetails { + final String revision + final String build + final String vendor + final int major + private final String osName + private final String extension + final String localPackageName + final String unpackedJdkName + private String arch = "x64" + + JDKDetails(versionYml, osName) { + revision = versionYml.bundled_jdk.revision + build = versionYml.bundled_jdk.build + vendor = versionYml.bundled_jdk.vendor + major = revision.split('\\.').first() as int + this.osName = osName + + switch (osName) { + case "windows": + extension = "zip" + break + default: + extension = "tar.gz" + } + unpackedJdkName = "jdk-${revision}-${osName}" + localPackageName = "${unpackedJdkName}.${extension}" + } + + String createDownloadUrl() { + switch (vendor) { + case "adoptopenjdk": + String releaseName = major > 8 ? + "jdk-${revision}+${build}": + "jdk${revision}u${build}" + String adoptOsName = adaptOsName(osName) + return "https://api.adoptopenjdk.net/v3/binary/version/${releaseName}/${adoptOsName}/${arch}/jdk/hotspot/normal/${vendor}" + default: + throw RuntimeException("Can't handle vendor: ${vendor}") + } + } + + private String adaptOsName(String osName) { + if (osName == "darwin") + return "mac" + return osName + } +} + +tasks.register("downloadJdk", Download) { + // CLI project properties: -Pjdk_bundle_os=[windows|linux|darwin] + + project.ext.set("versionFound", true) + String osName = selectOsType() + + def versionYml = new Yaml().load(new File("$projectDir/versions.yml").text) + def jdkDetails = new JDKDetails(versionYml, osName) + + description "Download JDK ${jdkDetails.major}, OS: ${osName}" + + // find url of build artifact + String artifactApiUrl = jdkDetails.createDownloadUrl() + + project.ext.set("jdkURL", System.getenv("JDK_URL") ?: artifactApiUrl) + project.ext.set("jdkDownloadLocation", "${projectDir}/build/${jdkDetails.localPackageName}") + project.ext.set("jdkDirectory", "${projectDir}/build/${jdkDetails.unpackedJdkName}") + + String jdkFolderName = osName == "darwin" ? "jdk.app" : "jdk" + project.ext.set("jdkBundlingDirectory", "${projectDir}/${jdkFolderName}") + + src project.ext.jdkURL + onlyIfNewer true + overwrite false + inputs.file("${projectDir}/versions.yml") + outputs.file(project.ext.jdkDownloadLocation) + dest new File(project.ext.jdkDownloadLocation) + + doLast { + mkdir project.ext.jdkBundlingDirectory + println "Downloaded to ${project.ext.jdkDownloadLocation}" + } +} + +tasks.register("deleteLocalJdk", Delete) { + // CLI project properties: -Pjdk_bundle_os=[windows|linux|darwin] + String osName = selectOsType() + String jdkFolderName = osName == "darwin" ? "jdk.app" : "jdk" + String jdkBundlingDirectory = "${projectDir}/${jdkFolderName}" + delete jdkBundlingDirectory +} + +// Cannot use tarTree as it does not handle symlinks +tasks.register("untarJdk", Exec) { + dependsOn downloadJdk + description = "unpack the downloaded JDK's tar.gz" + commandLine 'tar', 'xf', project.ext.jdkDownloadLocation, '-C', project.ext.jdkBundlingDirectory, '--strip-components', '1' + inputs.file(project.ext.jdkDownloadLocation) + outputs.dir(project.ext.jdkBundlingDirectory) +} + +tasks.register("unzipJdk", Copy) { + dependsOn downloadJdk + description = "unpack the downloaded JDK's zip" + String rootName = null + from(zipTree("$project.ext.jdkDownloadLocation")) { + eachFile { fcd -> + rootName = rootName ?: fcd.relativePath.segments[0] + fcd.relativePath = new RelativePath(true, fcd.relativePath.segments.drop(1)) + } + } + into project.ext.jdkBundlingDirectory + doLast { + delete "${project.ext.jdkBundlingDirectory}/$rootName" + } +} + +tasks.register("decompressJdk") { + description = "unpack the downloaded JDK's (wrapper task for unzipJdk, untarJdk)" + String osName = selectOsType() + switch (osName) { + case "windows": + dependsOn ":unzipJdk" + break + default: + dependsOn ":untarJdk" + } +} + +tasks.register("copyJdk", Copy) { + dependsOn = [decompressJdk, bootstrap] + description = "Download, unpack and copy the JDK" + // CLI project properties: -Pjdk_bundle_os=[windows|linux|darwin] + doLast { + System.out.println "Download location is ${project.ext.jdkDownloadLocation}, Decompressing ${project.ext.jdkDirectory} to \"${project.ext.jdkBundlingDirectory}\"" + } +} + +if (System.getenv('OSS') != 'true') { project(":logstash-xpack") { ["rubyTests", "rubyIntegrationTests", "test"].each { tsk -> tasks.getByPath(":logstash-xpack:" + tsk).configure { diff --git a/docker/templates/Dockerfile.j2 b/docker/templates/Dockerfile.j2 index d6987d63c..4931df84a 100644 --- a/docker/templates/Dockerfile.j2 +++ b/docker/templates/Dockerfile.j2 @@ -6,10 +6,10 @@ {% endif -%} {% if image_flavor == 'oss' -%} - {% set tarball = 'logstash-oss-%s.tar.gz' % elastic_version -%} + {% set tarball = 'logstash-oss-%s-linux-x86_64.tar.gz' % elastic_version -%} {% set license = 'Apache 2.0' -%} {% else -%} - {% set tarball = 'logstash-%s.tar.gz' % elastic_version -%} + {% set tarball = 'logstash-%s-linux-x86_64.tar.gz' % elastic_version -%} {% set license = 'Elastic License' -%} {% endif -%} @@ -29,7 +29,7 @@ FROM {{ base_image }} # Install Java and the "which" command, which is needed by Logstash's shell # scripts. # Minimal distributions also require findutils tar gzip (procps for integration tests) -RUN {{ package_manager }} update -y && {{ package_manager }} install -y procps findutils tar gzip java-11-openjdk-devel which && \ +RUN {{ package_manager }} update -y && {{ package_manager }} install -y procps findutils tar gzip which shadow-utils && \ {{ package_manager }} clean all # Provide a non-root user to run the process. diff --git a/qa/acceptance/spec/lib/artifact_operation_spec.rb b/qa/acceptance/spec/lib/artifact_operation_spec.rb index 82930e38a..982bdd134 100644 --- a/qa/acceptance/spec/lib/artifact_operation_spec.rb +++ b/qa/acceptance/spec/lib/artifact_operation_spec.rb @@ -17,6 +17,7 @@ require_relative '../spec_helper' require_relative '../shared_examples/installed' +require_relative '../shared_examples/installed_with_jdk' require_relative '../shared_examples/running' require_relative '../shared_examples/updated' @@ -26,6 +27,7 @@ describe "artifacts operation" do config.servers.each do |address| logstash = ServiceTester::Artifact.new(address, config.lookup[address]) it_behaves_like "installable", logstash + it_behaves_like "installable_with_jdk", logstash it_behaves_like "updated", logstash end end diff --git a/qa/acceptance/spec/shared_examples/cli/logstash-plugin/list.rb b/qa/acceptance/spec/shared_examples/cli/logstash-plugin/list.rb index 5598e9ab5..da1ede672 100644 --- a/qa/acceptance/spec/shared_examples/cli/logstash-plugin/list.rb +++ b/qa/acceptance/spec/shared_examples/cli/logstash-plugin/list.rb @@ -49,6 +49,7 @@ shared_examples "logstash list" do |logstash| stdout = StringIO.new(result.stdout) stdout.set_encoding(Encoding::UTF_8) while line = stdout.gets + next if line.match(/^Using system java:.*$/) match = line.match(/^#{plugin_name_with_version}$/) expect(match).to_not be_nil diff --git a/qa/acceptance/spec/shared_examples/installed_with_jdk.rb b/qa/acceptance/spec/shared_examples/installed_with_jdk.rb new file mode 100644 index 000000000..df74f4914 --- /dev/null +++ b/qa/acceptance/spec/shared_examples/installed_with_jdk.rb @@ -0,0 +1,52 @@ +# 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 '../spec_helper' +require 'logstash/version' + +# This test checks if a package is possible to be installed without errors. +RSpec.shared_examples "installable_with_jdk" do |logstash| + + before(:all) do + #unset to force it using bundled JDK to run LS + logstash.run_command("unset JAVA_HOME") + end + + before(:each) do + logstash.uninstall + logstash.install({:bundled_jdk => true, :version => LOGSTASH_VERSION}) + end + + after(:each) do + logstash.uninstall + end + + it "is installed on #{logstash.hostname}" do + expect(logstash).to be_installed + end + + it "is running on #{logstash.hostname}" do + logstash.start_service + expect(logstash).to be_running_with("/usr/share/logstash/jdk/bin/java") + logstash.stop_service + end + + it "is removable on #{logstash.hostname}" do + logstash.uninstall + expect(logstash).to be_removed + end +end diff --git a/qa/acceptance/spec/shared_examples/updated.rb b/qa/acceptance/spec/shared_examples/updated.rb index cae08700c..a0762497f 100644 --- a/qa/acceptance/spec/shared_examples/updated.rb +++ b/qa/acceptance/spec/shared_examples/updated.rb @@ -28,7 +28,7 @@ RSpec.shared_examples "updated" do |logstash| end before(:each) do - options={:version => LOGSTASH_LATEST_VERSION, :snapshot => false, :base => "./" } + options={:version => LOGSTASH_LATEST_VERSION, :snapshot => false, :base => "./", :skip_jdk_infix => true } logstash.install(options) # make sure latest version is installed end diff --git a/qa/docker/shared_examples/container.rb b/qa/docker/shared_examples/container.rb index 0d8f339b0..5d76d79fa 100644 --- a/qa/docker/shared_examples/container.rb +++ b/qa/docker/shared_examples/container.rb @@ -11,7 +11,17 @@ shared_examples_for 'the container is configured correctly' do |flavor| context 'logstash' do it 'should run with the correct version' do - expect(exec_in_container(@container, 'logstash --version')).to match /#{version}/ + console_out = exec_in_container(@container, 'logstash --version') + console_filtered = console_out.split("\n") + .delete_if do |line| + line =~ /Using JAVA_HOME defined java|Using system java: / + end.join + expect(console_filtered).to match /#{version}/ + end + + it 'should run with the bundled JDK' do + first_console_line = exec_in_container(@container, 'logstash --version').split("\n")[0] + expect(first_console_line).to match /Using bundled JDK: \/usr\/share\/logstash\/jdk/ end it 'should be running an API server on port 9600' do @@ -42,8 +52,8 @@ shared_examples_for 'the container is configured correctly' do |flavor| end it 'should have all files owned by the logstash user' do - expect(exec_in_container(@container, 'find /usr/share/logstash ! -user logstash')).to be_nil - expect(exec_in_container(@container, 'find /usr/share/logstash -user logstash')).not_to be_nil + expect(exec_in_container(@container, 'find /usr/share/logstash ! -user logstash')).to be_empty + expect(exec_in_container(@container, 'find /usr/share/logstash -user logstash')).not_to be_empty end it 'should have a logstash user with uid 1000' do diff --git a/qa/docker/spec/spec_helper.rb b/qa/docker/spec/spec_helper.rb index c98961d87..2cc712df0 100644 --- a/qa/docker/spec/spec_helper.rb +++ b/qa/docker/spec/spec_helper.rb @@ -77,7 +77,7 @@ def java_process(container, column) end def exec_in_container(container, command) - container.exec(command.split)[0][0] + container.exec(command.split)[0].join end def architecture_for_flavor(flavor) diff --git a/qa/integration/specs/cli/prepare_offline_pack_spec.rb b/qa/integration/specs/cli/prepare_offline_pack_spec.rb index 695529d8d..c3273d5a8 100644 --- a/qa/integration/specs/cli/prepare_offline_pack_spec.rb +++ b/qa/integration/specs/cli/prepare_offline_pack_spec.rb @@ -86,7 +86,7 @@ describe "CLI > logstash-plugin prepare-offline-pack" do filters = @logstash_plugin.list(plugins_to_pack.first) .stderr_and_stdout.split("\n") .delete_if do |line| - line =~ /cext|├──|└──|logstash-integration|JAVA_OPT|fatal|^WARNING|^warning: ignoring JAVA_TOOL_OPTIONS|^OpenJDK 64-Bit Server VM warning|Option \w+ was deprecated/ + line =~ /cext|├──|└──|logstash-integration|JAVA_OPT|fatal|^WARNING|^warning: ignoring JAVA_TOOL_OPTIONS|^OpenJDK 64-Bit Server VM warning|Option \w+ was deprecated|Using JAVA_HOME defined java|Using system java: |\[\[: not found/ end expect(unpacked.plugins.collect(&:name)).to include(*filters) diff --git a/qa/rspec/commands.rb b/qa/rspec/commands.rb index 4b48fcd1c..d2c97c132 100644 --- a/qa/rspec/commands.rb +++ b/qa/rspec/commands.rb @@ -42,6 +42,8 @@ module ServiceTester @host = host @options = options @client = CommandsFactory.fetch(options["type"], options["host"]) + @bundled_jdk = false + @skip_jdk_infix = false end def hostname @@ -74,7 +76,10 @@ module ServiceTester def install(options={}) base = options.fetch(:base, ServiceTester::Base::LOCATION) - package = client.package_for(filename(options), base) + @bundled_jdk = options.fetch(:bundled_jdk, false) + @skip_jdk_infix = options.fetch(:skip_jdk_infix, false) + filename = filename(options) + package = client.package_for(filename, @skip_jdk_infix, @bundled_jdk, base) client.install(package, host) end diff --git a/qa/rspec/commands/base.rb b/qa/rspec/commands/base.rb index 52804c862..1229f66be 100644 --- a/qa/rspec/commands/base.rb +++ b/qa/rspec/commands/base.rb @@ -82,5 +82,23 @@ module ServiceTester def delete_file(path, host) run_command("rm -rf #{path}", host) end + + def package_for(filename, skip_jdk_infix, bundled_jdk, base=ServiceTester::Base::LOCATION) + jdk_arch_ext = jdk_architecture_extension(skip_jdk_infix, bundled_jdk) + File.join(base, "#{filename}#{jdk_arch_ext}.#{package_extension}") + end + + private + def jdk_architecture_extension(skip_jdk_infix, bundled_jdk) + if skip_jdk_infix + "" + else + if bundled_jdk + "-" + architecture_extension + else + "-no-jdk" + end + end + end end end diff --git a/qa/rspec/commands/debian.rb b/qa/rspec/commands/debian.rb index f4a6d490a..160239664 100644 --- a/qa/rspec/commands/debian.rb +++ b/qa/rspec/commands/debian.rb @@ -32,8 +32,12 @@ module ServiceTester stdout.match(/^Status: install ok installed$/) end - def package_for(filename, base=ServiceTester::Base::LOCATION) - File.join(base, "#{filename}.deb") + def package_extension + "deb" + end + + def architecture_extension + "amd64" end def install(package, host=nil) diff --git a/qa/rspec/commands/redhat.rb b/qa/rspec/commands/redhat.rb index eaa6a1964..ee9ca909a 100644 --- a/qa/rspec/commands/redhat.rb +++ b/qa/rspec/commands/redhat.rb @@ -32,8 +32,12 @@ module ServiceTester stdout.match(/^logstash.noarch/) end - def package_for(filename, base=ServiceTester::Base::LOCATION) - File.join(base, "#{filename}.rpm") + def package_extension + "rpm" + end + + def architecture_extension + "x86_64" end def install(package, host=nil) diff --git a/qa/rspec/commands/suse.rb b/qa/rspec/commands/suse.rb index 733c0685a..c66ba048c 100644 --- a/qa/rspec/commands/suse.rb +++ b/qa/rspec/commands/suse.rb @@ -29,8 +29,12 @@ module ServiceTester stdout.match(/^i | logstash | An extensible logging pipeline | package$/) end - def package_for(filename, base=ServiceTester::Base::LOCATION) - File.join(base, "#{filename}.rpm") + def package_extension() + "rpm" + end + + def architecture_extension() + "x86_64" end def install(package, host=nil) diff --git a/qa/rspec/commands/system_helpers.rb b/qa/rspec/commands/system_helpers.rb index a720f7c84..58354687a 100644 --- a/qa/rspec/commands/system_helpers.rb +++ b/qa/rspec/commands/system_helpers.rb @@ -19,14 +19,16 @@ require_relative "base" module ServiceTester module SystemD - def running?(hosts, package) + def running?(hosts, package, jdk_path='/usr/bin/java') stdout = "" at(hosts, {in: :serial}) do |host| cmd = sudo_exec!("service #{package} status") stdout = cmd.stdout end + stdout.force_encoding(Encoding::UTF_8) ( stdout.match(/Active: active \(running\)/) && + stdout.match(/^\s*└─\d*\s.*#{jdk_path}/) && stdout.match(/#{package}.service - #{package}/) ) end @@ -40,13 +42,19 @@ module ServiceTester end module InitD - def running?(hosts, package) + def running?(hosts, package, jdk_path='/usr/bin/java') stdout = "" at(hosts, {in: :serial}) do |host| cmd = sudo_exec!("initctl status #{package}") stdout = cmd.stdout end - stdout.match(/#{package} start\/running/) + running = stdout.match(/#{package} start\/running/) + pid = stdout.match(/#{package} start\/running, process (\d*)/).captures[0] + at(hosts, {in: :serial}) do |host| + cmd = sudo_exec!("ps ax | grep #{pid}") + stdout = cmd.stdout + end + (running && stdout.match(/#{jdk_path}/)) end def service_manager(service, action, host=nil) diff --git a/qa/rspec/matchers/be_running.rb b/qa/rspec/matchers/be_running.rb index c02777693..f4463249e 100644 --- a/qa/rspec/matchers/be_running.rb +++ b/qa/rspec/matchers/be_running.rb @@ -23,3 +23,9 @@ RSpec::Matchers.define :be_running do subject.running?(subject.hosts, subject.name) end end + +RSpec::Matchers.define :be_running_with do |expected_jdk_path| + match do |subject| + subject.running?(subject.hosts, subject.name, expected_jdk_path) + end +end diff --git a/rakelib/artifacts.rake b/rakelib/artifacts.rake index fa085e68a..baf16f67c 100644 --- a/rakelib/artifacts.rake +++ b/rakelib/artifacts.rake @@ -59,9 +59,17 @@ namespace "artifact" do # plugins which use jar-dependencies. # See more in https://github.com/elastic/logstash/issues/4818 "vendor/??*/**/.mvn/**/*", + + # Without this when JRuby runs 'pleaserun' gem using the AdoptOpenJDK, during the post install script + # it claims that modules are not open for private introspection and suggest it's missing --add-opens + # so including these files JRuby run with modules opened to private introspection. + "vendor/jruby/bin/.jruby.java_opts", + "vendor/jruby/bin/.jruby.module_opts", "Gemfile", "Gemfile.lock", "x-pack/**/*", + "jdk/**/*", + "jdk.app/**/*", ] end @@ -124,53 +132,104 @@ namespace "artifact" do task "all" => ["prepare", "build"] task "docker_only" => ["prepare", "build_docker_full", "build_docker_oss", "build_docker_ubi8"] - desc "Build a tar.gz of default logstash plugins with all dependencies" - task "tar" => ["prepare", "generate_build_metadata"] do - puts("[artifact:tar] Building tar.gz of default plugins") + desc "Build all (jdk bundled and not) tar.gz and zip of default logstash plugins with all dependencies" + task "archives" => ["prepare", "generate_build_metadata"] do + #with bundled JDKs + ["linux", "windows", "darwin"].each do |os_name| + puts("[artifact:archives] Building tar.gz/zip of default plugins for OS: #{os_name}") + system("./gradlew copyJdk -Pjdk_bundle_os=#{os_name}") + case os_name + when "linux" + build_tar('ELASTIC-LICENSE', platform: '-linux-x86_64') + when "windows" + build_zip('ELASTIC-LICENSE', platform: '-windows-x86_64') + when "darwin" + build_tar('ELASTIC-LICENSE', platform: '-darwin-x86_64') + end + system("./gradlew deleteLocalJdk -Pjdk_bundle_os=#{os_name}") + end + + #without JDK + system("./gradlew bootstrap") #force the build of Logstash jars + build_tar('ELASTIC-LICENSE', platform: '-no-jdk') + build_zip('ELASTIC-LICENSE', platform: '-no-jdk') + end + + desc "Build a not JDK bundled tar.gz of default logstash plugins with all dependencies" + task "no_bundle_jdk_tar" => ["prepare", "generate_build_metadata"] do build_tar('ELASTIC-LICENSE') end - desc "Build an OSS tar.gz of default logstash plugins with all dependencies" - task "tar_oss" => ["prepare", "generate_build_metadata"] do - puts("[artifact:tar] Building tar.gz of default plugins") - build_tar('APACHE-LICENSE-2.0', "-oss", oss_excluder) - end + desc "Build all (jdk bundled and not) OSS tar.gz and zip of default logstash plugins with all dependencies" + task "archives_oss" => ["prepare", "generate_build_metadata"] do + #with bundled JDKs + ["linux", "windows", "darwin"].each do |os_name| + puts("[artifact:archives_oss] Building OSS tar.gz/zip of default plugins for OS: #{os_name}") + system("./gradlew copyJdk -Pjdk_bundle_os=#{os_name}") + case os_name + when "linux" + build_tar('APACHE-LICENSE-2.0', "-oss", oss_excluder, platform: '-linux-x86_64') + when "windows" + build_zip('APACHE-LICENSE-2.0', "-oss", oss_excluder, platform: '-windows-x86_64') + when "darwin" + build_tar('APACHE-LICENSE-2.0', "-oss", oss_excluder, platform: '-darwin-x86_64') + end + system("./gradlew deleteLocalJdk -Pjdk_bundle_os=#{os_name}") + end - desc "Build a zip of default logstash plugins with all dependencies" - task "zip" => ["prepare", "generate_build_metadata"] do - puts("[artifact:zip] Building zip of default plugins") - build_zip('ELASTIC-LICENSE') + #without JDK + system("./gradlew bootstrap") #force the build of Logstash jars + build_tar('APACHE-LICENSE-2.0',"-oss", oss_excluder, platform: '-no-jdk') + build_zip('APACHE-LICENSE-2.0',"-oss", oss_excluder, platform: '-no-jdk') end - desc "Build a zip of default logstash plugins with all dependencies" - task "zip_oss" => ["prepare", "generate_build_metadata"] do - puts("[artifact:zip] Building zip of default plugins") - build_zip('APACHE-LICENSE-2.0',"-oss", oss_excluder) - end - - desc "Build an RPM of logstash with all dependencies" task "rpm" => ["prepare", "generate_build_metadata"] do puts("[artifact:rpm] building rpm package") + system("./gradlew copyJdk -Pjdk_bundle_os=linux") + package_with_jdk("centos", "5") + system('./gradlew deleteLocalJdk -Pjdk_bundle_os=linux') + + #without JDKs + system("./gradlew bootstrap") #force the build of Logstash jars package("centos", "5") end desc "Build an RPM of logstash with all dependencies" task "rpm_oss" => ["prepare", "generate_build_metadata"] do puts("[artifact:rpm] building rpm package") + system("./gradlew copyJdk -Pjdk_bundle_os=linux") + package_with_jdk("centos", "5", :oss) + system('./gradlew deleteLocalJdk -Pjdk_bundle_os=linux') + + #without JDKs + system("./gradlew bootstrap") #force the build of Logstash jars package("centos", "5", :oss) end desc "Build a DEB of logstash with all dependencies" task "deb" => ["prepare", "generate_build_metadata"] do - puts("[artifact:deb] building deb package") + #with bundled JDKs + puts("[artifact:deb] building deb package for OS: linux") + system("./gradlew copyJdk -Pjdk_bundle_os=linux") + package_with_jdk("ubuntu", "12.04") + system('./gradlew deleteLocalJdk -Pjdk_bundle_os=linux') + + #without JDKs + system("./gradlew bootstrap") #force the build of Logstash jars package("ubuntu", "12.04") end desc "Build a DEB of logstash with all dependencies" task "deb_oss" => ["prepare", "generate_build_metadata"] do - puts("[artifact:deb] building deb package") + puts("[artifact:deb_oss] building deb package") + system("./gradlew copyJdk -Pjdk_bundle_os=linux") + package_with_jdk("ubuntu", "12.04", :oss) + system('./gradlew deleteLocalJdk -Pjdk_bundle_os=linux') + + #without JDKs + system("./gradlew bootstrap") #force the build of Logstash jars package("ubuntu", "12.04", :oss) end @@ -197,19 +256,19 @@ namespace "artifact" do end desc "Build docker image" - task "docker" => ["prepare", "generate_build_metadata", "tar"] do + task "docker" => ["prepare", "generate_build_metadata", "archives"] do puts("[docker] Building docker image") build_docker('full') end desc "Build OSS docker image" - task "docker_oss" => ["prepare", "generate_build_metadata", "tar_oss"] do + task "docker_oss" => ["prepare", "generate_build_metadata", "archives_oss"] do puts("[docker_oss] Building OSS docker image") build_docker('oss') end desc "Build UBI8 docker image" - task "docker_ubi8" => %w(prepare generate_build_metadata tar) do + task "docker_ubi8" => %w(prepare generate_build_metadata archives) do puts("[docker_ubi8] Building UBI docker image") build_docker('ubi8') end @@ -247,10 +306,8 @@ namespace "artifact" do Rake::Task["artifact:deb_oss"].invoke Rake::Task["artifact:rpm"].invoke Rake::Task["artifact:rpm_oss"].invoke - Rake::Task["artifact:zip"].invoke - Rake::Task["artifact:zip_oss"].invoke - Rake::Task["artifact:tar"].invoke - Rake::Task["artifact:tar_oss"].invoke + Rake::Task["artifact:archives"].invoke + Rake::Task["artifact:archives_oss"].invoke unless ENV['SKIP_DOCKER'] == "1" Rake::Task["artifact:docker"].invoke Rake::Task["artifact:docker_oss"].invoke @@ -343,47 +400,45 @@ namespace "artifact" do end end - def build_tar(license, tar_suffix = nil, excluder=nil) + + def build_tar(license, tar_suffix = nil, excluder=nil, platform: '') require "zlib" - require "archive/tar/minitar" + require 'rubygems' + require 'rubygems/package' ensure_logstash_version_constant_defined - tarpath = "build/logstash#{tar_suffix}-#{LOGSTASH_VERSION}#{PACKAGE_SUFFIX}.tar.gz" + tarpath = "build/logstash#{tar_suffix}-#{LOGSTASH_VERSION}#{PACKAGE_SUFFIX}#{platform}.tar.gz" if File.exist?(tarpath) && ENV['SKIP_PREPARE'] == "1" && !source_modified_since?(File.mtime(tarpath)) puts("[artifact:tar] Source code not modified. Skipping build of #{tarpath}") return end puts("[artifact:tar] building #{tarpath}") gz = Zlib::GzipWriter.new(File.new(tarpath, "wb"), Zlib::BEST_COMPRESSION) - tar = Archive::Tar::Minitar::Output.new(gz) - files(excluder).each do |path| - write_to_tar(tar, path, "logstash-#{LOGSTASH_VERSION}#{PACKAGE_SUFFIX}/#{path}") + Gem::Package::TarWriter.new(gz) do |tar| + files(excluder).each do |path| + write_to_tar(tar, path, "logstash-#{LOGSTASH_VERSION}#{PACKAGE_SUFFIX}/#{path}") + end + + source_license_path = "licenses/#{license}.txt" + fail("Missing source license: #{source_license_path}") unless File.exists?(source_license_path) + write_to_tar(tar, source_license_path, "logstash-#{LOGSTASH_VERSION}#{PACKAGE_SUFFIX}/LICENSE.txt") + + # add build.rb to tar + metadata_file_path_in_tar = File.join("logstash-core", "lib", "logstash", "build.rb") + path_in_tar = File.join("logstash-#{LOGSTASH_VERSION}#{PACKAGE_SUFFIX}", metadata_file_path_in_tar) + write_to_tar(tar, BUILD_METADATA_FILE.path, path_in_tar) end - - source_license_path = "licenses/#{license}.txt" - fail("Missing source license: #{source_license_path}") unless File.exists?(source_license_path) - write_to_tar(tar, source_license_path, "logstash-#{LOGSTASH_VERSION}#{PACKAGE_SUFFIX}/LICENSE.txt") - - # add build.rb to tar - metadata_file_path_in_tar = File.join("logstash-core", "lib", "logstash", "build.rb") - path_in_tar = File.join("logstash-#{LOGSTASH_VERSION}#{PACKAGE_SUFFIX}", metadata_file_path_in_tar) - write_to_tar(tar, BUILD_METADATA_FILE.path, path_in_tar) - - tar.close gz.close - puts "Complete: #{tarpath}" end + def write_to_tar(tar, path, path_in_tar) stat = File.lstat(path) - opts = { - :size => stat.size, - :mode => stat.mode, - :mtime => stat.mtime - } if stat.directory? - tar.tar.mkdir(path_in_tar, opts) + tar.mkdir(path_in_tar, stat.mode) + elsif stat.symlink? + tar.add_symlink(path_in_tar, File.readlink(path), stat.mode) else - tar.tar.add_file_simple(path_in_tar, opts) do |io| + tar.add_file_simple(path_in_tar, stat.mode, stat.size) do |io| File.open(path,'rb') do |fd| chunk = nil size = 0 @@ -396,10 +451,10 @@ namespace "artifact" do end end - def build_zip(license, zip_suffix = "", excluder=nil) + def build_zip(license, zip_suffix = "", excluder=nil, platform: '') require 'zip' ensure_logstash_version_constant_defined - zippath = "build/logstash#{zip_suffix}-#{LOGSTASH_VERSION}#{PACKAGE_SUFFIX}.zip" + zippath = "build/logstash#{zip_suffix}-#{LOGSTASH_VERSION}#{PACKAGE_SUFFIX}#{platform}.zip" puts("[artifact:zip] building #{zippath}") File.unlink(zippath) if File.exists?(zippath) Zip::File.open(zippath, Zip::File::CREATE) do |zipfile| @@ -422,7 +477,11 @@ namespace "artifact" do puts "Complete: #{zippath}" end - def package(platform, version, variant=:standard) + def package_with_jdk(platform, version, variant=:standard) + package(platform, version, variant, true) + end + + def package(platform, version, variant=:standard, bundle_jdk=false) oss = variant == :oss require "stud/temporary" @@ -482,8 +541,19 @@ namespace "artifact" do dir.input("#{path}=/etc/logstash") end + if bundle_jdk + case platform + when "debian", "ubuntu" + arch_suffix = "amd64" + else + arch_suffix = "x86_64" + end + else + arch_suffix = "no-jdk" + end + ensure_logstash_version_constant_defined - package_filename = "logstash#{suffix}-#{LOGSTASH_VERSION}#{PACKAGE_SUFFIX}.TYPE" + package_filename = "logstash#{suffix}-#{LOGSTASH_VERSION}#{PACKAGE_SUFFIX}-#{arch_suffix}.TYPE" File.join(basedir, "config", "startup.options").tap do |path| dir.input("#{path}=/etc/logstash") @@ -529,7 +599,7 @@ namespace "artifact" do out.license = license out.attributes[:deb_user] = "root" out.attributes[:deb_group] = "root" - out.attributes[:deb_suggests] = "java8-runtime-headless" + out.attributes[:deb_suggests] = "java8-runtime-headless" unless bundle_jdk out.config_files << "/etc/logstash/startup.options" out.config_files << "/etc/logstash/jvm.options" out.config_files << "/etc/logstash/log4j2.properties" @@ -553,13 +623,23 @@ namespace "artifact" do # TODO(sissel): Invoke Pleaserun to generate the init scripts/whatever out.name = oss ? "logstash-oss" : "logstash" - out.version = "#{LOGSTASH_VERSION}#{PACKAGE_SUFFIX}".gsub(/[.-]([[:alpha:]])/, '~\1') out.architecture = "all" + if bundle_jdk + case platform + when "redhat", "centos" + out.architecture = "x86_64" + when "debian", "ubuntu" + out.architecture = "amd64" + end + else + out.architecture = "all" + end + out.version = "#{LOGSTASH_VERSION}#{PACKAGE_SUFFIX}".gsub(/[.-]([[:alpha:]])/, '~\1') # TODO(sissel): Include the git commit hash? out.iteration = "1" # what revision? - out.url = "http://www.elasticsearch.org/overview/logstash/" + out.url = "https://www.elastic.co/logstash" out.description = "An extensible logging pipeline" - out.vendor = "Elasticsearch" + out.vendor = "Elastic" # Because we made a mistake in naming the RC version numbers, both rpm and deb view # "1.5.0.rc1" higher than "1.5.0". Setting the epoch to 1 ensures that we get a kind diff --git a/versions.yml b/versions.yml index 9280c3212..8881c2459 100644 --- a/versions.yml +++ b/versions.yml @@ -4,6 +4,12 @@ logstash: 7.10.0 logstash-core: 7.10.0 logstash-core-plugin-api: 2.1.16 +bundled_jdk: + # for AdoptOpenJDK/OpenJDK jdk-14.0.1+7.1, the revision is 14.0.1 while the build is 7.1 + vendor: "adoptopenjdk" + revision: 11.0.8 + build: 10 + # jruby must reference a *released* version of jruby which can be downloaded from the official download url # *and* for which jars artifacts are published for compile-time jruby: From 9668b9ec5cdfe1dcbb477fc88b47fb105f4a133b Mon Sep 17 00:00:00 2001 From: andsel Date: Wed, 2 Sep 2020 11:39:25 +0200 Subject: [PATCH 0602/1126] Bundle JDK (AdoptOpenJDK 11) in Logstash artifacts (ARM64) Changed Linux creation artifacts (tar.gz/deb/rpm) to include the ARM JDK. Extracted common parts of artifact.rake into functions to be shared between ARM and Intel bundling tasks --- build.gradle | 27 ++++-- qa/rspec/commands/debian.rb | 6 +- qa/rspec/commands/redhat.rb | 6 +- rakelib/artifacts.rake | 161 +++++++++++++++++++----------------- 4 files changed, 118 insertions(+), 82 deletions(-) diff --git a/build.gradle b/build.gradle index 572fa7735..083d6233c 100644 --- a/build.gradle +++ b/build.gradle @@ -541,9 +541,9 @@ class JDKDetails { private final String extension final String localPackageName final String unpackedJdkName - private String arch = "x64" + private String arch - JDKDetails(versionYml, osName) { + JDKDetails(versionYml, osName, jdkArch) { revision = versionYml.bundled_jdk.revision build = versionYml.bundled_jdk.build vendor = versionYml.bundled_jdk.vendor @@ -557,8 +557,9 @@ class JDKDetails { default: extension = "tar.gz" } + arch = parseJdkArchitecture(jdkArch) unpackedJdkName = "jdk-${revision}-${osName}" - localPackageName = "${unpackedJdkName}.${extension}" + localPackageName = "${unpackedJdkName}-${arch}.${extension}" } String createDownloadUrl() { @@ -579,16 +580,30 @@ class JDKDetails { return "mac" return osName } + + private String parseJdkArchitecture(String jdkArch) { + switch (jdkArch) { + case "x86_64": + return "x64" + break + case "arm64": + return "aarch64" + break + default: + throw RuntimeException("Can't handle CPU architechture: ${jdkArch}") + } + } } tasks.register("downloadJdk", Download) { - // CLI project properties: -Pjdk_bundle_os=[windows|linux|darwin] + // CLI project properties: -Pjdk_bundle_os=[windows|linux|darwin] -Pjdk_arch=[arm64|x86_64] project.ext.set("versionFound", true) String osName = selectOsType() def versionYml = new Yaml().load(new File("$projectDir/versions.yml").text) - def jdkDetails = new JDKDetails(versionYml, osName) + String jdkArch = project.ext.jdk_arch + def jdkDetails = new JDKDetails(versionYml, osName, jdkArch) description "Download JDK ${jdkDetails.major}, OS: ${osName}" @@ -663,7 +678,7 @@ tasks.register("decompressJdk") { tasks.register("copyJdk", Copy) { dependsOn = [decompressJdk, bootstrap] description = "Download, unpack and copy the JDK" - // CLI project properties: -Pjdk_bundle_os=[windows|linux|darwin] + // CLI project properties: -Pjdk_bundle_os=[windows|linux|darwin] -Pjdk_arch=[arm64|x86_64] doLast { System.out.println "Download location is ${project.ext.jdkDownloadLocation}, Decompressing ${project.ext.jdkDirectory} to \"${project.ext.jdkBundlingDirectory}\"" } diff --git a/qa/rspec/commands/debian.rb b/qa/rspec/commands/debian.rb index 160239664..dcbe28084 100644 --- a/qa/rspec/commands/debian.rb +++ b/qa/rspec/commands/debian.rb @@ -37,7 +37,11 @@ module ServiceTester end def architecture_extension - "amd64" + if java.lang.System.getProperty("os.arch") == "amd64" + "amd64" + else + "arm64" + end end def install(package, host=nil) diff --git a/qa/rspec/commands/redhat.rb b/qa/rspec/commands/redhat.rb index ee9ca909a..5929f982b 100644 --- a/qa/rspec/commands/redhat.rb +++ b/qa/rspec/commands/redhat.rb @@ -37,7 +37,11 @@ module ServiceTester end def architecture_extension - "x86_64" + if java.lang.System.getProperty("os.arch") == "amd64" + "x86_64" + else + "aarch64" + end end def install(package, host=nil) diff --git a/rakelib/artifacts.rake b/rakelib/artifacts.rake index baf16f67c..575dc9128 100644 --- a/rakelib/artifacts.rake +++ b/rakelib/artifacts.rake @@ -135,24 +135,37 @@ namespace "artifact" do desc "Build all (jdk bundled and not) tar.gz and zip of default logstash plugins with all dependencies" task "archives" => ["prepare", "generate_build_metadata"] do #with bundled JDKs - ["linux", "windows", "darwin"].each do |os_name| - puts("[artifact:archives] Building tar.gz/zip of default plugins for OS: #{os_name}") - system("./gradlew copyJdk -Pjdk_bundle_os=#{os_name}") - case os_name - when "linux" - build_tar('ELASTIC-LICENSE', platform: '-linux-x86_64') - when "windows" - build_zip('ELASTIC-LICENSE', platform: '-windows-x86_64') - when "darwin" - build_tar('ELASTIC-LICENSE', platform: '-darwin-x86_64') - end - system("./gradlew deleteLocalJdk -Pjdk_bundle_os=#{os_name}") - end + license_details = ['ELASTIC-LICENSE'] + create_archive_pack(license_details, "x86_64", "linux", "windows", "darwin") + create_archive_pack(license_details, "arm64", "linux") #without JDK system("./gradlew bootstrap") #force the build of Logstash jars - build_tar('ELASTIC-LICENSE', platform: '-no-jdk') - build_zip('ELASTIC-LICENSE', platform: '-no-jdk') + build_tar(*license_details, platform: '-no-jdk') + build_zip(*license_details, platform: '-no-jdk') + end + + def create_archive_pack(license_details, arch, *oses) + oses.each do |os_name| + puts("[artifact:archives] Building tar.gz/zip of default plugins for OS: #{os_name}, arch: #{arch}") + create_single_archive_pack(os_name, arch, license_details) + end + end + + def create_single_archive_pack(os_name, arch, license_details) + system("./gradlew copyJdk -Pjdk_bundle_os=#{os_name} -Pjdk_arch=#{arch}") + if arch == 'arm64' + arch = 'aarch64' + end + case os_name + when "linux" + build_tar(*license_details, platform: "-linux-#{arch}") + when "windows" + build_zip(*license_details, platform: "-windows-#{arch}") + when "darwin" + build_tar(*license_details, platform: "-darwin-#{arch}") + end + system("./gradlew deleteLocalJdk -Pjdk_bundle_os=#{os_name}") end desc "Build a not JDK bundled tar.gz of default logstash plugins with all dependencies" @@ -163,74 +176,71 @@ namespace "artifact" do desc "Build all (jdk bundled and not) OSS tar.gz and zip of default logstash plugins with all dependencies" task "archives_oss" => ["prepare", "generate_build_metadata"] do #with bundled JDKs - ["linux", "windows", "darwin"].each do |os_name| - puts("[artifact:archives_oss] Building OSS tar.gz/zip of default plugins for OS: #{os_name}") - system("./gradlew copyJdk -Pjdk_bundle_os=#{os_name}") - case os_name - when "linux" - build_tar('APACHE-LICENSE-2.0', "-oss", oss_excluder, platform: '-linux-x86_64') - when "windows" - build_zip('APACHE-LICENSE-2.0', "-oss", oss_excluder, platform: '-windows-x86_64') - when "darwin" - build_tar('APACHE-LICENSE-2.0', "-oss", oss_excluder, platform: '-darwin-x86_64') - end - system("./gradlew deleteLocalJdk -Pjdk_bundle_os=#{os_name}") - end + license_details = ['APACHE-LICENSE-2.0',"-oss", oss_excluder] + create_archive_pack(license_details, "x86_64", "linux", "windows", "darwin") + create_archive_pack(license_details, "arm64", "linux") #without JDK system("./gradlew bootstrap") #force the build of Logstash jars - build_tar('APACHE-LICENSE-2.0',"-oss", oss_excluder, platform: '-no-jdk') - build_zip('APACHE-LICENSE-2.0',"-oss", oss_excluder, platform: '-no-jdk') + build_tar(*license_details, platform: '-no-jdk') + build_zip(*license_details, platform: '-no-jdk') end desc "Build an RPM of logstash with all dependencies" task "rpm" => ["prepare", "generate_build_metadata"] do - puts("[artifact:rpm] building rpm package") - system("./gradlew copyJdk -Pjdk_bundle_os=linux") - package_with_jdk("centos", "5") - system('./gradlew deleteLocalJdk -Pjdk_bundle_os=linux') + #with bundled JDKs + puts("[artifact:rpm] building rpm package x86_64") + package_with_jdk("centos", "x86_64") + + puts("[artifact:rpm] building rpm package arm64") + package_with_jdk("centos", "arm64") #without JDKs system("./gradlew bootstrap") #force the build of Logstash jars - package("centos", "5") + package("centos") end desc "Build an RPM of logstash with all dependencies" task "rpm_oss" => ["prepare", "generate_build_metadata"] do - puts("[artifact:rpm] building rpm package") - system("./gradlew copyJdk -Pjdk_bundle_os=linux") - package_with_jdk("centos", "5", :oss) - system('./gradlew deleteLocalJdk -Pjdk_bundle_os=linux') + #with bundled JDKs + puts("[artifact:rpm] building rpm OSS package x86_64") + package_with_jdk("centos", "x86_64", :oss) + + puts("[artifact:rpm] building rpm OSS package arm64") + package_with_jdk("centos", "arm64", :oss) #without JDKs system("./gradlew bootstrap") #force the build of Logstash jars - package("centos", "5", :oss) + package("centos", :oss) end desc "Build a DEB of logstash with all dependencies" task "deb" => ["prepare", "generate_build_metadata"] do #with bundled JDKs - puts("[artifact:deb] building deb package for OS: linux") - system("./gradlew copyJdk -Pjdk_bundle_os=linux") - package_with_jdk("ubuntu", "12.04") - system('./gradlew deleteLocalJdk -Pjdk_bundle_os=linux') + puts("[artifact:deb] building deb package for x86_64") + package_with_jdk("ubuntu", "x86_64") + + puts("[artifact:deb] building deb package for OS: linux arm64") + package_with_jdk("ubuntu", "arm64") #without JDKs system("./gradlew bootstrap") #force the build of Logstash jars - package("ubuntu", "12.04") + package("ubuntu") end desc "Build a DEB of logstash with all dependencies" task "deb_oss" => ["prepare", "generate_build_metadata"] do - puts("[artifact:deb_oss] building deb package") - system("./gradlew copyJdk -Pjdk_bundle_os=linux") - package_with_jdk("ubuntu", "12.04", :oss) - system('./gradlew deleteLocalJdk -Pjdk_bundle_os=linux') + #with bundled JDKs + puts("[artifact:deb_oss] building deb OSS package x86_64") + package_with_jdk("ubuntu", "x86_64", :oss) + + puts("[artifact:deb_oss] building deb OSS package arm64") + package_with_jdk("ubuntu", "arm64", :oss) #without JDKs system("./gradlew bootstrap") #force the build of Logstash jars - package("ubuntu", "12.04", :oss) + package("ubuntu", :oss) end desc "Generate logstash core gems" @@ -477,11 +487,13 @@ namespace "artifact" do puts "Complete: #{zippath}" end - def package_with_jdk(platform, version, variant=:standard) - package(platform, version, variant, true) + def package_with_jdk(platform, jdk_arch, variant=:standard) + system("./gradlew copyJdk -Pjdk_bundle_os=linux -Pjdk_arch=#{jdk_arch}") + package(platform, variant, true, jdk_arch) + system('./gradlew deleteLocalJdk -Pjdk_bundle_os=linux') end - def package(platform, version, variant=:standard, bundle_jdk=false) + def package(platform, variant=:standard, bundle_jdk=false, jdk_arch='x86_64') oss = variant == :oss require "stud/temporary" @@ -541,16 +553,7 @@ namespace "artifact" do dir.input("#{path}=/etc/logstash") end - if bundle_jdk - case platform - when "debian", "ubuntu" - arch_suffix = "amd64" - else - arch_suffix = "x86_64" - end - else - arch_suffix = "no-jdk" - end + arch_suffix = bundle_jdk ? map_architecture_for_package_type(platform, jdk_arch) : "no-jdk" ensure_logstash_version_constant_defined package_filename = "logstash#{suffix}-#{LOGSTASH_VERSION}#{PACKAGE_SUFFIX}-#{arch_suffix}.TYPE" @@ -623,17 +626,7 @@ namespace "artifact" do # TODO(sissel): Invoke Pleaserun to generate the init scripts/whatever out.name = oss ? "logstash-oss" : "logstash" - out.architecture = "all" - if bundle_jdk - case platform - when "redhat", "centos" - out.architecture = "x86_64" - when "debian", "ubuntu" - out.architecture = "amd64" - end - else - out.architecture = "all" - end + out.architecture = bundle_jdk ? map_architecture_for_package_type(platform, jdk_arch) : "all" out.version = "#{LOGSTASH_VERSION}#{PACKAGE_SUFFIX}".gsub(/[.-]([[:alpha:]])/, '~\1') # TODO(sissel): Include the git commit hash? out.iteration = "1" # what revision? @@ -673,6 +666,26 @@ namespace "artifact" do end end # def package + def map_architecture_for_package_type(platform, jdk_arch) + if jdk_arch == 'x86_64' + case platform + when "debian", "ubuntu" + return "amd64" + else + return "x86_64" + end + elsif jdk_arch == 'arm64' + case platform + when "debian", "ubuntu" + return "arm64" + else + return "aarch64" + end + else + raise "CPU architecture not recognized: #{jdk_arch}" + end + end + def build_docker(flavor) env = { "ARTIFACTS_DIR" => ::File.join(Dir.pwd, "build"), From 97028a0320532c0f57a01f3721fdb655344c31f5 Mon Sep 17 00:00:00 2001 From: Rob Bavey Date: Thu, 1 Oct 2020 09:34:00 -0400 Subject: [PATCH 0603/1126] Update license information (#12294) Generate new notice file --- NOTICE.TXT | 2768 ++-------------------------------------------------- 1 file changed, 85 insertions(+), 2683 deletions(-) diff --git a/NOTICE.TXT b/NOTICE.TXT index 15e9e1138..efdca8ec5 100644 --- a/NOTICE.TXT +++ b/NOTICE.TXT @@ -207,6 +207,33 @@ 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. +========== +Notice for: amazing_print-1.2.1 +---------- + +MIT License + +Copyright (c) 2010-2019 Michael Dvorkin +Copyright (c) 2020 AmazingPrint + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. + ========== Notice for: atomic-1.1.101 ---------- @@ -387,7 +414,7 @@ THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. ========== -Notice for: avro-1.9.1 +Notice for: avro-1.10.0 ---------- Apache Avro @@ -398,41 +425,14 @@ The Apache Software Foundation (https://www.apache.org/). ========== -Notice for: awesome_print-1.7.0 ----------- - -Copyright (c) 2010-2013 Michael Dvorkin -http://www.dvorkin.net -%w(mike dvorkin.net) * "@" || "twitter.com/mid" - -Permission is hereby granted, free of charge, to any person obtaining -a copy of this software and associated documentation files (the -"Software"), to deal in the Software without restriction, including -without limitation the rights to use, copy, modify, merge, publish, -distribute, sublicense, and/or sell copies of the Software, and to -permit persons to whom the Software is furnished to do so, subject to -the following conditions: - -The above copyright notice and this permission notice shall be -included in all copies or substantial portions of the Software. - -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, -EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF -MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND -NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE -LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION -OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION -WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. - -========== -Notice for: aws-eventstream-1.0.3 +Notice for: aws-eventstream-1.1.0 ---------- AWS SDK for Ruby Copyright 2015 Amazon.com, Inc. or its affiliates. All Rights Reserved. ========== -Notice for: aws-sdk-2.11.436 +Notice for: aws-sdk-2.11.596 ---------- copyright 2013. amazon web services, inc. all rights reserved. @@ -640,7 +640,7 @@ copyright 2013. amazon web services, inc. all rights reserved. limitations under the License. ========== -Notice for: aws-sdk-core-2.11.436 +Notice for: aws-sdk-core-2.11.596 ---------- copyright 2013. amazon web services, inc. all rights reserved. @@ -848,7 +848,7 @@ copyright 2013. amazon web services, inc. all rights reserved. limitations under the License. ========== -Notice for: aws-sdk-resources-2.11.436 +Notice for: aws-sdk-resources-2.11.596 ---------- copyright 2013. amazon web services, inc. all rights reserved. @@ -1072,7 +1072,7 @@ 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. ========== -Notice for: aws-sigv4-1.1.0 +Notice for: aws-sigv4-1.2.2 ---------- copyright 2013. amazon web services, inc. all rights reserved. @@ -1298,7 +1298,7 @@ See the License for the specific language governing permissions and limitations under the License. ========== -Notice for: bindata-2.4.4 +Notice for: bindata-2.4.8 ---------- Copyright (C) 2007-2012 Dion Mendel. All rights reserved. @@ -1509,7 +1509,7 @@ OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. ========== -Notice for: coderay-1.1.2 +Notice for: coderay-1.1.3 ---------- Copyright (C) 2005-2012 Kornelius Kalnbach (@murphy_karasu) @@ -1979,7 +1979,7 @@ from the source code management (SCM) system project uses. See the License for the specific language governing permissions and limitations under the License. ========== -Notice for: com.fasterxml.jackson.core:jackson-databind-2.9.10.1 +Notice for: com.fasterxml.jackson.core:jackson-databind-2.9.10.4 ---------- # Jackson JSON processor @@ -2215,221 +2215,6 @@ http://www.apache.org/licenses/LICENSE-2.0 See the License for the specific language governing permissions and limitations under the License. ========== -Notice for: com.fasterxml.jackson.dataformat:jackson-dataformat-cbor-2.9.10 ----------- - -This copy of Jackson JSON processor databind module is licensed under the -Apache (Software) License, version 2.0 ("the License"). -See the License for details about distribution rights, and the -specific rights regarding derivate works. - -You may obtain a copy of the License at: - -http://www.apache.org/licenses/LICENSE-2.0 - - - Apache License - Version 2.0, January 2004 - http://www.apache.org/licenses/ - - TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION - - 1. Definitions. - - "License" shall mean the terms and conditions for use, reproduction, - and distribution as defined by Sections 1 through 9 of this document. - - "Licensor" shall mean the copyright owner or entity authorized by - the copyright owner that is granting the License. - - "Legal Entity" shall mean the union of the acting entity and all - other entities that control, are controlled by, or are under common - control with that entity. For the purposes of this definition, - "control" means (i) the power, direct or indirect, to cause the - direction or management of such entity, whether by contract or - otherwise, or (ii) ownership of fifty percent (50%) or more of the - outstanding shares, or (iii) beneficial ownership of such entity. - - "You" (or "Your") shall mean an individual or Legal Entity - exercising permissions granted by this License. - - "Source" form shall mean the preferred form for making modifications, - including but not limited to software source code, documentation - source, and configuration files. - - "Object" form shall mean any form resulting from mechanical - transformation or translation of a Source form, including but - not limited to compiled object code, generated documentation, - and conversions to other media types. - - "Work" shall mean the work of authorship, whether in Source or - Object form, made available under the License, as indicated by a - copyright notice that is included in or attached to the work - (an example is provided in the Appendix below). - - "Derivative Works" shall mean any work, whether in Source or Object - form, that is based on (or derived from) the Work and for which the - editorial revisions, annotations, elaborations, or other modifications - represent, as a whole, an original work of authorship. For the purposes - of this License, Derivative Works shall not include works that remain - separable from, or merely link (or bind by name) to the interfaces of, - the Work and Derivative Works thereof. - - "Contribution" shall mean any work of authorship, including - the original version of the Work and any modifications or additions - to that Work or Derivative Works thereof, that is intentionally - submitted to Licensor for inclusion in the Work by the copyright owner - or by an individual or Legal Entity authorized to submit on behalf of - the copyright owner. For the purposes of this definition, "submitted" - means any form of electronic, verbal, or written communication sent - to the Licensor or its representatives, including but not limited to - communication on electronic mailing lists, source code control systems, - and issue tracking systems that are managed by, or on behalf of, the - Licensor for the purpose of discussing and improving the Work, but - excluding communication that is conspicuously marked or otherwise - designated in writing by the copyright owner as "Not a Contribution." - - "Contributor" shall mean Licensor and any individual or Legal Entity - on behalf of whom a Contribution has been received by Licensor and - subsequently incorporated within the Work. - - 2. Grant of Copyright License. Subject to the terms and conditions of - this License, each Contributor hereby grants to You a perpetual, - worldwide, non-exclusive, no-charge, royalty-free, irrevocable - copyright license to reproduce, prepare Derivative Works of, - publicly display, publicly perform, sublicense, and distribute the - Work and such Derivative Works in Source or Object form. - - 3. Grant of Patent License. Subject to the terms and conditions of - this License, each Contributor hereby grants to You a perpetual, - worldwide, non-exclusive, no-charge, royalty-free, irrevocable - (except as stated in this section) patent license to make, have made, - use, offer to sell, sell, import, and otherwise transfer the Work, - where such license applies only to those patent claims licensable - by such Contributor that are necessarily infringed by their - Contribution(s) alone or by combination of their Contribution(s) - with the Work to which such Contribution(s) was submitted. If You - institute patent litigation against any entity (including a - cross-claim or counterclaim in a lawsuit) alleging that the Work - or a Contribution incorporated within the Work constitutes direct - or contributory patent infringement, then any patent licenses - granted to You under this License for that Work shall terminate - as of the date such litigation is filed. - - 4. Redistribution. You may reproduce and distribute copies of the - Work or Derivative Works thereof in any medium, with or without - modifications, and in Source or Object form, provided that You - meet the following conditions: - - (a) You must give any other recipients of the Work or - Derivative Works a copy of this License; and - - (b) You must cause any modified files to carry prominent notices - stating that You changed the files; and - - (c) You must retain, in the Source form of any Derivative Works - that You distribute, all copyright, patent, trademark, and - attribution notices from the Source form of the Work, - excluding those notices that do not pertain to any part of - the Derivative Works; and - - (d) If the Work includes a "NOTICE" text file as part of its - distribution, then any Derivative Works that You distribute must - include a readable copy of the attribution notices contained - within such NOTICE file, excluding those notices that do not - pertain to any part of the Derivative Works, in at least one - of the following places: within a NOTICE text file distributed - as part of the Derivative Works; within the Source form or - documentation, if provided along with the Derivative Works; or, - within a display generated by the Derivative Works, if and - wherever such third-party notices normally appear. The contents - of the NOTICE file are for informational purposes only and - do not modify the License. You may add Your own attribution - notices within Derivative Works that You distribute, alongside - or as an addendum to the NOTICE text from the Work, provided - that such additional attribution notices cannot be construed - as modifying the License. - - You may add Your own copyright statement to Your modifications and - may provide additional or different license terms and conditions - for use, reproduction, or distribution of Your modifications, or - for any such Derivative Works as a whole, provided Your use, - reproduction, and distribution of the Work otherwise complies with - the conditions stated in this License. - - 5. Submission of Contributions. Unless You explicitly state otherwise, - any Contribution intentionally submitted for inclusion in the Work - by You to the Licensor shall be under the terms and conditions of - this License, without any additional terms or conditions. - Notwithstanding the above, nothing herein shall supersede or modify - the terms of any separate license agreement you may have executed - with Licensor regarding such Contributions. - - 6. Trademarks. This License does not grant permission to use the trade - names, trademarks, service marks, or product names of the Licensor, - except as required for reasonable and customary use in describing the - origin of the Work and reproducing the content of the NOTICE file. - - 7. Disclaimer of Warranty. Unless required by applicable law or - agreed to in writing, Licensor provides the Work (and each - Contributor provides its Contributions) on an "AS IS" BASIS, - WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or - implied, including, without limitation, any warranties or conditions - of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A - PARTICULAR PURPOSE. You are solely responsible for determining the - appropriateness of using or redistributing the Work and assume any - risks associated with Your exercise of permissions under this License. - - 8. Limitation of Liability. In no event and under no legal theory, - whether in tort (including negligence), contract, or otherwise, - unless required by applicable law (such as deliberate and grossly - negligent acts) or agreed to in writing, shall any Contributor be - liable to You for damages, including any direct, indirect, special, - incidental, or consequential damages of any character arising as a - result of this License or out of the use or inability to use the - Work (including but not limited to damages for loss of goodwill, - work stoppage, computer failure or malfunction, or any and all - other commercial damages or losses), even if such Contributor - has been advised of the possibility of such damages. - - 9. Accepting Warranty or Additional Liability. While redistributing - the Work or Derivative Works thereof, You may choose to offer, - and charge a fee for, acceptance of support, warranty, indemnity, - or other liability obligations and/or rights consistent with this - License. However, in accepting such obligations, You may act only - on Your own behalf and on Your sole responsibility, not on behalf - of any other Contributor, and only if You agree to indemnify, - defend, and hold each Contributor harmless for any liability - incurred by, or claims asserted against, such Contributor by reason - of your accepting any such warranty or additional liability. - - END OF TERMS AND CONDITIONS - - APPENDIX: How to apply the Apache License to your work. - - To apply the Apache License to your work, attach the following - boilerplate notice, with the fields enclosed by brackets "[]" - replaced with your own identifying information. (Don't include - the brackets!) The text should be enclosed in the appropriate - comment syntax for the file format. We also recommend that a - file or class name and description of purpose be included on the - same "printed page" as the copyright notice for easier - identification within third-party archives. - - Copyright [yyyy] [name of copyright owner] - - Licensed 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. -========== Notice for: com.fasterxml.jackson.module:jackson-module-afterburner-2.9.10 ---------- @@ -2644,909 +2429,6 @@ http://www.apache.org/licenses/LICENSE-2.0 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. -========== -Notice for: com.google.code.findbugs:jsr305-1.3.9 ----------- - -Cannot find NOTICE.txt for the relatively old jsr305:1.3.9. Per https://search.maven.org/artifact/com.google.code.findbugs/jsr305/1.3.9/jar, the original source repo is at http://findbugs.googlecode.com/svn/trunk and is now defunct. - -========== -Notice for: com.google.errorprone:error_prone_annotations-2.0.18 ----------- - -Apache License - Version 2.0, January 2004 - http://www.apache.org/licenses/ - - TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION - - 1. Definitions. - - "License" shall mean the terms and conditions for use, reproduction, - and distribution as defined by Sections 1 through 9 of this document. - - "Licensor" shall mean the copyright owner or entity authorized by - the copyright owner that is granting the License. - - "Legal Entity" shall mean the union of the acting entity and all - other entities that control, are controlled by, or are under common - control with that entity. For the purposes of this definition, - "control" means (i) the power, direct or indirect, to cause the - direction or management of such entity, whether by contract or - otherwise, or (ii) ownership of fifty percent (50%) or more of the - outstanding shares, or (iii) beneficial ownership of such entity. - - "You" (or "Your") shall mean an individual or Legal Entity - exercising permissions granted by this License. - - "Source" form shall mean the preferred form for making modifications, - including but not limited to software source code, documentation - source, and configuration files. - - "Object" form shall mean any form resulting from mechanical - transformation or translation of a Source form, including but - not limited to compiled object code, generated documentation, - and conversions to other media types. - - "Work" shall mean the work of authorship, whether in Source or - Object form, made available under the License, as indicated by a - copyright notice that is included in or attached to the work - (an example is provided in the Appendix below). - - "Derivative Works" shall mean any work, whether in Source or Object - form, that is based on (or derived from) the Work and for which the - editorial revisions, annotations, elaborations, or other modifications - represent, as a whole, an original work of authorship. For the purposes - of this License, Derivative Works shall not include works that remain - separable from, or merely link (or bind by name) to the interfaces of, - the Work and Derivative Works thereof. - - "Contribution" shall mean any work of authorship, including - the original version of the Work and any modifications or additions - to that Work or Derivative Works thereof, that is intentionally - submitted to Licensor for inclusion in the Work by the copyright owner - or by an individual or Legal Entity authorized to submit on behalf of - the copyright owner. For the purposes of this definition, "submitted" - means any form of electronic, verbal, or written communication sent - to the Licensor or its representatives, including but not limited to - communication on electronic mailing lists, source code control systems, - and issue tracking systems that are managed by, or on behalf of, the - Licensor for the purpose of discussing and improving the Work, but - excluding communication that is conspicuously marked or otherwise - designated in writing by the copyright owner as "Not a Contribution." - - "Contributor" shall mean Licensor and any individual or Legal Entity - on behalf of whom a Contribution has been received by Licensor and - subsequently incorporated within the Work. - - 2. Grant of Copyright License. Subject to the terms and conditions of - this License, each Contributor hereby grants to You a perpetual, - worldwide, non-exclusive, no-charge, royalty-free, irrevocable - copyright license to reproduce, prepare Derivative Works of, - publicly display, publicly perform, sublicense, and distribute the - Work and such Derivative Works in Source or Object form. - - 3. Grant of Patent License. Subject to the terms and conditions of - this License, each Contributor hereby grants to You a perpetual, - worldwide, non-exclusive, no-charge, royalty-free, irrevocable - (except as stated in this section) patent license to make, have made, - use, offer to sell, sell, import, and otherwise transfer the Work, - where such license applies only to those patent claims licensable - by such Contributor that are necessarily infringed by their - Contribution(s) alone or by combination of their Contribution(s) - with the Work to which such Contribution(s) was submitted. If You - institute patent litigation against any entity (including a - cross-claim or counterclaim in a lawsuit) alleging that the Work - or a Contribution incorporated within the Work constitutes direct - or contributory patent infringement, then any patent licenses - granted to You under this License for that Work shall terminate - as of the date such litigation is filed. - - 4. Redistribution. You may reproduce and distribute copies of the - Work or Derivative Works thereof in any medium, with or without - modifications, and in Source or Object form, provided that You - meet the following conditions: - - (a) You must give any other recipients of the Work or - Derivative Works a copy of this License; and - - (b) You must cause any modified files to carry prominent notices - stating that You changed the files; and - - (c) You must retain, in the Source form of any Derivative Works - that You distribute, all copyright, patent, trademark, and - attribution notices from the Source form of the Work, - excluding those notices that do not pertain to any part of - the Derivative Works; and - - (d) If the Work includes a "NOTICE" text file as part of its - distribution, then any Derivative Works that You distribute must - include a readable copy of the attribution notices contained - within such NOTICE file, excluding those notices that do not - pertain to any part of the Derivative Works, in at least one - of the following places: within a NOTICE text file distributed - as part of the Derivative Works; within the Source form or - documentation, if provided along with the Derivative Works; or, - within a display generated by the Derivative Works, if and - wherever such third-party notices normally appear. The contents - of the NOTICE file are for informational purposes only and - do not modify the License. You may add Your own attribution - notices within Derivative Works that You distribute, alongside - or as an addendum to the NOTICE text from the Work, provided - that such additional attribution notices cannot be construed - as modifying the License. - - You may add Your own copyright statement to Your modifications and - may provide additional or different license terms and conditions - for use, reproduction, or distribution of Your modifications, or - for any such Derivative Works as a whole, provided Your use, - reproduction, and distribution of the Work otherwise complies with - the conditions stated in this License. - - 5. Submission of Contributions. Unless You explicitly state otherwise, - any Contribution intentionally submitted for inclusion in the Work - by You to the Licensor shall be under the terms and conditions of - this License, without any additional terms or conditions. - Notwithstanding the above, nothing herein shall supersede or modify - the terms of any separate license agreement you may have executed - with Licensor regarding such Contributions. - - 6. Trademarks. This License does not grant permission to use the trade - names, trademarks, service marks, or product names of the Licensor, - except as required for reasonable and customary use in describing the - origin of the Work and reproducing the content of the NOTICE file. - - 7. Disclaimer of Warranty. Unless required by applicable law or - agreed to in writing, Licensor provides the Work (and each - Contributor provides its Contributions) on an "AS IS" BASIS, - WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or - implied, including, without limitation, any warranties or conditions - of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A - PARTICULAR PURPOSE. You are solely responsible for determining the - appropriateness of using or redistributing the Work and assume any - risks associated with Your exercise of permissions under this License. - - 8. Limitation of Liability. In no event and under no legal theory, - whether in tort (including negligence), contract, or otherwise, - unless required by applicable law (such as deliberate and grossly - negligent acts) or agreed to in writing, shall any Contributor be - liable to You for damages, including any direct, indirect, special, - incidental, or consequential damages of any character arising as a - result of this License or out of the use or inability to use the - Work (including but not limited to damages for loss of goodwill, - work stoppage, computer failure or malfunction, or any and all - other commercial damages or losses), even if such Contributor - has been advised of the possibility of such damages. - - 9. Accepting Warranty or Additional Liability. While redistributing - the Work or Derivative Works thereof, You may choose to offer, - and charge a fee for, acceptance of support, warranty, indemnity, - or other liability obligations and/or rights consistent with this - License. However, in accepting such obligations, You may act only - on Your own behalf and on Your sole responsibility, not on behalf - of any other Contributor, and only if You agree to indemnify, - defend, and hold each Contributor harmless for any liability - incurred by, or claims asserted against, such Contributor by reason - of your accepting any such warranty or additional liability. - - END OF TERMS AND CONDITIONS - - APPENDIX: How to apply the Apache License to your work. - - To apply the Apache License to your work, attach the following - boilerplate notice, with the fields enclosed by brackets "[]" - replaced with your own identifying information. (Don't include - the brackets!) The text should be enclosed in the appropriate - comment syntax for the file format. We also recommend that a - file or class name and description of purpose be included on the - same "printed page" as the copyright notice for easier - identification within third-party archives. - - Copyright [yyyy] [name of copyright owner] - - Licensed 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. - - -========== -Notice for: com.google.googlejavaformat:google-java-format-1.1 ----------- - -Copyright 2015 Google Inc. - - Apache License - Version 2.0, January 2004 - http://www.apache.org/licenses/ - - TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION - - 1. Definitions. - - "License" shall mean the terms and conditions for use, reproduction, - and distribution as defined by Sections 1 through 9 of this document. - - "Licensor" shall mean the copyright owner or entity authorized by - the copyright owner that is granting the License. - - "Legal Entity" shall mean the union of the acting entity and all - other entities that control, are controlled by, or are under common - control with that entity. For the purposes of this definition, - "control" means (i) the power, direct or indirect, to cause the - direction or management of such entity, whether by contract or - otherwise, or (ii) ownership of fifty percent (50%) or more of the - outstanding shares, or (iii) beneficial ownership of such entity. - - "You" (or "Your") shall mean an individual or Legal Entity - exercising permissions granted by this License. - - "Source" form shall mean the preferred form for making modifications, - including but not limited to software source code, documentation - source, and configuration files. - - "Object" form shall mean any form resulting from mechanical - transformation or translation of a Source form, including but - not limited to compiled object code, generated documentation, - and conversions to other media types. - - "Work" shall mean the work of authorship, whether in Source or - Object form, made available under the License, as indicated by a - copyright notice that is included in or attached to the work - (an example is provided in the Appendix below). - - "Derivative Works" shall mean any work, whether in Source or Object - form, that is based on (or derived from) the Work and for which the - editorial revisions, annotations, elaborations, or other modifications - represent, as a whole, an original work of authorship. For the purposes - of this License, Derivative Works shall not include works that remain - separable from, or merely link (or bind by name) to the interfaces of, - the Work and Derivative Works thereof. - - "Contribution" shall mean any work of authorship, including - the original version of the Work and any modifications or additions - to that Work or Derivative Works thereof, that is intentionally - submitted to Licensor for inclusion in the Work by the copyright owner - or by an individual or Legal Entity authorized to submit on behalf of - the copyright owner. For the purposes of this definition, "submitted" - means any form of electronic, verbal, or written communication sent - to the Licensor or its representatives, including but not limited to - communication on electronic mailing lists, source code control systems, - and issue tracking systems that are managed by, or on behalf of, the - Licensor for the purpose of discussing and improving the Work, but - excluding communication that is conspicuously marked or otherwise - designated in writing by the copyright owner as "Not a Contribution." - - "Contributor" shall mean Licensor and any individual or Legal Entity - on behalf of whom a Contribution has been received by Licensor and - subsequently incorporated within the Work. - - 2. Grant of Copyright License. Subject to the terms and conditions of - this License, each Contributor hereby grants to You a perpetual, - worldwide, non-exclusive, no-charge, royalty-free, irrevocable - copyright license to reproduce, prepare Derivative Works of, - publicly display, publicly perform, sublicense, and distribute the - Work and such Derivative Works in Source or Object form. - - 3. Grant of Patent License. Subject to the terms and conditions of - this License, each Contributor hereby grants to You a perpetual, - worldwide, non-exclusive, no-charge, royalty-free, irrevocable - (except as stated in this section) patent license to make, have made, - use, offer to sell, sell, import, and otherwise transfer the Work, - where such license applies only to those patent claims licensable - by such Contributor that are necessarily infringed by their - Contribution(s) alone or by combination of their Contribution(s) - with the Work to which such Contribution(s) was submitted. If You - institute patent litigation against any entity (including a - cross-claim or counterclaim in a lawsuit) alleging that the Work - or a Contribution incorporated within the Work constitutes direct - or contributory patent infringement, then any patent licenses - granted to You under this License for that Work shall terminate - as of the date such litigation is filed. - - 4. Redistribution. You may reproduce and distribute copies of the - Work or Derivative Works thereof in any medium, with or without - modifications, and in Source or Object form, provided that You - meet the following conditions: - - (a) You must give any other recipients of the Work or - Derivative Works a copy of this License; and - - (b) You must cause any modified files to carry prominent notices - stating that You changed the files; and - - (c) You must retain, in the Source form of any Derivative Works - that You distribute, all copyright, patent, trademark, and - attribution notices from the Source form of the Work, - excluding those notices that do not pertain to any part of - the Derivative Works; and - - (d) If the Work includes a "NOTICE" text file as part of its - distribution, then any Derivative Works that You distribute must - include a readable copy of the attribution notices contained - within such NOTICE file, excluding those notices that do not - pertain to any part of the Derivative Works, in at least one - of the following places: within a NOTICE text file distributed - as part of the Derivative Works; within the Source form or - documentation, if provided along with the Derivative Works; or, - within a display generated by the Derivative Works, if and - wherever such third-party notices normally appear. The contents - of the NOTICE file are for informational purposes only and - do not modify the License. You may add Your own attribution - notices within Derivative Works that You distribute, alongside - or as an addendum to the NOTICE text from the Work, provided - that such additional attribution notices cannot be construed - as modifying the License. - - You may add Your own copyright statement to Your modifications and - may provide additional or different license terms and conditions - for use, reproduction, or distribution of Your modifications, or - for any such Derivative Works as a whole, provided Your use, - reproduction, and distribution of the Work otherwise complies with - the conditions stated in this License. - - 5. Submission of Contributions. Unless You explicitly state otherwise, - any Contribution intentionally submitted for inclusion in the Work - by You to the Licensor shall be under the terms and conditions of - this License, without any additional terms or conditions. - Notwithstanding the above, nothing herein shall supersede or modify - the terms of any separate license agreement you may have executed - with Licensor regarding such Contributions. - - 6. Trademarks. This License does not grant permission to use the trade - names, trademarks, service marks, or product names of the Licensor, - except as required for reasonable and customary use in describing the - origin of the Work and reproducing the content of the NOTICE file. - - 7. Disclaimer of Warranty. Unless required by applicable law or - agreed to in writing, Licensor provides the Work (and each - Contributor provides its Contributions) on an "AS IS" BASIS, - WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or - implied, including, without limitation, any warranties or conditions - of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A - PARTICULAR PURPOSE. You are solely responsible for determining the - appropriateness of using or redistributing the Work and assume any - risks associated with Your exercise of permissions under this License. - - 8. Limitation of Liability. In no event and under no legal theory, - whether in tort (including negligence), contract, or otherwise, - unless required by applicable law (such as deliberate and grossly - negligent acts) or agreed to in writing, shall any Contributor be - liable to You for damages, including any direct, indirect, special, - incidental, or consequential damages of any character arising as a - result of this License or out of the use or inability to use the - Work (including but not limited to damages for loss of goodwill, - work stoppage, computer failure or malfunction, or any and all - other commercial damages or losses), even if such Contributor - has been advised of the possibility of such damages. - - 9. Accepting Warranty or Additional Liability. While redistributing - the Work or Derivative Works thereof, You may choose to offer, - and charge a fee for, acceptance of support, warranty, indemnity, - or other liability obligations and/or rights consistent with this - License. However, in accepting such obligations, You may act only - on Your own behalf and on Your sole responsibility, not on behalf - of any other Contributor, and only if You agree to indemnify, - defend, and hold each Contributor harmless for any liability - incurred by, or claims asserted against, such Contributor by reason - of your accepting any such warranty or additional liability. - - END OF TERMS AND CONDITIONS - - APPENDIX: How to apply the Apache License to your work. - - To apply the Apache License to your work, attach the following - boilerplate notice, with the fields enclosed by brackets "[]" - replaced with your own identifying information. (Don't include - the brackets!) The text should be enclosed in the appropriate - comment syntax for the file format. We also recommend that a - file or class name and description of purpose be included on the - same "printed page" as the copyright notice for easier - identification within third-party archives. - - Copyright [yyyy] [name of copyright owner] - - Licensed 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. - ------------------------------------------------------------------------------- - -The following NCSA license applies only to google-java-format-diff.py. - -============================================================================== -LLVM Release License -============================================================================== -University of Illinois/NCSA -Open Source License - -Copyright (c) 2007-2015 University of Illinois at Urbana-Champaign. -All rights reserved. - -Developed by: - - LLVM Team - - University of Illinois at Urbana-Champaign - - http://llvm.org - -Permission is hereby granted, free of charge, to any person obtaining a copy of -this software and associated documentation files (the "Software"), to deal with -the Software without restriction, including without limitation the rights to -use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies -of the Software, and to permit persons to whom the Software is furnished to do -so, subject to the following conditions: - - * Redistributions of source code must retain the above copyright notice, - this list of conditions and the following disclaimers. - - * Redistributions in binary form must reproduce the above copyright notice, - this list of conditions and the following disclaimers in the - documentation and/or other materials provided with the distribution. - - * Neither the names of the LLVM Team, University of Illinois at - Urbana-Champaign, nor the names of its contributors may be used to - endorse or promote products derived from this Software without specific - prior written permission. - -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS -FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -CONTRIBUTORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS WITH THE -SOFTWARE. - -============================================================================== -The LLVM software contains code written by third parties. Such software will -have its own individual LICENSE.TXT file in the directory in which it appears. -This file will describe the copyrights, license, and restrictions which apply -to that code. - -The disclaimer of warranty in the University of Illinois Open Source License -applies to all code in the LLVM Distribution, and nothing in any of the -other licenses gives permission to use the names of the LLVM Team or the -University of Illinois to endorse or promote products derived from this -Software. - -The following pieces of software have additional or alternate copyrights, -licenses, and/or restrictions: - -Program Directory -------- --------- - - - -========== -Notice for: com.google.guava:guava-22.0 ----------- - - - Apache License - Version 2.0, January 2004 - http://www.apache.org/licenses/ - - TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION - - 1. Definitions. - - "License" shall mean the terms and conditions for use, reproduction, - and distribution as defined by Sections 1 through 9 of this document. - - "Licensor" shall mean the copyright owner or entity authorized by - the copyright owner that is granting the License. - - "Legal Entity" shall mean the union of the acting entity and all - other entities that control, are controlled by, or are under common - control with that entity. For the purposes of this definition, - "control" means (i) the power, direct or indirect, to cause the - direction or management of such entity, whether by contract or - otherwise, or (ii) ownership of fifty percent (50%) or more of the - outstanding shares, or (iii) beneficial ownership of such entity. - - "You" (or "Your") shall mean an individual or Legal Entity - exercising permissions granted by this License. - - "Source" form shall mean the preferred form for making modifications, - including but not limited to software source code, documentation - source, and configuration files. - - "Object" form shall mean any form resulting from mechanical - transformation or translation of a Source form, including but - not limited to compiled object code, generated documentation, - and conversions to other media types. - - "Work" shall mean the work of authorship, whether in Source or - Object form, made available under the License, as indicated by a - copyright notice that is included in or attached to the work - (an example is provided in the Appendix below). - - "Derivative Works" shall mean any work, whether in Source or Object - form, that is based on (or derived from) the Work and for which the - editorial revisions, annotations, elaborations, or other modifications - represent, as a whole, an original work of authorship. For the purposes - of this License, Derivative Works shall not include works that remain - separable from, or merely link (or bind by name) to the interfaces of, - the Work and Derivative Works thereof. - - "Contribution" shall mean any work of authorship, including - the original version of the Work and any modifications or additions - to that Work or Derivative Works thereof, that is intentionally - submitted to Licensor for inclusion in the Work by the copyright owner - or by an individual or Legal Entity authorized to submit on behalf of - the copyright owner. For the purposes of this definition, "submitted" - means any form of electronic, verbal, or written communication sent - to the Licensor or its representatives, including but not limited to - communication on electronic mailing lists, source code control systems, - and issue tracking systems that are managed by, or on behalf of, the - Licensor for the purpose of discussing and improving the Work, but - excluding communication that is conspicuously marked or otherwise - designated in writing by the copyright owner as "Not a Contribution." - - "Contributor" shall mean Licensor and any individual or Legal Entity - on behalf of whom a Contribution has been received by Licensor and - subsequently incorporated within the Work. - - 2. Grant of Copyright License. Subject to the terms and conditions of - this License, each Contributor hereby grants to You a perpetual, - worldwide, non-exclusive, no-charge, royalty-free, irrevocable - copyright license to reproduce, prepare Derivative Works of, - publicly display, publicly perform, sublicense, and distribute the - Work and such Derivative Works in Source or Object form. - - 3. Grant of Patent License. Subject to the terms and conditions of - this License, each Contributor hereby grants to You a perpetual, - worldwide, non-exclusive, no-charge, royalty-free, irrevocable - (except as stated in this section) patent license to make, have made, - use, offer to sell, sell, import, and otherwise transfer the Work, - where such license applies only to those patent claims licensable - by such Contributor that are necessarily infringed by their - Contribution(s) alone or by combination of their Contribution(s) - with the Work to which such Contribution(s) was submitted. If You - institute patent litigation against any entity (including a - cross-claim or counterclaim in a lawsuit) alleging that the Work - or a Contribution incorporated within the Work constitutes direct - or contributory patent infringement, then any patent licenses - granted to You under this License for that Work shall terminate - as of the date such litigation is filed. - - 4. Redistribution. You may reproduce and distribute copies of the - Work or Derivative Works thereof in any medium, with or without - modifications, and in Source or Object form, provided that You - meet the following conditions: - - (a) You must give any other recipients of the Work or - Derivative Works a copy of this License; and - - (b) You must cause any modified files to carry prominent notices - stating that You changed the files; and - - (c) You must retain, in the Source form of any Derivative Works - that You distribute, all copyright, patent, trademark, and - attribution notices from the Source form of the Work, - excluding those notices that do not pertain to any part of - the Derivative Works; and - - (d) If the Work includes a "NOTICE" text file as part of its - distribution, then any Derivative Works that You distribute must - include a readable copy of the attribution notices contained - within such NOTICE file, excluding those notices that do not - pertain to any part of the Derivative Works, in at least one - of the following places: within a NOTICE text file distributed - as part of the Derivative Works; within the Source form or - documentation, if provided along with the Derivative Works; or, - within a display generated by the Derivative Works, if and - wherever such third-party notices normally appear. The contents - of the NOTICE file are for informational purposes only and - do not modify the License. You may add Your own attribution - notices within Derivative Works that You distribute, alongside - or as an addendum to the NOTICE text from the Work, provided - that such additional attribution notices cannot be construed - as modifying the License. - - You may add Your own copyright statement to Your modifications and - may provide additional or different license terms and conditions - for use, reproduction, or distribution of Your modifications, or - for any such Derivative Works as a whole, provided Your use, - reproduction, and distribution of the Work otherwise complies with - the conditions stated in this License. - - 5. Submission of Contributions. Unless You explicitly state otherwise, - any Contribution intentionally submitted for inclusion in the Work - by You to the Licensor shall be under the terms and conditions of - this License, without any additional terms or conditions. - Notwithstanding the above, nothing herein shall supersede or modify - the terms of any separate license agreement you may have executed - with Licensor regarding such Contributions. - - 6. Trademarks. This License does not grant permission to use the trade - names, trademarks, service marks, or product names of the Licensor, - except as required for reasonable and customary use in describing the - origin of the Work and reproducing the content of the NOTICE file. - - 7. Disclaimer of Warranty. Unless required by applicable law or - agreed to in writing, Licensor provides the Work (and each - Contributor provides its Contributions) on an "AS IS" BASIS, - WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or - implied, including, without limitation, any warranties or conditions - of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A - PARTICULAR PURPOSE. You are solely responsible for determining the - appropriateness of using or redistributing the Work and assume any - risks associated with Your exercise of permissions under this License. - - 8. Limitation of Liability. In no event and under no legal theory, - whether in tort (including negligence), contract, or otherwise, - unless required by applicable law (such as deliberate and grossly - negligent acts) or agreed to in writing, shall any Contributor be - liable to You for damages, including any direct, indirect, special, - incidental, or consequential damages of any character arising as a - result of this License or out of the use or inability to use the - Work (including but not limited to damages for loss of goodwill, - work stoppage, computer failure or malfunction, or any and all - other commercial damages or losses), even if such Contributor - has been advised of the possibility of such damages. - - 9. Accepting Warranty or Additional Liability. While redistributing - the Work or Derivative Works thereof, You may choose to offer, - and charge a fee for, acceptance of support, warranty, indemnity, - or other liability obligations and/or rights consistent with this - License. However, in accepting such obligations, You may act only - on Your own behalf and on Your sole responsibility, not on behalf - of any other Contributor, and only if You agree to indemnify, - defend, and hold each Contributor harmless for any liability - incurred by, or claims asserted against, such Contributor by reason - of your accepting any such warranty or additional liability. - - END OF TERMS AND CONDITIONS - - APPENDIX: How to apply the Apache License to your work. - - To apply the Apache License to your work, attach the following - boilerplate notice, with the fields enclosed by brackets "[]" - replaced with your own identifying information. (Don't include - the brackets!) The text should be enclosed in the appropriate - comment syntax for the file format. We also recommend that a - file or class name and description of purpose be included on the - same "printed page" as the copyright notice for easier - identification within third-party archives. - - Copyright [yyyy] [name of copyright owner] - - Licensed 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. -========== -Notice for: com.google.j2objc:j2objc-annotations-1.1 ----------- - - - Apache License - Version 2.0, January 2004 - http://www.apache.org/licenses/ - - TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION - - 1. Definitions. - - "License" shall mean the terms and conditions for use, reproduction, - and distribution as defined by Sections 1 through 9 of this document. - - "Licensor" shall mean the copyright owner or entity authorized by - the copyright owner that is granting the License. - - "Legal Entity" shall mean the union of the acting entity and all - other entities that control, are controlled by, or are under common - control with that entity. For the purposes of this definition, - "control" means (i) the power, direct or indirect, to cause the - direction or management of such entity, whether by contract or - otherwise, or (ii) ownership of fifty percent (50%) or more of the - outstanding shares, or (iii) beneficial ownership of such entity. - - "You" (or "Your") shall mean an individual or Legal Entity - exercising permissions granted by this License. - - "Source" form shall mean the preferred form for making modifications, - including but not limited to software source code, documentation - source, and configuration files. - - "Object" form shall mean any form resulting from mechanical - transformation or translation of a Source form, including but - not limited to compiled object code, generated documentation, - and conversions to other media types. - - "Work" shall mean the work of authorship, whether in Source or - Object form, made available under the License, as indicated by a - copyright notice that is included in or attached to the work - (an example is provided in the Appendix below). - - "Derivative Works" shall mean any work, whether in Source or Object - form, that is based on (or derived from) the Work and for which the - editorial revisions, annotations, elaborations, or other modifications - represent, as a whole, an original work of authorship. For the purposes - of this License, Derivative Works shall not include works that remain - separable from, or merely link (or bind by name) to the interfaces of, - the Work and Derivative Works thereof. - - "Contribution" shall mean any work of authorship, including - the original version of the Work and any modifications or additions - to that Work or Derivative Works thereof, that is intentionally - submitted to Licensor for inclusion in the Work by the copyright owner - or by an individual or Legal Entity authorized to submit on behalf of - the copyright owner. For the purposes of this definition, "submitted" - means any form of electronic, verbal, or written communication sent - to the Licensor or its representatives, including but not limited to - communication on electronic mailing lists, source code control systems, - and issue tracking systems that are managed by, or on behalf of, the - Licensor for the purpose of discussing and improving the Work, but - excluding communication that is conspicuously marked or otherwise - designated in writing by the copyright owner as "Not a Contribution." - - "Contributor" shall mean Licensor and any individual or Legal Entity - on behalf of whom a Contribution has been received by Licensor and - subsequently incorporated within the Work. - - 2. Grant of Copyright License. Subject to the terms and conditions of - this License, each Contributor hereby grants to You a perpetual, - worldwide, non-exclusive, no-charge, royalty-free, irrevocable - copyright license to reproduce, prepare Derivative Works of, - publicly display, publicly perform, sublicense, and distribute the - Work and such Derivative Works in Source or Object form. - - 3. Grant of Patent License. Subject to the terms and conditions of - this License, each Contributor hereby grants to You a perpetual, - worldwide, non-exclusive, no-charge, royalty-free, irrevocable - (except as stated in this section) patent license to make, have made, - use, offer to sell, sell, import, and otherwise transfer the Work, - where such license applies only to those patent claims licensable - by such Contributor that are necessarily infringed by their - Contribution(s) alone or by combination of their Contribution(s) - with the Work to which such Contribution(s) was submitted. If You - institute patent litigation against any entity (including a - cross-claim or counterclaim in a lawsuit) alleging that the Work - or a Contribution incorporated within the Work constitutes direct - or contributory patent infringement, then any patent licenses - granted to You under this License for that Work shall terminate - as of the date such litigation is filed. - - 4. Redistribution. You may reproduce and distribute copies of the - Work or Derivative Works thereof in any medium, with or without - modifications, and in Source or Object form, provided that You - meet the following conditions: - - (a) You must give any other recipients of the Work or - Derivative Works a copy of this License; and - - (b) You must cause any modified files to carry prominent notices - stating that You changed the files; and - - (c) You must retain, in the Source form of any Derivative Works - that You distribute, all copyright, patent, trademark, and - attribution notices from the Source form of the Work, - excluding those notices that do not pertain to any part of - the Derivative Works; and - - (d) If the Work includes a "NOTICE" text file as part of its - distribution, then any Derivative Works that You distribute must - include a readable copy of the attribution notices contained - within such NOTICE file, excluding those notices that do not - pertain to any part of the Derivative Works, in at least one - of the following places: within a NOTICE text file distributed - as part of the Derivative Works; within the Source form or - documentation, if provided along with the Derivative Works; or, - within a display generated by the Derivative Works, if and - wherever such third-party notices normally appear. The contents - of the NOTICE file are for informational purposes only and - do not modify the License. You may add Your own attribution - notices within Derivative Works that You distribute, alongside - or as an addendum to the NOTICE text from the Work, provided - that such additional attribution notices cannot be construed - as modifying the License. - - You may add Your own copyright statement to Your modifications and - may provide additional or different license terms and conditions - for use, reproduction, or distribution of Your modifications, or - for any such Derivative Works as a whole, provided Your use, - reproduction, and distribution of the Work otherwise complies with - the conditions stated in this License. - - 5. Submission of Contributions. Unless You explicitly state otherwise, - any Contribution intentionally submitted for inclusion in the Work - by You to the Licensor shall be under the terms and conditions of - this License, without any additional terms or conditions. - Notwithstanding the above, nothing herein shall supersede or modify - the terms of any separate license agreement you may have executed - with Licensor regarding such Contributions. - - 6. Trademarks. This License does not grant permission to use the trade - names, trademarks, service marks, or product names of the Licensor, - except as required for reasonable and customary use in describing the - origin of the Work and reproducing the content of the NOTICE file. - - 7. Disclaimer of Warranty. Unless required by applicable law or - agreed to in writing, Licensor provides the Work (and each - Contributor provides its Contributions) on an "AS IS" BASIS, - WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or - implied, including, without limitation, any warranties or conditions - of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A - PARTICULAR PURPOSE. You are solely responsible for determining the - appropriateness of using or redistributing the Work and assume any - risks associated with Your exercise of permissions under this License. - - 8. Limitation of Liability. In no event and under no legal theory, - whether in tort (including negligence), contract, or otherwise, - unless required by applicable law (such as deliberate and grossly - negligent acts) or agreed to in writing, shall any Contributor be - liable to You for damages, including any direct, indirect, special, - incidental, or consequential damages of any character arising as a - result of this License or out of the use or inability to use the - Work (including but not limited to damages for loss of goodwill, - work stoppage, computer failure or malfunction, or any and all - other commercial damages or losses), even if such Contributor - has been advised of the possibility of such damages. - - 9. Accepting Warranty or Additional Liability. While redistributing - the Work or Derivative Works thereof, You may choose to offer, - and charge a fee for, acceptance of support, warranty, indemnity, - or other liability obligations and/or rights consistent with this - License. However, in accepting such obligations, You may act only - on Your own behalf and on Your sole responsibility, not on behalf - of any other Contributor, and only if You agree to indemnify, - defend, and hold each Contributor harmless for any liability - incurred by, or claims asserted against, such Contributor by reason - of your accepting any such warranty or additional liability. - - END OF TERMS AND CONDITIONS - - APPENDIX: How to apply the Apache License to your work. - - To apply the Apache License to your work, attach the following - boilerplate notice, with the fields enclosed by brackets "[]" - replaced with your own identifying information. (Don't include - the brackets!) The text should be enclosed in the appropriate - comment syntax for the file format. We also recommend that a - file or class name and description of purpose be included on the - same "printed page" as the copyright notice for easier - identification within third-party archives. - - Copyright [yyyy] [name of copyright owner] - - Licensed 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. - - ========== Notice for: commons-codec:commons-codec-1.10.0 ---------- @@ -3984,7 +2866,7 @@ The Apache Software Foundation (http://www.apache.org/). See the License for the specific language governing permissions and limitations under the License. ========== -Notice for: concurrent-ruby-1.1.5 +Notice for: concurrent-ruby-1.1.7 ---------- Copyright (c) Jerry D'Antonio -- released under the MIT license. @@ -4010,7 +2892,7 @@ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. ========== -Notice for: dalli-2.7.10 +Notice for: dalli-2.7.11 ---------- Copyright (c) Peter M. Goldstein, Mike Perham @@ -4118,7 +3000,7 @@ This file is generated from the Public Suffix List https://mozilla.org/MPL/2.0/ ========== -Notice for: dotenv-2.7.5 +Notice for: dotenv-2.7.6 ---------- Copyright (c) 2012 Brandon Keepers @@ -4171,6 +3053,15 @@ LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +========== +Notice for: elastic-app-search-7.8.0 +---------- + +source: https://github.com/elastic/app-search-ruby/blob/v7.8.0/NOTICE.txt + +Elastic App Search Ruby client. + +Copyright 2012-2019 Elasticsearch B.V. ========== Notice for: elasticsearch-5.0.5 ---------- @@ -4274,7 +3165,7 @@ The above copyright notice and this permission notice shall be included in all c THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. ========== -Notice for: ffi-1.12.1 +Notice for: ffi-1.13.1 ---------- source: https://github.com/ffi/ffi/blob/1.9.23/LICENSE @@ -4387,214 +3278,6 @@ LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. -========== -Notice for: gradle.plugin.com.github.jk1:gradle-license-report-0.7.1 ----------- - -source: https://github.com/jk1/Gradle-License-Report/blob/master/LICENSE - - Apache License - Version 2.0, January 2004 - http://www.apache.org/licenses/ - - TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION - - 1. Definitions. - - "License" shall mean the terms and conditions for use, reproduction, - and distribution as defined by Sections 1 through 9 of this document. - - "Licensor" shall mean the copyright owner or entity authorized by - the copyright owner that is granting the License. - - "Legal Entity" shall mean the union of the acting entity and all - other entities that control, are controlled by, or are under common - control with that entity. For the purposes of this definition, - "control" means (i) the power, direct or indirect, to cause the - direction or management of such entity, whether by contract or - otherwise, or (ii) ownership of fifty percent (50%) or more of the - outstanding shares, or (iii) beneficial ownership of such entity. - - "You" (or "Your") shall mean an individual or Legal Entity - exercising permissions granted by this License. - - "Source" form shall mean the preferred form for making modifications, - including but not limited to software source code, documentation - source, and configuration files. - - "Object" form shall mean any form resulting from mechanical - transformation or translation of a Source form, including but - not limited to compiled object code, generated documentation, - and conversions to other media types. - - "Work" shall mean the work of authorship, whether in Source or - Object form, made available under the License, as indicated by a - copyright notice that is included in or attached to the work - (an example is provided in the Appendix below). - - "Derivative Works" shall mean any work, whether in Source or Object - form, that is based on (or derived from) the Work and for which the - editorial revisions, annotations, elaborations, or other modifications - represent, as a whole, an original work of authorship. For the purposes - of this License, Derivative Works shall not include works that remain - separable from, or merely link (or bind by name) to the interfaces of, - the Work and Derivative Works thereof. - - "Contribution" shall mean any work of authorship, including - the original version of the Work and any modifications or additions - to that Work or Derivative Works thereof, that is intentionally - submitted to Licensor for inclusion in the Work by the copyright owner - or by an individual or Legal Entity authorized to submit on behalf of - the copyright owner. For the purposes of this definition, "submitted" - means any form of electronic, verbal, or written communication sent - to the Licensor or its representatives, including but not limited to - communication on electronic mailing lists, source code control systems, - and issue tracking systems that are managed by, or on behalf of, the - Licensor for the purpose of discussing and improving the Work, but - excluding communication that is conspicuously marked or otherwise - designated in writing by the copyright owner as "Not a Contribution." - - "Contributor" shall mean Licensor and any individual or Legal Entity - on behalf of whom a Contribution has been received by Licensor and - subsequently incorporated within the Work. - - 2. Grant of Copyright License. Subject to the terms and conditions of - this License, each Contributor hereby grants to You a perpetual, - worldwide, non-exclusive, no-charge, royalty-free, irrevocable - copyright license to reproduce, prepare Derivative Works of, - publicly display, publicly perform, sublicense, and distribute the - Work and such Derivative Works in Source or Object form. - - 3. Grant of Patent License. Subject to the terms and conditions of - this License, each Contributor hereby grants to You a perpetual, - worldwide, non-exclusive, no-charge, royalty-free, irrevocable - (except as stated in this section) patent license to make, have made, - use, offer to sell, sell, import, and otherwise transfer the Work, - where such license applies only to those patent claims licensable - by such Contributor that are necessarily infringed by their - Contribution(s) alone or by combination of their Contribution(s) - with the Work to which such Contribution(s) was submitted. If You - institute patent litigation against any entity (including a - cross-claim or counterclaim in a lawsuit) alleging that the Work - or a Contribution incorporated within the Work constitutes direct - or contributory patent infringement, then any patent licenses - granted to You under this License for that Work shall terminate - as of the date such litigation is filed. - - 4. Redistribution. You may reproduce and distribute copies of the - Work or Derivative Works thereof in any medium, with or without - modifications, and in Source or Object form, provided that You - meet the following conditions: - - (a) You must give any other recipients of the Work or - Derivative Works a copy of this License; and - - (b) You must cause any modified files to carry prominent notices - stating that You changed the files; and - - (c) You must retain, in the Source form of any Derivative Works - that You distribute, all copyright, patent, trademark, and - attribution notices from the Source form of the Work, - excluding those notices that do not pertain to any part of - the Derivative Works; and - - (d) If the Work includes a "NOTICE" text file as part of its - distribution, then any Derivative Works that You distribute must - include a readable copy of the attribution notices contained - within such NOTICE file, excluding those notices that do not - pertain to any part of the Derivative Works, in at least one - of the following places: within a NOTICE text file distributed - as part of the Derivative Works; within the Source form or - documentation, if provided along with the Derivative Works; or, - within a display generated by the Derivative Works, if and - wherever such third-party notices normally appear. The contents - of the NOTICE file are for informational purposes only and - do not modify the License. You may add Your own attribution - notices within Derivative Works that You distribute, alongside - or as an addendum to the NOTICE text from the Work, provided - that such additional attribution notices cannot be construed - as modifying the License. - - You may add Your own copyright statement to Your modifications and - may provide additional or different license terms and conditions - for use, reproduction, or distribution of Your modifications, or - for any such Derivative Works as a whole, provided Your use, - reproduction, and distribution of the Work otherwise complies with - the conditions stated in this License. - - 5. Submission of Contributions. Unless You explicitly state otherwise, - any Contribution intentionally submitted for inclusion in the Work - by You to the Licensor shall be under the terms and conditions of - this License, without any additional terms or conditions. - Notwithstanding the above, nothing herein shall supersede or modify - the terms of any separate license agreement you may have executed - with Licensor regarding such Contributions. - - 6. Trademarks. This License does not grant permission to use the trade - names, trademarks, service marks, or product names of the Licensor, - except as required for reasonable and customary use in describing the - origin of the Work and reproducing the content of the NOTICE file. - - 7. Disclaimer of Warranty. Unless required by applicable law or - agreed to in writing, Licensor provides the Work (and each - Contributor provides its Contributions) on an "AS IS" BASIS, - WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or - implied, including, without limitation, any warranties or conditions - of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A - PARTICULAR PURPOSE. You are solely responsible for determining the - appropriateness of using or redistributing the Work and assume any - risks associated with Your exercise of permissions under this License. - - 8. Limitation of Liability. In no event and under no legal theory, - whether in tort (including negligence), contract, or otherwise, - unless required by applicable law (such as deliberate and grossly - negligent acts) or agreed to in writing, shall any Contributor be - liable to You for damages, including any direct, indirect, special, - incidental, or consequential damages of any character arising as a - result of this License or out of the use or inability to use the - Work (including but not limited to damages for loss of goodwill, - work stoppage, computer failure or malfunction, or any and all - other commercial damages or losses), even if such Contributor - has been advised of the possibility of such damages. - - 9. Accepting Warranty or Additional Liability. While redistributing - the Work or Derivative Works thereof, You may choose to offer, - and charge a fee for, acceptance of support, warranty, indemnity, - or other liability obligations and/or rights consistent with this - License. However, in accepting such obligations, You may act only - on Your own behalf and on Your sole responsibility, not on behalf - of any other Contributor, and only if You agree to indemnify, - defend, and hold each Contributor harmless for any liability - incurred by, or claims asserted against, such Contributor by reason - of your accepting any such warranty or additional liability. - - END OF TERMS AND CONDITIONS - - APPENDIX: How to apply the Apache License to your work. - - To apply the Apache License to your work, attach the following - boilerplate notice, with the fields enclosed by brackets "{}" - replaced with your own identifying information. (Don't include - the brackets!) The text should be enclosed in the appropriate - comment syntax for the file format. We also recommend that a - file or class name and description of purpose be included on the - same "printed page" as the copyright notice for easier - identification within third-party archives. - - Copyright {yyyy} {name of copyright owner} - - Licensed 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. - ========== Notice for: hitimes-1.3.1 ---------- @@ -4677,7 +3360,7 @@ OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. ========== -Notice for: http-form_data-2.2.0 +Notice for: http-form_data-2.3.0 ---------- source: https://github.com/httprb/form_data/blob/v1.0.1/LICENSE.txt @@ -4734,7 +3417,7 @@ FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. ========== -Notice for: i18n-1.8.2 +Notice for: i18n-1.8.5 ---------- source: https://github.com/svenfuchs/i18n/blob/v0.6.9/MIT-LICENSE @@ -4781,7 +3464,7 @@ See the License for the specific language governing permissions and limitations under the License. ========== -Notice for: jar-dependencies-0.4.0 +Notice for: jar-dependencies-0.4.1 ---------- source: https://github.com/mkristian/jar-dependencies/blob/0.3.12/MIT-LICENSE @@ -5219,7 +3902,7 @@ TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION of your accepting any such warranty or additional liability. ========== -Notice for: jrjackson-0.4.11 +Notice for: jrjackson-0.4.12 ---------- https://github.com/guyboertje/jrjackson/blob/v0.4.6/README.md @@ -7711,7 +6394,7 @@ See the License for the specific language governing permissions and limitations under the License. ========== -Notice for: jruby-openssl-0.10.2 +Notice for: jruby-openssl-0.10.4 ---------- source: https://github.com/jruby/jruby-openssl/blob/v0.9.21/LICENSE.txt @@ -7799,6 +6482,19 @@ LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. ========== +Notice for: jwt-2.2.2 +---------- + +source: https://github.com/jwt/ruby-jwt/blob/v2.2.2/LICENSE + +Copyright (c) 2011 Jeff Lindsay + +Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +========== Notice for: lru_redux-1.1.0 ---------- @@ -7854,7 +6550,7 @@ TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. ========== -Notice for: manticore-0.6.4 +Notice for: manticore-0.7.0 ---------- source: https://github.com/cheald/manticore/blob/v0.6.1/LICENSE.txt @@ -7881,7 +6577,7 @@ OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. ========== -Notice for: march_hare-4.1.1 +Notice for: march_hare-4.3.0 ---------- source: https://github.com/ruby-amqp/march_hare/blob/v3.1.1/LICENSE @@ -7935,7 +6631,7 @@ LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. ========== -Notice for: method_source-0.9.2 +Notice for: method_source-1.0.0 ---------- source: https://github.com/banister/method_source/blob/v0.9.0/README.markdown#license @@ -8028,7 +6724,7 @@ terms of Ruby’s licence or the Simplified BSD licence. * Portions copyright 2004 Mauricio Julio Fernández Pradier. ========== -Notice for: msgpack-1.3.1 +Notice for: msgpack-1.3.3 ---------- source: https://github.com/msgpack/msgpack-ruby/blob/v1.2.4/ext/msgpack/ @@ -8047,7 +6743,7 @@ source: https://github.com/msgpack/msgpack-ruby/blob/v1.2.4/ext/msgpack/ See the License for the specific language governing permissions and limitations under the License. ========== -Notice for: multi_json-1.14.1 +Notice for: multi_json-1.15.0 ---------- source: https://github.com/intridea/multi_json/blob/v1.13.1/LICENSE.md @@ -8213,7 +6909,7 @@ OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. ========== -Notice for: nio4r-2.5.2 +Notice for: nio4r-2.5.4 ---------- Released under the MIT license. @@ -8228,7 +6924,7 @@ The above copyright notice and this permission notice shall be included in all c THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. ========== -Notice for: nokogiri-1.10.7 +Notice for: nokogiri-1.10.10 ---------- source: https://github.com/sparklemotion/nokogiri/blob/v1.8.2/LICENSE.md @@ -8296,1300 +6992,6 @@ ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. -========== -Notice for: org.apache.logging.log4j:log4j-api-2.12.1 ----------- - -source: https://git-wip-us.apache.org/repos/asf?p=logging-log4j2.git;a=blob;f=NOTICE.txt;h=bd95322f254fc6f691b47e77df8c21229f47b8d4;hb=HEAD - -Apache Log4j -Copyright 1999-2017 Apache Software Foundation - -This product includes software developed at -The Apache Software Foundation (http://www.apache.org/). - -ResolverUtil.java -Copyright 2005-2006 Tim Fennell - -Dumbster SMTP test server -Copyright 2004 Jason Paul Kitchen - -TypeUtil.java -Copyright 2002-2012 Ramnivas Laddad, Juergen Hoeller, Chris Beams - -picocli (http://picocli.info) -Copyright 2017 Remko Popma -========== -Notice for: org.apache.logging.log4j:log4j-core-2.12.1 ----------- - -source: https://git-wip-us.apache.org/repos/asf?p=logging-log4j2.git;a=blob;f=NOTICE.txt;h=bd95322f254fc6f691b47e77df8c21229f47b8d4;hb=HEAD - -Apache Log4j -Copyright 1999-2017 Apache Software Foundation - -This product includes software developed at -The Apache Software Foundation (http://www.apache.org/). - -ResolverUtil.java -Copyright 2005-2006 Tim Fennell - -Dumbster SMTP test server -Copyright 2004 Jason Paul Kitchen - -TypeUtil.java -Copyright 2002-2012 Ramnivas Laddad, Juergen Hoeller, Chris Beams - -picocli (http://picocli.info) -Copyright 2017 Remko Popma -========== -Notice for: org.apache.logging.log4j:log4j-slf4j-impl-2.12.1 ----------- - -source: https://git-wip-us.apache.org/repos/asf?p=logging-log4j2.git;a=blob;f=NOTICE.txt;h=bd95322f254fc6f691b47e77df8c21229f47b8d4;hb=HEAD - -Apache Log4j -Copyright 1999-2017 Apache Software Foundation - -This product includes software developed at -The Apache Software Foundation (http://www.apache.org/). - -ResolverUtil.java -Copyright 2005-2006 Tim Fennell - -Dumbster SMTP test server -Copyright 2004 Jason Paul Kitchen - -TypeUtil.java -Copyright 2002-2012 Ramnivas Laddad, Juergen Hoeller, Chris Beams - -picocli (http://picocli.info) -Copyright 2017 Remko Popma -========== -Notice for: org.codehaus.janino:commons-compiler-3.1.0 ----------- - -Janino - An embedded Java[TM] compiler - -Copyright (c) 2001-2016, Arno Unkrig -Copyright (c) 2015-2016 TIBCO Software Inc. -All rights reserved. - -Redistribution and use in source and binary forms, with or without -modification, are permitted provided that the following conditions -are met: - - 1. Redistributions of source code must retain the above copyright - notice, this list of conditions and the following disclaimer. - 2. Redistributions in binary form must reproduce the above - copyright notice, this list of conditions and the following - disclaimer in the documentation and/or other materials - provided with the distribution. - 3. Neither the name of JANINO nor the names of its contributors - may be used to endorse or promote products derived from this - software without specific prior written permission. - -THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" -AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE -IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE -ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDERS OR CONTRIBUTORS BE -LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR -CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF -SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS -INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER -IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR -OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN -IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - -========== -Notice for: org.codehaus.janino:janino-3.1.0 ----------- - -Janino - An embedded Java[TM] compiler - -Copyright (c) 2001-2016, Arno Unkrig -Copyright (c) 2015-2016 TIBCO Software Inc. -All rights reserved. - -Redistribution and use in source and binary forms, with or without -modification, are permitted provided that the following conditions -are met: - - 1. Redistributions of source code must retain the above copyright - notice, this list of conditions and the following disclaimer. - 2. Redistributions in binary form must reproduce the above - copyright notice, this list of conditions and the following - disclaimer in the documentation and/or other materials - provided with the distribution. - 3. Neither the name of JANINO nor the names of its contributors - may be used to endorse or promote products derived from this - software without specific prior written permission. - -THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" -AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE -IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE -ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDERS OR CONTRIBUTORS BE -LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR -CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF -SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS -INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER -IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR -OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN -IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - -========== -Notice for: org.codehaus.mojo:animal-sniffer-annotations-1.14 ----------- - - The MIT License - - Copyright (c) 2009 codehaus.org. - - Permission is hereby granted, free of charge, to any person obtaining a copy - of this software and associated documentation files (the "Software"), to deal - in the Software without restriction, including without limitation the rights - to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - copies of the Software, and to permit persons to whom the Software is - furnished to do so, subject to the following conditions: - - The above copyright notice and this permission notice shall be included in - all copies or substantial portions of the Software. - - THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN - THE SOFTWARE. - - -========== -Notice for: org.eclipse.core:org.eclipse.core.commands-3.6.0 ----------- - -Copyright © Eclipse Foundation, Inc. All Rights Reserved. - -Eclipse Public License - v 1.0 -THE ACCOMPANYING PROGRAM IS PROVIDED UNDER THE TERMS OF THIS ECLIPSE PUBLIC LICENSE ("AGREEMENT"). ANY USE, REPRODUCTION OR DISTRIBUTION OF THE PROGRAM CONSTITUTES RECIPIENT'S ACCEPTANCE OF THIS AGREEMENT. - -1. DEFINITIONS - -"Contribution" means: - -a) in the case of the initial Contributor, the initial code and documentation distributed under this Agreement, and - -b) in the case of each subsequent Contributor: - -i) changes to the Program, and - -ii) additions to the Program; - -where such changes and/or additions to the Program originate from and are distributed by that particular Contributor. A Contribution 'originates' from a Contributor if it was added to the Program by such Contributor itself or anyone acting on such Contributor's behalf. Contributions do not include additions to the Program which: (i) are separate modules of software distributed in conjunction with the Program under their own license agreement, and (ii) are not derivative works of the Program. - -"Contributor" means any person or entity that distributes the Program. - -"Licensed Patents" mean patent claims licensable by a Contributor which are necessarily infringed by the use or sale of its Contribution alone or when combined with the Program. - -"Program" means the Contributions distributed in accordance with this Agreement. - -"Recipient" means anyone who receives the Program under this Agreement, including all Contributors. - -2. GRANT OF RIGHTS - -a) Subject to the terms of this Agreement, each Contributor hereby grants Recipient a non-exclusive, worldwide, royalty-free copyright license to reproduce, prepare derivative works of, publicly display, publicly perform, distribute and sublicense the Contribution of such Contributor, if any, and such derivative works, in source code and object code form. - -b) Subject to the terms of this Agreement, each Contributor hereby grants Recipient a non-exclusive, worldwide, royalty-free patent license under Licensed Patents to make, use, sell, offer to sell, import and otherwise transfer the Contribution of such Contributor, if any, in source code and object code form. This patent license shall apply to the combination of the Contribution and the Program if, at the time the Contribution is added by the Contributor, such addition of the Contribution causes such combination to be covered by the Licensed Patents. The patent license shall not apply to any other combinations which include the Contribution. No hardware per se is licensed hereunder. - -c) Recipient understands that although each Contributor grants the licenses to its Contributions set forth herein, no assurances are provided by any Contributor that the Program does not infringe the patent or other intellectual property rights of any other entity. Each Contributor disclaims any liability to Recipient for claims brought by any other entity based on infringement of intellectual property rights or otherwise. As a condition to exercising the rights and licenses granted hereunder, each Recipient hereby assumes sole responsibility to secure any other intellectual property rights needed, if any. For example, if a third party patent license is required to allow Recipient to distribute the Program, it is Recipient's responsibility to acquire that license before distributing the Program. - -d) Each Contributor represents that to its knowledge it has sufficient copyright rights in its Contribution, if any, to grant the copyright license set forth in this Agreement. - -3. REQUIREMENTS - -A Contributor may choose to distribute the Program in object code form under its own license agreement, provided that: - -a) it complies with the terms and conditions of this Agreement; and - -b) its license agreement: - -i) effectively disclaims on behalf of all Contributors all warranties and conditions, express and implied, including warranties or conditions of title and non-infringement, and implied warranties or conditions of merchantability and fitness for a particular purpose; - -ii) effectively excludes on behalf of all Contributors all liability for damages, including direct, indirect, special, incidental and consequential damages, such as lost profits; - -iii) states that any provisions which differ from this Agreement are offered by that Contributor alone and not by any other party; and - -iv) states that source code for the Program is available from such Contributor, and informs licensees how to obtain it in a reasonable manner on or through a medium customarily used for software exchange. - -When the Program is made available in source code form: - -a) it must be made available under this Agreement; and - -b) a copy of this Agreement must be included with each copy of the Program. - -Contributors may not remove or alter any copyright notices contained within the Program. - -Each Contributor must identify itself as the originator of its Contribution, if any, in a manner that reasonably allows subsequent Recipients to identify the originator of the Contribution. - -4. COMMERCIAL DISTRIBUTION - -Commercial distributors of software may accept certain responsibilities with respect to end users, business partners and the like. While this license is intended to facilitate the commercial use of the Program, the Contributor who includes the Program in a commercial product offering should do so in a manner which does not create potential liability for other Contributors. Therefore, if a Contributor includes the Program in a commercial product offering, such Contributor ("Commercial Contributor") hereby agrees to defend and indemnify every other Contributor ("Indemnified Contributor") against any losses, damages and costs (collectively "Losses") arising from claims, lawsuits and other legal actions brought by a third party against the Indemnified Contributor to the extent caused by the acts or omissions of such Commercial Contributor in connection with its distribution of the Program in a commercial product offering. The obligations in this section do not apply to any claims or Losses relating to any actual or alleged intellectual property infringement. In order to qualify, an Indemnified Contributor must: a) promptly notify the Commercial Contributor in writing of such claim, and b) allow the Commercial Contributor to control, and cooperate with the Commercial Contributor in, the defense and any related settlement negotiations. The Indemnified Contributor may participate in any such claim at its own expense. - -For example, a Contributor might include the Program in a commercial product offering, Product X. That Contributor is then a Commercial Contributor. If that Commercial Contributor then makes performance claims, or offers warranties related to Product X, those performance claims and warranties are such Commercial Contributor's responsibility alone. Under this section, the Commercial Contributor would have to defend claims against the other Contributors related to those performance claims and warranties, and if a court requires any other Contributor to pay any damages as a result, the Commercial Contributor must pay those damages. - -5. NO WARRANTY - -EXCEPT AS EXPRESSLY SET FORTH IN THIS AGREEMENT, THE PROGRAM IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED INCLUDING, WITHOUT LIMITATION, ANY WARRANTIES OR CONDITIONS OF TITLE, NON-INFRINGEMENT, MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE. Each Recipient is solely responsible for determining the appropriateness of using and distributing the Program and assumes all risks associated with its exercise of rights under this Agreement , including but not limited to the risks and costs of program errors, compliance with applicable laws, damage to or loss of data, programs or equipment, and unavailability or interruption of operations. - -6. DISCLAIMER OF LIABILITY - -EXCEPT AS EXPRESSLY SET FORTH IN THIS AGREEMENT, NEITHER RECIPIENT NOR ANY CONTRIBUTORS SHALL HAVE ANY LIABILITY FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING WITHOUT LIMITATION LOST PROFITS), HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OR DISTRIBUTION OF THE PROGRAM OR THE EXERCISE OF ANY RIGHTS GRANTED HEREUNDER, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGES. - -7. GENERAL - -If any provision of this Agreement is invalid or unenforceable under applicable law, it shall not affect the validity or enforceability of the remainder of the terms of this Agreement, and without further action by the parties hereto, such provision shall be reformed to the minimum extent necessary to make such provision valid and enforceable. - -If Recipient institutes patent litigation against any entity (including a cross-claim or counterclaim in a lawsuit) alleging that the Program itself (excluding combinations of the Program with other software or hardware) infringes such Recipient's patent(s), then such Recipient's rights granted under Section 2(b) shall terminate as of the date such litigation is filed. - -All Recipient's rights under this Agreement shall terminate if it fails to comply with any of the material terms or conditions of this Agreement and does not cure such failure in a reasonable period of time after becoming aware of such noncompliance. If all Recipient's rights under this Agreement terminate, Recipient agrees to cease use and distribution of the Program as soon as reasonably practicable. However, Recipient's obligations under this Agreement and any licenses granted by Recipient relating to the Program shall continue and survive. - -Everyone is permitted to copy and distribute copies of this Agreement, but in order to avoid inconsistency the Agreement is copyrighted and may only be modified in the following manner. The Agreement Steward reserves the right to publish new versions (including revisions) of this Agreement from time to time. No one other than the Agreement Steward has the right to modify this Agreement. The Eclipse Foundation is the initial Agreement Steward. The Eclipse Foundation may assign the responsibility to serve as the Agreement Steward to a suitable separate entity. Each new version of the Agreement will be given a distinguishing version number. The Program (including Contributions) may always be distributed subject to the version of the Agreement under which it was received. In addition, after a new version of the Agreement is published, Contributor may elect to distribute the Program (including its Contributions) under the new version. Except as expressly stated in Sections 2(a) and 2(b) above, Recipient receives no rights or licenses to the intellectual property of any Contributor under this Agreement, whether expressly, by implication, estoppel or otherwise. All rights in the Program not expressly granted under this Agreement are reserved. - -This Agreement is governed by the laws of the State of New York and the intellectual property laws of the United States of America. No party to this Agreement will bring a legal action under this Agreement more than one year after the cause of action arose. Each party waives its rights to a jury trial in any resulting litigation. -========== -Notice for: org.eclipse.core:org.eclipse.core.contenttype-3.4.100 ----------- - -Copyright © Eclipse Foundation, Inc. All Rights Reserved. - -Eclipse Public License - v 1.0 -THE ACCOMPANYING PROGRAM IS PROVIDED UNDER THE TERMS OF THIS ECLIPSE PUBLIC LICENSE ("AGREEMENT"). ANY USE, REPRODUCTION OR DISTRIBUTION OF THE PROGRAM CONSTITUTES RECIPIENT'S ACCEPTANCE OF THIS AGREEMENT. - -1. DEFINITIONS - -"Contribution" means: - -a) in the case of the initial Contributor, the initial code and documentation distributed under this Agreement, and - -b) in the case of each subsequent Contributor: - -i) changes to the Program, and - -ii) additions to the Program; - -where such changes and/or additions to the Program originate from and are distributed by that particular Contributor. A Contribution 'originates' from a Contributor if it was added to the Program by such Contributor itself or anyone acting on such Contributor's behalf. Contributions do not include additions to the Program which: (i) are separate modules of software distributed in conjunction with the Program under their own license agreement, and (ii) are not derivative works of the Program. - -"Contributor" means any person or entity that distributes the Program. - -"Licensed Patents" mean patent claims licensable by a Contributor which are necessarily infringed by the use or sale of its Contribution alone or when combined with the Program. - -"Program" means the Contributions distributed in accordance with this Agreement. - -"Recipient" means anyone who receives the Program under this Agreement, including all Contributors. - -2. GRANT OF RIGHTS - -a) Subject to the terms of this Agreement, each Contributor hereby grants Recipient a non-exclusive, worldwide, royalty-free copyright license to reproduce, prepare derivative works of, publicly display, publicly perform, distribute and sublicense the Contribution of such Contributor, if any, and such derivative works, in source code and object code form. - -b) Subject to the terms of this Agreement, each Contributor hereby grants Recipient a non-exclusive, worldwide, royalty-free patent license under Licensed Patents to make, use, sell, offer to sell, import and otherwise transfer the Contribution of such Contributor, if any, in source code and object code form. This patent license shall apply to the combination of the Contribution and the Program if, at the time the Contribution is added by the Contributor, such addition of the Contribution causes such combination to be covered by the Licensed Patents. The patent license shall not apply to any other combinations which include the Contribution. No hardware per se is licensed hereunder. - -c) Recipient understands that although each Contributor grants the licenses to its Contributions set forth herein, no assurances are provided by any Contributor that the Program does not infringe the patent or other intellectual property rights of any other entity. Each Contributor disclaims any liability to Recipient for claims brought by any other entity based on infringement of intellectual property rights or otherwise. As a condition to exercising the rights and licenses granted hereunder, each Recipient hereby assumes sole responsibility to secure any other intellectual property rights needed, if any. For example, if a third party patent license is required to allow Recipient to distribute the Program, it is Recipient's responsibility to acquire that license before distributing the Program. - -d) Each Contributor represents that to its knowledge it has sufficient copyright rights in its Contribution, if any, to grant the copyright license set forth in this Agreement. - -3. REQUIREMENTS - -A Contributor may choose to distribute the Program in object code form under its own license agreement, provided that: - -a) it complies with the terms and conditions of this Agreement; and - -b) its license agreement: - -i) effectively disclaims on behalf of all Contributors all warranties and conditions, express and implied, including warranties or conditions of title and non-infringement, and implied warranties or conditions of merchantability and fitness for a particular purpose; - -ii) effectively excludes on behalf of all Contributors all liability for damages, including direct, indirect, special, incidental and consequential damages, such as lost profits; - -iii) states that any provisions which differ from this Agreement are offered by that Contributor alone and not by any other party; and - -iv) states that source code for the Program is available from such Contributor, and informs licensees how to obtain it in a reasonable manner on or through a medium customarily used for software exchange. - -When the Program is made available in source code form: - -a) it must be made available under this Agreement; and - -b) a copy of this Agreement must be included with each copy of the Program. - -Contributors may not remove or alter any copyright notices contained within the Program. - -Each Contributor must identify itself as the originator of its Contribution, if any, in a manner that reasonably allows subsequent Recipients to identify the originator of the Contribution. - -4. COMMERCIAL DISTRIBUTION - -Commercial distributors of software may accept certain responsibilities with respect to end users, business partners and the like. While this license is intended to facilitate the commercial use of the Program, the Contributor who includes the Program in a commercial product offering should do so in a manner which does not create potential liability for other Contributors. Therefore, if a Contributor includes the Program in a commercial product offering, such Contributor ("Commercial Contributor") hereby agrees to defend and indemnify every other Contributor ("Indemnified Contributor") against any losses, damages and costs (collectively "Losses") arising from claims, lawsuits and other legal actions brought by a third party against the Indemnified Contributor to the extent caused by the acts or omissions of such Commercial Contributor in connection with its distribution of the Program in a commercial product offering. The obligations in this section do not apply to any claims or Losses relating to any actual or alleged intellectual property infringement. In order to qualify, an Indemnified Contributor must: a) promptly notify the Commercial Contributor in writing of such claim, and b) allow the Commercial Contributor to control, and cooperate with the Commercial Contributor in, the defense and any related settlement negotiations. The Indemnified Contributor may participate in any such claim at its own expense. - -For example, a Contributor might include the Program in a commercial product offering, Product X. That Contributor is then a Commercial Contributor. If that Commercial Contributor then makes performance claims, or offers warranties related to Product X, those performance claims and warranties are such Commercial Contributor's responsibility alone. Under this section, the Commercial Contributor would have to defend claims against the other Contributors related to those performance claims and warranties, and if a court requires any other Contributor to pay any damages as a result, the Commercial Contributor must pay those damages. - -5. NO WARRANTY - -EXCEPT AS EXPRESSLY SET FORTH IN THIS AGREEMENT, THE PROGRAM IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED INCLUDING, WITHOUT LIMITATION, ANY WARRANTIES OR CONDITIONS OF TITLE, NON-INFRINGEMENT, MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE. Each Recipient is solely responsible for determining the appropriateness of using and distributing the Program and assumes all risks associated with its exercise of rights under this Agreement , including but not limited to the risks and costs of program errors, compliance with applicable laws, damage to or loss of data, programs or equipment, and unavailability or interruption of operations. - -6. DISCLAIMER OF LIABILITY - -EXCEPT AS EXPRESSLY SET FORTH IN THIS AGREEMENT, NEITHER RECIPIENT NOR ANY CONTRIBUTORS SHALL HAVE ANY LIABILITY FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING WITHOUT LIMITATION LOST PROFITS), HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OR DISTRIBUTION OF THE PROGRAM OR THE EXERCISE OF ANY RIGHTS GRANTED HEREUNDER, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGES. - -7. GENERAL - -If any provision of this Agreement is invalid or unenforceable under applicable law, it shall not affect the validity or enforceability of the remainder of the terms of this Agreement, and without further action by the parties hereto, such provision shall be reformed to the minimum extent necessary to make such provision valid and enforceable. - -If Recipient institutes patent litigation against any entity (including a cross-claim or counterclaim in a lawsuit) alleging that the Program itself (excluding combinations of the Program with other software or hardware) infringes such Recipient's patent(s), then such Recipient's rights granted under Section 2(b) shall terminate as of the date such litigation is filed. - -All Recipient's rights under this Agreement shall terminate if it fails to comply with any of the material terms or conditions of this Agreement and does not cure such failure in a reasonable period of time after becoming aware of such noncompliance. If all Recipient's rights under this Agreement terminate, Recipient agrees to cease use and distribution of the Program as soon as reasonably practicable. However, Recipient's obligations under this Agreement and any licenses granted by Recipient relating to the Program shall continue and survive. - -Everyone is permitted to copy and distribute copies of this Agreement, but in order to avoid inconsistency the Agreement is copyrighted and may only be modified in the following manner. The Agreement Steward reserves the right to publish new versions (including revisions) of this Agreement from time to time. No one other than the Agreement Steward has the right to modify this Agreement. The Eclipse Foundation is the initial Agreement Steward. The Eclipse Foundation may assign the responsibility to serve as the Agreement Steward to a suitable separate entity. Each new version of the Agreement will be given a distinguishing version number. The Program (including Contributions) may always be distributed subject to the version of the Agreement under which it was received. In addition, after a new version of the Agreement is published, Contributor may elect to distribute the Program (including its Contributions) under the new version. Except as expressly stated in Sections 2(a) and 2(b) above, Recipient receives no rights or licenses to the intellectual property of any Contributor under this Agreement, whether expressly, by implication, estoppel or otherwise. All rights in the Program not expressly granted under this Agreement are reserved. - -This Agreement is governed by the laws of the State of New York and the intellectual property laws of the United States of America. No party to this Agreement will bring a legal action under this Agreement more than one year after the cause of action arose. Each party waives its rights to a jury trial in any resulting litigation. -========== -Notice for: org.eclipse.core:org.eclipse.core.expressions-3.4.300 ----------- - -Copyright © Eclipse Foundation, Inc. All Rights Reserved. - -Eclipse Public License - v 1.0 -THE ACCOMPANYING PROGRAM IS PROVIDED UNDER THE TERMS OF THIS ECLIPSE PUBLIC LICENSE ("AGREEMENT"). ANY USE, REPRODUCTION OR DISTRIBUTION OF THE PROGRAM CONSTITUTES RECIPIENT'S ACCEPTANCE OF THIS AGREEMENT. - -1. DEFINITIONS - -"Contribution" means: - -a) in the case of the initial Contributor, the initial code and documentation distributed under this Agreement, and - -b) in the case of each subsequent Contributor: - -i) changes to the Program, and - -ii) additions to the Program; - -where such changes and/or additions to the Program originate from and are distributed by that particular Contributor. A Contribution 'originates' from a Contributor if it was added to the Program by such Contributor itself or anyone acting on such Contributor's behalf. Contributions do not include additions to the Program which: (i) are separate modules of software distributed in conjunction with the Program under their own license agreement, and (ii) are not derivative works of the Program. - -"Contributor" means any person or entity that distributes the Program. - -"Licensed Patents" mean patent claims licensable by a Contributor which are necessarily infringed by the use or sale of its Contribution alone or when combined with the Program. - -"Program" means the Contributions distributed in accordance with this Agreement. - -"Recipient" means anyone who receives the Program under this Agreement, including all Contributors. - -2. GRANT OF RIGHTS - -a) Subject to the terms of this Agreement, each Contributor hereby grants Recipient a non-exclusive, worldwide, royalty-free copyright license to reproduce, prepare derivative works of, publicly display, publicly perform, distribute and sublicense the Contribution of such Contributor, if any, and such derivative works, in source code and object code form. - -b) Subject to the terms of this Agreement, each Contributor hereby grants Recipient a non-exclusive, worldwide, royalty-free patent license under Licensed Patents to make, use, sell, offer to sell, import and otherwise transfer the Contribution of such Contributor, if any, in source code and object code form. This patent license shall apply to the combination of the Contribution and the Program if, at the time the Contribution is added by the Contributor, such addition of the Contribution causes such combination to be covered by the Licensed Patents. The patent license shall not apply to any other combinations which include the Contribution. No hardware per se is licensed hereunder. - -c) Recipient understands that although each Contributor grants the licenses to its Contributions set forth herein, no assurances are provided by any Contributor that the Program does not infringe the patent or other intellectual property rights of any other entity. Each Contributor disclaims any liability to Recipient for claims brought by any other entity based on infringement of intellectual property rights or otherwise. As a condition to exercising the rights and licenses granted hereunder, each Recipient hereby assumes sole responsibility to secure any other intellectual property rights needed, if any. For example, if a third party patent license is required to allow Recipient to distribute the Program, it is Recipient's responsibility to acquire that license before distributing the Program. - -d) Each Contributor represents that to its knowledge it has sufficient copyright rights in its Contribution, if any, to grant the copyright license set forth in this Agreement. - -3. REQUIREMENTS - -A Contributor may choose to distribute the Program in object code form under its own license agreement, provided that: - -a) it complies with the terms and conditions of this Agreement; and - -b) its license agreement: - -i) effectively disclaims on behalf of all Contributors all warranties and conditions, express and implied, including warranties or conditions of title and non-infringement, and implied warranties or conditions of merchantability and fitness for a particular purpose; - -ii) effectively excludes on behalf of all Contributors all liability for damages, including direct, indirect, special, incidental and consequential damages, such as lost profits; - -iii) states that any provisions which differ from this Agreement are offered by that Contributor alone and not by any other party; and - -iv) states that source code for the Program is available from such Contributor, and informs licensees how to obtain it in a reasonable manner on or through a medium customarily used for software exchange. - -When the Program is made available in source code form: - -a) it must be made available under this Agreement; and - -b) a copy of this Agreement must be included with each copy of the Program. - -Contributors may not remove or alter any copyright notices contained within the Program. - -Each Contributor must identify itself as the originator of its Contribution, if any, in a manner that reasonably allows subsequent Recipients to identify the originator of the Contribution. - -4. COMMERCIAL DISTRIBUTION - -Commercial distributors of software may accept certain responsibilities with respect to end users, business partners and the like. While this license is intended to facilitate the commercial use of the Program, the Contributor who includes the Program in a commercial product offering should do so in a manner which does not create potential liability for other Contributors. Therefore, if a Contributor includes the Program in a commercial product offering, such Contributor ("Commercial Contributor") hereby agrees to defend and indemnify every other Contributor ("Indemnified Contributor") against any losses, damages and costs (collectively "Losses") arising from claims, lawsuits and other legal actions brought by a third party against the Indemnified Contributor to the extent caused by the acts or omissions of such Commercial Contributor in connection with its distribution of the Program in a commercial product offering. The obligations in this section do not apply to any claims or Losses relating to any actual or alleged intellectual property infringement. In order to qualify, an Indemnified Contributor must: a) promptly notify the Commercial Contributor in writing of such claim, and b) allow the Commercial Contributor to control, and cooperate with the Commercial Contributor in, the defense and any related settlement negotiations. The Indemnified Contributor may participate in any such claim at its own expense. - -For example, a Contributor might include the Program in a commercial product offering, Product X. That Contributor is then a Commercial Contributor. If that Commercial Contributor then makes performance claims, or offers warranties related to Product X, those performance claims and warranties are such Commercial Contributor's responsibility alone. Under this section, the Commercial Contributor would have to defend claims against the other Contributors related to those performance claims and warranties, and if a court requires any other Contributor to pay any damages as a result, the Commercial Contributor must pay those damages. - -5. NO WARRANTY - -EXCEPT AS EXPRESSLY SET FORTH IN THIS AGREEMENT, THE PROGRAM IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED INCLUDING, WITHOUT LIMITATION, ANY WARRANTIES OR CONDITIONS OF TITLE, NON-INFRINGEMENT, MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE. Each Recipient is solely responsible for determining the appropriateness of using and distributing the Program and assumes all risks associated with its exercise of rights under this Agreement , including but not limited to the risks and costs of program errors, compliance with applicable laws, damage to or loss of data, programs or equipment, and unavailability or interruption of operations. - -6. DISCLAIMER OF LIABILITY - -EXCEPT AS EXPRESSLY SET FORTH IN THIS AGREEMENT, NEITHER RECIPIENT NOR ANY CONTRIBUTORS SHALL HAVE ANY LIABILITY FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING WITHOUT LIMITATION LOST PROFITS), HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OR DISTRIBUTION OF THE PROGRAM OR THE EXERCISE OF ANY RIGHTS GRANTED HEREUNDER, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGES. - -7. GENERAL - -If any provision of this Agreement is invalid or unenforceable under applicable law, it shall not affect the validity or enforceability of the remainder of the terms of this Agreement, and without further action by the parties hereto, such provision shall be reformed to the minimum extent necessary to make such provision valid and enforceable. - -If Recipient institutes patent litigation against any entity (including a cross-claim or counterclaim in a lawsuit) alleging that the Program itself (excluding combinations of the Program with other software or hardware) infringes such Recipient's patent(s), then such Recipient's rights granted under Section 2(b) shall terminate as of the date such litigation is filed. - -All Recipient's rights under this Agreement shall terminate if it fails to comply with any of the material terms or conditions of this Agreement and does not cure such failure in a reasonable period of time after becoming aware of such noncompliance. If all Recipient's rights under this Agreement terminate, Recipient agrees to cease use and distribution of the Program as soon as reasonably practicable. However, Recipient's obligations under this Agreement and any licenses granted by Recipient relating to the Program shall continue and survive. - -Everyone is permitted to copy and distribute copies of this Agreement, but in order to avoid inconsistency the Agreement is copyrighted and may only be modified in the following manner. The Agreement Steward reserves the right to publish new versions (including revisions) of this Agreement from time to time. No one other than the Agreement Steward has the right to modify this Agreement. The Eclipse Foundation is the initial Agreement Steward. The Eclipse Foundation may assign the responsibility to serve as the Agreement Steward to a suitable separate entity. Each new version of the Agreement will be given a distinguishing version number. The Program (including Contributions) may always be distributed subject to the version of the Agreement under which it was received. In addition, after a new version of the Agreement is published, Contributor may elect to distribute the Program (including its Contributions) under the new version. Except as expressly stated in Sections 2(a) and 2(b) above, Recipient receives no rights or licenses to the intellectual property of any Contributor under this Agreement, whether expressly, by implication, estoppel or otherwise. All rights in the Program not expressly granted under this Agreement are reserved. - -This Agreement is governed by the laws of the State of New York and the intellectual property laws of the United States of America. No party to this Agreement will bring a legal action under this Agreement more than one year after the cause of action arose. Each party waives its rights to a jury trial in any resulting litigation. -========== -Notice for: org.eclipse.core:org.eclipse.core.filesystem-1.3.100 ----------- - -Copyright © Eclipse Foundation, Inc. All Rights Reserved. - -Eclipse Public License - v 1.0 -THE ACCOMPANYING PROGRAM IS PROVIDED UNDER THE TERMS OF THIS ECLIPSE PUBLIC LICENSE ("AGREEMENT"). ANY USE, REPRODUCTION OR DISTRIBUTION OF THE PROGRAM CONSTITUTES RECIPIENT'S ACCEPTANCE OF THIS AGREEMENT. - -1. DEFINITIONS - -"Contribution" means: - -a) in the case of the initial Contributor, the initial code and documentation distributed under this Agreement, and - -b) in the case of each subsequent Contributor: - -i) changes to the Program, and - -ii) additions to the Program; - -where such changes and/or additions to the Program originate from and are distributed by that particular Contributor. A Contribution 'originates' from a Contributor if it was added to the Program by such Contributor itself or anyone acting on such Contributor's behalf. Contributions do not include additions to the Program which: (i) are separate modules of software distributed in conjunction with the Program under their own license agreement, and (ii) are not derivative works of the Program. - -"Contributor" means any person or entity that distributes the Program. - -"Licensed Patents" mean patent claims licensable by a Contributor which are necessarily infringed by the use or sale of its Contribution alone or when combined with the Program. - -"Program" means the Contributions distributed in accordance with this Agreement. - -"Recipient" means anyone who receives the Program under this Agreement, including all Contributors. - -2. GRANT OF RIGHTS - -a) Subject to the terms of this Agreement, each Contributor hereby grants Recipient a non-exclusive, worldwide, royalty-free copyright license to reproduce, prepare derivative works of, publicly display, publicly perform, distribute and sublicense the Contribution of such Contributor, if any, and such derivative works, in source code and object code form. - -b) Subject to the terms of this Agreement, each Contributor hereby grants Recipient a non-exclusive, worldwide, royalty-free patent license under Licensed Patents to make, use, sell, offer to sell, import and otherwise transfer the Contribution of such Contributor, if any, in source code and object code form. This patent license shall apply to the combination of the Contribution and the Program if, at the time the Contribution is added by the Contributor, such addition of the Contribution causes such combination to be covered by the Licensed Patents. The patent license shall not apply to any other combinations which include the Contribution. No hardware per se is licensed hereunder. - -c) Recipient understands that although each Contributor grants the licenses to its Contributions set forth herein, no assurances are provided by any Contributor that the Program does not infringe the patent or other intellectual property rights of any other entity. Each Contributor disclaims any liability to Recipient for claims brought by any other entity based on infringement of intellectual property rights or otherwise. As a condition to exercising the rights and licenses granted hereunder, each Recipient hereby assumes sole responsibility to secure any other intellectual property rights needed, if any. For example, if a third party patent license is required to allow Recipient to distribute the Program, it is Recipient's responsibility to acquire that license before distributing the Program. - -d) Each Contributor represents that to its knowledge it has sufficient copyright rights in its Contribution, if any, to grant the copyright license set forth in this Agreement. - -3. REQUIREMENTS - -A Contributor may choose to distribute the Program in object code form under its own license agreement, provided that: - -a) it complies with the terms and conditions of this Agreement; and - -b) its license agreement: - -i) effectively disclaims on behalf of all Contributors all warranties and conditions, express and implied, including warranties or conditions of title and non-infringement, and implied warranties or conditions of merchantability and fitness for a particular purpose; - -ii) effectively excludes on behalf of all Contributors all liability for damages, including direct, indirect, special, incidental and consequential damages, such as lost profits; - -iii) states that any provisions which differ from this Agreement are offered by that Contributor alone and not by any other party; and - -iv) states that source code for the Program is available from such Contributor, and informs licensees how to obtain it in a reasonable manner on or through a medium customarily used for software exchange. - -When the Program is made available in source code form: - -a) it must be made available under this Agreement; and - -b) a copy of this Agreement must be included with each copy of the Program. - -Contributors may not remove or alter any copyright notices contained within the Program. - -Each Contributor must identify itself as the originator of its Contribution, if any, in a manner that reasonably allows subsequent Recipients to identify the originator of the Contribution. - -4. COMMERCIAL DISTRIBUTION - -Commercial distributors of software may accept certain responsibilities with respect to end users, business partners and the like. While this license is intended to facilitate the commercial use of the Program, the Contributor who includes the Program in a commercial product offering should do so in a manner which does not create potential liability for other Contributors. Therefore, if a Contributor includes the Program in a commercial product offering, such Contributor ("Commercial Contributor") hereby agrees to defend and indemnify every other Contributor ("Indemnified Contributor") against any losses, damages and costs (collectively "Losses") arising from claims, lawsuits and other legal actions brought by a third party against the Indemnified Contributor to the extent caused by the acts or omissions of such Commercial Contributor in connection with its distribution of the Program in a commercial product offering. The obligations in this section do not apply to any claims or Losses relating to any actual or alleged intellectual property infringement. In order to qualify, an Indemnified Contributor must: a) promptly notify the Commercial Contributor in writing of such claim, and b) allow the Commercial Contributor to control, and cooperate with the Commercial Contributor in, the defense and any related settlement negotiations. The Indemnified Contributor may participate in any such claim at its own expense. - -For example, a Contributor might include the Program in a commercial product offering, Product X. That Contributor is then a Commercial Contributor. If that Commercial Contributor then makes performance claims, or offers warranties related to Product X, those performance claims and warranties are such Commercial Contributor's responsibility alone. Under this section, the Commercial Contributor would have to defend claims against the other Contributors related to those performance claims and warranties, and if a court requires any other Contributor to pay any damages as a result, the Commercial Contributor must pay those damages. - -5. NO WARRANTY - -EXCEPT AS EXPRESSLY SET FORTH IN THIS AGREEMENT, THE PROGRAM IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED INCLUDING, WITHOUT LIMITATION, ANY WARRANTIES OR CONDITIONS OF TITLE, NON-INFRINGEMENT, MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE. Each Recipient is solely responsible for determining the appropriateness of using and distributing the Program and assumes all risks associated with its exercise of rights under this Agreement , including but not limited to the risks and costs of program errors, compliance with applicable laws, damage to or loss of data, programs or equipment, and unavailability or interruption of operations. - -6. DISCLAIMER OF LIABILITY - -EXCEPT AS EXPRESSLY SET FORTH IN THIS AGREEMENT, NEITHER RECIPIENT NOR ANY CONTRIBUTORS SHALL HAVE ANY LIABILITY FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING WITHOUT LIMITATION LOST PROFITS), HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OR DISTRIBUTION OF THE PROGRAM OR THE EXERCISE OF ANY RIGHTS GRANTED HEREUNDER, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGES. - -7. GENERAL - -If any provision of this Agreement is invalid or unenforceable under applicable law, it shall not affect the validity or enforceability of the remainder of the terms of this Agreement, and without further action by the parties hereto, such provision shall be reformed to the minimum extent necessary to make such provision valid and enforceable. - -If Recipient institutes patent litigation against any entity (including a cross-claim or counterclaim in a lawsuit) alleging that the Program itself (excluding combinations of the Program with other software or hardware) infringes such Recipient's patent(s), then such Recipient's rights granted under Section 2(b) shall terminate as of the date such litigation is filed. - -All Recipient's rights under this Agreement shall terminate if it fails to comply with any of the material terms or conditions of this Agreement and does not cure such failure in a reasonable period of time after becoming aware of such noncompliance. If all Recipient's rights under this Agreement terminate, Recipient agrees to cease use and distribution of the Program as soon as reasonably practicable. However, Recipient's obligations under this Agreement and any licenses granted by Recipient relating to the Program shall continue and survive. - -Everyone is permitted to copy and distribute copies of this Agreement, but in order to avoid inconsistency the Agreement is copyrighted and may only be modified in the following manner. The Agreement Steward reserves the right to publish new versions (including revisions) of this Agreement from time to time. No one other than the Agreement Steward has the right to modify this Agreement. The Eclipse Foundation is the initial Agreement Steward. The Eclipse Foundation may assign the responsibility to serve as the Agreement Steward to a suitable separate entity. Each new version of the Agreement will be given a distinguishing version number. The Program (including Contributions) may always be distributed subject to the version of the Agreement under which it was received. In addition, after a new version of the Agreement is published, Contributor may elect to distribute the Program (including its Contributions) under the new version. Except as expressly stated in Sections 2(a) and 2(b) above, Recipient receives no rights or licenses to the intellectual property of any Contributor under this Agreement, whether expressly, by implication, estoppel or otherwise. All rights in the Program not expressly granted under this Agreement are reserved. - -This Agreement is governed by the laws of the State of New York and the intellectual property laws of the United States of America. No party to this Agreement will bring a legal action under this Agreement more than one year after the cause of action arose. Each party waives its rights to a jury trial in any resulting litigation. -========== -Notice for: org.eclipse.core:org.eclipse.core.jobs-3.5.100 ----------- - -Copyright © Eclipse Foundation, Inc. All Rights Reserved. - -Eclipse Public License - v 1.0 -THE ACCOMPANYING PROGRAM IS PROVIDED UNDER THE TERMS OF THIS ECLIPSE PUBLIC LICENSE ("AGREEMENT"). ANY USE, REPRODUCTION OR DISTRIBUTION OF THE PROGRAM CONSTITUTES RECIPIENT'S ACCEPTANCE OF THIS AGREEMENT. - -1. DEFINITIONS - -"Contribution" means: - -a) in the case of the initial Contributor, the initial code and documentation distributed under this Agreement, and - -b) in the case of each subsequent Contributor: - -i) changes to the Program, and - -ii) additions to the Program; - -where such changes and/or additions to the Program originate from and are distributed by that particular Contributor. A Contribution 'originates' from a Contributor if it was added to the Program by such Contributor itself or anyone acting on such Contributor's behalf. Contributions do not include additions to the Program which: (i) are separate modules of software distributed in conjunction with the Program under their own license agreement, and (ii) are not derivative works of the Program. - -"Contributor" means any person or entity that distributes the Program. - -"Licensed Patents" mean patent claims licensable by a Contributor which are necessarily infringed by the use or sale of its Contribution alone or when combined with the Program. - -"Program" means the Contributions distributed in accordance with this Agreement. - -"Recipient" means anyone who receives the Program under this Agreement, including all Contributors. - -2. GRANT OF RIGHTS - -a) Subject to the terms of this Agreement, each Contributor hereby grants Recipient a non-exclusive, worldwide, royalty-free copyright license to reproduce, prepare derivative works of, publicly display, publicly perform, distribute and sublicense the Contribution of such Contributor, if any, and such derivative works, in source code and object code form. - -b) Subject to the terms of this Agreement, each Contributor hereby grants Recipient a non-exclusive, worldwide, royalty-free patent license under Licensed Patents to make, use, sell, offer to sell, import and otherwise transfer the Contribution of such Contributor, if any, in source code and object code form. This patent license shall apply to the combination of the Contribution and the Program if, at the time the Contribution is added by the Contributor, such addition of the Contribution causes such combination to be covered by the Licensed Patents. The patent license shall not apply to any other combinations which include the Contribution. No hardware per se is licensed hereunder. - -c) Recipient understands that although each Contributor grants the licenses to its Contributions set forth herein, no assurances are provided by any Contributor that the Program does not infringe the patent or other intellectual property rights of any other entity. Each Contributor disclaims any liability to Recipient for claims brought by any other entity based on infringement of intellectual property rights or otherwise. As a condition to exercising the rights and licenses granted hereunder, each Recipient hereby assumes sole responsibility to secure any other intellectual property rights needed, if any. For example, if a third party patent license is required to allow Recipient to distribute the Program, it is Recipient's responsibility to acquire that license before distributing the Program. - -d) Each Contributor represents that to its knowledge it has sufficient copyright rights in its Contribution, if any, to grant the copyright license set forth in this Agreement. - -3. REQUIREMENTS - -A Contributor may choose to distribute the Program in object code form under its own license agreement, provided that: - -a) it complies with the terms and conditions of this Agreement; and - -b) its license agreement: - -i) effectively disclaims on behalf of all Contributors all warranties and conditions, express and implied, including warranties or conditions of title and non-infringement, and implied warranties or conditions of merchantability and fitness for a particular purpose; - -ii) effectively excludes on behalf of all Contributors all liability for damages, including direct, indirect, special, incidental and consequential damages, such as lost profits; - -iii) states that any provisions which differ from this Agreement are offered by that Contributor alone and not by any other party; and - -iv) states that source code for the Program is available from such Contributor, and informs licensees how to obtain it in a reasonable manner on or through a medium customarily used for software exchange. - -When the Program is made available in source code form: - -a) it must be made available under this Agreement; and - -b) a copy of this Agreement must be included with each copy of the Program. - -Contributors may not remove or alter any copyright notices contained within the Program. - -Each Contributor must identify itself as the originator of its Contribution, if any, in a manner that reasonably allows subsequent Recipients to identify the originator of the Contribution. - -4. COMMERCIAL DISTRIBUTION - -Commercial distributors of software may accept certain responsibilities with respect to end users, business partners and the like. While this license is intended to facilitate the commercial use of the Program, the Contributor who includes the Program in a commercial product offering should do so in a manner which does not create potential liability for other Contributors. Therefore, if a Contributor includes the Program in a commercial product offering, such Contributor ("Commercial Contributor") hereby agrees to defend and indemnify every other Contributor ("Indemnified Contributor") against any losses, damages and costs (collectively "Losses") arising from claims, lawsuits and other legal actions brought by a third party against the Indemnified Contributor to the extent caused by the acts or omissions of such Commercial Contributor in connection with its distribution of the Program in a commercial product offering. The obligations in this section do not apply to any claims or Losses relating to any actual or alleged intellectual property infringement. In order to qualify, an Indemnified Contributor must: a) promptly notify the Commercial Contributor in writing of such claim, and b) allow the Commercial Contributor to control, and cooperate with the Commercial Contributor in, the defense and any related settlement negotiations. The Indemnified Contributor may participate in any such claim at its own expense. - -For example, a Contributor might include the Program in a commercial product offering, Product X. That Contributor is then a Commercial Contributor. If that Commercial Contributor then makes performance claims, or offers warranties related to Product X, those performance claims and warranties are such Commercial Contributor's responsibility alone. Under this section, the Commercial Contributor would have to defend claims against the other Contributors related to those performance claims and warranties, and if a court requires any other Contributor to pay any damages as a result, the Commercial Contributor must pay those damages. - -5. NO WARRANTY - -EXCEPT AS EXPRESSLY SET FORTH IN THIS AGREEMENT, THE PROGRAM IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED INCLUDING, WITHOUT LIMITATION, ANY WARRANTIES OR CONDITIONS OF TITLE, NON-INFRINGEMENT, MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE. Each Recipient is solely responsible for determining the appropriateness of using and distributing the Program and assumes all risks associated with its exercise of rights under this Agreement , including but not limited to the risks and costs of program errors, compliance with applicable laws, damage to or loss of data, programs or equipment, and unavailability or interruption of operations. - -6. DISCLAIMER OF LIABILITY - -EXCEPT AS EXPRESSLY SET FORTH IN THIS AGREEMENT, NEITHER RECIPIENT NOR ANY CONTRIBUTORS SHALL HAVE ANY LIABILITY FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING WITHOUT LIMITATION LOST PROFITS), HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OR DISTRIBUTION OF THE PROGRAM OR THE EXERCISE OF ANY RIGHTS GRANTED HEREUNDER, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGES. - -7. GENERAL - -If any provision of this Agreement is invalid or unenforceable under applicable law, it shall not affect the validity or enforceability of the remainder of the terms of this Agreement, and without further action by the parties hereto, such provision shall be reformed to the minimum extent necessary to make such provision valid and enforceable. - -If Recipient institutes patent litigation against any entity (including a cross-claim or counterclaim in a lawsuit) alleging that the Program itself (excluding combinations of the Program with other software or hardware) infringes such Recipient's patent(s), then such Recipient's rights granted under Section 2(b) shall terminate as of the date such litigation is filed. - -All Recipient's rights under this Agreement shall terminate if it fails to comply with any of the material terms or conditions of this Agreement and does not cure such failure in a reasonable period of time after becoming aware of such noncompliance. If all Recipient's rights under this Agreement terminate, Recipient agrees to cease use and distribution of the Program as soon as reasonably practicable. However, Recipient's obligations under this Agreement and any licenses granted by Recipient relating to the Program shall continue and survive. - -Everyone is permitted to copy and distribute copies of this Agreement, but in order to avoid inconsistency the Agreement is copyrighted and may only be modified in the following manner. The Agreement Steward reserves the right to publish new versions (including revisions) of this Agreement from time to time. No one other than the Agreement Steward has the right to modify this Agreement. The Eclipse Foundation is the initial Agreement Steward. The Eclipse Foundation may assign the responsibility to serve as the Agreement Steward to a suitable separate entity. Each new version of the Agreement will be given a distinguishing version number. The Program (including Contributions) may always be distributed subject to the version of the Agreement under which it was received. In addition, after a new version of the Agreement is published, Contributor may elect to distribute the Program (including its Contributions) under the new version. Except as expressly stated in Sections 2(a) and 2(b) above, Recipient receives no rights or licenses to the intellectual property of any Contributor under this Agreement, whether expressly, by implication, estoppel or otherwise. All rights in the Program not expressly granted under this Agreement are reserved. - -This Agreement is governed by the laws of the State of New York and the intellectual property laws of the United States of America. No party to this Agreement will bring a legal action under this Agreement more than one year after the cause of action arose. Each party waives its rights to a jury trial in any resulting litigation. -========== -Notice for: org.eclipse.core:org.eclipse.core.resources-3.7.100 ----------- - -Copyright © Eclipse Foundation, Inc. All Rights Reserved. - -Eclipse Public License - v 1.0 -THE ACCOMPANYING PROGRAM IS PROVIDED UNDER THE TERMS OF THIS ECLIPSE PUBLIC LICENSE ("AGREEMENT"). ANY USE, REPRODUCTION OR DISTRIBUTION OF THE PROGRAM CONSTITUTES RECIPIENT'S ACCEPTANCE OF THIS AGREEMENT. - -1. DEFINITIONS - -"Contribution" means: - -a) in the case of the initial Contributor, the initial code and documentation distributed under this Agreement, and - -b) in the case of each subsequent Contributor: - -i) changes to the Program, and - -ii) additions to the Program; - -where such changes and/or additions to the Program originate from and are distributed by that particular Contributor. A Contribution 'originates' from a Contributor if it was added to the Program by such Contributor itself or anyone acting on such Contributor's behalf. Contributions do not include additions to the Program which: (i) are separate modules of software distributed in conjunction with the Program under their own license agreement, and (ii) are not derivative works of the Program. - -"Contributor" means any person or entity that distributes the Program. - -"Licensed Patents" mean patent claims licensable by a Contributor which are necessarily infringed by the use or sale of its Contribution alone or when combined with the Program. - -"Program" means the Contributions distributed in accordance with this Agreement. - -"Recipient" means anyone who receives the Program under this Agreement, including all Contributors. - -2. GRANT OF RIGHTS - -a) Subject to the terms of this Agreement, each Contributor hereby grants Recipient a non-exclusive, worldwide, royalty-free copyright license to reproduce, prepare derivative works of, publicly display, publicly perform, distribute and sublicense the Contribution of such Contributor, if any, and such derivative works, in source code and object code form. - -b) Subject to the terms of this Agreement, each Contributor hereby grants Recipient a non-exclusive, worldwide, royalty-free patent license under Licensed Patents to make, use, sell, offer to sell, import and otherwise transfer the Contribution of such Contributor, if any, in source code and object code form. This patent license shall apply to the combination of the Contribution and the Program if, at the time the Contribution is added by the Contributor, such addition of the Contribution causes such combination to be covered by the Licensed Patents. The patent license shall not apply to any other combinations which include the Contribution. No hardware per se is licensed hereunder. - -c) Recipient understands that although each Contributor grants the licenses to its Contributions set forth herein, no assurances are provided by any Contributor that the Program does not infringe the patent or other intellectual property rights of any other entity. Each Contributor disclaims any liability to Recipient for claims brought by any other entity based on infringement of intellectual property rights or otherwise. As a condition to exercising the rights and licenses granted hereunder, each Recipient hereby assumes sole responsibility to secure any other intellectual property rights needed, if any. For example, if a third party patent license is required to allow Recipient to distribute the Program, it is Recipient's responsibility to acquire that license before distributing the Program. - -d) Each Contributor represents that to its knowledge it has sufficient copyright rights in its Contribution, if any, to grant the copyright license set forth in this Agreement. - -3. REQUIREMENTS - -A Contributor may choose to distribute the Program in object code form under its own license agreement, provided that: - -a) it complies with the terms and conditions of this Agreement; and - -b) its license agreement: - -i) effectively disclaims on behalf of all Contributors all warranties and conditions, express and implied, including warranties or conditions of title and non-infringement, and implied warranties or conditions of merchantability and fitness for a particular purpose; - -ii) effectively excludes on behalf of all Contributors all liability for damages, including direct, indirect, special, incidental and consequential damages, such as lost profits; - -iii) states that any provisions which differ from this Agreement are offered by that Contributor alone and not by any other party; and - -iv) states that source code for the Program is available from such Contributor, and informs licensees how to obtain it in a reasonable manner on or through a medium customarily used for software exchange. - -When the Program is made available in source code form: - -a) it must be made available under this Agreement; and - -b) a copy of this Agreement must be included with each copy of the Program. - -Contributors may not remove or alter any copyright notices contained within the Program. - -Each Contributor must identify itself as the originator of its Contribution, if any, in a manner that reasonably allows subsequent Recipients to identify the originator of the Contribution. - -4. COMMERCIAL DISTRIBUTION - -Commercial distributors of software may accept certain responsibilities with respect to end users, business partners and the like. While this license is intended to facilitate the commercial use of the Program, the Contributor who includes the Program in a commercial product offering should do so in a manner which does not create potential liability for other Contributors. Therefore, if a Contributor includes the Program in a commercial product offering, such Contributor ("Commercial Contributor") hereby agrees to defend and indemnify every other Contributor ("Indemnified Contributor") against any losses, damages and costs (collectively "Losses") arising from claims, lawsuits and other legal actions brought by a third party against the Indemnified Contributor to the extent caused by the acts or omissions of such Commercial Contributor in connection with its distribution of the Program in a commercial product offering. The obligations in this section do not apply to any claims or Losses relating to any actual or alleged intellectual property infringement. In order to qualify, an Indemnified Contributor must: a) promptly notify the Commercial Contributor in writing of such claim, and b) allow the Commercial Contributor to control, and cooperate with the Commercial Contributor in, the defense and any related settlement negotiations. The Indemnified Contributor may participate in any such claim at its own expense. - -For example, a Contributor might include the Program in a commercial product offering, Product X. That Contributor is then a Commercial Contributor. If that Commercial Contributor then makes performance claims, or offers warranties related to Product X, those performance claims and warranties are such Commercial Contributor's responsibility alone. Under this section, the Commercial Contributor would have to defend claims against the other Contributors related to those performance claims and warranties, and if a court requires any other Contributor to pay any damages as a result, the Commercial Contributor must pay those damages. - -5. NO WARRANTY - -EXCEPT AS EXPRESSLY SET FORTH IN THIS AGREEMENT, THE PROGRAM IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED INCLUDING, WITHOUT LIMITATION, ANY WARRANTIES OR CONDITIONS OF TITLE, NON-INFRINGEMENT, MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE. Each Recipient is solely responsible for determining the appropriateness of using and distributing the Program and assumes all risks associated with its exercise of rights under this Agreement , including but not limited to the risks and costs of program errors, compliance with applicable laws, damage to or loss of data, programs or equipment, and unavailability or interruption of operations. - -6. DISCLAIMER OF LIABILITY - -EXCEPT AS EXPRESSLY SET FORTH IN THIS AGREEMENT, NEITHER RECIPIENT NOR ANY CONTRIBUTORS SHALL HAVE ANY LIABILITY FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING WITHOUT LIMITATION LOST PROFITS), HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OR DISTRIBUTION OF THE PROGRAM OR THE EXERCISE OF ANY RIGHTS GRANTED HEREUNDER, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGES. - -7. GENERAL - -If any provision of this Agreement is invalid or unenforceable under applicable law, it shall not affect the validity or enforceability of the remainder of the terms of this Agreement, and without further action by the parties hereto, such provision shall be reformed to the minimum extent necessary to make such provision valid and enforceable. - -If Recipient institutes patent litigation against any entity (including a cross-claim or counterclaim in a lawsuit) alleging that the Program itself (excluding combinations of the Program with other software or hardware) infringes such Recipient's patent(s), then such Recipient's rights granted under Section 2(b) shall terminate as of the date such litigation is filed. - -All Recipient's rights under this Agreement shall terminate if it fails to comply with any of the material terms or conditions of this Agreement and does not cure such failure in a reasonable period of time after becoming aware of such noncompliance. If all Recipient's rights under this Agreement terminate, Recipient agrees to cease use and distribution of the Program as soon as reasonably practicable. However, Recipient's obligations under this Agreement and any licenses granted by Recipient relating to the Program shall continue and survive. - -Everyone is permitted to copy and distribute copies of this Agreement, but in order to avoid inconsistency the Agreement is copyrighted and may only be modified in the following manner. The Agreement Steward reserves the right to publish new versions (including revisions) of this Agreement from time to time. No one other than the Agreement Steward has the right to modify this Agreement. The Eclipse Foundation is the initial Agreement Steward. The Eclipse Foundation may assign the responsibility to serve as the Agreement Steward to a suitable separate entity. Each new version of the Agreement will be given a distinguishing version number. The Program (including Contributions) may always be distributed subject to the version of the Agreement under which it was received. In addition, after a new version of the Agreement is published, Contributor may elect to distribute the Program (including its Contributions) under the new version. Except as expressly stated in Sections 2(a) and 2(b) above, Recipient receives no rights or licenses to the intellectual property of any Contributor under this Agreement, whether expressly, by implication, estoppel or otherwise. All rights in the Program not expressly granted under this Agreement are reserved. - -This Agreement is governed by the laws of the State of New York and the intellectual property laws of the United States of America. No party to this Agreement will bring a legal action under this Agreement more than one year after the cause of action arose. Each party waives its rights to a jury trial in any resulting litigation. -========== -Notice for: org.eclipse.core:org.eclipse.core.runtime-3.7.0 ----------- - -Copyright © Eclipse Foundation, Inc. All Rights Reserved. - -Eclipse Public License - v 1.0 -THE ACCOMPANYING PROGRAM IS PROVIDED UNDER THE TERMS OF THIS ECLIPSE PUBLIC LICENSE ("AGREEMENT"). ANY USE, REPRODUCTION OR DISTRIBUTION OF THE PROGRAM CONSTITUTES RECIPIENT'S ACCEPTANCE OF THIS AGREEMENT. - -1. DEFINITIONS - -"Contribution" means: - -a) in the case of the initial Contributor, the initial code and documentation distributed under this Agreement, and - -b) in the case of each subsequent Contributor: - -i) changes to the Program, and - -ii) additions to the Program; - -where such changes and/or additions to the Program originate from and are distributed by that particular Contributor. A Contribution 'originates' from a Contributor if it was added to the Program by such Contributor itself or anyone acting on such Contributor's behalf. Contributions do not include additions to the Program which: (i) are separate modules of software distributed in conjunction with the Program under their own license agreement, and (ii) are not derivative works of the Program. - -"Contributor" means any person or entity that distributes the Program. - -"Licensed Patents" mean patent claims licensable by a Contributor which are necessarily infringed by the use or sale of its Contribution alone or when combined with the Program. - -"Program" means the Contributions distributed in accordance with this Agreement. - -"Recipient" means anyone who receives the Program under this Agreement, including all Contributors. - -2. GRANT OF RIGHTS - -a) Subject to the terms of this Agreement, each Contributor hereby grants Recipient a non-exclusive, worldwide, royalty-free copyright license to reproduce, prepare derivative works of, publicly display, publicly perform, distribute and sublicense the Contribution of such Contributor, if any, and such derivative works, in source code and object code form. - -b) Subject to the terms of this Agreement, each Contributor hereby grants Recipient a non-exclusive, worldwide, royalty-free patent license under Licensed Patents to make, use, sell, offer to sell, import and otherwise transfer the Contribution of such Contributor, if any, in source code and object code form. This patent license shall apply to the combination of the Contribution and the Program if, at the time the Contribution is added by the Contributor, such addition of the Contribution causes such combination to be covered by the Licensed Patents. The patent license shall not apply to any other combinations which include the Contribution. No hardware per se is licensed hereunder. - -c) Recipient understands that although each Contributor grants the licenses to its Contributions set forth herein, no assurances are provided by any Contributor that the Program does not infringe the patent or other intellectual property rights of any other entity. Each Contributor disclaims any liability to Recipient for claims brought by any other entity based on infringement of intellectual property rights or otherwise. As a condition to exercising the rights and licenses granted hereunder, each Recipient hereby assumes sole responsibility to secure any other intellectual property rights needed, if any. For example, if a third party patent license is required to allow Recipient to distribute the Program, it is Recipient's responsibility to acquire that license before distributing the Program. - -d) Each Contributor represents that to its knowledge it has sufficient copyright rights in its Contribution, if any, to grant the copyright license set forth in this Agreement. - -3. REQUIREMENTS - -A Contributor may choose to distribute the Program in object code form under its own license agreement, provided that: - -a) it complies with the terms and conditions of this Agreement; and - -b) its license agreement: - -i) effectively disclaims on behalf of all Contributors all warranties and conditions, express and implied, including warranties or conditions of title and non-infringement, and implied warranties or conditions of merchantability and fitness for a particular purpose; - -ii) effectively excludes on behalf of all Contributors all liability for damages, including direct, indirect, special, incidental and consequential damages, such as lost profits; - -iii) states that any provisions which differ from this Agreement are offered by that Contributor alone and not by any other party; and - -iv) states that source code for the Program is available from such Contributor, and informs licensees how to obtain it in a reasonable manner on or through a medium customarily used for software exchange. - -When the Program is made available in source code form: - -a) it must be made available under this Agreement; and - -b) a copy of this Agreement must be included with each copy of the Program. - -Contributors may not remove or alter any copyright notices contained within the Program. - -Each Contributor must identify itself as the originator of its Contribution, if any, in a manner that reasonably allows subsequent Recipients to identify the originator of the Contribution. - -4. COMMERCIAL DISTRIBUTION - -Commercial distributors of software may accept certain responsibilities with respect to end users, business partners and the like. While this license is intended to facilitate the commercial use of the Program, the Contributor who includes the Program in a commercial product offering should do so in a manner which does not create potential liability for other Contributors. Therefore, if a Contributor includes the Program in a commercial product offering, such Contributor ("Commercial Contributor") hereby agrees to defend and indemnify every other Contributor ("Indemnified Contributor") against any losses, damages and costs (collectively "Losses") arising from claims, lawsuits and other legal actions brought by a third party against the Indemnified Contributor to the extent caused by the acts or omissions of such Commercial Contributor in connection with its distribution of the Program in a commercial product offering. The obligations in this section do not apply to any claims or Losses relating to any actual or alleged intellectual property infringement. In order to qualify, an Indemnified Contributor must: a) promptly notify the Commercial Contributor in writing of such claim, and b) allow the Commercial Contributor to control, and cooperate with the Commercial Contributor in, the defense and any related settlement negotiations. The Indemnified Contributor may participate in any such claim at its own expense. - -For example, a Contributor might include the Program in a commercial product offering, Product X. That Contributor is then a Commercial Contributor. If that Commercial Contributor then makes performance claims, or offers warranties related to Product X, those performance claims and warranties are such Commercial Contributor's responsibility alone. Under this section, the Commercial Contributor would have to defend claims against the other Contributors related to those performance claims and warranties, and if a court requires any other Contributor to pay any damages as a result, the Commercial Contributor must pay those damages. - -5. NO WARRANTY - -EXCEPT AS EXPRESSLY SET FORTH IN THIS AGREEMENT, THE PROGRAM IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED INCLUDING, WITHOUT LIMITATION, ANY WARRANTIES OR CONDITIONS OF TITLE, NON-INFRINGEMENT, MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE. Each Recipient is solely responsible for determining the appropriateness of using and distributing the Program and assumes all risks associated with its exercise of rights under this Agreement , including but not limited to the risks and costs of program errors, compliance with applicable laws, damage to or loss of data, programs or equipment, and unavailability or interruption of operations. - -6. DISCLAIMER OF LIABILITY - -EXCEPT AS EXPRESSLY SET FORTH IN THIS AGREEMENT, NEITHER RECIPIENT NOR ANY CONTRIBUTORS SHALL HAVE ANY LIABILITY FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING WITHOUT LIMITATION LOST PROFITS), HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OR DISTRIBUTION OF THE PROGRAM OR THE EXERCISE OF ANY RIGHTS GRANTED HEREUNDER, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGES. - -7. GENERAL - -If any provision of this Agreement is invalid or unenforceable under applicable law, it shall not affect the validity or enforceability of the remainder of the terms of this Agreement, and without further action by the parties hereto, such provision shall be reformed to the minimum extent necessary to make such provision valid and enforceable. - -If Recipient institutes patent litigation against any entity (including a cross-claim or counterclaim in a lawsuit) alleging that the Program itself (excluding combinations of the Program with other software or hardware) infringes such Recipient's patent(s), then such Recipient's rights granted under Section 2(b) shall terminate as of the date such litigation is filed. - -All Recipient's rights under this Agreement shall terminate if it fails to comply with any of the material terms or conditions of this Agreement and does not cure such failure in a reasonable period of time after becoming aware of such noncompliance. If all Recipient's rights under this Agreement terminate, Recipient agrees to cease use and distribution of the Program as soon as reasonably practicable. However, Recipient's obligations under this Agreement and any licenses granted by Recipient relating to the Program shall continue and survive. - -Everyone is permitted to copy and distribute copies of this Agreement, but in order to avoid inconsistency the Agreement is copyrighted and may only be modified in the following manner. The Agreement Steward reserves the right to publish new versions (including revisions) of this Agreement from time to time. No one other than the Agreement Steward has the right to modify this Agreement. The Eclipse Foundation is the initial Agreement Steward. The Eclipse Foundation may assign the responsibility to serve as the Agreement Steward to a suitable separate entity. Each new version of the Agreement will be given a distinguishing version number. The Program (including Contributions) may always be distributed subject to the version of the Agreement under which it was received. In addition, after a new version of the Agreement is published, Contributor may elect to distribute the Program (including its Contributions) under the new version. Except as expressly stated in Sections 2(a) and 2(b) above, Recipient receives no rights or licenses to the intellectual property of any Contributor under this Agreement, whether expressly, by implication, estoppel or otherwise. All rights in the Program not expressly granted under this Agreement are reserved. - -This Agreement is governed by the laws of the State of New York and the intellectual property laws of the United States of America. No party to this Agreement will bring a legal action under this Agreement more than one year after the cause of action arose. Each party waives its rights to a jury trial in any resulting litigation. -========== -Notice for: org.eclipse.equinox:org.eclipse.equinox.app-1.3.100 ----------- - - Copyright (c) 2012 Eclipse Foundation. - All rights reserved. This program and the accompanying materials - are made available under the terms of the Eclipse Distribution License v1.0 - which accompanies this distribution, and is available at - http://www.eclipse.org/org/documents/edl-v10.php -========== -Notice for: org.eclipse.equinox:org.eclipse.equinox.common-3.6.0 ----------- - - Copyright (c) 2012 Eclipse Foundation. - All rights reserved. This program and the accompanying materials - are made available under the terms of the Eclipse Distribution License v1.0 - which accompanies this distribution, and is available at - http://www.eclipse.org/org/documents/edl-v10.php -========== -Notice for: org.eclipse.equinox:org.eclipse.equinox.preferences-3.4.1 ----------- - - Copyright (c) 2012 Eclipse Foundation. - All rights reserved. This program and the accompanying materials - are made available under the terms of the Eclipse Distribution License v1.0 - which accompanies this distribution, and is available at - http://www.eclipse.org/org/documents/edl-v10.php -========== -Notice for: org.eclipse.equinox:org.eclipse.equinox.registry-3.5.101 ----------- - - Copyright (c) 2012 Eclipse Foundation. - All rights reserved. This program and the accompanying materials - are made available under the terms of the Eclipse Distribution License v1.0 - which accompanies this distribution, and is available at - http://www.eclipse.org/org/documents/edl-v10.php -========== -Notice for: org.eclipse.jdt:org.eclipse.jdt.core-3.10.0 ----------- - - Copyright (c) 2012, 2016 Eclipse Foundation and others. - All rights reserved. This program and the accompanying materials - are made available under the terms of the Eclipse Distribution License v1.0 - which accompanies this distribution, and is available at - http://www.eclipse.org/org/documents/edl-v10.php -========== -Notice for: org.eclipse.osgi:org.eclipse.osgi-3.7.1 ----------- - - Copyright (c) 2012, 2017 Eclipse Foundation. - All rights reserved. This program and the accompanying materials - are made available under the terms of the Eclipse Distribution License v1.0 - which accompanies this distribution, and is available at - http://www.eclipse.org/org/documents/edl-v10.php -========== -Notice for: org.eclipse.text:org.eclipse.text-3.5.101 ----------- - -Copyright © Eclipse Foundation, Inc. All Rights Reserved. - -Eclipse Public License - v 1.0 -THE ACCOMPANYING PROGRAM IS PROVIDED UNDER THE TERMS OF THIS ECLIPSE PUBLIC LICENSE ("AGREEMENT"). ANY USE, REPRODUCTION OR DISTRIBUTION OF THE PROGRAM CONSTITUTES RECIPIENT'S ACCEPTANCE OF THIS AGREEMENT. - -1. DEFINITIONS - -"Contribution" means: - -a) in the case of the initial Contributor, the initial code and documentation distributed under this Agreement, and - -b) in the case of each subsequent Contributor: - -i) changes to the Program, and - -ii) additions to the Program; - -where such changes and/or additions to the Program originate from and are distributed by that particular Contributor. A Contribution 'originates' from a Contributor if it was added to the Program by such Contributor itself or anyone acting on such Contributor's behalf. Contributions do not include additions to the Program which: (i) are separate modules of software distributed in conjunction with the Program under their own license agreement, and (ii) are not derivative works of the Program. - -"Contributor" means any person or entity that distributes the Program. - -"Licensed Patents" mean patent claims licensable by a Contributor which are necessarily infringed by the use or sale of its Contribution alone or when combined with the Program. - -"Program" means the Contributions distributed in accordance with this Agreement. - -"Recipient" means anyone who receives the Program under this Agreement, including all Contributors. - -2. GRANT OF RIGHTS - -a) Subject to the terms of this Agreement, each Contributor hereby grants Recipient a non-exclusive, worldwide, royalty-free copyright license to reproduce, prepare derivative works of, publicly display, publicly perform, distribute and sublicense the Contribution of such Contributor, if any, and such derivative works, in source code and object code form. - -b) Subject to the terms of this Agreement, each Contributor hereby grants Recipient a non-exclusive, worldwide, royalty-free patent license under Licensed Patents to make, use, sell, offer to sell, import and otherwise transfer the Contribution of such Contributor, if any, in source code and object code form. This patent license shall apply to the combination of the Contribution and the Program if, at the time the Contribution is added by the Contributor, such addition of the Contribution causes such combination to be covered by the Licensed Patents. The patent license shall not apply to any other combinations which include the Contribution. No hardware per se is licensed hereunder. - -c) Recipient understands that although each Contributor grants the licenses to its Contributions set forth herein, no assurances are provided by any Contributor that the Program does not infringe the patent or other intellectual property rights of any other entity. Each Contributor disclaims any liability to Recipient for claims brought by any other entity based on infringement of intellectual property rights or otherwise. As a condition to exercising the rights and licenses granted hereunder, each Recipient hereby assumes sole responsibility to secure any other intellectual property rights needed, if any. For example, if a third party patent license is required to allow Recipient to distribute the Program, it is Recipient's responsibility to acquire that license before distributing the Program. - -d) Each Contributor represents that to its knowledge it has sufficient copyright rights in its Contribution, if any, to grant the copyright license set forth in this Agreement. - -3. REQUIREMENTS - -A Contributor may choose to distribute the Program in object code form under its own license agreement, provided that: - -a) it complies with the terms and conditions of this Agreement; and - -b) its license agreement: - -i) effectively disclaims on behalf of all Contributors all warranties and conditions, express and implied, including warranties or conditions of title and non-infringement, and implied warranties or conditions of merchantability and fitness for a particular purpose; - -ii) effectively excludes on behalf of all Contributors all liability for damages, including direct, indirect, special, incidental and consequential damages, such as lost profits; - -iii) states that any provisions which differ from this Agreement are offered by that Contributor alone and not by any other party; and - -iv) states that source code for the Program is available from such Contributor, and informs licensees how to obtain it in a reasonable manner on or through a medium customarily used for software exchange. - -When the Program is made available in source code form: - -a) it must be made available under this Agreement; and - -b) a copy of this Agreement must be included with each copy of the Program. - -Contributors may not remove or alter any copyright notices contained within the Program. - -Each Contributor must identify itself as the originator of its Contribution, if any, in a manner that reasonably allows subsequent Recipients to identify the originator of the Contribution. - -4. COMMERCIAL DISTRIBUTION - -Commercial distributors of software may accept certain responsibilities with respect to end users, business partners and the like. While this license is intended to facilitate the commercial use of the Program, the Contributor who includes the Program in a commercial product offering should do so in a manner which does not create potential liability for other Contributors. Therefore, if a Contributor includes the Program in a commercial product offering, such Contributor ("Commercial Contributor") hereby agrees to defend and indemnify every other Contributor ("Indemnified Contributor") against any losses, damages and costs (collectively "Losses") arising from claims, lawsuits and other legal actions brought by a third party against the Indemnified Contributor to the extent caused by the acts or omissions of such Commercial Contributor in connection with its distribution of the Program in a commercial product offering. The obligations in this section do not apply to any claims or Losses relating to any actual or alleged intellectual property infringement. In order to qualify, an Indemnified Contributor must: a) promptly notify the Commercial Contributor in writing of such claim, and b) allow the Commercial Contributor to control, and cooperate with the Commercial Contributor in, the defense and any related settlement negotiations. The Indemnified Contributor may participate in any such claim at its own expense. - -For example, a Contributor might include the Program in a commercial product offering, Product X. That Contributor is then a Commercial Contributor. If that Commercial Contributor then makes performance claims, or offers warranties related to Product X, those performance claims and warranties are such Commercial Contributor's responsibility alone. Under this section, the Commercial Contributor would have to defend claims against the other Contributors related to those performance claims and warranties, and if a court requires any other Contributor to pay any damages as a result, the Commercial Contributor must pay those damages. - -5. NO WARRANTY - -EXCEPT AS EXPRESSLY SET FORTH IN THIS AGREEMENT, THE PROGRAM IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED INCLUDING, WITHOUT LIMITATION, ANY WARRANTIES OR CONDITIONS OF TITLE, NON-INFRINGEMENT, MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE. Each Recipient is solely responsible for determining the appropriateness of using and distributing the Program and assumes all risks associated with its exercise of rights under this Agreement , including but not limited to the risks and costs of program errors, compliance with applicable laws, damage to or loss of data, programs or equipment, and unavailability or interruption of operations. - -6. DISCLAIMER OF LIABILITY - -EXCEPT AS EXPRESSLY SET FORTH IN THIS AGREEMENT, NEITHER RECIPIENT NOR ANY CONTRIBUTORS SHALL HAVE ANY LIABILITY FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING WITHOUT LIMITATION LOST PROFITS), HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OR DISTRIBUTION OF THE PROGRAM OR THE EXERCISE OF ANY RIGHTS GRANTED HEREUNDER, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGES. - -7. GENERAL - -If any provision of this Agreement is invalid or unenforceable under applicable law, it shall not affect the validity or enforceability of the remainder of the terms of this Agreement, and without further action by the parties hereto, such provision shall be reformed to the minimum extent necessary to make such provision valid and enforceable. - -If Recipient institutes patent litigation against any entity (including a cross-claim or counterclaim in a lawsuit) alleging that the Program itself (excluding combinations of the Program with other software or hardware) infringes such Recipient's patent(s), then such Recipient's rights granted under Section 2(b) shall terminate as of the date such litigation is filed. - -All Recipient's rights under this Agreement shall terminate if it fails to comply with any of the material terms or conditions of this Agreement and does not cure such failure in a reasonable period of time after becoming aware of such noncompliance. If all Recipient's rights under this Agreement terminate, Recipient agrees to cease use and distribution of the Program as soon as reasonably practicable. However, Recipient's obligations under this Agreement and any licenses granted by Recipient relating to the Program shall continue and survive. - -Everyone is permitted to copy and distribute copies of this Agreement, but in order to avoid inconsistency the Agreement is copyrighted and may only be modified in the following manner. The Agreement Steward reserves the right to publish new versions (including revisions) of this Agreement from time to time. No one other than the Agreement Steward has the right to modify this Agreement. The Eclipse Foundation is the initial Agreement Steward. The Eclipse Foundation may assign the responsibility to serve as the Agreement Steward to a suitable separate entity. Each new version of the Agreement will be given a distinguishing version number. The Program (including Contributions) may always be distributed subject to the version of the Agreement under which it was received. In addition, after a new version of the Agreement is published, Contributor may elect to distribute the Program (including its Contributions) under the new version. Except as expressly stated in Sections 2(a) and 2(b) above, Recipient receives no rights or licenses to the intellectual property of any Contributor under this Agreement, whether expressly, by implication, estoppel or otherwise. All rights in the Program not expressly granted under this Agreement are reserved. - -This Agreement is governed by the laws of the State of New York and the intellectual property laws of the United States of America. No party to this Agreement will bring a legal action under this Agreement more than one year after the cause of action arose. Each party waives its rights to a jury trial in any resulting litigation. -========== -Notice for: org.javassist:javassist-3.26.0-GA ----------- - -Copyright (C) 1999-2019 by Shigeru Chiba, All rights reserved. - -This software is distributed under the Mozilla Public License Version 1.1, the GNU Lesser General Public License Version 2.1 or later, or the Apache License Version 2.0. - -========== -Notice for: org.jruby:jruby-complete-9.2.9.0 ----------- - -JRuby is Copyright (c) 2007-2018 The JRuby project - -Eclipse Public License - v 2.0 - - THE ACCOMPANYING PROGRAM IS PROVIDED UNDER THE TERMS OF THIS ECLIPSE - PUBLIC LICENSE ("AGREEMENT"). ANY USE, REPRODUCTION OR DISTRIBUTION - OF THE PROGRAM CONSTITUTES RECIPIENT'S ACCEPTANCE OF THIS AGREEMENT. - - 1. DEFINITIONS - - "Contribution" means: - - a) in the case of the initial Contributor, the initial content - Distributed under this Agreement, and - - b) in the case of each subsequent Contributor: - i) changes to the Program, and - ii) additions to the Program; - where such changes and/or additions to the Program originate from - and are Distributed by that particular Contributor. A Contribution - "originates" from a Contributor if it was added to the Program by - such Contributor itself or anyone acting on such Contributor's behalf. - Contributions do not include changes or additions to the Program that - are not Modified Works. - - "Contributor" means any person or entity that Distributes the Program. - - "Licensed Patents" mean patent claims licensable by a Contributor which - are necessarily infringed by the use or sale of its Contribution alone - or when combined with the Program. - - "Program" means the Contributions Distributed in accordance with this - Agreement. - - "Recipient" means anyone who receives the Program under this Agreement - or any Secondary License (as applicable), including Contributors. - - "Derivative Works" shall mean any work, whether in Source Code or other - form, that is based on (or derived from) the Program and for which the - editorial revisions, annotations, elaborations, or other modifications - represent, as a whole, an original work of authorship. - - "Modified Works" shall mean any work in Source Code or other form that - results from an addition to, deletion from, or modification of the - contents of the Program, including, for purposes of clarity any new file - in Source Code form that contains any contents of the Program. Modified - Works shall not include works that contain only declarations, - interfaces, types, classes, structures, or files of the Program solely - in each case in order to link to, bind by name, or subclass the Program - or Modified Works thereof. - - "Distribute" means the acts of a) distributing or b) making available - in any manner that enables the transfer of a copy. - - "Source Code" means the form of a Program preferred for making - modifications, including but not limited to software source code, - documentation source, and configuration files. - - "Secondary License" means either the GNU General Public License, - Version 2.0, or any later versions of that license, including any - exceptions or additional permissions as identified by the initial - Contributor. - - 2. GRANT OF RIGHTS - - a) Subject to the terms of this Agreement, each Contributor hereby - grants Recipient a non-exclusive, worldwide, royalty-free copyright - license to reproduce, prepare Derivative Works of, publicly display, - publicly perform, Distribute and sublicense the Contribution of such - Contributor, if any, and such Derivative Works. - - b) Subject to the terms of this Agreement, each Contributor hereby - grants Recipient a non-exclusive, worldwide, royalty-free patent - license under Licensed Patents to make, use, sell, offer to sell, - import and otherwise transfer the Contribution of such Contributor, - if any, in Source Code or other form. This patent license shall - apply to the combination of the Contribution and the Program if, at - the time the Contribution is added by the Contributor, such addition - of the Contribution causes such combination to be covered by the - Licensed Patents. The patent license shall not apply to any other - combinations which include the Contribution. No hardware per se is - licensed hereunder. - - c) Recipient understands that although each Contributor grants the - licenses to its Contributions set forth herein, no assurances are - provided by any Contributor that the Program does not infringe the - patent or other intellectual property rights of any other entity. - Each Contributor disclaims any liability to Recipient for claims - brought by any other entity based on infringement of intellectual - property rights or otherwise. As a condition to exercising the - rights and licenses granted hereunder, each Recipient hereby - assumes sole responsibility to secure any other intellectual - property rights needed, if any. For example, if a third party - patent license is required to allow Recipient to Distribute the - Program, it is Recipient's responsibility to acquire that license - before distributing the Program. - - d) Each Contributor represents that to its knowledge it has - sufficient copyright rights in its Contribution, if any, to grant - the copyright license set forth in this Agreement. - - e) Notwithstanding the terms of any Secondary License, no - Contributor makes additional grants to any Recipient (other than - those set forth in this Agreement) as a result of such Recipient's - receipt of the Program under the terms of a Secondary License - (if permitted under the terms of Section 3). - - 3. REQUIREMENTS - - 3.1 If a Contributor Distributes the Program in any form, then: - - a) the Program must also be made available as Source Code, in - accordance with section 3.2, and the Contributor must accompany - the Program with a statement that the Source Code for the Program - is available under this Agreement, and informs Recipients how to - obtain it in a reasonable manner on or through a medium customarily - used for software exchange; and - - b) the Contributor may Distribute the Program under a license - different than this Agreement, provided that such license: - i) effectively disclaims on behalf of all other Contributors all - warranties and conditions, express and implied, including - warranties or conditions of title and non-infringement, and - implied warranties or conditions of merchantability and fitness - for a particular purpose; - - ii) effectively excludes on behalf of all other Contributors all - liability for damages, including direct, indirect, special, - incidental and consequential damages, such as lost profits; - - iii) does not attempt to limit or alter the recipients' rights - in the Source Code under section 3.2; and - - iv) requires any subsequent distribution of the Program by any - party to be under a license that satisfies the requirements - of this section 3. - - 3.2 When the Program is Distributed as Source Code: - - a) it must be made available under this Agreement, or if the - Program (i) is combined with other material in a separate file or - files made available under a Secondary License, and (ii) the initial - Contributor attached to the Source Code the notice described in - Exhibit A of this Agreement, then the Program may be made available - under the terms of such Secondary Licenses, and - - b) a copy of this Agreement must be included with each copy of - the Program. - - 3.3 Contributors may not remove or alter any copyright, patent, - trademark, attribution notices, disclaimers of warranty, or limitations - of liability ("notices") contained within the Program from any copy of - the Program which they Distribute, provided that Contributors may add - their own appropriate notices. - - 4. COMMERCIAL DISTRIBUTION - - Commercial distributors of software may accept certain responsibilities - with respect to end users, business partners and the like. While this - license is intended to facilitate the commercial use of the Program, - the Contributor who includes the Program in a commercial product - offering should do so in a manner which does not create potential - liability for other Contributors. Therefore, if a Contributor includes - the Program in a commercial product offering, such Contributor - ("Commercial Contributor") hereby agrees to defend and indemnify every - other Contributor ("Indemnified Contributor") against any losses, - damages and costs (collectively "Losses") arising from claims, lawsuits - and other legal actions brought by a third party against the Indemnified - Contributor to the extent caused by the acts or omissions of such - Commercial Contributor in connection with its distribution of the Program - in a commercial product offering. The obligations in this section do not - apply to any claims or Losses relating to any actual or alleged - intellectual property infringement. In order to qualify, an Indemnified - Contributor must: a) promptly notify the Commercial Contributor in - writing of such claim, and b) allow the Commercial Contributor to control, - and cooperate with the Commercial Contributor in, the defense and any - related settlement negotiations. The Indemnified Contributor may - participate in any such claim at its own expense. - - For example, a Contributor might include the Program in a commercial - product offering, Product X. That Contributor is then a Commercial - Contributor. If that Commercial Contributor then makes performance - claims, or offers warranties related to Product X, those performance - claims and warranties are such Commercial Contributor's responsibility - alone. Under this section, the Commercial Contributor would have to - defend claims against the other Contributors related to those performance - claims and warranties, and if a court requires any other Contributor to - pay any damages as a result, the Commercial Contributor must pay - those damages. - - 5. NO WARRANTY - - EXCEPT AS EXPRESSLY SET FORTH IN THIS AGREEMENT, AND TO THE EXTENT - PERMITTED BY APPLICABLE LAW, THE PROGRAM IS PROVIDED ON AN "AS IS" - BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, EITHER EXPRESS OR - IMPLIED INCLUDING, WITHOUT LIMITATION, ANY WARRANTIES OR CONDITIONS OF - TITLE, NON-INFRINGEMENT, MERCHANTABILITY OR FITNESS FOR A PARTICULAR - PURPOSE. Each Recipient is solely responsible for determining the - appropriateness of using and distributing the Program and assumes all - risks associated with its exercise of rights under this Agreement, - including but not limited to the risks and costs of program errors, - compliance with applicable laws, damage to or loss of data, programs - or equipment, and unavailability or interruption of operations. - - 6. DISCLAIMER OF LIABILITY - - EXCEPT AS EXPRESSLY SET FORTH IN THIS AGREEMENT, AND TO THE EXTENT - PERMITTED BY APPLICABLE LAW, NEITHER RECIPIENT NOR ANY CONTRIBUTORS - SHALL HAVE ANY LIABILITY FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, - EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING WITHOUT LIMITATION LOST - PROFITS), HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN - CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) - ARISING IN ANY WAY OUT OF THE USE OR DISTRIBUTION OF THE PROGRAM OR THE - EXERCISE OF ANY RIGHTS GRANTED HEREUNDER, EVEN IF ADVISED OF THE - POSSIBILITY OF SUCH DAMAGES. - - 7. GENERAL - - If any provision of this Agreement is invalid or unenforceable under - applicable law, it shall not affect the validity or enforceability of - the remainder of the terms of this Agreement, and without further - action by the parties hereto, such provision shall be reformed to the - minimum extent necessary to make such provision valid and enforceable. - - If Recipient institutes patent litigation against any entity - (including a cross-claim or counterclaim in a lawsuit) alleging that the - Program itself (excluding combinations of the Program with other software - or hardware) infringes such Recipient's patent(s), then such Recipient's - rights granted under Section 2(b) shall terminate as of the date such - litigation is filed. - - All Recipient's rights under this Agreement shall terminate if it - fails to comply with any of the material terms or conditions of this - Agreement and does not cure such failure in a reasonable period of - time after becoming aware of such noncompliance. If all Recipient's - rights under this Agreement terminate, Recipient agrees to cease use - and distribution of the Program as soon as reasonably practicable. - However, Recipient's obligations under this Agreement and any licenses - granted by Recipient relating to the Program shall continue and survive. - - Everyone is permitted to copy and distribute copies of this Agreement, - but in order to avoid inconsistency the Agreement is copyrighted and - may only be modified in the following manner. The Agreement Steward - reserves the right to publish new versions (including revisions) of - this Agreement from time to time. No one other than the Agreement - Steward has the right to modify this Agreement. The Eclipse Foundation - is the initial Agreement Steward. The Eclipse Foundation may assign the - responsibility to serve as the Agreement Steward to a suitable separate - entity. Each new version of the Agreement will be given a distinguishing - version number. The Program (including Contributions) may always be - Distributed subject to the version of the Agreement under which it was - received. In addition, after a new version of the Agreement is published, - Contributor may elect to Distribute the Program (including its - Contributions) under the new version. - - Except as expressly stated in Sections 2(a) and 2(b) above, Recipient - receives no rights or licenses to the intellectual property of any - Contributor under this Agreement, whether expressly, by implication, - estoppel or otherwise. All rights in the Program not expressly granted - under this Agreement are reserved. Nothing in this Agreement is intended - to be enforceable by any entity that is not a Contributor or Recipient. - No third-party beneficiary rights are created under this Agreement. - - Exhibit A - Form of Secondary Licenses Notice - - "This Source Code may also be made available under the following - Secondary Licenses when the conditions for such availability set forth - in the Eclipse Public License, v. 2.0 are satisfied: {name license(s), - version(s), and exceptions or additional permissions here}." - - Simply including a copy of this Agreement, including this Exhibit A - is not sufficient to license the Source Code under Secondary Licenses. - - If it is not possible or desirable to put the notice in a particular - file, then You may include the notice in a location (such as a LICENSE - file in a relevant directory) where a recipient would be likely to - look for such a notice. - - You may add additional accurate notices of copyright ownership. -========== -Notice for: org.reflections:reflections-0.9.11 ----------- - - DO WHAT THE FUCK YOU WANT TO PUBLIC LICENSE - Version 2, December 2004 - - Copyright (C) 2004 Sam Hocevar - - Everyone is permitted to copy and distribute verbatim or modified - copies of this license document, and changing it is allowed as long - as the name is changed. - - DO WHAT THE FUCK YOU WANT TO PUBLIC LICENSE - TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION - - 0. You just DO WHAT THE FUCK YOU WANT TO. - -Also licensed under BSD-2-Clause according to https://github.com/ronmamo/reflections/blob/0.9.11/pom.xml#L20-L22 - -========== -Notice for: org.slf4j:slf4j-api-1.7.25 ----------- - -Copyright (c) 2004-2007 QOS.ch -All rights reserved. - -Permission is hereby granted, free of charge, to any person obtaining -a copy of this software and associated documentation files (the -"Software"), to deal in the Software without restriction, including -without limitation the rights to use, copy, modify, merge, publish, -distribute, sublicense, and/or sell copies of the Software, and to -permit persons to whom the Software is furnished to do so, subject to -the following conditions: - -The above copyright notice and this permission notice shall be -included in all copies or substantial portions of the Software. - -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, -EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF -MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND -NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE -LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION -OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION -WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. ========== Notice for: paquet-0.2.1 ---------- @@ -9608,7 +7010,7 @@ 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. ========== -Notice for: pleaserun-0.0.30 +Notice for: pleaserun-0.0.31 ---------- Copyright 2014 Jordan Sissel contributors. @@ -9650,7 +7052,7 @@ LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. ========== -Notice for: pry-0.12.2 +Notice for: pry-0.13.1 ---------- Copyright (c) 2016 John Mair (banisterfiend) @@ -9702,7 +7104,7 @@ OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. ========== -Notice for: puma-4.3.1 +Notice for: puma-4.3.6 ---------- Some code copyright (c) 2005, Zed Shaw @@ -9733,7 +7135,7 @@ OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. ========== -Notice for: rack-2.1.2 +Notice for: rack-2.2.3 ---------- The MIT License (MIT) @@ -9757,7 +7159,7 @@ THE AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. ========== -Notice for: rack-protection-2.0.8.1 +Notice for: rack-protection-2.1.0 ---------- The MIT License (MIT) @@ -9810,7 +7212,7 @@ WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. ========== -Notice for: redis-4.1.3 +Notice for: redis-4.2.2 ---------- Copyright (c) 2009 Ezra Zygmuntowicz @@ -9973,7 +7375,7 @@ See the License for the specific language governing permissions and limitations under the License. ========== -Notice for: sequel-5.28.0 +Notice for: sequel-5.36.0 ---------- Copyright (c) 2007-2008 Sharon Rosner @@ -10022,7 +7424,7 @@ OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. ========== -Notice for: sinatra-2.0.8.1 +Notice for: sinatra-2.1.0 ---------- Copyright (c) 2007, 2008, 2009 Blake Mizerany @@ -10460,7 +7862,7 @@ IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. ========== -Notice for: treetop-1.6.10 +Notice for: treetop-1.6.11 ---------- Copyright (c) 2007 Nathan Sobo. @@ -10509,7 +7911,7 @@ OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. ========== -Notice for: tzinfo-2.0.1 +Notice for: tzinfo-2.0.2 ---------- Copyright (c) 2005-2018 Philip Ross @@ -10533,7 +7935,7 @@ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. ========== -Notice for: tzinfo-data-1.2019.3 +Notice for: tzinfo-data-1.2020.1 ---------- Copyright (c) 2005-2018 Philip Ross From 23141e8f7e5846c44a3efe4a88a60b31c4800365 Mon Sep 17 00:00:00 2001 From: Rob Bavey Date: Fri, 2 Oct 2020 15:47:25 -0400 Subject: [PATCH 0604/1126] Add RedHat Univeral Base Image license information (#12296) Clean backport of #12287 --- NOTICE.TXT | 90 +++++++++++++++++++ .../lib/logstash/dependency_report.rb | 3 +- .../src/main/resources/acceptableLicenses.csv | 3 +- .../src/main/resources/licenseMapping.csv | 1 + ...at Universal Base Image minimal-NOTICE.txt | 85 ++++++++++++++++++ 5 files changed, 180 insertions(+), 2 deletions(-) create mode 100644 tools/dependencies-report/src/main/resources/notices/Red Hat Universal Base Image minimal-NOTICE.txt diff --git a/NOTICE.TXT b/NOTICE.TXT index efdca8ec5..68c48fb6c 100644 --- a/NOTICE.TXT +++ b/NOTICE.TXT @@ -1,4 +1,94 @@ +========== +Notice for: Red Hat Universal Base Image minimal-8 +---------- + +source: https://www.redhat.com/licenses/EULA_Red_Hat_Universal_Base_Image_English_20190422.pdf + +END USER LICENSE AGREEMENT +RED HAT UNIVERSAL BASE IMAGE + +PLEASE READ THIS END USER LICENSE AGREEMENT CAREFULLY BEFORE USING SOFTWARE FROM RED HAT. BY USING RED HAT +SOFTWARE, YOU SIGNIFY YOUR ASSENT TO AND ACCEPTANCE OF THIS END USER LICENSE AGREEMENT AND ACKNOWLEDGE YOU +HAVE READ AND UNDERSTAND THE TERMS. AN INDIVIDUAL ACTING ON BEHALF OF AN ENTITY REPRESENTS THAT HE OR SHE HAS THE +AUTHORITY TO ENTER INTO THIS END USER LICENSE AGREEMENT ON BEHALF OF THAT ENTITY. IF YOU DO NOT ACCEPT THE TERMS +OF THIS AGREEMENT, THEN YOU MUST NOT USE THE RED HAT SOFTWARE. THIS END USER LICENSE AGREEMENT DOES NOT PROVIDE +ANY RIGHTS TO RED HAT SERVICES SUCH AS SOFTWARE MAINTENANCE, UPGRADES OR SUPPORT. PLEASE REVIEW YOUR SERVICE +OR SUBSCRIPTION AGREEMENT(S) THAT YOU MAY HAVE WITH RED HAT OR OTHER AUTHORIZED RED HAT SERVICE PROVIDERS +REGARDING SERVICES AND ASSOCIATED PAYMENTS. + +This end user license agreement (“EULA”) governs the use of Red Hat Universal Base Image and associated software supporting such container(s) +and any related updates, source code, including the appearance, structure and organization (the “Programs”), regardless of the delivery mechanism. +If a Red Hat Universal Base Image is included in another Red Hat product, the EULA terms of such other Red Hat product will apply and supersede +this EULA. If a Red Hat Universal Base Image is included in a third party work, the terms of this EULA will continue to govern the Red Hat Universal +Base Image. + +1. License Grant. Subject to the terms of this EULA, Red Hat, Inc. (“Red Hat”) grants to you a perpetual, worldwide license to the Programs (each +of which may include multiple software components). With the exception of the Red Hat trademark identified in Section 2 below, each software +component is governed by a license that permits you to run, copy, modify, and redistribute (subject to certain obligations in some cases) the +software components. This EULA pertains solely to the Programs and does not limit your rights under, or grant you rights that supersede, the +license terms applicable to any particular component. The license terms applicable to each software component are provided in the source code +of that component. + +2. Intellectual Property Rights. The Programs and each of their components are owned by Red Hat and other licensors and are protected under +copyright law and other laws as applicable. Title to the Programs and any component shall remain with Red Hat and other licensors, subject to +the applicable license, excluding any independently developed and licensed work. The “Red Hat” trademark is a registered trademark of Red +Hat and its affiliates in the U.S. and other countries. Subject to Red Hat’s trademark usage guidelines (set forth at +http://www.redhat.com/about/corporate/trademark/), this EULA permits you to distribute the Programs that include the Red Hat trademark, +provided you do not make any statements on behalf of Red Hat, including but not limited to, stating or in any way suggesting (in any public, +private and/or confidential statement (whether written or verbal)) that Red Hat supports or endorses software built and delivered with a Red Hat +Universal Base Image(s) (such derivative works referred to as a “Red Hat Based Container Images”); provided if a Red Hat Based Container +Image is Red Hat Certified and deployed on a Red Hat supported configuration as set forth at https://access.redhat.com/articles/2726611 then +you may state that the Red Hat Universal Base Image is supported by Red Hat. You agree to include this unmodified EULA in all distributions of +container images sourced, built or otherwise derived from the Programs. If you modify the Red Hat Universal Base Image(s), you must remove +any Red Hat trademark(s) prior to any subsequent distribution. Any breach of this Section 2 is a material breach of the EULA and you may no +longer use and/or distribute the Red Hat trademark(s). Modifications to the software may corrupt the Programs. + +3. Limited Warranty. Except as specifically stated in this Section 3, a separate agreement with Red Hat, or a license for a particular component, +to the maximum extent permitted under applicable law, the Programs and the components are provided and licensed “as is” without +warranty of any kind, expressed or implied, including the implied warranties of merchantability, non-infringement or fitness for a +particular purpose. Neither Red Hat nor its affiliates warrant that the functions contained in the Programs will meet your requirements or that +the operation of the Programs will be entirely error free, appear or perform precisely as described in the accompanying documentation, or comply +with regulatory requirements. Red Hat warrants that the media on which the Programs and the components are provided will be free from defects +in materials and manufacture under normal use for a period of 30 days from the date of delivery to you. This warranty extends only to the party +that purchases subscription services for the supported configurations from Red Hat and/or its affiliates or a Red Hat authorized +distributor. + +4. Limitation of Remedies and Liability. To the maximum extent permitted by applicable law, your exclusive remedy under this EULA is to return +any defective media within 30 days of delivery along with a copy of your payment receipt and Red Hat, at its option, will replace it or refund the +money you paid for the media. To the maximum extent permitted under applicable law, under no circumstances will Red Hat, its affiliates, +any Red Hat authorized distributor, or the licensor of any component provided to you under this EULA be liable to you for any incidental +or consequential damages, including lost profits or lost savings arising out of the use or inability to use the Programs or any +component, even if Red Hat, its affiliates, an authorized distributor, and/or licensor has been advised of the possibility of such +damages. In no event shall Red Hat's or its affiliates’ liability, an authorized distributor’s liability or the liability of the licensor of a +component provided to you under this EULA exceed the amount that you paid to Red Hat for the media under this EULA. + +5. Export Control. As required by the laws of the United States and other countries, you represent and warrant that you: (a) understand that the +Programs and their components may be subject to export controls under the U.S. Commerce Department’s Export Administration Regulations +(“EAR”); (b) are not located in a prohibited destination country under the EAR or U.S. sanctions regulations (currently Cuba, Iran, North Korea, +Sudan, Syria, and the Crimea Region of Ukraine, subject to change as posted by the United States government); (c) will not export, re-export, or +transfer the Programs to any prohibited destination, persons or entities on the U.S. Bureau of Industry and Security Denied Parties List or Entity +List, or the U.S. Office of Foreign Assets Control list of Specially Designated Nationals and Blocked Persons, or any similar lists maintained by +other countries, without the necessary export license(s) or authorizations(s); (d) will not use or transfer the Programs for use in connection with +any nuclear, chemical or biological weapons, missile technology, or military end-uses where prohibited by an applicable arms embargo, unless +authorized by the relevant government agency by regulation or specific license; (e) understand and agree that if you are in the United States and +export or transfer the Programs to eligible end users, you will, to the extent required by EAR Section 740.17(e), submit semi-annual reports to +the Commerce Department’s Bureau of Industry and Security, which include the name and address (including country) of each transferee; and +(f) understand that countries including the United States may restrict the import, use, or export of encryption products (which may include the +Programs and the components) and agree that you shall be solely responsible for compliance with any such import, use, or export restrictions. + +6. Third Party Software. The Program may be provided with third party software programs subject to their own license terms. The license terms +either accompany the third party software programs or, in some instances, may be viewed at registry.access.redhat.com. If you do not agree to +abide by the applicable license terms for the third party software programs, then you may not install, distribute or use them. + +7. General. If any provision of this EULA is held to be unenforceable, the enforceability of the remaining provisions shall not be affected. Any claim, +controversy or dispute arising under or relating to this EULA shall be governed by the laws of the State of New York and of the United States, +without regard to any conflict of laws provisions. The rights and obligations of the parties to this EULA shall not be governed by the United +Nations Convention on the International Sale of Goods. + +Copyright © 2019 Red Hat, Inc. All rights reserved. “Red Hat,” is a registered trademark of Red Hat, Inc. +All other trademarks are the property of their respective owners. + ========== Notice for: addressable-2.7.0 ---------- diff --git a/logstash-core/lib/logstash/dependency_report.rb b/logstash-core/lib/logstash/dependency_report.rb index 9b35153a2..8d45b7641 100644 --- a/logstash-core/lib/logstash/dependency_report.rb +++ b/logstash-core/lib/logstash/dependency_report.rb @@ -30,7 +30,8 @@ class LogStash::DependencyReport < Clamp::Command :required => true, :attribute_name => :output_path OTHER_DEPENDENCIES = [ - ["jruby", "", "http://jruby.org", "EPL-2.0"] + ["jruby", "", "http://jruby.org", "EPL-2.0"], + ["Red Hat Universal Base Image minimal","8","https://catalog.redhat.com/software/containers/ubi8/ubi-minimal/5c359a62bed8bd75a2c3fba8","Custom;https://www.redhat.com/licenses/EULA_Red_Hat_Universal_Base_Image_English_20190422.pdf"] ] def execute diff --git a/tools/dependencies-report/src/main/resources/acceptableLicenses.csv b/tools/dependencies-report/src/main/resources/acceptableLicenses.csv index 9e2e6d69a..221feae0a 100644 --- a/tools/dependencies-report/src/main/resources/acceptableLicenses.csv +++ b/tools/dependencies-report/src/main/resources/acceptableLicenses.csv @@ -7,4 +7,5 @@ EPL-1.0 EPL-2.0 ISC MIT -Ruby \ No newline at end of file +Ruby +Custom;https://www.redhat.com/licenses/EULA_Red_Hat_Universal_Base_Image_English_20190422.pdf \ No newline at end of file diff --git a/tools/dependencies-report/src/main/resources/licenseMapping.csv b/tools/dependencies-report/src/main/resources/licenseMapping.csv index 34acd7aa2..419e93113 100644 --- a/tools/dependencies-report/src/main/resources/licenseMapping.csv +++ b/tools/dependencies-report/src/main/resources/licenseMapping.csv @@ -121,6 +121,7 @@ dependency,dependencyUrl,licenseOverride "rack-protection:",http://github.com/rkh/rack-protection,MIT "rack:",http://rack.github.io/,MIT "rake:",https://github.com/ruby/rake,MIT +"Red Hat Universal Base Image minimal:",https://catalog.redhat.com/software/containers/ubi8/ubi-minimal/5c359a62bed8bd75a2c3fba8,Custom;https://www.redhat.com/licenses/EULA_Red_Hat_Universal_Base_Image_English_20190422.pdf "redis:",https://github.com/redis/redis-rb,MIT "ruby-progressbar:",https://github.com/jfelchner/ruby-progressbar,MIT "rubyzip:",https://github.com/rubyzip/rubyzip,BSD-2-Clause-FreeBSD diff --git a/tools/dependencies-report/src/main/resources/notices/Red Hat Universal Base Image minimal-NOTICE.txt b/tools/dependencies-report/src/main/resources/notices/Red Hat Universal Base Image minimal-NOTICE.txt new file mode 100644 index 000000000..dc945c768 --- /dev/null +++ b/tools/dependencies-report/src/main/resources/notices/Red Hat Universal Base Image minimal-NOTICE.txt @@ -0,0 +1,85 @@ +source: https://www.redhat.com/licenses/EULA_Red_Hat_Universal_Base_Image_English_20190422.pdf + +END USER LICENSE AGREEMENT +RED HAT UNIVERSAL BASE IMAGE + +PLEASE READ THIS END USER LICENSE AGREEMENT CAREFULLY BEFORE USING SOFTWARE FROM RED HAT. BY USING RED HAT +SOFTWARE, YOU SIGNIFY YOUR ASSENT TO AND ACCEPTANCE OF THIS END USER LICENSE AGREEMENT AND ACKNOWLEDGE YOU +HAVE READ AND UNDERSTAND THE TERMS. AN INDIVIDUAL ACTING ON BEHALF OF AN ENTITY REPRESENTS THAT HE OR SHE HAS THE +AUTHORITY TO ENTER INTO THIS END USER LICENSE AGREEMENT ON BEHALF OF THAT ENTITY. IF YOU DO NOT ACCEPT THE TERMS +OF THIS AGREEMENT, THEN YOU MUST NOT USE THE RED HAT SOFTWARE. THIS END USER LICENSE AGREEMENT DOES NOT PROVIDE +ANY RIGHTS TO RED HAT SERVICES SUCH AS SOFTWARE MAINTENANCE, UPGRADES OR SUPPORT. PLEASE REVIEW YOUR SERVICE +OR SUBSCRIPTION AGREEMENT(S) THAT YOU MAY HAVE WITH RED HAT OR OTHER AUTHORIZED RED HAT SERVICE PROVIDERS +REGARDING SERVICES AND ASSOCIATED PAYMENTS. + +This end user license agreement (“EULA”) governs the use of Red Hat Universal Base Image and associated software supporting such container(s) +and any related updates, source code, including the appearance, structure and organization (the “Programs”), regardless of the delivery mechanism. +If a Red Hat Universal Base Image is included in another Red Hat product, the EULA terms of such other Red Hat product will apply and supersede +this EULA. If a Red Hat Universal Base Image is included in a third party work, the terms of this EULA will continue to govern the Red Hat Universal +Base Image. + +1. License Grant. Subject to the terms of this EULA, Red Hat, Inc. (“Red Hat”) grants to you a perpetual, worldwide license to the Programs (each +of which may include multiple software components). With the exception of the Red Hat trademark identified in Section 2 below, each software +component is governed by a license that permits you to run, copy, modify, and redistribute (subject to certain obligations in some cases) the +software components. This EULA pertains solely to the Programs and does not limit your rights under, or grant you rights that supersede, the +license terms applicable to any particular component. The license terms applicable to each software component are provided in the source code +of that component. + +2. Intellectual Property Rights. The Programs and each of their components are owned by Red Hat and other licensors and are protected under +copyright law and other laws as applicable. Title to the Programs and any component shall remain with Red Hat and other licensors, subject to +the applicable license, excluding any independently developed and licensed work. The “Red Hat” trademark is a registered trademark of Red +Hat and its affiliates in the U.S. and other countries. Subject to Red Hat’s trademark usage guidelines (set forth at +http://www.redhat.com/about/corporate/trademark/), this EULA permits you to distribute the Programs that include the Red Hat trademark, +provided you do not make any statements on behalf of Red Hat, including but not limited to, stating or in any way suggesting (in any public, +private and/or confidential statement (whether written or verbal)) that Red Hat supports or endorses software built and delivered with a Red Hat +Universal Base Image(s) (such derivative works referred to as a “Red Hat Based Container Images”); provided if a Red Hat Based Container +Image is Red Hat Certified and deployed on a Red Hat supported configuration as set forth at https://access.redhat.com/articles/2726611 then +you may state that the Red Hat Universal Base Image is supported by Red Hat. You agree to include this unmodified EULA in all distributions of +container images sourced, built or otherwise derived from the Programs. If you modify the Red Hat Universal Base Image(s), you must remove +any Red Hat trademark(s) prior to any subsequent distribution. Any breach of this Section 2 is a material breach of the EULA and you may no +longer use and/or distribute the Red Hat trademark(s). Modifications to the software may corrupt the Programs. + +3. Limited Warranty. Except as specifically stated in this Section 3, a separate agreement with Red Hat, or a license for a particular component, +to the maximum extent permitted under applicable law, the Programs and the components are provided and licensed “as is” without +warranty of any kind, expressed or implied, including the implied warranties of merchantability, non-infringement or fitness for a +particular purpose. Neither Red Hat nor its affiliates warrant that the functions contained in the Programs will meet your requirements or that +the operation of the Programs will be entirely error free, appear or perform precisely as described in the accompanying documentation, or comply +with regulatory requirements. Red Hat warrants that the media on which the Programs and the components are provided will be free from defects +in materials and manufacture under normal use for a period of 30 days from the date of delivery to you. This warranty extends only to the party +that purchases subscription services for the supported configurations from Red Hat and/or its affiliates or a Red Hat authorized +distributor. + +4. Limitation of Remedies and Liability. To the maximum extent permitted by applicable law, your exclusive remedy under this EULA is to return +any defective media within 30 days of delivery along with a copy of your payment receipt and Red Hat, at its option, will replace it or refund the +money you paid for the media. To the maximum extent permitted under applicable law, under no circumstances will Red Hat, its affiliates, +any Red Hat authorized distributor, or the licensor of any component provided to you under this EULA be liable to you for any incidental +or consequential damages, including lost profits or lost savings arising out of the use or inability to use the Programs or any +component, even if Red Hat, its affiliates, an authorized distributor, and/or licensor has been advised of the possibility of such +damages. In no event shall Red Hat's or its affiliates’ liability, an authorized distributor’s liability or the liability of the licensor of a +component provided to you under this EULA exceed the amount that you paid to Red Hat for the media under this EULA. + +5. Export Control. As required by the laws of the United States and other countries, you represent and warrant that you: (a) understand that the +Programs and their components may be subject to export controls under the U.S. Commerce Department’s Export Administration Regulations +(“EAR”); (b) are not located in a prohibited destination country under the EAR or U.S. sanctions regulations (currently Cuba, Iran, North Korea, +Sudan, Syria, and the Crimea Region of Ukraine, subject to change as posted by the United States government); (c) will not export, re-export, or +transfer the Programs to any prohibited destination, persons or entities on the U.S. Bureau of Industry and Security Denied Parties List or Entity +List, or the U.S. Office of Foreign Assets Control list of Specially Designated Nationals and Blocked Persons, or any similar lists maintained by +other countries, without the necessary export license(s) or authorizations(s); (d) will not use or transfer the Programs for use in connection with +any nuclear, chemical or biological weapons, missile technology, or military end-uses where prohibited by an applicable arms embargo, unless +authorized by the relevant government agency by regulation or specific license; (e) understand and agree that if you are in the United States and +export or transfer the Programs to eligible end users, you will, to the extent required by EAR Section 740.17(e), submit semi-annual reports to +the Commerce Department’s Bureau of Industry and Security, which include the name and address (including country) of each transferee; and +(f) understand that countries including the United States may restrict the import, use, or export of encryption products (which may include the +Programs and the components) and agree that you shall be solely responsible for compliance with any such import, use, or export restrictions. + +6. Third Party Software. The Program may be provided with third party software programs subject to their own license terms. The license terms +either accompany the third party software programs or, in some instances, may be viewed at registry.access.redhat.com. If you do not agree to +abide by the applicable license terms for the third party software programs, then you may not install, distribute or use them. + +7. General. If any provision of this EULA is held to be unenforceable, the enforceability of the remaining provisions shall not be affected. Any claim, +controversy or dispute arising under or relating to this EULA shall be governed by the laws of the State of New York and of the United States, +without regard to any conflict of laws provisions. The rights and obligations of the parties to this EULA shall not be governed by the United +Nations Convention on the International Sale of Goods. + +Copyright © 2019 Red Hat, Inc. All rights reserved. “Red Hat,” is a registered trademark of Red Hat, Inc. +All other trademarks are the property of their respective owners. From 19d8a170e0ea07b0a72a2a5be7dde2807de7117a Mon Sep 17 00:00:00 2001 From: Rob Bavey Date: Mon, 5 Oct 2020 09:03:35 -0400 Subject: [PATCH 0605/1126] fix dependency issue, jruby-openssl, of integration test (#12301) Backport of #12300 Co-authored-by: kaisecheng <69120390+kaisecheng@users.noreply.github.com> --- logstash-core/logstash-core.gemspec | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/logstash-core/logstash-core.gemspec b/logstash-core/logstash-core.gemspec index 03748524e..c43b1282e 100644 --- a/logstash-core/logstash-core.gemspec +++ b/logstash-core/logstash-core.gemspec @@ -57,7 +57,7 @@ Gem::Specification.new do |gem| gem.add_runtime_dependency "mustermann", '~> 1.0.3' gem.add_runtime_dependency "sinatra", '~> 2' gem.add_runtime_dependency 'puma', '~> 4' - gem.add_runtime_dependency "jruby-openssl", "~> 0.10" # >= 0.9.13 Required to support TLSv1.2 + gem.add_runtime_dependency "jruby-openssl", "= 0.10.4" # >= 0.9.13 Required to support TLSv1.2; 0.10.5 is causing dependency issue in integration test #12299 gem.add_runtime_dependency "chronic_duration", "~> 0.10" gem.add_runtime_dependency "treetop", "~> 1" #(MIT license) From ccbc5691cb9d6d815be3f58c23e922207f6d41b1 Mon Sep 17 00:00:00 2001 From: Rob Bavey Date: Mon, 5 Oct 2020 13:38:09 -0400 Subject: [PATCH 0606/1126] Docker Build: Add ability to detect/set build architecture (#12303) Clean backport of #12302 This commit adds the ability for the docker build to build artifacts for multiple architectures. By default, the target architecture is inferred from the architecture of the machine the build is being run from - running the build from an aarch64 machine will build an aarch64 docker image, while building from an x86_64 machine will build an x86_64 docker image. This can be overridden by setting the environment variable DOCKER_ARCHITECTURE to either `x86_64` or `aarch64`. This commit also updates the integration tests to test against the architecture from the machine the test is being run on, and includes the target architecture in the test description. --- docker/Makefile | 10 +++++++++ docker/templates/Dockerfile.j2 | 4 ++-- qa/docker/shared_examples/image_metadata.rb | 4 ++-- qa/docker/spec/spec_helper.rb | 25 ++++++++++++++++----- 4 files changed, 33 insertions(+), 10 deletions(-) diff --git a/docker/Makefile b/docker/Makefile index 7ac714e24..d2533058a 100644 --- a/docker/Makefile +++ b/docker/Makefile @@ -12,6 +12,12 @@ else VERSION_TAG := $(ELASTIC_VERSION) endif +ifdef DOCKER_ARCHITECTURE + ARCHITECTURE := $(DOCKER_ARCHITECTURE) +else + ARCHITECTURE := $(shell uname -m) +endif + IMAGE_FLAVORS ?= oss full ubi8 DEFAULT_IMAGE_FLAVOR ?= full @@ -85,6 +91,7 @@ public-dockerfiles_full: venv templates/Dockerfile.j2 docker_paths $(COPY_FILES) jinja2 \ -D created_date='$(DATE)' \ -D elastic_version='$(ELASTIC_VERSION)' \ + -D arch='${ARCHITECTURE}' \ -D version_tag='$(VERSION_TAG)' \ -D image_flavor='full' \ -D local_artifacts='false' \ @@ -98,6 +105,7 @@ public-dockerfiles_oss: venv templates/Dockerfile.j2 docker_paths $(COPY_FILES) jinja2 \ -D created_date='$(DATE)' \ -D elastic_version='$(ELASTIC_VERSION)' \ + -D arch='${ARCHITECTURE}' \ -D version_tag='$(VERSION_TAG)' \ -D image_flavor='oss' \ -D local_artifacts='false' \ @@ -111,6 +119,7 @@ public-dockerfiles_ubi8: venv templates/Dockerfile.j2 docker_paths $(COPY_FILES) jinja2 \ -D created_date='$(DATE)' \ -D elastic_version='$(ELASTIC_VERSION)' \ + -D arch='${ARCHITECTURE}' \ -D version_tag='$(VERSION_TAG)' \ -D image_flavor='ubi8' \ -D local_artifacts='false' \ @@ -166,6 +175,7 @@ dockerfile: venv templates/Dockerfile.j2 jinja2 \ -D created_date='$(DATE)' \ -D elastic_version='$(ELASTIC_VERSION)' \ + -D arch='${ARCHITECTURE}' \ -D version_tag='$(VERSION_TAG)' \ -D image_flavor='$(FLAVOR)' \ -D local_artifacts='true' \ diff --git a/docker/templates/Dockerfile.j2 b/docker/templates/Dockerfile.j2 index 4931df84a..ee48872c5 100644 --- a/docker/templates/Dockerfile.j2 +++ b/docker/templates/Dockerfile.j2 @@ -6,10 +6,10 @@ {% endif -%} {% if image_flavor == 'oss' -%} - {% set tarball = 'logstash-oss-%s-linux-x86_64.tar.gz' % elastic_version -%} + {% set tarball = 'logstash-oss-%s-linux-%s.tar.gz' % (elastic_version, arch) -%} {% set license = 'Apache 2.0' -%} {% else -%} - {% set tarball = 'logstash-%s-linux-x86_64.tar.gz' % elastic_version -%} + {% set tarball = 'logstash-%s-linux-%s.tar.gz' % (elastic_version, arch) -%} {% set license = 'Elastic License' -%} {% endif -%} diff --git a/qa/docker/shared_examples/image_metadata.rb b/qa/docker/shared_examples/image_metadata.rb index 56d1ea56d..10dccd329 100644 --- a/qa/docker/shared_examples/image_metadata.rb +++ b/qa/docker/shared_examples/image_metadata.rb @@ -9,8 +9,8 @@ shared_examples_for 'the metadata is set correctly' do |flavor| expect(@image_config['WorkingDir']).to eql '/usr/share/logstash' end - it 'should have the correct Architecture' do - expect(@image.json['Architecture']).to have_correct_architecture_for_flavor(flavor) + it "should have an architecture of #{running_architecture}" do + expect(@image.json['Architecture']).to have_correct_architecture end %w(license org.label-schema.license org.opencontainers.image.licenses).each do |label| diff --git a/qa/docker/spec/spec_helper.rb b/qa/docker/spec/spec_helper.rb index 2cc712df0..cbba2a389 100644 --- a/qa/docker/spec/spec_helper.rb +++ b/qa/docker/spec/spec_helper.rb @@ -80,10 +80,24 @@ def exec_in_container(container, command) container.exec(command.split)[0].join end -def architecture_for_flavor(flavor) - flavor.match(/aarch64/) ? 'arm64' : 'amd64' +def running_architecture + architecture = ENV['DOCKER_ARCHITECTURE'] + architecture = normalized_architecture(`uname -m`.strip) if architecture.nil? + architecture end +def normalized_architecture(cpu) + case cpu + when 'x86_64' + 'amd64' + when 'aarch64' + 'arm64' + else + cpu + end +end + + RSpec::Matchers.define :have_correct_license_label do |expected| match do |actual| values_match? license_label_for_flavor(expected), actual @@ -103,13 +117,12 @@ RSpec::Matchers.define :have_correct_license_agreement do |expected| end end -RSpec::Matchers.define :have_correct_architecture_for_flavor do |expected| +RSpec::Matchers.define :have_correct_architecture do match do |actual| - values_match? architecture_for_flavor(expected), actual - true + values_match? running_architecture, actual end failure_message do |actual| - "expected Architecture: #{actual} to be #{architecture_for_flavor(expected)}" + "expected Architecture: #{actual} to be #{running_architecture}" end end From c606e9f5b1ef7b7f7deb1f7639c71c994b0f0f40 Mon Sep 17 00:00:00 2001 From: Ry Biesemeyer Date: Tue, 6 Oct 2020 08:33:11 -0700 Subject: [PATCH 0607/1126] ECS Compatibility 7.x Backport (#12308) Implements a plugin `ecs_compatibility` option, whose default value is powered by the pipeline-level setting `pipeline.ecs_compatibility`, in line with the proposal in elastic/logstash#11623: In order to increase the confidence a user has when upgrading Logstash, this implementation uses the deprecation logger to warn when `ecs_compatibility` is used without an explicit directive. For now, as we continue to add ECS Compatibility Modes, an opting into a specific ECS Compatibility mode at a pipeline level is considered a BETA feature. All plugins using the [ECS Compatibility Support][] adapter will use the setting correctly, but pipelines configured in this way do not guarantee consistent behaviour across minor versions of Logstash or the plugins it bundles (e.g., upgraded plugins that have newly-implemented an ECS Compatibility mode will use the pipeline-level setting as a default, causing them to potentially behave differently after the upgrade). This change-set also includes a significant amount of work within the `PluginFactory`, which allows us to ensure that pipeline-level settings are available to a Logstash plugin _before_ its `initialize` is executed, including the maintaining of context for codecs that are routinely cloned. * JEE: instantiate codecs only once * PluginFactory: use passed FilterDelegator class * PluginFactory: require engine name in init * NOOP: remove useless secondary plugin factory interface * PluginFactory: simplify, compute java args only when necessary * PluginFactory: accept explicit id when vertex unavailable * PluginFactory: make source optional, args required * PluginFactory: threadsafe refactor of id duplicate tracking * PluginFactory: make id extraction/geration more abstract/understandable * PluginFactory: extract or generate ID when source not available * PluginFactory: inject ExecutionContext before initializing plugins * Codec: propagate execution_context and metric to clones * Plugin: intercept string-specified codecs and propagate execution_context * Plugin: implement `ecs_compatibility` for all plugins * Plugin: deprecate use of `Config::Mixin::DSL::validate_value(String, :codec)` --- docker/data/logstash/env2yaml/env2yaml.go | 1 + logstash-core/lib/logstash/agent.rb | 8 + logstash-core/lib/logstash/codecs/base.rb | 4 +- .../lib/logstash/config/config_ast.rb | 6 +- logstash-core/lib/logstash/config/mixin.rb | 19 +- logstash-core/lib/logstash/environment.rb | 1 + logstash-core/lib/logstash/inputs/base.rb | 8 +- logstash-core/lib/logstash/outputs/base.rb | 8 +- logstash-core/lib/logstash/pipeline.rb | 4 +- logstash-core/lib/logstash/plugin.rb | 16 +- .../plugins/ecs_compatibility_support.rb | 53 ++++ logstash-core/lib/logstash/runner.rb | 5 + logstash-core/lib/logstash/settings.rb | 1 + logstash-core/locales/en.yml | 15 ++ .../spec/logstash/config/mixin_spec.rb | 25 ++ .../execution_context_factory_spec.rb | 59 ++++ .../spec/logstash/execution_context_spec.rb | 8 +- .../spec/logstash/inputs/base_spec.rb | 34 ++- .../spec/logstash/outputs/base_spec.rb | 34 ++- logstash-core/spec/logstash/plugin_spec.rb | 85 +++++- logstash-core/spec/support/shared_contexts.rb | 3 +- .../src/main/java/org/logstash/RubyUtil.java | 23 +- .../logstash/config/ir/CompiledPipeline.java | 78 ++---- .../config/ir/compiler/OutputStrategyExt.java | 25 +- .../config/ir/compiler/PluginFactory.java | 90 ------- .../config/ir/compiler/RubyIntegration.java | 12 +- .../java/org/logstash/execution/Engine.java | 7 + .../execution/ExecutionContextExt.java | 14 +- .../execution/JavaBasePipelineExt.java | 3 +- .../plugins/factory/ContextualizerExt.java | 99 +++++++ .../factory/ExecutionContextFactoryExt.java | 6 +- .../plugins/factory/PluginFactoryExt.java | 251 +++++++++++++----- .../config/ir/CompiledPipelineTest.java | 58 ++-- .../config/ir/compiler/PluginFactoryTest.java | 35 --- .../logstash/plugins/TestPluginFactory.java | 16 +- .../plugins/factory/PluginFactoryExtTest.java | 6 +- 36 files changed, 751 insertions(+), 369 deletions(-) create mode 100644 logstash-core/lib/logstash/plugins/ecs_compatibility_support.rb create mode 100644 logstash-core/spec/logstash/execution_context_factory_spec.rb delete mode 100644 logstash-core/src/main/java/org/logstash/config/ir/compiler/PluginFactory.java create mode 100644 logstash-core/src/main/java/org/logstash/execution/Engine.java create mode 100644 logstash-core/src/main/java/org/logstash/plugins/factory/ContextualizerExt.java delete mode 100644 logstash-core/src/test/java/org/logstash/config/ir/compiler/PluginFactoryTest.java diff --git a/docker/data/logstash/env2yaml/env2yaml.go b/docker/data/logstash/env2yaml/env2yaml.go index 82483aae8..860d4da8f 100644 --- a/docker/data/logstash/env2yaml/env2yaml.go +++ b/docker/data/logstash/env2yaml/env2yaml.go @@ -57,6 +57,7 @@ func normalizeSetting(setting string) (string, error) { "pipeline.batch.delay", "pipeline.unsafe_shutdown", "pipeline.java_execution", + "pipeline.ecs_compatibility" "pipeline.plugin_classloaders", "path.config", "config.string", diff --git a/logstash-core/lib/logstash/agent.rb b/logstash-core/lib/logstash/agent.rb index f05a3b9f7..d1f4743f9 100644 --- a/logstash-core/lib/logstash/agent.rb +++ b/logstash-core/lib/logstash/agent.rb @@ -75,6 +75,14 @@ class LogStash::Agent logger.warn("deprecated setting `config.field_reference.parser` set; field reference parsing is strict by default") end + if @settings.set?('pipeline.ecs_compatibility') + ecs_compatibility_value = settings.get('pipeline.ecs_compatibility') + if ecs_compatibility_value != 'disabled' + logger.warn("Setting `pipeline.ecs_compatibility` given as `#{ecs_compatibility_value}`; " + + "values other than `disabled` are currently considered BETA and may have unintended consequences when upgrading minor versions of Logstash.") + end + end + # This is for backward compatibility in the tests if source_loader.nil? @source_loader = LogStash::Config::SourceLoader.new diff --git a/logstash-core/lib/logstash/codecs/base.rb b/logstash-core/lib/logstash/codecs/base.rb index db4cde703..081a3b376 100644 --- a/logstash-core/lib/logstash/codecs/base.rb +++ b/logstash-core/lib/logstash/codecs/base.rb @@ -92,6 +92,8 @@ module LogStash::Codecs; class Base < LogStash::Plugin public def clone - return self.class.new(params) + LogStash::Plugins::Contextualizer.initialize_plugin(execution_context, self.class, params).tap do |klone| + klone.metric = @metric if klone.instance_variable_get(:@metric).nil? + end end end; end # class LogStash::Codecs::Base diff --git a/logstash-core/lib/logstash/config/config_ast.rb b/logstash-core/lib/logstash/config/config_ast.rb index e3d413bf5..c7c5f9cfe 100644 --- a/logstash-core/lib/logstash/config/config_ast.rb +++ b/logstash-core/lib/logstash/config/config_ast.rb @@ -249,12 +249,12 @@ module LogStash; module Config; module AST # If any parent is a Plugin, this must be a codec. if attributes.elements.nil? - return "plugin(#{plugin_type.inspect}, #{plugin_name.inspect}, line_to_source(#{source_meta.line}, #{source_meta.column}))" << (plugin_type == "codec" ? "" : "\n") + return "plugin(#{plugin_type.inspect}, #{plugin_name.inspect}, {}, line_to_source(#{source_meta.line}, #{source_meta.column}))" << (plugin_type == "codec" ? "" : "\n") else settings = attributes.recursive_select(Attribute).collect(&:compile).reject(&:empty?) attributes_code = "LogStash::Util.hash_merge_many(#{settings.map { |c| "{ #{c} }" }.join(", ")})" - return "plugin(#{plugin_type.inspect}, #{plugin_name.inspect}, line_to_source(#{source_meta.line}, #{source_meta.column}), #{attributes_code})" << (plugin_type == "codec" ? "" : "\n") + return "plugin(#{plugin_type.inspect}, #{plugin_name.inspect}, #{attributes_code}, line_to_source(#{source_meta.line}, #{source_meta.column}))" << (plugin_type == "codec" ? "" : "\n") end end @@ -271,7 +271,7 @@ module LogStash; module Config; module AST when "codec" settings = attributes.recursive_select(Attribute).collect(&:compile).reject(&:empty?) attributes_code = "LogStash::Util.hash_merge_many(#{settings.map { |c| "{ #{c} }" }.join(", ")})" - return "plugin(#{plugin_type.inspect}, #{plugin_name.inspect}, line_to_source(#{source_meta.line}, #{source_meta.column}), #{attributes_code})" + return "plugin(#{plugin_type.inspect}, #{plugin_name.inspect}, #{attributes_code}, line_to_source(#{source_meta.line}, #{source_meta.column}))" end end diff --git a/logstash-core/lib/logstash/config/mixin.rb b/logstash-core/lib/logstash/config/mixin.rb index a8febea0b..38ef99b9d 100644 --- a/logstash-core/lib/logstash/config/mixin.rb +++ b/logstash-core/lib/logstash/config/mixin.rb @@ -49,6 +49,7 @@ LogStash::Environment.load_locale! module LogStash::Config::Mixin include LogStash::Util::SubstitutionVariables + include LogStash::Util::Loggable attr_accessor :config attr_accessor :original_params @@ -99,6 +100,17 @@ module LogStash::Config::Mixin params[name.to_s] = deep_replace(value) end + # Intercept codecs that have not been instantiated + params.each do |name, value| + validator = self.class.validator_find(name) + next unless validator && validator[:validate] == :codec && value.kind_of?(String) + + codec_klass = LogStash::Plugin.lookup("codec", value) + codec_instance = LogStash::Plugins::Contextualizer.initialize_plugin(execution_context, codec_klass) + + params[name.to_s] = LogStash::Codecs::Delegator.new(codec_instance) + end + if !self.class.validate(params) raise LogStash::ConfigurationError, I18n.t("logstash.runner.configuration.invalid_plugin_settings") @@ -190,7 +202,7 @@ module LogStash::Config::Mixin name = name.to_s if name.is_a?(Symbol) @config[name] = opts # ok if this is empty - if name.is_a?(String) + if name.is_a?(String) && opts.fetch(:attr_accessor, true) define_method(name) { instance_variable_get("@#{name}") } define_method("#{name}=") { |v| instance_variable_set("@#{name}", v) } end @@ -429,6 +441,11 @@ module LogStash::Config::Mixin case validator when :codec if value.first.is_a?(String) + # A plugin's codecs should be instantiated by `PluginFactory` or in `Config::Mixin#config_init(Hash)`, + # which ensure the inner plugin has access to the outer's execution context and metric store. + # This deprecation exists to warn plugins that call `Config::Mixin::validate_value` directly. + self.deprecation_logger.deprecated("Codec instantiated by `Config::Mixin::DSL::validate_value(String, :codec)` which cannot propagate parent plugin's execution context or metrics. ", + self.logger.debug? ? {:backtrace => caller} : {}) value = LogStash::Codecs::Delegator.new LogStash::Plugin.lookup("codec", value.first).new return true, value else diff --git a/logstash-core/lib/logstash/environment.rb b/logstash-core/lib/logstash/environment.rb index 89d5ad1c8..72e1f6d95 100644 --- a/logstash-core/lib/logstash/environment.rb +++ b/logstash-core/lib/logstash/environment.rb @@ -62,6 +62,7 @@ module LogStash Setting::Boolean.new("pipeline.plugin_classloaders", false), Setting::Boolean.new("pipeline.separate_logs", false), Setting::CoercibleString.new("pipeline.ordered", "auto", true, ["auto", "true", "false"]), + Setting::CoercibleString.new("pipeline.ecs_compatibility", "disabled", true, %w(disabled v1 v2)), Setting.new("path.plugins", Array, []), Setting::NullableString.new("interactive", nil, false), Setting::Boolean.new("config.debug", false), diff --git a/logstash-core/lib/logstash/inputs/base.rb b/logstash-core/lib/logstash/inputs/base.rb index a01b011e3..3ea40a339 100644 --- a/logstash-core/lib/logstash/inputs/base.rb +++ b/logstash-core/lib/logstash/inputs/base.rb @@ -124,10 +124,10 @@ class LogStash::Inputs::Base < LogStash::Plugin def execution_context=(context) super - # There is no easy way to propage an instance variable into the codec, because the codec - # are created at the class level - # TODO(talevy): Codecs should have their own execution_context, for now they will inherit their - # parent plugin's + # Setting the execution context after initialization is deprecated and will be removed in + # a future release of Logstash. While this code is no longer executed from Logstash core, + # we continue to propagate a set execution context to an input's codec, and rely on super's + # deprecation warning. @codec.execution_context = context context end diff --git a/logstash-core/lib/logstash/outputs/base.rb b/logstash-core/lib/logstash/outputs/base.rb index c52dad18f..ed3a28272 100644 --- a/logstash-core/lib/logstash/outputs/base.rb +++ b/logstash-core/lib/logstash/outputs/base.rb @@ -127,10 +127,10 @@ class LogStash::Outputs::Base < LogStash::Plugin def execution_context=(context) super - # There is no easy way to propage an instance variable into the codec, because the codec - # are created at the class level - # TODO(talevy): Codecs should have their own execution_context, for now they will inherit their - # parent plugin's + # Setting the execution context after initialization is deprecated and will be removed in + # a future release of Logstash. While this code is no longer executed from Logstash core, + # we continue to propagate a set execution context to an output's codec, and rely on super's + # deprecation warning. @codec.execution_context = context context end diff --git a/logstash-core/lib/logstash/pipeline.rb b/logstash-core/lib/logstash/pipeline.rb index 54089d518..6b3ec1733 100644 --- a/logstash-core/lib/logstash/pipeline.rb +++ b/logstash-core/lib/logstash/pipeline.rb @@ -89,8 +89,8 @@ module LogStash; class BasePipeline < AbstractPipeline private - def plugin(plugin_type, name, source, *args) - @plugin_factory.plugin(plugin_type, name, source, *args) + def plugin(plugin_type, name, args, source) + @plugin_factory.plugin(plugin_type, name, args, source) end def default_logging_keys(other_keys = {}) diff --git a/logstash-core/lib/logstash/plugin.rb b/logstash-core/lib/logstash/plugin.rb index b376bd7d7..a21e18392 100644 --- a/logstash-core/lib/logstash/plugin.rb +++ b/logstash-core/lib/logstash/plugin.rb @@ -16,6 +16,7 @@ # under the License. require "logstash/config/mixin" +require "logstash/plugins/ecs_compatibility_support" require "concurrent" require "securerandom" @@ -24,11 +25,12 @@ require_relative 'plugin_metadata' class LogStash::Plugin include LogStash::Util::Loggable - attr_accessor :params, :execution_context + attr_accessor :params NL = "\n" include LogStash::Config::Mixin + include LogStash::Plugins::ECSCompatibilitySupport # Disable or enable metric logging for this specific plugin instance # by default we record all the metrics we can, but you can disable metrics collection @@ -60,7 +62,7 @@ class LogStash::Plugin self.class.name == other.class.name && @params == other.params end - def initialize(params=nil) + def initialize(params={}) @logger = self.logger @deprecation_logger = self.deprecation_logger # need to access settings statically because plugins are initialized in config_ast with no context. @@ -177,4 +179,14 @@ class LogStash::Plugin def plugin_metadata LogStash::PluginMetadata.for_plugin(self.id) end + + # Deprecated attr_writer for execution_context + def execution_context=(new_context) + @deprecation_logger.deprecated("LogStash::Plugin#execution_context=(new_ctx) is deprecated. Use LogStash::Plugins::Contextualizer#initialize_plugin(new_ctx, klass, args) instead", :caller => caller.first) + @execution_context = new_context + end + + def execution_context + @execution_context || LogStash::ExecutionContext::Empty + end end # class LogStash::Plugin diff --git a/logstash-core/lib/logstash/plugins/ecs_compatibility_support.rb b/logstash-core/lib/logstash/plugins/ecs_compatibility_support.rb new file mode 100644 index 000000000..f87aff81c --- /dev/null +++ b/logstash-core/lib/logstash/plugins/ecs_compatibility_support.rb @@ -0,0 +1,53 @@ +module LogStash + module Plugins + module ECSCompatibilitySupport + def self.included(base) + base.extend(ArgumentValidator) + base.config(:ecs_compatibility, :validate => :ecs_compatibility_argument, + :attr_accessor => false) + end + + MUTEX = Mutex.new + private_constant :MUTEX + + def ecs_compatibility + @_ecs_compatibility || MUTEX.synchronize do + @_ecs_compatibility ||= begin + # use config_init-set value if present + break @ecs_compatibility unless @ecs_compatibility.nil? + + pipeline = execution_context.pipeline + pipeline_settings = pipeline && pipeline.settings + pipeline_settings ||= LogStash::SETTINGS + + if !pipeline_settings.set?('pipeline.ecs_compatibility') + deprecation_logger.deprecated("Relying on default value of `pipeline.ecs_compatibility`, which may change in a future major release of Logstash. " + + "To avoid unexpected changes when upgrading Logstash, please explicitly declare your desired ECS Compatibility mode.") + end + + pipeline_settings.get_value('pipeline.ecs_compatibility').to_sym + end + end + end + + module ArgumentValidator + V_PREFIXED_INTEGER_PATTERN = %r(\Av[1-9][0-9]?\Z).freeze + private_constant :V_PREFIXED_INTEGER_PATTERN + + def validate_value(value, validator) + return super unless validator == :ecs_compatibility_argument + + value = deep_replace(value) + value = hash_or_array(value) + + if value.size == 1 + return true, :disabled if value.first.to_s == 'disabled' + return true, value.first.to_sym if value.first.to_s =~ V_PREFIXED_INTEGER_PATTERN + end + + return false, "Expected a v-prefixed integer major-version number (e.g., `v1`) or the literal `disabled`, got #{value.inspect}" + end + end + end + end +end diff --git a/logstash-core/lib/logstash/runner.rb b/logstash-core/lib/logstash/runner.rb index 0b5304e53..9a0cf1bcf 100644 --- a/logstash-core/lib/logstash/runner.rb +++ b/logstash-core/lib/logstash/runner.rb @@ -154,6 +154,11 @@ class LogStash::Runner < Clamp::StrictCommand :attribute_name => "pipeline.unsafe_shutdown", :default => LogStash::SETTINGS.get_default("pipeline.unsafe_shutdown") + option ["--pipeline.ecs_compatibility"], "STRING", + I18n.t("logstash.runner.flag.ecs_compatibility"), + :attribute_name => "pipeline.ecs_compatibility", + :default => LogStash::SETTINGS.get_default('pipeline.ecs_compatibility') + # Data Path Setting option ["--path.data"] , "PATH", I18n.t("logstash.runner.flag.datapath"), diff --git a/logstash-core/lib/logstash/settings.rb b/logstash-core/lib/logstash/settings.rb index 5f648c1e1..96270911c 100644 --- a/logstash-core/lib/logstash/settings.rb +++ b/logstash-core/lib/logstash/settings.rb @@ -48,6 +48,7 @@ module LogStash "pipeline.system", "pipeline.workers", "pipeline.ordered", + "pipeline.ecs_compatibility", "queue.checkpoint.acks", "queue.checkpoint.interval", "queue.checkpoint.writes", diff --git a/logstash-core/locales/en.yml b/logstash-core/locales/en.yml index 25a8304e2..8890d9ecd 100644 --- a/logstash-core/locales/en.yml +++ b/logstash-core/locales/en.yml @@ -362,6 +362,21 @@ en: if there are still inflight events in memory. By default, logstash will refuse to quit until all received events have been pushed to the outputs. + ecs_compatibility: |+ + Sets the pipeline's default value for `ecs_compatibility`, + a setting that is available to plugins that implement + an ECS Compatibility mode for use with the Elastic Common + Schema. + Possible values are: + - disabled (default) + - v1 + - v2 + This option allows the early opt-in (or preemptive opt-out) + of ECS Compatibility modes in plugins, which is scheduled to + be on-by-default in a future major release of Logstash. + + Values other than `disabled` are currently considered BETA, + and may produce unintended consequences when upgrading Logstash. rubyshell: |+ Drop to shell instead of running as normal. Valid shells are "irb" and "pry" diff --git a/logstash-core/spec/logstash/config/mixin_spec.rb b/logstash-core/spec/logstash/config/mixin_spec.rb index 3fa8f0965..60c261136 100644 --- a/logstash-core/spec/logstash/config/mixin_spec.rb +++ b/logstash-core/spec/logstash/config/mixin_spec.rb @@ -47,6 +47,31 @@ describe LogStash::Config::Mixin do end end + context 'DSL::validate_value(String, :codec)' do + subject(:plugin_class) { Class.new(LogStash::Filters::Base) { config_name "test_deprecated_two" } } + let(:codec_class) { Class.new(LogStash::Codecs::Base) { config_name 'dummy' } } + let(:deprecation_logger) { double("DeprecationLogger").as_null_object } + + before(:each) do + allow(plugin_class).to receive(:deprecation_logger).and_return(deprecation_logger) + allow(LogStash::Plugin).to receive(:lookup).with("codec", codec_class.config_name).and_return(codec_class) + end + + it 'instantiates the codec' do + success, codec = plugin_class.validate_value(codec_class.config_name, :codec) + + expect(success).to be true + expect(codec.class).to eq(codec_class) + end + + it 'logs a deprecation' do + plugin_class.validate_value(codec_class.config_name, :codec) + expect(deprecation_logger).to have_received(:deprecated) do |message| + expect(message).to include("validate_value(String, :codec)") + end + end + end + context "when validating :bytes successfully" do subject do local_num_bytes = num_bytes # needs to be locally scoped :( diff --git a/logstash-core/spec/logstash/execution_context_factory_spec.rb b/logstash-core/spec/logstash/execution_context_factory_spec.rb new file mode 100644 index 000000000..e20fd6cb6 --- /dev/null +++ b/logstash-core/spec/logstash/execution_context_factory_spec.rb @@ -0,0 +1,59 @@ +# 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 "spec_helper" + +describe LogStash::Plugins::ExecutionContextFactory do + let(:pipeline) { double('Pipeline') } + let(:agent) { double('Agent') } + let(:inner_dlq_writer) { nil } + + subject(:factory) { described_class.new(agent, pipeline, inner_dlq_writer) } + + context '#create' do + let(:plugin_id) { SecureRandom.uuid } + let(:plugin_type) { 'input' } + + context 'the resulting instance' do + subject(:instance) { factory.create(plugin_id, plugin_type) } + + it 'retains the pipeline from the factory' do + expect(instance.pipeline).to be(pipeline) + end + + it 'retains the agent from the factory' do + expect(instance.agent).to be(agent) + end + + it 'has a dlq_writer' do + expect(instance.dlq_writer).to_not be_nil + end + + context 'dlq_writer' do + subject(:instance_dlq_writer) { instance.dlq_writer } + + it 'retains the plugin id' do + expect(instance_dlq_writer.plugin_id).to eq(plugin_id) + end + + it 'retains the plugin type' do + expect(instance_dlq_writer.plugin_type).to eq(plugin_type) + end + end + end + end +end diff --git a/logstash-core/spec/logstash/execution_context_spec.rb b/logstash-core/spec/logstash/execution_context_spec.rb index d1e529cbf..4ec9acb21 100644 --- a/logstash-core/spec/logstash/execution_context_spec.rb +++ b/logstash-core/spec/logstash/execution_context_spec.rb @@ -30,7 +30,7 @@ describe LogStash::ExecutionContext do allow(pipeline).to receive(:pipeline_id).and_return(pipeline_id) end - subject { described_class.new(pipeline, agent, plugin_id, plugin_type, dlq_writer) } + subject { described_class.new(pipeline, agent, dlq_writer) } it "returns the `pipeline_id`" do expect(subject.pipeline_id).to eq(pipeline_id) @@ -44,9 +44,7 @@ describe LogStash::ExecutionContext do expect(subject.agent).to eq(agent) end - it "returns the plugin-specific dlq writer" do - expect(subject.dlq_writer.plugin_type).to eq(plugin_type) - expect(subject.dlq_writer.plugin_id).to eq(plugin_id) - expect(subject.dlq_writer.inner_writer).to eq(dlq_writer) + it "returns the dlq writer" do + expect(subject.dlq_writer).to be(dlq_writer) end end diff --git a/logstash-core/spec/logstash/inputs/base_spec.rb b/logstash-core/spec/logstash/inputs/base_spec.rb index 9540bbe38..ecb34c0d1 100644 --- a/logstash-core/spec/logstash/inputs/base_spec.rb +++ b/logstash-core/spec/logstash/inputs/base_spec.rb @@ -86,18 +86,34 @@ describe "LogStash::Inputs::Base#decorate" do subject(:instance) { klass.new({}) } - it "allow to set the context" do - expect(instance.execution_context).to be_nil - instance.execution_context = execution_context + context 'execution_context=' do + let(:deprecation_logger_stub) { double('DeprecationLogger').as_null_object } + before(:each) do + allow(klass).to receive(:deprecation_logger).and_return(deprecation_logger_stub) + end - expect(instance.execution_context).to eq(execution_context) - end + it "allow to set the context" do + new_ctx = execution_context.dup + subject.execution_context = new_ctx + expect(subject.execution_context).to be(new_ctx) + end - it "propagate the context to the codec" do - expect(instance.codec.execution_context).to be_nil - instance.execution_context = execution_context + it "propagate the context to the codec" do + new_ctx = execution_context.dup + expect(instance.codec.execution_context).to_not be(new_ctx) + instance.execution_context = new_ctx - expect(instance.codec.execution_context).to eq(execution_context) + expect(instance.execution_context).to be(new_ctx) + expect(instance.codec.execution_context).to be(new_ctx) + end + + it 'emits a deprecation warning' do + expect(deprecation_logger_stub).to receive(:deprecated) do |message| + expect(message).to match(/execution_context=/) + end + + instance.execution_context = execution_context + end end end diff --git a/logstash-core/spec/logstash/outputs/base_spec.rb b/logstash-core/spec/logstash/outputs/base_spec.rb index 191d82751..0e7df6d52 100644 --- a/logstash-core/spec/logstash/outputs/base_spec.rb +++ b/logstash-core/spec/logstash/outputs/base_spec.rb @@ -102,18 +102,34 @@ describe "LogStash::Outputs::Base#new" do subject(:instance) { klass.new(params.dup) } - it "allow to set the context" do - expect(instance.execution_context).to be_nil - instance.execution_context = execution_context + context 'execution_context=' do + let(:deprecation_logger_stub) { double('DeprecationLogger').as_null_object } + before(:each) do + allow(klass).to receive(:deprecation_logger).and_return(deprecation_logger_stub) + end - expect(instance.execution_context).to eq(execution_context) - end + it "allow to set the context" do + new_ctx = execution_context.dup + subject.execution_context = new_ctx + expect(subject.execution_context).to be(new_ctx) + end - it "propagate the context to the codec" do - expect(instance.codec.execution_context).to be_nil - instance.execution_context = execution_context + it "propagate the context to the codec" do + new_ctx = execution_context.dup + expect(instance.codec.execution_context).to_not be(new_ctx) + instance.execution_context = new_ctx - expect(instance.codec.execution_context).to eq(execution_context) + expect(instance.execution_context).to be(new_ctx) + expect(instance.codec.execution_context).to be(new_ctx) + end + + it 'emits a deprecation warning' do + expect(deprecation_logger_stub).to receive(:deprecated) do |message| + expect(message).to match(/execution_context=/) + end + + instance.execution_context = execution_context + end end end diff --git a/logstash-core/spec/logstash/plugin_spec.rb b/logstash-core/spec/logstash/plugin_spec.rb index e56299dd5..e286e2950 100644 --- a/logstash-core/spec/logstash/plugin_spec.rb +++ b/logstash-core/spec/logstash/plugin_spec.rb @@ -69,13 +69,28 @@ describe LogStash::Plugin do end context "#execution_context" do - subject { Class.new(LogStash::Plugin).new({}) } + let(:klass) { Class.new(LogStash::Plugin) } + subject(:instance) { klass.new({}) } include_context "execution_context" - it "can be set and get" do - expect(subject.execution_context).to be_nil - subject.execution_context = execution_context - expect(subject.execution_context).to eq(execution_context) + context 'execution_context=' do + let(:deprecation_logger_stub) { double('DeprecationLogger').as_null_object } + before(:each) do + allow(klass).to receive(:deprecation_logger).and_return(deprecation_logger_stub) + end + + it "can be set and get" do + new_ctx = execution_context.dup + subject.execution_context = new_ctx + expect(subject.execution_context).to eq(new_ctx) + end + + it 'emits a deprecation warning' do + expect(deprecation_logger_stub).to receive(:deprecated) do |message| + expect(message).to match(/execution_context=/) + end + instance.execution_context = execution_context + end end end @@ -402,6 +417,66 @@ describe LogStash::Plugin do end end + describe "#ecs_compatibility" do + let(:plugin_class) do + Class.new(LogStash::Filters::Base) do + config_name "ecs_validator_sample" + def register; end + end + end + let(:config) { Hash.new } + let(:instance) { plugin_class.new(config) } + + let(:deprecation_logger_stub) { double('DeprecationLogger').as_null_object } + before(:each) do + allow(plugin_class).to receive(:deprecation_logger).and_return(deprecation_logger_stub) + end + + context 'when plugin initialized with explicit value' do + let(:config) { super().merge("ecs_compatibility" => "v17") } + it 'returns the explicitly-given value' do + expect(instance.ecs_compatibility).to eq(:v17) + end + end + + context 'when plugin is not initialized with an explicit value' do + let(:settings_stub) { LogStash::SETTINGS.clone } + + before(:each) do + allow(settings_stub).to receive(:get_value).with(anything).and_call_original # allow spies + stub_const('LogStash::SETTINGS', settings_stub) + end + + context 'and pipeline-level setting is explicitly `v1`' do + let(:settings_stub) do + super().tap do |settings| + settings.set_value('pipeline.ecs_compatibility', 'v1') + end + end + it 'reads the setting' do + expect(instance.ecs_compatibility).to eq(:v1) + + expect(settings_stub).to have_received(:get_value) + end + end + + context 'and pipeline-level setting is not specified' do + it 'emits a deprecation warning about using the default which may change' do + instance.ecs_compatibility + + expect(deprecation_logger_stub).to have_received(:deprecated) do |message| + expect(message).to include("Relying on default value of `pipeline.ecs_compatibility`") + end + end + it 'returns `disabled`' do + # Default value of `pipeline.ecs_compatibility` + expect(instance.ecs_compatibility).to eq(:disabled) + end + end + end + + end + describe "deprecation logger" do let(:config) do { diff --git a/logstash-core/spec/support/shared_contexts.rb b/logstash-core/spec/support/shared_contexts.rb index 0dce17993..042869df5 100644 --- a/logstash-core/spec/support/shared_contexts.rb +++ b/logstash-core/spec/support/shared_contexts.rb @@ -22,8 +22,9 @@ shared_context "execution_context" do let(:plugin_id) { :plugin_id } let(:plugin_type) { :plugin_type } let(:dlq_writer) { double("dlq_writer") } + let(:execution_context_factory) { ::LogStash::Plugins::ExecutionContextFactory.new(agent, pipeline, dlq_writer) } let(:execution_context) do - ::LogStash::ExecutionContext.new(pipeline, agent, plugin_id, plugin_type, dlq_writer) + execution_context_factory.create(plugin_id, plugin_type) end before do diff --git a/logstash-core/src/main/java/org/logstash/RubyUtil.java b/logstash-core/src/main/java/org/logstash/RubyUtil.java index d80267923..abf864802 100644 --- a/logstash-core/src/main/java/org/logstash/RubyUtil.java +++ b/logstash-core/src/main/java/org/logstash/RubyUtil.java @@ -26,6 +26,7 @@ import org.jruby.RubyModule; import org.jruby.anno.JRubyClass; import org.jruby.exceptions.RaiseException; import org.jruby.javasupport.JavaUtil; +import org.jruby.runtime.Block; import org.jruby.runtime.ObjectAllocator; import org.jruby.runtime.builtin.IRubyObject; import org.logstash.ackedqueue.QueueFactoryExt; @@ -74,6 +75,7 @@ import org.logstash.log.LoggerExt; import org.logstash.log.SlowLoggerExt; import org.logstash.plugins.HooksRegistryExt; import org.logstash.plugins.UniversalPluginExt; +import org.logstash.plugins.factory.ContextualizerExt; import org.logstash.util.UtilExt; import org.logstash.plugins.factory.ExecutionContextFactoryExt; import org.logstash.plugins.factory.PluginMetricsFactoryExt; @@ -199,6 +201,8 @@ public final class RubyUtil { public static final RubyClass PLUGIN_FACTORY_CLASS; + public static final RubyModule PLUGIN_CONTEXTUALIZER_MODULE; + public static final RubyClass LOGGER; public static final RubyModule LOGGABLE_MODULE; @@ -333,7 +337,7 @@ public final class RubyUtil { UTIL_MODULE = LOGSTASH_MODULE.defineModuleUnder("Util"); UTIL_MODULE.defineAnnotatedMethods(UtilExt.class); ABSTRACT_DLQ_WRITER_CLASS = UTIL_MODULE.defineClassUnder( - "AbstractDeadLetterQueueWriterExt", RUBY.getObject(), + "AbstractDeadLetterQueueWriter", RUBY.getObject(), ObjectAllocator.NOT_ALLOCATABLE_ALLOCATOR ); ABSTRACT_DLQ_WRITER_CLASS.defineAnnotatedMethods(AbstractDeadLetterQueueWriterExt.class); @@ -401,6 +405,7 @@ public final class RubyUtil { EXECUTION_CONTEXT_CLASS = setupLogstashClass( ExecutionContextExt::new, ExecutionContextExt.class ); + EXECUTION_CONTEXT_CLASS.defineConstant("Empty", EXECUTION_CONTEXT_CLASS.newInstance(RUBY.getCurrentContext(), RUBY.getNil(), RUBY.getNil(), RUBY.getNil(), Block.NULL_BLOCK)); RUBY_TIMESTAMP_CLASS = setupLogstashClass( JrubyTimestampExtLibrary.RubyTimestamp::new, JrubyTimestampExtLibrary.RubyTimestamp.class ); @@ -551,6 +556,8 @@ public final class RubyUtil { "PluginFactory", RUBY.getObject(), PluginFactoryExt::new ); PLUGIN_FACTORY_CLASS.defineAnnotatedMethods(PluginFactoryExt.class); + PLUGIN_CONTEXTUALIZER_MODULE = PLUGINS_MODULE.defineOrGetModuleUnder("Contextualizer"); + PLUGIN_CONTEXTUALIZER_MODULE.defineAnnotatedMethods(ContextualizerExt.class); UNIVERSAL_PLUGIN_CLASS = setupLogstashClass(UniversalPluginExt::new, UniversalPluginExt.class); EVENT_DISPATCHER_CLASS = @@ -636,4 +643,18 @@ public final class RubyUtil { return JavaUtil.convertJavaToRuby(RUBY, javaObject); } + /** + * Cast an IRubyObject that may be nil to a specific class + * @param objectOrNil an object of either type {@code } or nil. + * @param the type to cast non-nil values to + * @return The given value, cast to {@code }, or null. + */ + public static T nilSafeCast(final IRubyObject objectOrNil) { + if (objectOrNil == null || objectOrNil.isNil()) { return null; } + + @SuppressWarnings("unchecked") + final T objectAsCasted = (T) objectOrNil; + + return objectAsCasted; + } } diff --git a/logstash-core/src/main/java/org/logstash/config/ir/CompiledPipeline.java b/logstash-core/src/main/java/org/logstash/config/ir/CompiledPipeline.java index 092e1c0e5..026ef64c9 100644 --- a/logstash-core/src/main/java/org/logstash/config/ir/CompiledPipeline.java +++ b/logstash-core/src/main/java/org/logstash/config/ir/CompiledPipeline.java @@ -164,8 +164,9 @@ public final class CompiledPipeline { outs.forEach(v -> { final PluginDefinition def = v.getPluginDefinition(); final SourceWithMetadata source = v.getSourceWithMetadata(); + final Map args = expandArguments(def, cve); res.put(v.getId(), pluginFactory.buildOutput( - RubyUtil.RUBY.newString(def.getName()), source, convertArgs(def), convertJavaArgs(def, cve) + RubyUtil.RUBY.newString(def.getName()), convertArgs(args), source )); }); return res; @@ -181,8 +182,9 @@ public final class CompiledPipeline { for (final PluginVertex vertex : filterPlugins) { final PluginDefinition def = vertex.getPluginDefinition(); final SourceWithMetadata source = vertex.getSourceWithMetadata(); + final Map args = expandArguments(def, cve); res.put(vertex.getId(), pluginFactory.buildFilter( - RubyUtil.RUBY.newString(def.getName()), source, convertArgs(def), convertJavaArgs(def, cve) + RubyUtil.RUBY.newString(def.getName()), convertArgs(args), source )); } return res; @@ -197,71 +199,47 @@ public final class CompiledPipeline { vertices.forEach(v -> { final PluginDefinition def = v.getPluginDefinition(); final SourceWithMetadata source = v.getSourceWithMetadata(); + final Map args = expandArguments(def, cve); IRubyObject o = pluginFactory.buildInput( - RubyUtil.RUBY.newString(def.getName()), source, convertArgs(def), convertJavaArgs(def, cve)); + RubyUtil.RUBY.newString(def.getName()), convertArgs(args), source); nodes.add(o); }); return nodes; } - /** - * Converts plugin arguments from the format provided by {@link PipelineIR} into coercible - * Ruby types. - * @param def PluginDefinition as provided by {@link PipelineIR} - * @return RubyHash of plugin arguments as understood by {@link RubyIntegration.PluginFactory} - * methods - */ - private RubyHash convertArgs(final PluginDefinition def) { + + final RubyHash convertArgs(final Map input) { final RubyHash converted = RubyHash.newHash(RubyUtil.RUBY); - for (final Map.Entry entry : def.getArguments().entrySet()) { + for (final Map.Entry entry : input.entrySet()) { final Object value = entry.getValue(); final String key = entry.getKey(); - final Object toput; - if (value instanceof PluginStatement) { - final PluginDefinition codec = ((PluginStatement) value).getPluginDefinition(); - SourceWithMetadata source = ((PluginStatement) value).getSourceWithMetadata(); - toput = pluginFactory.buildCodec( - RubyUtil.RUBY.newString(codec.getName()), - source, - Rubyfier.deep(RubyUtil.RUBY, codec.getArguments()), - codec.getArguments() - ); - } else { - toput = value; - } - converted.put(key, toput); + converted.put(key, value); } + return converted; } - /** - * Converts plugin arguments from the format provided by {@link PipelineIR} into coercible - * Java types for consumption by Java plugins. - * @param def PluginDefinition as provided by {@link PipelineIR} - * @return Map of plugin arguments as understood by the {@link RubyIntegration.PluginFactory} - * methods that create Java plugins - */ - private Map convertJavaArgs(final PluginDefinition def, ConfigVariableExpander cve) { - Map args = expandConfigVariables(cve, def.getArguments()); - for (final Map.Entry entry : args.entrySet()) { - final Object value = entry.getValue(); + + private Map expandArguments(final PluginDefinition pluginDefinition, final ConfigVariableExpander cve) { + Map arguments = expandConfigVariables(cve, pluginDefinition.getArguments()); + + // Intercept codec definitions from LIR + for (final Map.Entry entry : arguments.entrySet()) { final String key = entry.getKey(); - final IRubyObject toput; + final Object value = entry.getValue(); if (value instanceof PluginStatement) { - final PluginDefinition codec = ((PluginStatement) value).getPluginDefinition(); - SourceWithMetadata source = ((PluginStatement) value).getSourceWithMetadata(); - Map codecArgs = expandConfigVariables(cve, codec.getArguments()); - toput = pluginFactory.buildCodec( - RubyUtil.RUBY.newString(codec.getName()), - source, - Rubyfier.deep(RubyUtil.RUBY, codec.getArguments()), - codecArgs - ); - Codec javaCodec = (Codec)JavaUtil.unwrapJavaValue(toput); - args.put(key, javaCodec); + final PluginStatement codecPluginStatement = (PluginStatement) value; + final PluginDefinition codecDefinition = codecPluginStatement.getPluginDefinition(); + final SourceWithMetadata codecSource = codecPluginStatement.getSourceWithMetadata(); + final Map codecArguments = expandArguments(codecDefinition, cve); + IRubyObject codecInstance = pluginFactory.buildCodec(RubyUtil.RUBY.newString(codecDefinition.getName()), + Rubyfier.deep(RubyUtil.RUBY, codecArguments), + codecSource); + arguments.put(key, codecInstance); } } - return args; + + return arguments; } @SuppressWarnings({"rawtypes", "unchecked"}) diff --git a/logstash-core/src/main/java/org/logstash/config/ir/compiler/OutputStrategyExt.java b/logstash-core/src/main/java/org/logstash/config/ir/compiler/OutputStrategyExt.java index c5afaac05..b50f76652 100644 --- a/logstash-core/src/main/java/org/logstash/config/ir/compiler/OutputStrategyExt.java +++ b/logstash-core/src/main/java/org/logstash/config/ir/compiler/OutputStrategyExt.java @@ -32,9 +32,14 @@ import org.jruby.RubyObject; import org.jruby.anno.JRubyClass; import org.jruby.anno.JRubyMethod; import org.jruby.internal.runtime.methods.DynamicMethod; +import org.jruby.runtime.Block; import org.jruby.runtime.ThreadContext; import org.jruby.runtime.builtin.IRubyObject; import org.logstash.RubyUtil; +import org.logstash.execution.ExecutionContextExt; +import org.logstash.plugins.factory.ContextualizerExt; + +import static org.logstash.RubyUtil.PLUGIN_CONTEXTUALIZER_MODULE; public final class OutputStrategyExt { @@ -176,6 +181,9 @@ public final class OutputStrategyExt { @JRubyMethod(required = 4) public IRubyObject initialize(final ThreadContext context, final IRubyObject[] args) { + final RubyClass outputClass = (RubyClass) args[0]; + final IRubyObject metric = args[1]; + final ExecutionContextExt executionContext = (ExecutionContextExt) args[2]; final RubyHash pluginArgs = (RubyHash) args[3]; workerCount = pluginArgs.op_aref(context, context.runtime.newString("workers")); if (workerCount.isNil()) { @@ -185,12 +193,9 @@ public final class OutputStrategyExt { workerQueue = new ArrayBlockingQueue<>(count); workers = context.runtime.newArray(count); for (int i = 0; i < count; ++i) { - final RubyClass outputClass = (RubyClass) args[0]; - // Calling "new" here manually to allow mocking the ctor in RSpec Tests - final IRubyObject output = outputClass.callMethod(context, "new", pluginArgs); + final IRubyObject output = ContextualizerExt.initializePlugin(context, executionContext, outputClass, pluginArgs); initOutputCallsite(outputClass); - output.callMethod(context, "metric=", args[1]); - output.callMethod(context, "execution_context=", args[2]); + output.callMethod(context, "metric=", metric); workers.append(output); workerQueue.add(output); } @@ -248,11 +253,15 @@ public final class OutputStrategyExt { @JRubyMethod(required = 4) public IRubyObject initialize(final ThreadContext context, final IRubyObject[] args) { final RubyClass outputClass = (RubyClass) args[0]; + final IRubyObject metric = args[1]; + final ExecutionContextExt executionContext = (ExecutionContextExt) args[2]; + final RubyHash pluginArgs = (RubyHash) args[3]; + // TODO: fixup mocks // Calling "new" here manually to allow mocking the ctor in RSpec Tests - output = args[0].callMethod(context, "new", args[3]); + output = ContextualizerExt.initializePlugin(context, executionContext, outputClass, pluginArgs); + initOutputCallsite(outputClass); - output.callMethod(context, "metric=", args[1]); - output.callMethod(context, "execution_context=", args[2]); + output.callMethod(context, "metric=", metric); return this; } diff --git a/logstash-core/src/main/java/org/logstash/config/ir/compiler/PluginFactory.java b/logstash-core/src/main/java/org/logstash/config/ir/compiler/PluginFactory.java deleted file mode 100644 index e476ad436..000000000 --- a/logstash-core/src/main/java/org/logstash/config/ir/compiler/PluginFactory.java +++ /dev/null @@ -1,90 +0,0 @@ -/* - * 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. - */ - - -package org.logstash.config.ir.compiler; - -import co.elastic.logstash.api.Codec; -import org.jruby.RubyString; -import org.jruby.runtime.builtin.IRubyObject; -import co.elastic.logstash.api.Configuration; -import co.elastic.logstash.api.Context; -import co.elastic.logstash.api.Filter; -import co.elastic.logstash.api.Input; -import org.logstash.common.SourceWithMetadata; - -import java.util.Map; - -/** - * Factory that can instantiate Java plugins as well as Ruby plugins. - */ -public interface PluginFactory extends RubyIntegration.PluginFactory { - - Input buildInput(String name, String id, Configuration configuration, Context context); - - Filter buildFilter(String name, String id, Configuration configuration, Context context); - - final class Default implements PluginFactory { - - private final RubyIntegration.PluginFactory rubyFactory; - - public Default(final RubyIntegration.PluginFactory rubyFactory) { - this.rubyFactory = rubyFactory; - } - - @Override - public Input buildInput(final String name, final String id, final Configuration configuration, final Context context) { - return null; - } - - @Override - public Filter buildFilter(final String name, final String id, final Configuration configuration, final Context context) { - return null; - } - - @Override - public IRubyObject buildInput(final RubyString name, SourceWithMetadata source, - final IRubyObject args, Map pluginArgs) { - return rubyFactory.buildInput(name, source, args, pluginArgs); - } - - @Override - public AbstractOutputDelegatorExt buildOutput(final RubyString name, SourceWithMetadata source, - final IRubyObject args, final Map pluginArgs) { - return rubyFactory.buildOutput(name, source, args, pluginArgs); - } - - @Override - public AbstractFilterDelegatorExt buildFilter(final RubyString name, SourceWithMetadata source, - final IRubyObject args, final Map pluginArgs) { - return rubyFactory.buildFilter(name, source, args, pluginArgs); - } - - @Override - public IRubyObject buildCodec(final RubyString name, SourceWithMetadata source, final IRubyObject args, - Map pluginArgs) { - return rubyFactory.buildCodec(name, source, args, pluginArgs); - } - - @Override - public Codec buildDefaultCodec(final String codecName) { - return null; - } - } -} diff --git a/logstash-core/src/main/java/org/logstash/config/ir/compiler/RubyIntegration.java b/logstash-core/src/main/java/org/logstash/config/ir/compiler/RubyIntegration.java index faac9f66d..bc66371c6 100644 --- a/logstash-core/src/main/java/org/logstash/config/ir/compiler/RubyIntegration.java +++ b/logstash-core/src/main/java/org/logstash/config/ir/compiler/RubyIntegration.java @@ -41,17 +41,13 @@ public final class RubyIntegration { */ public interface PluginFactory { - IRubyObject buildInput(RubyString name, SourceWithMetadata source, - IRubyObject args, Map pluginArgs); + IRubyObject buildInput(RubyString name, IRubyObject args, SourceWithMetadata source); - AbstractOutputDelegatorExt buildOutput(RubyString name, SourceWithMetadata source, - IRubyObject args, Map pluginArgs); + AbstractOutputDelegatorExt buildOutput(RubyString name, IRubyObject args, SourceWithMetadata source); - AbstractFilterDelegatorExt buildFilter(RubyString name, SourceWithMetadata source, IRubyObject args, - Map pluginArgs); + AbstractFilterDelegatorExt buildFilter(RubyString name, IRubyObject args, SourceWithMetadata source); - IRubyObject buildCodec(RubyString name, SourceWithMetadata source, IRubyObject args, - Map pluginArgs); + IRubyObject buildCodec(RubyString name, IRubyObject args, SourceWithMetadata source); Codec buildDefaultCodec(String codecName); diff --git a/logstash-core/src/main/java/org/logstash/execution/Engine.java b/logstash-core/src/main/java/org/logstash/execution/Engine.java new file mode 100644 index 000000000..112b6bf2d --- /dev/null +++ b/logstash-core/src/main/java/org/logstash/execution/Engine.java @@ -0,0 +1,7 @@ +package org.logstash.execution; + +public enum Engine { + RUBY, + JAVA, + ; +} diff --git a/logstash-core/src/main/java/org/logstash/execution/ExecutionContextExt.java b/logstash-core/src/main/java/org/logstash/execution/ExecutionContextExt.java index e99cd52aa..f7815c746 100644 --- a/logstash-core/src/main/java/org/logstash/execution/ExecutionContextExt.java +++ b/logstash-core/src/main/java/org/logstash/execution/ExecutionContextExt.java @@ -25,6 +25,7 @@ import org.jruby.RubyClass; import org.jruby.RubyObject; import org.jruby.anno.JRubyClass; import org.jruby.anno.JRubyMethod; +import org.jruby.runtime.Block; import org.jruby.runtime.ThreadContext; import org.jruby.runtime.builtin.IRubyObject; import org.logstash.RubyUtil; @@ -45,14 +46,16 @@ public final class ExecutionContextExt extends RubyObject { super(runtime, metaClass); } - @JRubyMethod(required = 5) + @JRubyMethod(required = 2, optional = 1) public ExecutionContextExt initialize(final ThreadContext context, final IRubyObject[] args) { pipeline = args[0]; agent = args[1]; - dlqWriter = new AbstractDeadLetterQueueWriterExt.PluginDeadLetterQueueWriterExt( - context.runtime, RubyUtil.PLUGIN_DLQ_WRITER_CLASS - ).initialize(context, args[4], args[2], args[3]); + if (args.length > 2 && !args[2].isNil()) { + dlqWriter = (AbstractDeadLetterQueueWriterExt) args[2]; + } else { + dlqWriter = (AbstractDeadLetterQueueWriterExt) RubyUtil.DUMMY_DLQ_WRITER_CLASS.newInstance(context, Block.NULL_BLOCK); + } return this; } @@ -73,6 +76,9 @@ public final class ExecutionContextExt extends RubyObject { @JRubyMethod(name = "pipeline_id") public IRubyObject pipelineId(final ThreadContext context) { + if (pipeline.isNil()) { + return context.nil; + } return pipeline.callMethod(context, "pipeline_id"); } } diff --git a/logstash-core/src/main/java/org/logstash/execution/JavaBasePipelineExt.java b/logstash-core/src/main/java/org/logstash/execution/JavaBasePipelineExt.java index aea003dde..7d58f2c1a 100644 --- a/logstash-core/src/main/java/org/logstash/execution/JavaBasePipelineExt.java +++ b/logstash-core/src/main/java/org/logstash/execution/JavaBasePipelineExt.java @@ -77,7 +77,8 @@ public final class JavaBasePipelineExt extends AbstractPipelineExt { new ExecutionContextFactoryExt( context.runtime, RubyUtil.EXECUTION_CONTEXT_FACTORY_CLASS ).initialize(context, args[3], this, dlqWriter(context)), - RubyUtil.FILTER_DELEGATOR_CLASS + RubyUtil.FILTER_DELEGATOR_CLASS, + Engine.JAVA ), getSecretStore(context) ); diff --git a/logstash-core/src/main/java/org/logstash/plugins/factory/ContextualizerExt.java b/logstash-core/src/main/java/org/logstash/plugins/factory/ContextualizerExt.java new file mode 100644 index 000000000..becba99cb --- /dev/null +++ b/logstash-core/src/main/java/org/logstash/plugins/factory/ContextualizerExt.java @@ -0,0 +1,99 @@ +package org.logstash.plugins.factory; + +import org.jruby.RubyClass; +import org.jruby.RubyHash; +import org.jruby.RubyModule; +import org.jruby.anno.JRubyMethod; +import org.jruby.anno.JRubyModule; +import org.jruby.runtime.Block; +import org.jruby.runtime.ThreadContext; +import org.jruby.runtime.builtin.IRubyObject; +import org.logstash.RubyUtil; +import org.logstash.execution.ExecutionContextExt; + +import javax.annotation.Nullable; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.List; + +import static org.jruby.runtime.Helpers.invokeSuper; +import static org.logstash.RubyUtil.PLUGIN_CONTEXTUALIZER_MODULE; + +/** + * The {@link ContextualizerExt} is used to inject {@link org.logstash.execution.ExecutionContextExt } to plugins + * before they are initialized. + * + * @see ContextualizerExt#initializePlugin(ThreadContext, IRubyObject, IRubyObject[], Block) + */ +@JRubyModule(name = "Contextualizer") +public class ContextualizerExt { + + private static final String EXECUTION_CONTEXT_IVAR_NAME = "@execution_context"; + + /* + * @overload PluginContextualizer::initialize_plugin(execution_context, plugin_class, *plugin_args, &pluginBlock) + */ + @JRubyMethod(name = "initialize_plugin", meta = true, required = 2, rest = true) + public static IRubyObject initializePlugin(final ThreadContext context, + final IRubyObject recv, + final IRubyObject[] args, + final Block block) { + final List argsList = new ArrayList<>(Arrays.asList(args)); + final ExecutionContextExt executionContext = RubyUtil.nilSafeCast(argsList.remove(0)); + final RubyClass pluginClass = (RubyClass) argsList.remove(0); + final IRubyObject[] pluginArgs = argsList.toArray(new IRubyObject[]{}); + + return initializePlugin(context, (RubyModule) recv, executionContext, pluginClass, pluginArgs, block); + } + + public static IRubyObject initializePlugin(final ThreadContext context, + @Nullable final ExecutionContextExt executionContextExt, + final RubyClass pluginClass, + final RubyHash pluginArgs) { + return initializePlugin(context, PLUGIN_CONTEXTUALIZER_MODULE, executionContextExt, pluginClass, new IRubyObject[]{pluginArgs}, Block.NULL_BLOCK); + } + + private static IRubyObject initializePlugin(final ThreadContext context, + final RubyModule recv, + @Nullable final ExecutionContextExt executionContext, + final RubyClass pluginClass, + final IRubyObject[] pluginArgs, + final Block block) { + synchronized (ContextualizerExt.class) { + if (!pluginClass.hasModuleInPrepends(recv)) { + pluginClass.prepend(context, new IRubyObject[]{recv}); + } + } + + final IRubyObject[] pluginInitArgs; + if (executionContext == null) { + pluginInitArgs = pluginArgs; + } else { + List pluginInitArgList = new ArrayList<>(1 + pluginArgs.length); + pluginInitArgList.add(executionContext); + pluginInitArgList.addAll(Arrays.asList(pluginArgs)); + pluginInitArgs = pluginInitArgList.toArray(new IRubyObject[]{}); + } + + // We must use IRubyObject#callMethod(...,"new",...) here to continue supporting + // mocking/validating from rspec. + return pluginClass.callMethod(context, "new", pluginInitArgs, block); + } + + @JRubyMethod(name = "initialize", rest = true, frame = true) // framed for invokeSuper + public static IRubyObject initialize(final ThreadContext context, + final IRubyObject recv, + final IRubyObject[] args, + final Block block) { + final List argsList = new ArrayList<>(Arrays.asList(args)); + + if (args.length > 0 && args[0] instanceof ExecutionContextExt) { + final ExecutionContextExt executionContext = (ExecutionContextExt) argsList.remove(0); + recv.getInstanceVariables().setInstanceVariable(EXECUTION_CONTEXT_IVAR_NAME, executionContext); + } + + final IRubyObject[] restArgs = argsList.toArray(new IRubyObject[]{}); + + return invokeSuper(context, recv, restArgs, block); + } +} diff --git a/logstash-core/src/main/java/org/logstash/plugins/factory/ExecutionContextFactoryExt.java b/logstash-core/src/main/java/org/logstash/plugins/factory/ExecutionContextFactoryExt.java index d72ef4a5c..2799eb12c 100644 --- a/logstash-core/src/main/java/org/logstash/plugins/factory/ExecutionContextFactoryExt.java +++ b/logstash-core/src/main/java/org/logstash/plugins/factory/ExecutionContextFactoryExt.java @@ -46,10 +46,14 @@ public final class ExecutionContextFactoryExt extends RubyBasicObject { @JRubyMethod public ExecutionContextExt create(final ThreadContext context, final IRubyObject id, final IRubyObject classConfigName) { + final AbstractDeadLetterQueueWriterExt dlqWriterForInstance = new AbstractDeadLetterQueueWriterExt.PluginDeadLetterQueueWriterExt( + context.runtime, RubyUtil.PLUGIN_DLQ_WRITER_CLASS + ).initialize(context, dlqWriter, id, classConfigName); + return new ExecutionContextExt( context.runtime, RubyUtil.EXECUTION_CONTEXT_CLASS ).initialize( - context, new IRubyObject[]{pipeline, agent, id, classConfigName, dlqWriter} + context, new IRubyObject[]{pipeline, agent, dlqWriterForInstance} ); } diff --git a/logstash-core/src/main/java/org/logstash/plugins/factory/PluginFactoryExt.java b/logstash-core/src/main/java/org/logstash/plugins/factory/PluginFactoryExt.java index a226e57d5..0d3226e07 100644 --- a/logstash-core/src/main/java/org/logstash/plugins/factory/PluginFactoryExt.java +++ b/logstash-core/src/main/java/org/logstash/plugins/factory/PluginFactoryExt.java @@ -5,6 +5,7 @@ import org.jruby.*; import org.jruby.anno.JRubyClass; import org.jruby.anno.JRubyMethod; import org.jruby.javasupport.JavaUtil; +import org.jruby.runtime.Block; import org.jruby.runtime.ThreadContext; import org.jruby.runtime.builtin.IRubyObject; import org.logstash.RubyUtil; @@ -13,6 +14,7 @@ import org.logstash.common.SourceWithMetadata; import org.logstash.config.ir.PipelineIR; import org.logstash.config.ir.compiler.*; import org.logstash.config.ir.graph.Vertex; +import org.logstash.execution.Engine; import org.logstash.execution.ExecutionContextExt; import org.logstash.instrument.metrics.AbstractMetricExt; import org.logstash.instrument.metrics.AbstractNamespacedMetricExt; @@ -21,6 +23,7 @@ import org.logstash.plugins.ConfigVariableExpander; import org.logstash.plugins.PluginLookup; import java.util.*; +import java.util.concurrent.ConcurrentHashMap; @JRubyClass(name = "PluginFactory") public final class PluginFactoryExt extends RubyBasicObject @@ -35,7 +38,9 @@ public final class PluginFactoryExt extends RubyBasicObject private static final RubyString ID_KEY = RubyUtil.RUBY.newString("id"); - private final Collection pluginsById = new HashSet<>(); + private final Collection pluginsById = ConcurrentHashMap.newKeySet(); + + private Engine engine; private PipelineIR lir; @@ -43,7 +48,7 @@ public final class PluginFactoryExt extends RubyBasicObject private PluginMetricsFactoryExt metrics; - private RubyClass filterClass; + private RubyClass filterDelegatorClass; private ConfigVariableExpander configVariables; @@ -54,16 +59,22 @@ public final class PluginFactoryExt extends RubyBasicObject @JRubyMethod(name = "filter_delegator", meta = true, required = 5) public static IRubyObject filterDelegator(final ThreadContext context, final IRubyObject recv, final IRubyObject... args) { + // filterDelegatorClass, klass, rubyArgs, typeScopedMetric, executionCntx + final RubyClass filterDelegatorClass = (RubyClass) args[0]; + final RubyClass klass = (RubyClass) args[1]; final RubyHash arguments = (RubyHash) args[2]; - final IRubyObject filterInstance = args[1].callMethod(context, "new", arguments); + final AbstractMetricExt typeScopedMetric = (AbstractMetricExt) args[3]; + final ExecutionContextExt executionContext = (ExecutionContextExt) args[4]; + + final IRubyObject filterInstance = ContextualizerExt.initializePlugin(context, executionContext, klass, arguments); + final RubyString id = (RubyString) arguments.op_aref(context, ID_KEY); filterInstance.callMethod( context, "metric=", - ((AbstractMetricExt) args[3]).namespace(context, id.intern()) + typeScopedMetric.namespace(context, id.intern()) ); - filterInstance.callMethod(context, "execution_context=", args[4]); - return new FilterDelegatorExt(context.runtime, RubyUtil.FILTER_DELEGATOR_CLASS) - .initialize(context, filterInstance, id); + + return filterDelegatorClass.newInstance(context, filterInstance, id, Block.NULL_BLOCK); } public PluginFactoryExt(final Ruby runtime, final RubyClass metaClass) { @@ -80,25 +91,33 @@ public final class PluginFactoryExt extends RubyBasicObject final IRubyObject[] args) { return init( args[0].toJava(PipelineIR.class), - (PluginMetricsFactoryExt) args[1], (ExecutionContextFactoryExt) args[2], - (RubyClass) args[3] + (PluginMetricsFactoryExt) args[1], + (ExecutionContextFactoryExt) args[2], + (RubyClass) args[3], + EnvironmentVariableProvider.defaultProvider(), + Engine.RUBY ); } - public PluginFactoryExt init(final PipelineIR lir, final PluginMetricsFactoryExt metrics, - final ExecutionContextFactoryExt executionContextFactoryExt, - final RubyClass filterClass) { - return this.init(lir, metrics, executionContextFactoryExt, filterClass, EnvironmentVariableProvider.defaultProvider()); + public PluginFactoryExt init(final PipelineIR lir, + final PluginMetricsFactoryExt metrics, + final ExecutionContextFactoryExt executionContextFactoryExt, + final RubyClass filterClass, + final Engine engine) { + return this.init(lir, metrics, executionContextFactoryExt, filterClass, EnvironmentVariableProvider.defaultProvider(), engine); } - PluginFactoryExt init(final PipelineIR lir, final PluginMetricsFactoryExt metrics, + PluginFactoryExt init(final PipelineIR lir, + final PluginMetricsFactoryExt metrics, final ExecutionContextFactoryExt executionContextFactoryExt, final RubyClass filterClass, - final EnvironmentVariableProvider envVars) { + final EnvironmentVariableProvider envVars, + final Engine engine) { this.lir = lir; this.metrics = metrics; this.executionContextFactory = executionContextFactoryExt; - this.filterClass = filterClass; + this.filterDelegatorClass = filterClass; + this.engine = engine; this.pluginCreatorsRegistry.put(PluginLookup.PluginType.INPUT, new InputPluginCreator(this)); this.pluginCreatorsRegistry.put(PluginLookup.PluginType.CODEC, new CodecPluginCreator()); this.pluginCreatorsRegistry.put(PluginLookup.PluginType.FILTER, new FilterPluginCreator()); @@ -109,71 +128,102 @@ public final class PluginFactoryExt extends RubyBasicObject @SuppressWarnings("unchecked") @Override - public IRubyObject buildInput(final RubyString name, SourceWithMetadata source, - final IRubyObject args, Map pluginArgs) { + public IRubyObject buildInput(final RubyString name, + final IRubyObject args, + final SourceWithMetadata source) { return plugin( - RubyUtil.RUBY.getCurrentContext(), PluginLookup.PluginType.INPUT, name.asJavaString(), - source, (Map) args, pluginArgs + RubyUtil.RUBY.getCurrentContext(), + PluginLookup.PluginType.INPUT, + name.asJavaString(), + (RubyHash) args, + source ); } @SuppressWarnings("unchecked") @Override - public AbstractOutputDelegatorExt buildOutput(final RubyString name, SourceWithMetadata source, - final IRubyObject args, Map pluginArgs) { + public AbstractOutputDelegatorExt buildOutput(final RubyString name, + final IRubyObject args, + final SourceWithMetadata source) { return (AbstractOutputDelegatorExt) plugin( RubyUtil.RUBY.getCurrentContext(), PluginLookup.PluginType.OUTPUT, name.asJavaString(), - source, (Map) args, pluginArgs + (RubyHash) args, source ); } @SuppressWarnings("unchecked") @Override - public AbstractFilterDelegatorExt buildFilter(final RubyString name, SourceWithMetadata source, - final IRubyObject args, Map pluginArgs) { + public AbstractFilterDelegatorExt buildFilter(final RubyString name, + final IRubyObject args, + final SourceWithMetadata source) { return (AbstractFilterDelegatorExt) plugin( RubyUtil.RUBY.getCurrentContext(), PluginLookup.PluginType.FILTER, name.asJavaString(), - source, (Map) args, pluginArgs + (RubyHash) args, source ); } @SuppressWarnings("unchecked") @Override - public IRubyObject buildCodec(final RubyString name, SourceWithMetadata source, final IRubyObject args, - Map pluginArgs) { + public IRubyObject buildCodec(final RubyString name, + final IRubyObject args, + final SourceWithMetadata source) { return plugin( - RubyUtil.RUBY.getCurrentContext(), PluginLookup.PluginType.CODEC, - name.asJavaString(), source, (Map) args, pluginArgs + RubyUtil.RUBY.getCurrentContext(), + PluginLookup.PluginType.CODEC, + name.asJavaString(), + (RubyHash) args, + source ); } @Override public Codec buildDefaultCodec(String codecName) { return (Codec) JavaUtil.unwrapJavaValue(plugin( - RubyUtil.RUBY.getCurrentContext(), PluginLookup.PluginType.CODEC, - codecName, null, Collections.emptyMap(), Collections.emptyMap() + RubyUtil.RUBY.getCurrentContext(), + PluginLookup.PluginType.CODEC, + codecName, + RubyHash.newHash(RubyUtil.RUBY), + null )); } @SuppressWarnings("unchecked") @JRubyMethod(required = 3, optional = 1) public IRubyObject plugin(final ThreadContext context, final IRubyObject[] args) { + final SourceWithMetadata source = args.length > 3 ? (SourceWithMetadata) JavaUtil.unwrapIfJavaObject(args[3]) : null; + return plugin( context, PluginLookup.PluginType.valueOf(args[0].asJavaString().toUpperCase(Locale.ENGLISH)), args[1].asJavaString(), - JavaUtil.unwrapIfJavaObject(args[2]), - args.length > 3 ? (Map) args[3] : new HashMap<>(), - null + (RubyHash) args[2], + source ); } @SuppressWarnings("unchecked") - private IRubyObject plugin(final ThreadContext context, final PluginLookup.PluginType type, final String name, - SourceWithMetadata source, final Map args, - Map pluginArgs) { - final String id = generateOrRetrievePluginId(context, type, name, source); - pluginsById.add(id); + private IRubyObject plugin(final ThreadContext context, + final PluginLookup.PluginType type, + final String name, + final RubyHash args, + final SourceWithMetadata source) { + final String id = generateOrRetrievePluginId(type, source, args); + + if (id == null) { + throw context.runtime.newRaiseException( + RubyUtil.CONFIGURATION_ERROR_CLASS, + String.format( + "Could not determine ID for %s/%s", type.rubyLabel().asJavaString(), name + ) + ); + } + if (!pluginsById.add(id)) { + throw context.runtime.newRaiseException( + RubyUtil.CONFIGURATION_ERROR_CLASS, + String.format("Two plugins have the id '%s', please fix this conflict", id) + ); + } + final AbstractNamespacedMetricExt typeScopedMetric = metrics.create(context, type.rubyLabel()); final PluginLookup.PluginClass pluginClass = pluginResolver.resolve(type, name); @@ -199,19 +249,19 @@ public final class PluginFactoryExt extends RubyBasicObject } else if (type == PluginLookup.PluginType.FILTER) { return filterDelegator( context, null, - filterClass, klass, rubyArgs, typeScopedMetric, executionCntx); + filterDelegatorClass, klass, rubyArgs, typeScopedMetric, executionCntx); } else { - final IRubyObject pluginInstance = klass.callMethod(context, "new", rubyArgs); + final IRubyObject pluginInstance = ContextualizerExt.initializePlugin(context, executionCntx, klass, rubyArgs); + final AbstractNamespacedMetricExt scopedMetric = typeScopedMetric.namespace(context, RubyUtil.RUBY.newSymbol(id)); scopedMetric.gauge(context, MetricKeys.NAME_KEY, pluginInstance.callMethod(context, "config_name")); pluginInstance.callMethod(context, "metric=", scopedMetric); - pluginInstance.callMethod(context, "execution_context=", executionCntx); return pluginInstance; } } else { - if (pluginArgs == null) { - String err = String.format("Cannot start the Java plugin '%s' in the Ruby execution engine." + - " The Java execution engine is required to run Java plugins.", name); + if (engine != Engine.JAVA) { + String err = String.format("Cannot start the Java plugin '%s' in the %s execution engine." + + " The Java execution engine is required to run Java plugins.", name, engine); throw new IllegalStateException(err); } @@ -221,38 +271,97 @@ public final class PluginFactoryExt extends RubyBasicObject } Context contextWithMetrics = executionContextFactory.toContext(type, metrics.getRoot(context)); - return pluginCreator.createDelegator(name, pluginArgs, id, typeScopedMetric, pluginClass, contextWithMetrics); + return pluginCreator.createDelegator(name, convertToJavaCoercible(args), id, typeScopedMetric, pluginClass, contextWithMetrics); } } - private String generateOrRetrievePluginId(ThreadContext context, PluginLookup.PluginType type, String name, - SourceWithMetadata source) { - final String id; - if (type == PluginLookup.PluginType.CODEC) { - id = UUID.randomUUID().toString(); + private Map convertToJavaCoercible(Map input) { + final Map output = new HashMap<>(input); + + // Intercept Codecs + for (final Map.Entry entry : input.entrySet()) { + final String key = entry.getKey(); + final Object value = entry.getValue(); + if (value instanceof IRubyObject) { + final Object unwrapped = JavaUtil.unwrapJavaValue((IRubyObject) value); + if (unwrapped instanceof Codec) { + output.put(key, unwrapped); + } + } + } + + return output; + } + + // TODO: caller seems to think that the args is `Map`, but + // at least any `id` present is actually a `String`. + private String generateOrRetrievePluginId(final PluginLookup.PluginType type, + final SourceWithMetadata source, + final Map args) { + final Optional unprocessedId; + if (source == null) { + unprocessedId = extractId(() -> extractIdFromArgs(args), + this::generateUUID); } else { - String unresolvedId = lir.getGraph().vertices() - .filter(v -> v.getSourceWithMetadata() != null - && v.getSourceWithMetadata().equalsWithoutText(source)) - .findFirst() - .map(Vertex::getId).orElse(null); - id = (String) configVariables.expand(unresolvedId); + unprocessedId = extractId(() -> extractIdFromLIR(source), + () -> extractIdFromArgs(args), + () -> generateUUIDForCodecs(type)); } - if (id == null) { - throw context.runtime.newRaiseException( - RubyUtil.CONFIGURATION_ERROR_CLASS, - String.format( - "Could not determine ID for %s/%s", type.rubyLabel().asJavaString(), name - ) - ); + + return unprocessedId + .map(configVariables::expand) + .filter(String.class::isInstance) + .map(String.class::cast) + .orElse(null); + } + + private Optional extractId(final IdExtractor... extractors) { + for (IdExtractor extractor : extractors) { + final Optional extracted = extractor.extract(); + if (extracted.isPresent()) { + return extracted; + } } - if (pluginsById.contains(id)) { - throw context.runtime.newRaiseException( - RubyUtil.CONFIGURATION_ERROR_CLASS, - String.format("Two plugins have the id '%s', please fix this conflict", id) - ); + return Optional.empty(); + } + + @FunctionalInterface + interface IdExtractor { + Optional extract(); + } + + private Optional extractIdFromArgs(final Map args) { + if (!args.containsKey("id")) { + return Optional.empty(); } - return id; + + final Object explicitId = args.get("id"); + if (explicitId instanceof String) { + return Optional.of((String) explicitId); + } else if (explicitId instanceof RubyString) { + return Optional.of(((RubyString) explicitId).asJavaString()); + } else { + return Optional.empty(); + } + } + + private Optional generateUUID() { + return Optional.of(UUID.randomUUID().toString()); + } + + private Optional generateUUIDForCodecs(final PluginLookup.PluginType pluginType) { + if (pluginType == PluginLookup.PluginType.CODEC) { + return generateUUID(); + } + return Optional.empty(); + } + + private Optional extractIdFromLIR(final SourceWithMetadata source) { + return lir.getGraph().vertices() + .filter(v -> v.getSourceWithMetadata() != null + && v.getSourceWithMetadata().equalsWithoutText(source)) + .findFirst() + .map(Vertex::getId); } ExecutionContextFactoryExt getExecutionContextFactory() { diff --git a/logstash-core/src/test/java/org/logstash/config/ir/CompiledPipelineTest.java b/logstash-core/src/test/java/org/logstash/config/ir/CompiledPipelineTest.java index 0ac719527..bf93b73d1 100644 --- a/logstash-core/src/test/java/org/logstash/config/ir/CompiledPipelineTest.java +++ b/logstash-core/src/test/java/org/logstash/config/ir/CompiledPipelineTest.java @@ -54,12 +54,8 @@ import org.logstash.config.ir.compiler.AbstractFilterDelegatorExt; import org.logstash.config.ir.compiler.AbstractOutputDelegatorExt; import org.logstash.config.ir.compiler.ComputeStepSyntaxElement; import org.logstash.config.ir.compiler.FilterDelegatorExt; -import org.logstash.config.ir.compiler.PluginFactory; +import org.logstash.config.ir.compiler.RubyIntegration; import org.logstash.ext.JrubyEventExtLibrary; -import co.elastic.logstash.api.Configuration; -import co.elastic.logstash.api.Filter; -import co.elastic.logstash.api.Input; -import co.elastic.logstash.api.Context; import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertTrue; @@ -494,9 +490,9 @@ public final class CompiledPipelineTest extends RubyEnvTestCase { } /** - * Configurable Mock {@link PluginFactory} + * Configurable Mock {@link RubyIntegration.PluginFactory} */ - static final class MockPluginFactory implements PluginFactory { + static final class MockPluginFactory implements RubyIntegration.PluginFactory { private final Map> inputs; @@ -514,20 +510,20 @@ public final class CompiledPipelineTest extends RubyEnvTestCase { } @Override - public IRubyObject buildInput(final RubyString name, SourceWithMetadata source, - final IRubyObject args, Map pluginArgs) { + public IRubyObject buildInput(final RubyString name, final IRubyObject args, + SourceWithMetadata source) { return setupPlugin(name, inputs); } @Override - public AbstractOutputDelegatorExt buildOutput(final RubyString name, SourceWithMetadata source, - final IRubyObject args, Map pluginArgs) { + public AbstractOutputDelegatorExt buildOutput(final RubyString name, final IRubyObject args, + SourceWithMetadata source) { return PipelineTestUtil.buildOutput(setupPlugin(name, outputs)); } @Override - public AbstractFilterDelegatorExt buildFilter(final RubyString name, SourceWithMetadata source, - final IRubyObject args, Map pluginArgs) { + public AbstractFilterDelegatorExt buildFilter(final RubyString name, final IRubyObject args, + SourceWithMetadata source) { final RubyObject configNameDouble = org.logstash.config.ir.PluginConfigNameMethodDouble.create(name); return new FilterDelegatorExt( RubyUtil.RUBY, RubyUtil.FILTER_DELEGATOR_CLASS) @@ -535,8 +531,7 @@ public final class CompiledPipelineTest extends RubyEnvTestCase { } @Override - public IRubyObject buildCodec(final RubyString name, SourceWithMetadata source, final IRubyObject args, - Map pluginArgs) { + public IRubyObject buildCodec(final RubyString name, final IRubyObject args, SourceWithMetadata source) { throw new IllegalStateException("No codec setup expected in this test."); } @@ -555,17 +550,6 @@ public final class CompiledPipelineTest extends RubyEnvTestCase { } return suppliers.get(name.asJavaString()).get(); } - - @Override - public Input buildInput(final String name, final String id, final Configuration configuration, final Context context) { - return null; - } - - @Override - public Filter buildFilter(final String name, final String id, - final Configuration configuration, final Context context) { - return null; - } } @Test @@ -698,9 +682,9 @@ public final class CompiledPipelineTest extends RubyEnvTestCase { } /** - * Fixed Mock {@link PluginFactory} + * Fixed Mock {@link RubyIntegration.PluginFactory} * */ - static final class FixedPluginFactory implements PluginFactory { + static final class FixedPluginFactory implements RubyIntegration.PluginFactory { private Supplier input; private Supplier filter; @@ -714,27 +698,17 @@ public final class CompiledPipelineTest extends RubyEnvTestCase { } @Override - public Input buildInput(String name, String id, Configuration configuration, Context context) { - return null; - } - - @Override - public Filter buildFilter(String name, String id, Configuration configuration, Context context) { - return null; - } - - @Override - public IRubyObject buildInput(RubyString name, SourceWithMetadata source, IRubyObject args, Map pluginArgs) { + public IRubyObject buildInput(RubyString name, IRubyObject args, SourceWithMetadata source) { return this.input.get(); } @Override - public AbstractOutputDelegatorExt buildOutput(RubyString name, SourceWithMetadata source, IRubyObject args, Map pluginArgs) { + public AbstractOutputDelegatorExt buildOutput(RubyString name, IRubyObject args, SourceWithMetadata source) { return PipelineTestUtil.buildOutput(this.output.get()); } @Override - public AbstractFilterDelegatorExt buildFilter(RubyString name, SourceWithMetadata source, IRubyObject args, Map pluginArgs) { + public AbstractFilterDelegatorExt buildFilter(RubyString name, IRubyObject args, SourceWithMetadata source) { final RubyObject configNameDouble = org.logstash.config.ir.PluginConfigNameMethodDouble.create(name); return new FilterDelegatorExt( RubyUtil.RUBY, RubyUtil.FILTER_DELEGATOR_CLASS) @@ -742,7 +716,7 @@ public final class CompiledPipelineTest extends RubyEnvTestCase { } @Override - public IRubyObject buildCodec(RubyString name, SourceWithMetadata source, IRubyObject args, Map pluginArgs) { + public IRubyObject buildCodec(RubyString name, IRubyObject args, SourceWithMetadata source) { return null; } diff --git a/logstash-core/src/test/java/org/logstash/config/ir/compiler/PluginFactoryTest.java b/logstash-core/src/test/java/org/logstash/config/ir/compiler/PluginFactoryTest.java deleted file mode 100644 index ebc399069..000000000 --- a/logstash-core/src/test/java/org/logstash/config/ir/compiler/PluginFactoryTest.java +++ /dev/null @@ -1,35 +0,0 @@ -/* - * 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. - */ - - -package org.logstash.config.ir.compiler; - -import org.junit.Test; - -/** - * Tests for {@link PluginFactory.Default}. - */ -public final class PluginFactoryTest { - - @Test - public void testBuildJavaFilter() throws Exception { - - } - -} diff --git a/logstash-core/src/test/java/org/logstash/plugins/TestPluginFactory.java b/logstash-core/src/test/java/org/logstash/plugins/TestPluginFactory.java index ca2c2f02c..2476b4c0b 100644 --- a/logstash-core/src/test/java/org/logstash/plugins/TestPluginFactory.java +++ b/logstash-core/src/test/java/org/logstash/plugins/TestPluginFactory.java @@ -30,31 +30,29 @@ import org.logstash.config.ir.compiler.RubyIntegration; import org.logstash.plugins.codecs.Line; import java.util.Collections; -import java.util.Map; public class TestPluginFactory implements RubyIntegration.PluginFactory { @Override - public IRubyObject buildInput(RubyString name, SourceWithMetadata source, - IRubyObject args, Map pluginArgs) { + public IRubyObject buildInput(RubyString name, IRubyObject args, + SourceWithMetadata source) { return null; } @Override - public AbstractOutputDelegatorExt buildOutput(RubyString name, SourceWithMetadata source, - IRubyObject args, Map pluginArgs) { + public AbstractOutputDelegatorExt buildOutput(RubyString name, IRubyObject args, + SourceWithMetadata source) { return null; } @Override - public AbstractFilterDelegatorExt buildFilter(RubyString name, SourceWithMetadata source, - IRubyObject args, Map pluginArgs) { + public AbstractFilterDelegatorExt buildFilter(RubyString name, IRubyObject args, + SourceWithMetadata source) { return null; } @Override - public IRubyObject buildCodec(RubyString name, SourceWithMetadata source, IRubyObject args, - Map pluginArgs) { + public IRubyObject buildCodec(RubyString name, IRubyObject args, SourceWithMetadata source) { return null; } diff --git a/logstash-core/src/test/java/org/logstash/plugins/factory/PluginFactoryExtTest.java b/logstash-core/src/test/java/org/logstash/plugins/factory/PluginFactoryExtTest.java index ded3049a6..1f621b90b 100644 --- a/logstash-core/src/test/java/org/logstash/plugins/factory/PluginFactoryExtTest.java +++ b/logstash-core/src/test/java/org/logstash/plugins/factory/PluginFactoryExtTest.java @@ -30,6 +30,7 @@ import org.logstash.config.ir.ConfigCompiler; import org.logstash.config.ir.InvalidIRException; import org.logstash.config.ir.PipelineIR; import org.logstash.config.ir.RubyEnvTestCase; +import org.logstash.execution.Engine; import org.logstash.instrument.metrics.NamespacedMetricExt; import org.logstash.plugins.MetricTestCase; import org.logstash.plugins.PluginLookup; @@ -93,13 +94,12 @@ public final class PluginFactoryExtTest extends RubyEnvTestCase { envVars.put("CUSTOM", "test"); PluginFactoryExt sut = new PluginFactoryExt(RubyUtil.RUBY, RubyUtil.PLUGIN_FACTORY_CLASS, mockPluginResolver); - sut.init(pipelineIR, metricsFactory, execContextFactory, RubyUtil.FILTER_DELEGATOR_CLASS, envVars::get); + sut.init(pipelineIR, metricsFactory, execContextFactory, RubyUtil.FILTER_DELEGATOR_CLASS, envVars::get, Engine.JAVA); RubyString pluginName = RubyUtil.RUBY.newString("mockinput"); // Exercise - IRubyObject pluginInstance = sut.buildInput(pluginName, sourceWithMetadata, RubyHash.newHash(RubyUtil.RUBY), - Collections.emptyMap()); + IRubyObject pluginInstance = sut.buildInput(pluginName, RubyHash.newHash(RubyUtil.RUBY), sourceWithMetadata); //Verify IRubyObject id = pluginInstance.callMethod(RUBY.getCurrentContext(), "id"); From a93d45468840bd821aba24c14cacfe0273b5817d Mon Sep 17 00:00:00 2001 From: kaisecheng <69120390+kaisecheng@users.noreply.github.com> Date: Tue, 6 Oct 2020 21:19:36 +0200 Subject: [PATCH 0608/1126] replace direct access of hidden indices with system indices api (#12279) * replace direct hidden indices access with system indices api * fulfill backward compatibility * fix log msg, rename class, simplify response handling * modularise fetcher --- .../config_management/elasticsearch_source.rb | 120 +++- .../management/multiple_pipelines_spec.rb | 2 +- .../management/read_configuration_spec.rb | 2 +- x-pack/qa/integration/support/helpers.rb | 27 +- .../elasticsearch_source_spec.rb | 584 +++++++++++------- 5 files changed, 479 insertions(+), 256 deletions(-) diff --git a/x-pack/lib/config_management/elasticsearch_source.rb b/x-pack/lib/config_management/elasticsearch_source.rb index 9e04121fc..fa5c3736c 100644 --- a/x-pack/lib/config_management/elasticsearch_source.rb +++ b/x-pack/lib/config_management/elasticsearch_source.rb @@ -18,7 +18,6 @@ module LogStash class RemoteConfigError < LogStash::Error; end - PIPELINE_INDEX = ".logstash" # exclude basic VALID_LICENSES = %w(trial standard gold platinum enterprise) FEATURE_INTERNAL = 'management' @@ -50,6 +49,21 @@ module LogStash false end + # decide using system indices api (7.10+) or legacy api (< 7.10) base on elasticsearch server version + def get_pipeline_fetcher + response = client.get("/") + + if response["error"] + raise RemoteConfigError, "Cannot find elasticsearch version, server returned status: `#{response["status"]}`, message: `#{response["error"]}`" + end + + logger.debug("Reading configuration from Elasticsearch version {}", response["version"]["number"]) + version_number = response["version"]["number"].split(".") + first = version_number[0].to_i + second = version_number[1].to_i + (first >= 8 || (first == 7 && second >= 10))? SystemIndicesFetcher.new: LegacyHiddenIndicesFetcher.new + end + def pipeline_configs logger.trace("Fetch remote config pipeline", :pipeline_ids => pipeline_ids) @@ -63,33 +77,21 @@ module LogStash end end - response = fetch_config(pipeline_ids) + fetcher = get_pipeline_fetcher + fetcher.fetch_config(pipeline_ids, client) - if response["error"] - raise RemoteConfigError, "Cannot find find configuration for pipeline_id: #{pipeline_ids}, server returned status: `#{response["status"]}`, message: `#{response["error"]}`" - end - - if response["docs"].nil? - logger.debug("Server returned an unknown or malformed document structure", :response => response) - raise RemoteConfigError, "Elasticsearch returned an unknown or malformed document structure" - end - - # Cache pipelines to handle the case where a remote configuration error can render a pipeline unusable - # it is not reloadable - @cached_pipelines = response["docs"].collect do |document| - get_pipeline(document) + @cached_pipelines = pipeline_ids.collect do |pid| + get_pipeline(pid, fetcher) end.compact end - def get_pipeline(response) - pipeline_id = response["_id"] - - if response["found"] == false + def get_pipeline(pipeline_id, fetcher) + unless fetcher.config_exist?(pipeline_id) logger.debug("Could not find a remote configuration for a specific `pipeline_id`", :pipeline_id => pipeline_id) return nil end - config_string = response.fetch("_source", {})["pipeline"] + config_string = fetcher.get_single_pipeline_setting(pipeline_id)["pipeline"] raise RemoteConfigError, "Empty configuration for pipeline_id: #{pipeline_id}" if config_string.nil? || config_string.empty? @@ -100,7 +102,7 @@ module LogStash settings.set("pipeline.id", pipeline_id) # override global settings with pipeline settings from ES, if any - pipeline_settings = response["_source"]["pipeline_settings"] + pipeline_settings = fetcher.get_single_pipeline_setting(pipeline_id)["pipeline_settings"] unless pipeline_settings.nil? pipeline_settings.each do |setting, value| if SUPPORTED_PIPELINE_SETTINGS.include? setting @@ -127,15 +129,6 @@ module LogStash es.build_client end - def fetch_config(pipeline_ids) - request_body_string = LogStash::Json.dump({ "docs" => pipeline_ids.collect { |pipeline_id| { "_id" => pipeline_id } } }) - client.post(config_path, {}, request_body_string) - end - - def config_path - "#{PIPELINE_INDEX}/_mget" - end - def populate_license_state(xpack_info) if xpack_info.failed? { @@ -193,5 +186,72 @@ module LogStash @client ||= build_client end end + + module Fetcher + def config_exist?(pipeline_id) + @response.has_key?(pipeline_id) + end + + def fetch_config(pipeline_ids, client) end + def get_single_pipeline_setting(pipeline_id) end + end + + class SystemIndicesFetcher + include LogStash::Util::Loggable, Fetcher + + SYSTEM_INDICES_API_PATH = "_logstash/pipeline" + + def fetch_config(pipeline_ids, client) + path_ids = pipeline_ids.join(",") + response = client.get("#{SYSTEM_INDICES_API_PATH}/#{path_ids}") + + if response["error"] + raise ElasticsearchSource::RemoteConfigError, "Cannot find find configuration for pipeline_id: #{pipeline_ids}, server returned status: `#{response["status"]}`, message: `#{response["error"]}`" + end + + @response = response + end + + def get_single_pipeline_setting(pipeline_id) + @response.fetch(pipeline_id, {}) + end + end + + # clean up LegacyHiddenIndicesFetcher https://github.com/elastic/logstash/issues/12291 + class LegacyHiddenIndicesFetcher + include LogStash::Util::Loggable, Fetcher + + PIPELINE_INDEX = ".logstash" + + def fetch_config(pipeline_ids, client) + request_body_string = LogStash::Json.dump({ "docs" => pipeline_ids.collect { |pipeline_id| { "_id" => pipeline_id } } }) + response = client.post("#{PIPELINE_INDEX}/_mget", {}, request_body_string) + + if response["error"] + raise ElasticsearchSource::RemoteConfigError, "Cannot find find configuration for pipeline_id: #{pipeline_ids}, server returned status: `#{response["status"]}`, message: `#{response["error"]}`" + end + + if response["docs"].nil? + logger.debug("Server returned an unknown or malformed document structure", :response => response) + raise ElasticsearchSource::RemoteConfigError, "Elasticsearch returned an unknown or malformed document structure" + end + + @response = format_response(response) + end + + def get_single_pipeline_setting(pipeline_id) + @response.fetch(pipeline_id, {}).fetch("_source", {}) + end + + private + # transform legacy response to be similar to system indices response + def format_response(response) + response["docs"].map { |pipeline| + {pipeline["_id"] => pipeline} if pipeline.fetch("found", false) + }.compact + .reduce({}, :merge) + end + end + end end diff --git a/x-pack/qa/integration/management/multiple_pipelines_spec.rb b/x-pack/qa/integration/management/multiple_pipelines_spec.rb index b069fa89a..680f04976 100644 --- a/x-pack/qa/integration/management/multiple_pipelines_spec.rb +++ b/x-pack/qa/integration/management/multiple_pipelines_spec.rb @@ -17,7 +17,7 @@ describe "Read configuration from elasticsearch" do "hello" => nil } - cleanup_elasticsearch(".logstash*") + cleanup_system_indices(@pipelines.keys) cleanup_elasticsearch(".monitoring-logstash*") @pipelines.each do |pipeline_id, config| diff --git a/x-pack/qa/integration/management/read_configuration_spec.rb b/x-pack/qa/integration/management/read_configuration_spec.rb index 809d70c89..c60537f39 100644 --- a/x-pack/qa/integration/management/read_configuration_spec.rb +++ b/x-pack/qa/integration/management/read_configuration_spec.rb @@ -31,7 +31,7 @@ describe "Read configuration from elasticsearch" do def start_services(elasticsearch_options, logstash_options) @elasticsearch_service = elasticsearch(elasticsearch_options) - cleanup_elasticsearch(".logstash*") + cleanup_system_indices([PIPELINE_ID]) config = "input { generator { count => 100 } tcp { port => 6000 } } output { null {} }" push_elasticsearch_config(PIPELINE_ID, config) diff --git a/x-pack/qa/integration/support/helpers.rb b/x-pack/qa/integration/support/helpers.rb index 8b7e9dee4..bdc75ef73 100644 --- a/x-pack/qa/integration/support/helpers.rb +++ b/x-pack/qa/integration/support/helpers.rb @@ -8,6 +8,7 @@ require "elasticsearch" require "fileutils" require "stud/try" require "open3" +require "time" VERSIONS_YML_PATH = File.join(File.dirname(__FILE__), "..", "..", "..", "..", "versions.yml") VERSION_PATH = File.join(File.dirname(__FILE__), "..", "..", "..", "VERSION") @@ -94,8 +95,19 @@ def elasticsearch_client(options = { :url => "http://elastic:#{elastic_password} Elasticsearch::Client.new(options) end +def es_version + response = elasticsearch_client.perform_request(:get, "") + response.body["version"]["number"].gsub(/(\d+\.\d+)\..+/, '\1').to_f +end + def push_elasticsearch_config(pipeline_id, config) - elasticsearch_client.index :index => '.logstash', :type => "_doc", id: pipeline_id, :body => { :pipeline => config } + if es_version >= 7.10 + elasticsearch_client.perform_request(:put, "_logstash/pipeline/#{pipeline_id}", {}, + { :pipeline => config, :username => "log.stash", :pipeline_metadata => {:version => "1" }, + :pipeline_settings => {"pipeline.batch.delay": "50"}, :last_modified => Time.now.utc.iso8601}) + else + elasticsearch_client.index :index => '.logstash', :type => "_doc", id: pipeline_id, :body => { :pipeline => config } + end end def cleanup_elasticsearch(index = MONITORING_INDEXES) @@ -103,6 +115,17 @@ def cleanup_elasticsearch(index = MONITORING_INDEXES) elasticsearch_client.indices.refresh end +def cleanup_system_indices(pipeline_ids) + pipeline_ids.each do |id| + begin + elasticsearch_client.perform_request(:delete, "_logstash/pipeline/#{id}") + rescue Elasticsearch::Transport::Transport::Errors::NotFound => e + puts ".logstash can be empty #{e.message}" + end + end + elasticsearch_client.indices.refresh +end + def logstash_command_append(cmd, argument, value) if cmd !~ /#{Regexp.escape(argument)}/ cmd << " #{argument} #{value}" @@ -136,4 +159,4 @@ def verify_response!(cmd, response) unless response.successful? raise "Something went wrong when installing xpack,\ncmd: #{cmd}\nresponse: #{response}" end -end +end \ No newline at end of file diff --git a/x-pack/spec/config_management/elasticsearch_source_spec.rb b/x-pack/spec/config_management/elasticsearch_source_spec.rb index 927d853b2..28d10593a 100644 --- a/x-pack/spec/config_management/elasticsearch_source_spec.rb +++ b/x-pack/spec/config_management/elasticsearch_source_spec.rb @@ -12,6 +12,8 @@ require "monitoring/monitoring" require "stud/temporary" describe LogStash::ConfigManagement::ElasticsearchSource do + let(:system_indices_api) { LogStash::ConfigManagement::SystemIndicesFetcher::SYSTEM_INDICES_API_PATH } + let(:system_indices_url_regex) { Regexp.new("^#{system_indices_api}") } let(:elasticsearch_url) { ["https://localhost:9898"] } let(:elasticsearch_username) { "elastictest" } let(:elasticsearch_password) { "testchangeme" } @@ -41,7 +43,6 @@ describe LogStash::ConfigManagement::ElasticsearchSource do }" } - let(:valid_xpack_response) { { "license" => { @@ -83,7 +84,6 @@ describe LogStash::ConfigManagement::ElasticsearchSource do }") } - let(:settings) do { "xpack.management.enabled" => true, @@ -94,6 +94,38 @@ describe LogStash::ConfigManagement::ElasticsearchSource do } end + let(:es_version_response) { es_version_8_response } + let(:es_version_8_response) { generate_es_version_response("8.0.0-SNAPSHOT") } + let(:es_version_7_9_response) { generate_es_version_response("7.9.1") } + + let(:elasticsearch_7_9_err_response) { + {"error"=> + {"root_cause"=> + [{"type"=>"parse_exception", + "reason"=>"request body or source parameter is required"}], + "type"=>"parse_exception", + "reason"=>"request body or source parameter is required"}, + "status"=>400} + } + + let(:elasticsearch_8_err_response) { + {"error"=> + {"root_cause"=> + [{"type"=>"index_not_found_exception", + "reason"=>"no such index [.logstash]", + "resource.type"=>"index_expression", + "resource.id"=>".logstash", + "index_uuid"=>"_na_", + "index"=>".logstash"}], + "type"=>"index_not_found_exception", + "reason"=>"no such index [.logstash]", + "resource.type"=>"index_expression", + "resource.id"=>".logstash", + "index_uuid"=>"_na_", + "index"=>".logstash"}, + "status"=>404} + } + before do extension.additionals_settings(system_settings) apply_settings(settings, system_settings) @@ -162,22 +194,85 @@ describe LogStash::ConfigManagement::ElasticsearchSource do end end - describe "#config_path" do - before do - # we are testing the arguments here, not the behavior of the elasticsearch output - allow_any_instance_of(described_class).to receive(:build_client).and_return(nil) - end + describe LogStash::ConfigManagement::SystemIndicesFetcher do + subject { described_class.new } - let(:pipeline_id) { "foobar" } - let(:settings) do - { - "xpack.management.pipeline.id" => pipeline_id, - "xpack.management.elasticsearch.password" => "testpassword" + describe "system indices api" do + let(:mock_client) { double("http_client") } + let(:config) { "input { generator { count => 100 } tcp { port => 6005 } } output { }}" } + let(:pipeline_id) { "super_generator" } + let(:elasticsearch_response) { {"#{pipeline_id}"=> {"pipeline"=> "#{config}"}} } + + it "#fetch_config" do + expect(mock_client).to receive(:get).with("#{described_class::SYSTEM_INDICES_API_PATH}/#{pipeline_id}").and_return(elasticsearch_response) + expect(subject.fetch_config([pipeline_id], mock_client)).to eq(elasticsearch_response) + expect(subject.get_single_pipeline_setting(pipeline_id)).to eq({"pipeline"=> "#{config}"}) + end + + it "#fetch_config should raise error" do + expect(mock_client).to receive(:get).with("#{described_class::SYSTEM_INDICES_API_PATH}/apache,nginx").and_return(elasticsearch_8_err_response) + expect{ subject.fetch_config(["apache", "nginx"], mock_client) }.to raise_error(LogStash::ConfigManagement::ElasticsearchSource::RemoteConfigError) + end + end + end + + describe LogStash::ConfigManagement::LegacyHiddenIndicesFetcher do + subject { described_class.new } + + describe "legacy api" do + let(:mock_client) { double("http_client") } + let(:config) { "input { generator { count => 100 } tcp { port => 6005 } } output { }}" } + let(:another_config) { "input { generator { count => 100 } tcp { port => 6006 } } output { }}" } + let(:pipeline_id) { "super_generator" } + let(:another_pipeline_id) { "another_generator" } + let(:elasticsearch_response) { + {"docs"=> + [{"_index"=>".logstash", + "_id"=>"#{pipeline_id}", + "_version"=>2, + "_seq_no"=>2, + "_primary_term"=>1, + "found"=>true, + "_source"=> + {"pipeline"=> "#{config}"}}, + {"_index"=>".logstash", + "_id"=>"#{another_pipeline_id}", + "_version"=>2, + "_seq_no"=>3, + "_primary_term"=>1, + "found"=>true, + "_source"=> + {"pipeline"=> "#{another_config}"}}, + {"_index"=>".logstash", "_id"=>"not_exists", "found"=>false}]} } - end - it "generates the path to get the configuration" do - expect(subject.config_path).to eq("#{described_class::PIPELINE_INDEX}/_mget") + let(:formatted_es_response) { + {"super_generator"=>{"_index"=>".logstash", "_id"=>"super_generator", "_version"=>2, "_seq_no"=>2, "_primary_term"=>1, "found"=>true, "_source"=>{"pipeline"=>"input { generator { count => 100 } tcp { port => 6005 } } output { }}"}}} + } + + it "#fetch_config" do + expect(mock_client).to receive(:post).with("#{described_class::PIPELINE_INDEX}/_mget", {}, "{\"docs\":[{\"_id\":\"#{pipeline_id}\"},{\"_id\":\"#{another_pipeline_id}\"}]}").and_return(elasticsearch_response) + expect(subject.fetch_config([pipeline_id, another_pipeline_id], mock_client).size).to eq(2) + expect(subject.get_single_pipeline_setting(pipeline_id)).to eq({"pipeline" => "#{config}"}) + expect(subject.get_single_pipeline_setting(another_pipeline_id)).to eq({"pipeline" => "#{another_config}"}) + end + + it "#fetch_config should raise error" do + expect(mock_client).to receive(:post).with("#{described_class::PIPELINE_INDEX}/_mget", {}, "{\"docs\":[{\"_id\":\"#{pipeline_id}\"},{\"_id\":\"#{another_pipeline_id}\"}]}").and_return(elasticsearch_7_9_err_response) + expect{ subject.fetch_config([pipeline_id, another_pipeline_id], mock_client) }.to raise_error(LogStash::ConfigManagement::ElasticsearchSource::RemoteConfigError) + end + + it "#fetch_config should raise error when response is empty" do + expect(mock_client).to receive(:post).with("#{described_class::PIPELINE_INDEX}/_mget", {}, "{\"docs\":[{\"_id\":\"#{pipeline_id}\"},{\"_id\":\"#{another_pipeline_id}\"}]}").and_return(LogStash::Json.load("{}")) + expect{ subject.fetch_config([pipeline_id, another_pipeline_id], mock_client) }.to raise_error(LogStash::ConfigManagement::ElasticsearchSource::RemoteConfigError) + end + + it "#format_response should return pipelines" do + result = subject.send(:format_response, elasticsearch_response) + expect(result.size).to eq(2) + expect(result.has_key?(pipeline_id)).to be_truthy + expect(result.has_key?(another_pipeline_id)).to be_truthy + end end end @@ -216,267 +311,312 @@ describe LogStash::ConfigManagement::ElasticsearchSource do let(:pipeline_id) { "apache" } let(:mock_client) { double("http_client") } let(:settings) { super.merge({ "xpack.management.pipeline.id" => pipeline_id }) } - let(:es_path) { "#{described_class::PIPELINE_INDEX}/_mget" } + let(:config) { "input { generator {} } filter { mutate {} } output { }" } + let(:elasticsearch_response) { elasticsearch_8_response } + let(:elasticsearch_8_response) { + "{\"#{pipeline_id}\":{ + \"username\":\"log.stash\", + \"modified_timestamp\":\"2017-02-28T23:02:17.023Z\", + \"pipeline_metadata\":{\"version\":5,\"type\":\"logstash_pipeline\"}, + \"pipeline\":\"#{config}\", + \"pipeline_settings\":{\"pipeline.batch.delay\":\"50\", \"pipeline.workers\":\"99\", \"pipeline.output.workers\":\"99\", \"nonsensical.invalid.setting\":\"-9999\"}}}" } + + let(:elasticsearch_7_9_response) { + "{ \"docs\":[{ + \"_index\":\".logstash\", + \"_type\":\"pipelines\", + \"_id\":\"#{pipeline_id}\", + \"_version\":8, + \"found\":true, + \"_source\":{ + \"id\":\"apache\", + \"description\":\"Process apache logs\", + \"modified_timestamp\":\"2017-02-28T23:02:17.023Z\", + \"pipeline_metadata\":{\"version\":5,\"type\":\"logstash_pipeline\",\"username\":\"elastic\"}, + \"pipeline\":\"#{config}\", + \"pipeline_settings\":{\"pipeline.workers\":\"99\", \"pipeline.output.workers\":\"99\", \"nonsensical.invalid.setting\":\"-9999\"}}}]}" } + let(:es_path) { ".logstash/_mget" } let(:request_body_string) { LogStash::Json.dump({ "docs" => [{ "_id" => pipeline_id }] }) } before do - allow(mock_client).to receive(:post).with(es_path, {}, request_body_string).and_return(LogStash::Json.load(elasticsearch_response)) + allow(mock_client).to receive(:get).with(system_indices_url_regex).and_return(LogStash::Json.load(elasticsearch_response)) + allow(mock_client).to receive(:get).with("/").and_return(es_version_response) + allow(mock_client).to receive(:post).with(es_path, {}, request_body_string).and_return(LogStash::Json.load(elasticsearch_7_9_response)) allow(mock_license_client).to receive(:get).with('_xpack').and_return(valid_xpack_response) allow_any_instance_of(LogStash::LicenseChecker::LicenseReader).to receive(:client).and_return(mock_license_client) - end - context "with one `pipeline_id` configured" do - context "when successfully fetching a remote configuration" do + describe "system indices [8] and legacy api [7.9]" do + [8, 7.9].each { |es_version| + let(:elasticsearch_response) { (es_version >= 8)? elasticsearch_8_response: elasticsearch_7_9_response } before :each do - expect_any_instance_of(described_class).to receive(:build_client).and_return(mock_client) + allow(mock_client).to receive(:get).with("/").and_return(es_version >= 8? es_version_response: es_version_7_9_response) end - let(:config) { "input { generator {} } filter { mutate {} } output { }" } - let(:whitelisted_pipeline_setting_name) {"pipeline.workers"} - let(:whitelisted_pipeline_setting_value) {"99"} - let(:non_whitelisted_pipeline_setting_name) {"pipeline.output.workers"} - let(:non_whitelisted_pipeline_setting_value) {"99"} - let(:invalid_pipeline_setting) {"nonsensical.invalid.setting"} - let(:elasticsearch_response) { - %{ - { "docs": [{ - "_index":".logstash", - "_type":"pipelines", - "_id":"#{pipeline_id}", - "_version":8, - "found":true, - "_source": { - "id":"apache", - "description":"Process apache logs", - "modified_timestamp":"2017-02-28T23:02:17.023Z", - "pipeline_metadata":{ - "version":5, - "type":"logstash_pipeline", - "username":"elastic" - }, - "pipeline":"#{config}", - "pipeline_settings": { - "#{whitelisted_pipeline_setting_name}":#{whitelisted_pipeline_setting_value}, - "#{non_whitelisted_pipeline_setting_name}":#{non_whitelisted_pipeline_setting_value}, - "#{invalid_pipeline_setting}":-9999 - } + context "with one `pipeline_id` configured [#{es_version}]" do + context "when successfully fetching a remote configuration" do + before :each do + expect_any_instance_of(described_class).to receive(:build_client).and_return(mock_client) + allow(mock_client).to receive(:post).with(es_path, {}, request_body_string).and_return(LogStash::Json.load(elasticsearch_7_9_response)) + end + + let(:config) { "input { generator {} } filter { mutate {} } output { }" } + + it "returns a valid pipeline config" do + pipeline_config = subject.pipeline_configs + + expect(pipeline_config.first.config_string).to match(config) + expect(pipeline_config.first.pipeline_id.to_sym).to eq(pipeline_id.to_sym) + end + + it "ignores non-whitelisted and invalid settings" do + pipeline_config = subject.pipeline_configs + settings_hash = pipeline_config[0].settings.to_hash + + expect(settings_hash["pipeline.workers"]).to eq(99) + expect(settings_hash["pipeline.output.workers"]).not_to eq(99) + expect(settings_hash["nonsensical.invalid.setting"]).to be_falsey + end + end + + context "when the license has expired [#{es_version}]" do + let(:license_status) { 'expired'} + let(:license_expiry_date) { Time.now - (60 * 60 * 24)} + + before :each do + expect_any_instance_of(described_class).to receive(:build_client).and_return(mock_client) + end + + it "returns a valid pipeline config" do + pipeline_config = subject.pipeline_configs + + expect(pipeline_config.first.config_string).to match(config) + expect(pipeline_config.first.pipeline_id.to_sym).to eq(pipeline_id.to_sym) + end + end + + context "when the license server is not available [#{es_version}]" do + before :each do + allow(mock_license_client).to receive(:get).with('_xpack').and_raise("An error is here") + allow_any_instance_of(LogStash::LicenseChecker::LicenseReader).to receive(:build_client).and_return(mock_license_client) + end + + it 'should raise an error' do + expect{subject.pipeline_configs}.to raise_error(LogStash::LicenseChecker::LicenseError) + end + end + + context "when the xpack is not installed [#{es_version}]" do + before :each do + expect(mock_license_client).to receive(:get).with('_xpack').and_return(no_xpack_response) + allow_any_instance_of(LogStash::LicenseChecker::LicenseReader).to receive(:build_client).and_return(mock_license_client) + end + + it 'should raise an error' do + expect{subject.pipeline_configs}.to raise_error(LogStash::LicenseChecker::LicenseError) + end + end + + describe "security enabled/disabled in Elasticsearch [#{es_version}]" do + let(:xpack_response) do + { + "license"=> { + "status"=> license_status, + "uid"=> "9a48c67c-ce2c-4169-97bf-37d324b8ab80", + "type"=> license_type, + "expiry_date_in_millis"=> license_expiry_in_millis + }, + "features" => { + "security" => { + "description" => "Security for the Elastic Stack", + "available" => true, + "enabled" => security_enabled + } + } } - }] - } - } - } + end - it "returns a valid pipeline config" do - pipeline_config = subject.pipeline_configs + before :each do + allow(mock_license_client).to receive(:get).with('_xpack').and_return(xpack_response) + allow_any_instance_of(LogStash::LicenseChecker::LicenseReader).to receive(:build_client).and_return(mock_license_client) + end - expect(pipeline_config.first.config_string).to match(config) - expect(pipeline_config.first.pipeline_id.to_sym).to eq(pipeline_id.to_sym) - end + context "when security is disabled in Elasticsearch [#{es_version}]" do + let(:security_enabled) { false } + it 'should raise an error' do + expect { subject.pipeline_configs }.to raise_error(LogStash::LicenseChecker::LicenseError) + end + end - it "ignores non-whitelisted and invalid settings" do - pipeline_config = subject.pipeline_configs - settings_hash = pipeline_config[0].settings.to_hash + context "when security is enabled in Elasticsearch [#{es_version}]" do + let(:security_enabled) { true } + it 'should not raise an error' do + expect_any_instance_of(described_class).to receive(:build_client).and_return(mock_client) + expect { subject.pipeline_configs }.not_to raise_error + end + end + end - expect(settings_hash[whitelisted_pipeline_setting_name]).to eq(whitelisted_pipeline_setting_value.to_i) - expect(settings_hash[non_whitelisted_pipeline_setting_name]).not_to eq(non_whitelisted_pipeline_setting_value.to_i) - expect(settings_hash[invalid_pipeline_setting]).to be_falsey - end - end - context 'when the license has expired' do - let(:config) { "input { generator {} } filter { mutate {} } output { }" } - let(:elasticsearch_response) { "{ \"docs\":[{\"_index\":\".logstash\",\"_type\":\"pipelines\",\"_id\":\"#{pipeline_id}\",\"_version\":8,\"found\":true,\"_source\":{\"id\":\"apache\",\"description\":\"Process apache logs\",\"modified_timestamp\":\"2017-02-28T23:02:17.023Z\",\"pipeline_metadata\":{\"version\":5,\"type\":\"logstash_pipeline\",\"username\":\"elastic\"},\"pipeline\":\"#{config}\"}}]}" } - let(:license_status) { 'expired'} - let(:license_expiry_date) { Time.now - (60 * 60 * 24)} + context "With an invalid basic license, it should raise an error [#{es_version}]" do + let(:license_type) { 'basic' } - before :each do - expect_any_instance_of(described_class).to receive(:build_client).and_return(mock_client) - end + it 'should raise an error' do + expect{subject.pipeline_configs}.to raise_error(LogStash::LicenseChecker::LicenseError) + end + end - it "returns a valid pipeline config" do - pipeline_config = subject.pipeline_configs + # config management can be used with any license type except basic + (::LogStash::LicenseChecker::LICENSE_TYPES - ["basic"]).each do |license_type| + context "With a valid #{license_type} license, it should return a pipeline [#{es_version}]" do + before do + expect_any_instance_of(described_class).to receive(:build_client).and_return(mock_client) + end - expect(pipeline_config.first.config_string).to match(config) - expect(pipeline_config.first.pipeline_id.to_sym).to eq(pipeline_id.to_sym) - end - end + let(:license_type) { license_type } - context 'when the license server is not available' do - let(:config) { "input { generator {} } filter { mutate {} } output { }" } - let(:elasticsearch_response) { "{ \"docs\":[{\"_index\":\".logstash\",\"_type\":\"pipelines\",\"_id\":\"#{pipeline_id}\",\"_version\":8,\"found\":true,\"_source\":{\"id\":\"apache\",\"description\":\"Process apache logs\",\"modified_timestamp\":\"2017-02-28T23:02:17.023Z\",\"pipeline_metadata\":{\"version\":5,\"type\":\"logstash_pipeline\",\"username\":\"elastic\"},\"pipeline\":\"#{config}\"}}]}" } + it "returns a valid pipeline config" do + pipeline_config = subject.pipeline_configs - before :each do - allow(mock_license_client).to receive(:get).with('_xpack').and_raise("An error is here") - allow_any_instance_of(LogStash::LicenseChecker::LicenseReader).to receive(:build_client).and_return(mock_license_client) - end - - it 'should raise an error' do - expect{subject.pipeline_configs}.to raise_error(LogStash::LicenseChecker::LicenseError) - end - end - - context 'when the xpack is not installed' do - let(:config) { "input { generator {} } filter { mutate {} } output { }" } - let(:elasticsearch_response) { "{ \"docs\":[{\"_index\":\".logstash\",\"_type\":\"pipelines\",\"_id\":\"#{pipeline_id}\",\"_version\":8,\"found\":true,\"_source\":{\"id\":\"apache\",\"description\":\"Process apache logs\",\"modified_timestamp\":\"2017-02-28T23:02:17.023Z\",\"pipeline_metadata\":{\"version\":5,\"type\":\"logstash_pipeline\",\"username\":\"elastic\"},\"pipeline\":\"#{config}\"}}]}" } - - before :each do - expect(mock_license_client).to receive(:get).with('_xpack').and_return(no_xpack_response) - allow_any_instance_of(LogStash::LicenseChecker::LicenseReader).to receive(:build_client).and_return(mock_license_client) - end - - it 'should raise an error' do - expect{subject.pipeline_configs}.to raise_error(LogStash::LicenseChecker::LicenseError) - end - end - - describe 'security enabled/disabled in Elasticsearch' do - let(:config) { "input { generator {} } filter { mutate {} } output { }" } - let(:elasticsearch_response) { "{ \"docs\":[{\"_index\":\".logstash\",\"_type\":\"pipelines\",\"_id\":\"#{pipeline_id}\",\"_version\":8,\"found\":true,\"_source\":{\"id\":\"apache\",\"description\":\"Process apache logs\",\"modified_timestamp\":\"2017-02-28T23:02:17.023Z\",\"pipeline_metadata\":{\"version\":5,\"type\":\"logstash_pipeline\",\"username\":\"elastic\"},\"pipeline\":\"#{config}\"}}]}" } - - let(:xpack_response) do - { - "license"=> { - "status"=> license_status, - "uid"=> "9a48c67c-ce2c-4169-97bf-37d324b8ab80", - "type"=> license_type, - "expiry_date_in_millis"=> license_expiry_in_millis - }, - "features" => { - "security" => { - "description" => "Security for the Elastic Stack", - "available" => true, - "enabled" => security_enabled - } - } - } - end - - before :each do - allow(mock_license_client).to receive(:get).with('_xpack').and_return(xpack_response) - allow_any_instance_of(LogStash::LicenseChecker::LicenseReader).to receive(:build_client).and_return(mock_license_client) - end - - context 'when security is disabled in Elasticsearch' do - let(:security_enabled) { false } - it 'should raise an error' do - expect { subject.pipeline_configs }.to raise_error(LogStash::LicenseChecker::LicenseError) + expect(pipeline_config.first.config_string).to match(config) + expect(pipeline_config.first.pipeline_id.to_sym).to eq(pipeline_id.to_sym) + end + end end end - context 'when security is enabled in Elasticsearch' do - let(:security_enabled) { true } - it 'should not raise an error' do + context "with multiples `pipeline_id` configured [#{es_version}]" do + before do expect_any_instance_of(described_class).to receive(:build_client).and_return(mock_client) - expect { subject.pipeline_configs }.not_to raise_error + end + + context "when successfully fetching multiple remote configuration" do + let(:pipelines) do + { + "apache" => config_apache, + "firewall" => config_firewall + } + end + let(:pipeline_id) { pipelines.keys } + + let(:config_apache) { "input { generator { id => '123'} } filter { mutate {} } output { }" } + let(:config_firewall) { "input { generator { id => '321' } } filter { mutate {} } output { }" } + let(:elasticsearch_response) do + content = "{" + content << pipelines.collect do |pipeline_id, config| + "\"#{pipeline_id}\":{\"username\":\"log.stash\",\"modified_timestamp\":\"2017-02-28T23:02:17.023Z\",\"pipeline_metadata\":{\"version\":5,\"type\":\"logstash_pipeline\"},\"pipeline\":\"#{config}\",\"pipeline_settings\":{\"pipeline.batch.delay\":\"50\"}}" + end.join(",") + content << "}" + content + end + + let(:elasticsearch_7_9_response) do + content = "{ \"docs\":[" + content << pipelines.collect do |pipeline_id, config| + "{\"_index\":\".logstash\",\"_type\":\"pipelines\",\"_id\":\"#{pipeline_id}\",\"_version\":8,\"found\":true,\"_source\":{\"id\":\"apache\",\"description\":\"Process apache logs\",\"modified_timestamp\":\"2017-02-28T23:02:17.023Z\",\"pipeline_metadata\":{\"version\":5,\"type\":\"logstash_pipeline\",\"username\":\"elastic\"},\"pipeline\":\"#{config}\"}}" + end.join(",") + content << "]}" + content + end + let(:request_body_string) { LogStash::Json.dump({ "docs" => pipeline_id.collect { |pipeline_id| { "_id" => pipeline_id } } }) } + + it "returns a valid pipeline config" do + pipeline_config = subject.pipeline_configs + + expect(pipeline_config.collect(&:config_string)).to include(*pipelines.values) + expect(pipeline_config.map(&:pipeline_id).collect(&:to_sym)).to include(*pipelines.keys.collect(&:to_sym)) + end end end - end - - context "With an invalid basic license, it should raise an error" do - let(:config) { "input { generator {} } filter { mutate {} } output { }" } - let(:elasticsearch_response) { "{ \"docs\":[{\"_index\":\".logstash\",\"_type\":\"pipelines\",\"_id\":\"#{pipeline_id}\",\"_version\":8,\"found\":true,\"_source\":{\"id\":\"apache\",\"description\":\"Process apache logs\",\"modified_timestamp\":\"2017-02-28T23:02:17.023Z\",\"pipeline_metadata\":{\"version\":5,\"type\":\"logstash_pipeline\",\"username\":\"elastic\"},\"pipeline\":\"#{config}\"}}]}" } - let(:license_type) { 'basic' } - - it 'should raise an error' do - expect{subject.pipeline_configs}.to raise_error(LogStash::LicenseChecker::LicenseError) - end - end - - # config management can be used with any license type except basic - (::LogStash::LicenseChecker::LICENSE_TYPES - ["basic"]).each do |license_type| - context "With a valid #{license_type} license, it should return a pipeline" do + context "when the configuration is not found [#{es_version}]" do + let(:elasticsearch_8_response) { "{}" } + let(:elasticsearch_7_9_response) { "{ \"docs\": [{\"_index\":\".logstash\",\"_type\":\"pipelines\",\"_id\":\"donotexist\",\"found\":false}]}" } before do expect_any_instance_of(described_class).to receive(:build_client).and_return(mock_client) end - let(:config) { "input { generator {} } filter { mutate {} } output { }" } - let(:elasticsearch_response) { "{ \"docs\":[{\"_index\":\".logstash\",\"_type\":\"pipelines\",\"_id\":\"#{pipeline_id}\",\"_version\":8,\"found\":true,\"_source\":{\"id\":\"apache\",\"description\":\"Process apache logs\",\"modified_timestamp\":\"2017-02-28T23:02:17.023Z\",\"pipeline_metadata\":{\"version\":5,\"type\":\"logstash_pipeline\",\"username\":\"elastic\"},\"pipeline\":\"#{config}\"}}]}" } - let(:license_type) { license_type } - - it "returns a valid pipeline config" do - pipeline_config = subject.pipeline_configs - - expect(pipeline_config.first.config_string).to match(config) - expect(pipeline_config.first.pipeline_id.to_sym).to eq(pipeline_id.to_sym) + it "returns no pipeline config" do + expect(subject.pipeline_configs).to be_empty end end - end + + context "when any error returned from elasticsearch [#{es_version}]" do + let(:elasticsearch_8_response){"{\"error\" : \"no handler found for uri [/_logstash/pipelines?pretty] and method [GET]\"}" } + let(:elasticsearch_7_9_response) { '{ "error":{"root_cause":[{"type":"illegal_argument_exception","reason":"No endpoint or operation is available at [testing_ph]"}],"type":"illegal_argument_exception","reason":"No endpoint or operation is available at [testing_ph]"},"status":400}' } + + before do + expect_any_instance_of(described_class).to receive(:build_client).and_return(mock_client) + end + + it "raises a `RemoteConfigError`" do + expect { subject.pipeline_configs }.to raise_error LogStash::ConfigManagement::ElasticsearchSource::RemoteConfigError + end + end + + } end - context "with multiples `pipeline_id` configured" do - - before do - allow(mock_client).to receive(:post).with(es_path, {}, request_body_string).and_return(LogStash::Json.load(elasticsearch_response)) - expect_any_instance_of(described_class).to receive(:build_client).and_return(mock_client) - end - - context "when successfully fetching multiple remote configuration" do - let(:pipelines) do - { - "apache" => config_apache, - "firewall" => config_firewall - } - end - - let(:config_apache) { "input { generator { id => '123'} } filter { mutate {} } output { }" } - let(:config_firewall) { "input { generator { id => '321' } } filter { mutate {} } output { }" } - let(:elasticsearch_response) do - content = "{ \"docs\":[" - content << pipelines.collect do |pipeline_id, config| - "{\"_index\":\".logstash\",\"_type\":\"pipelines\",\"_id\":\"#{pipeline_id}\",\"_version\":8,\"found\":true,\"_source\":{\"id\":\"apache\",\"description\":\"Process apache logs\",\"modified_timestamp\":\"2017-02-28T23:02:17.023Z\",\"pipeline_metadata\":{\"version\":5,\"type\":\"logstash_pipeline\",\"username\":\"elastic\"},\"pipeline\":\"#{config}\"}}" - end.join(",") - content << "]}" - content - end - - it "returns a valid pipeline config" do - pipeline_config = subject.pipeline_configs - - expect(pipeline_config.collect(&:config_string)).to include(*pipelines.values) - expect(pipeline_config.map(&:pipeline_id).collect(&:to_sym)).to include(*pipelines.keys.collect(&:to_sym)) - end - end - end - - context "when the configuration is not found" do - let(:elasticsearch_response) { "{ \"docs\": [{\"_index\":\".logstash\",\"_type\":\"pipelines\",\"_id\":\"donotexist\",\"found\":false}]}" } - + describe "create pipeline fetcher by es version" do before do expect_any_instance_of(described_class).to receive(:build_client).and_return(mock_client) end - it "returns no pipeline config" do - expect(subject.pipeline_configs).to be_empty + it "should give SystemIndicesFetcher in [8]" do + allow(mock_client).to receive(:get).with("/").and_return(es_version_response) + expect(subject.get_pipeline_fetcher).to be_an_instance_of LogStash::ConfigManagement::SystemIndicesFetcher + end + + it "should give SystemIndicesFetcher in [7.10]" do + allow(mock_client).to receive(:get).with("/").and_return(generate_es_version_response("7.10.0-SNAPSHOT")) + expect(subject.get_pipeline_fetcher).to be_an_instance_of LogStash::ConfigManagement::SystemIndicesFetcher + end + + it "should give LegacyHiddenIndicesFetcher in [7.9]" do + allow(mock_client).to receive(:get).with("/").and_return(es_version_7_9_response) + expect(subject.get_pipeline_fetcher).to be_an_instance_of LogStash::ConfigManagement::LegacyHiddenIndicesFetcher end end - context "when any error returned from elasticsearch" do - let(:elasticsearch_response){'{ "error":{"root_cause":[{"type":"illegal_argument_exception","reason":"No endpoint or operation is available at [testing_ph]"}],"type":"illegal_argument_exception","reason":"No endpoint or operation is available at [testing_ph]"},"status":400}' } - - before do - expect_any_instance_of(described_class).to receive(:build_client).and_return(mock_client) - end - - it "raises a `RemoteConfigError`" do - expect { subject.pipeline_configs }.to raise_error /illegal_argument_exception/ - end - end - - context "when exception occur" do + describe "when exception occur" do let(:elasticsearch_response) { "" } before do expect_any_instance_of(described_class).to receive(:build_client).and_return(mock_client) end - it "raises the exception upstream" do + it "raises the exception upstream in [8]" do + allow(mock_client).to receive(:get).with("/").and_return(es_version_response) + allow(mock_client).to receive(:get).with(system_indices_url_regex).and_raise("Something bad") + expect { subject.pipeline_configs }.to raise_error /Something bad/ + end + + + it "raises the exception upstream in [7.9]" do + allow(mock_client).to receive(:get).with("/").and_return(es_version_7_9_response) expect(mock_client).to receive(:post).with(es_path, {}, request_body_string).and_raise("Something bad") expect { subject.pipeline_configs }.to raise_error /Something bad/ end end + + end + + def generate_es_version_response(version) + {"name"=>"MacBook-Pro", + "cluster_name"=>"elasticsearch", + "cluster_uuid"=>"YgpKq8VkTJuGTSb9aidlIA", + "version"=> + {"number"=>"#{version}", + "build_flavor"=>"default", + "build_type"=>"tar", + "build_hash"=>"26eb422dc55236a1c5625e8a73e5d866e54610a2", + "build_date"=>"2020-09-24T09:37:06.459350Z", + "build_snapshot"=>true, + "lucene_version"=>"8.7.0", + "minimum_wire_compatibility_version"=>"7.10.0", + "minimum_index_compatibility_version"=>"7.0.0"}, + "tagline"=>"You Know, for Search"} end end From 5ad7bbb03bd0189f77e168b4045dd52b0c9d3131 Mon Sep 17 00:00:00 2001 From: andsel Date: Wed, 7 Oct 2020 15:05:23 +0200 Subject: [PATCH 0609/1126] Bump 7.11 --- README.md | 16 ++++++++-------- versions.yml | 4 ++-- 2 files changed, 10 insertions(+), 10 deletions(-) diff --git a/README.md b/README.md index 023c531dc..375590c2f 100644 --- a/README.md +++ b/README.md @@ -28,14 +28,14 @@ These builds are created nightly and have undergone no formal QA, so they should | [deb-complete][] | [deb-oss][] | | [rpm-complete][] | [rpm-oss][] | -[tar-complete]: https://snapshots.elastic.co/downloads/logstash/logstash-7.10.0-SNAPSHOT.tar.gz -[zip-complete]: https://snapshots.elastic.co/downloads/logstash/logstash-7.10.0-SNAPSHOT.zip -[deb-complete]: https://snapshots.elastic.co/downloads/logstash/logstash-7.10.0-SNAPSHOT.deb -[rpm-complete]: https://snapshots.elastic.co/downloads/logstash/logstash-7.10.0-SNAPSHOT.rpm -[tar-oss]: https://snapshots.elastic.co/downloads/logstash/logstash-oss-7.10.0-SNAPSHOT.tar.gz -[zip-oss]: https://snapshots.elastic.co/downloads/logstash/logstash-oss-7.10.0-SNAPSHOT.zip -[deb-oss]: https://snapshots.elastic.co/downloads/logstash/logstash-oss-7.10.0-SNAPSHOT.deb -[rpm-oss]: https://snapshots.elastic.co/downloads/logstash/logstash-oss-7.10.0-SNAPSHOT.rpm +[tar-complete]: https://snapshots.elastic.co/downloads/logstash/logstash-7.11.0-SNAPSHOT.tar.gz +[zip-complete]: https://snapshots.elastic.co/downloads/logstash/logstash-7.11.0-SNAPSHOT.zip +[deb-complete]: https://snapshots.elastic.co/downloads/logstash/logstash-7.11.0-SNAPSHOT.deb +[rpm-complete]: https://snapshots.elastic.co/downloads/logstash/logstash-7.11.0-SNAPSHOT.rpm +[tar-oss]: https://snapshots.elastic.co/downloads/logstash/logstash-oss-7.11.0-SNAPSHOT.tar.gz +[zip-oss]: https://snapshots.elastic.co/downloads/logstash/logstash-oss-7.11.0-SNAPSHOT.zip +[deb-oss]: https://snapshots.elastic.co/downloads/logstash/logstash-oss-7.11.0-SNAPSHOT.deb +[rpm-oss]: https://snapshots.elastic.co/downloads/logstash/logstash-oss-7.11.0-SNAPSHOT.rpm ## Need Help? diff --git a/versions.yml b/versions.yml index 8881c2459..df3eaa86d 100644 --- a/versions.yml +++ b/versions.yml @@ -1,7 +1,7 @@ --- # alpha and beta qualifiers are now added via VERSION_QUALIFIER environment var -logstash: 7.10.0 -logstash-core: 7.10.0 +logstash: 7.11.0 +logstash-core: 7.11.0 logstash-core-plugin-api: 2.1.16 bundled_jdk: From a6a31ec428d70fc532ddba92549fc5bcc72625a6 Mon Sep 17 00:00:00 2001 From: Rob Bavey Date: Wed, 7 Oct 2020 11:38:50 -0400 Subject: [PATCH 0610/1126] [7x backport] Remove redundant shouldRunAfter (#12316) Clean backport of #12314 The `shouldRunAfter` specified in the main script body was causing the runIntegrationTests task to be evaluated even when it should not have been, causing unnecessary failures when artifacts required only for integration tests are unavailable. This can be removed, because the `shouldRunAfter` relationship for the `runIntegrationTests` task is already defined in the task body. --- build.gradle | 1 - 1 file changed, 1 deletion(-) diff --git a/build.gradle b/build.gradle index 083d6233c..d895ebd80 100644 --- a/build.gradle +++ b/build.gradle @@ -513,7 +513,6 @@ bootstrap.dependsOn assemblyDeps // to compartimentalize failures is needed going forward //check.dependsOn runIntegrationTest -runIntegrationTests.shouldRunAfter tasks.getByPath(":logstash-core:test") def selectOsType() { if (project.ext.has("jdk_bundle_os")) { From 708c156c1b6d4c096bb620ce186604fd7037a883 Mon Sep 17 00:00:00 2001 From: Rob Bavey Date: Wed, 7 Oct 2020 14:37:49 -0400 Subject: [PATCH 0611/1126] [7x backport] Write DLQ entries to temp file first (#12304) (#12318) Clean backport of #12304 This commit changes the DLQ writer to write to a temporary file which will be renamed on "completion", to avoid the possibility of the DLQ reader reading an incomplete DLQ segment. The temp file will be renamed and made available, either when the capacity of this segment is reached, or if a configurable 'flush interval' has elapsed since the last event reached the dead letter queue. This commit fixes #8022, #10275, #10967 This commit replaces #11127 --- config/logstash.yml | 8 + config/pipelines.yml | 9 + docker/data/logstash/env2yaml/env2yaml.go | 1 + docs/static/dead-letter-queues.asciidoc | 19 ++ logstash-core/lib/logstash/environment.rb | 1 + logstash-core/lib/logstash/settings.rb | 1 + .../common/DeadLetterQueueFactory.java | 10 +- .../common/io/DeadLetterQueueWriter.java | 249 +++++++++++++----- .../logstash/common/io/RecordIOReader.java | 31 ++- .../logstash/common/io/RecordIOWriter.java | 21 ++ .../execution/AbstractPipelineExt.java | 8 +- .../common/DeadLetterQueueFactoryTest.java | 9 +- .../common/io/DeadLetterQueueReaderTest.java | 225 ++++++++++++++-- .../common/io/DeadLetterQueueWriterTest.java | 105 +++++--- .../common/io/RecordIOReaderTest.java | 34 +++ qa/integration/build.gradle | 9 + qa/integration/specs/dlq_spec.rb | 17 +- qa/integration/specs/spec_helper.rb | 6 +- 18 files changed, 615 insertions(+), 148 deletions(-) diff --git a/config/logstash.yml b/config/logstash.yml index fb211819f..a9a80e858 100644 --- a/config/logstash.yml +++ b/config/logstash.yml @@ -211,6 +211,14 @@ pipeline.ordered: auto # Default is 1024mb # dead_letter_queue.max_bytes: 1024mb +# If using dead_letter_queue.enable: true, the interval in milliseconds where if no further events eligible for the DLQ +# have been created, a dead letter queue file will be written. A low value here will mean that more, smaller, queue files +# may be written, while a larger value will introduce more latency between items being "written" to the dead letter queue, and +# being available to be read by the dead_letter_queue input when items are are written infrequently. +# Default is 5000. +# +# dead_letter_queue.flush_interval: 5000 + # If using dead_letter_queue.enable: true, the directory path where the data files will be stored. # Default is path.data/dead_letter_queue # diff --git a/config/pipelines.yml b/config/pipelines.yml index 5ea696462..99d96c530 100644 --- a/config/pipelines.yml +++ b/config/pipelines.yml @@ -70,6 +70,15 @@ # will be dropped if they would increase the size of the dead letter queue beyond this setting. # Default is 1024mb # dead_letter_queue.max_bytes: 1024mb +# +# If using dead_letter_queue.enable: true, the interval in milliseconds where if no further events eligible for the DLQ +# have been created, a dead letter queue file will be written. A low value here will mean that more, smaller, queue files +# may be written, while a larger value will introduce more latency between items being "written" to the dead letter queue, and +# being available to be read by the dead_letter_queue input when items are are written infrequently. +# Default is 5000. +# +# dead_letter_queue.flush_interval: 5000 + # # If using dead_letter_queue.enable: true, the directory path where the data files will be stored. # Default is path.data/dead_letter_queue diff --git a/docker/data/logstash/env2yaml/env2yaml.go b/docker/data/logstash/env2yaml/env2yaml.go index 860d4da8f..cd3bf24f0 100644 --- a/docker/data/logstash/env2yaml/env2yaml.go +++ b/docker/data/logstash/env2yaml/env2yaml.go @@ -77,6 +77,7 @@ func normalizeSetting(setting string) (string, error) { "queue.drain", "dead_letter_queue.enable", "dead_letter_queue.max_bytes", + "dead_letter_queue.flush_interval", "path.dead_letter_queue", "http.host", "http.port", diff --git a/docs/static/dead-letter-queues.asciidoc b/docs/static/dead-letter-queues.asciidoc index e451fc4fd..125b84486 100644 --- a/docs/static/dead-letter-queues.asciidoc +++ b/docs/static/dead-letter-queues.asciidoc @@ -72,6 +72,25 @@ specify a different path for the files: path.dead_letter_queue: "path/to/data/dead_letter_queue" ------------------------------------------------------------------------------- +Dead letter queue entries are written to a temporary file, which is then renamed + to a dead letter queue segment file, which is then eligible for ingestion. The rename + happens either when this temporary file is considered 'full', or when a period + of time has elapsed since the last dead letter queue eligible event was written + to the temporary file. + +This length of time can be set using the `dead_letter_queue.flush_interval` setting. + This setting is in milliseconds, and defaults to 5000ms. A low value here will mean + in the event of infrequent writes to the dead letter queue more, smaller, queue + files may be written, while a larger value will introduce more latency between + items being "written" to the dead letter queue, and being made available for + reading by the dead_letter_queue input. + + Note that this value cannot be set to lower than 1000ms. + +[source,yaml] +------------------------------------------------------------------------------- +dead_letter_queue.flush_interval: 5000 +------------------------------------------------------------------------------- NOTE: You may not use the same `dead_letter_queue` path for two different Logstash instances. diff --git a/logstash-core/lib/logstash/environment.rb b/logstash-core/lib/logstash/environment.rb index 72e1f6d95..8e22d0517 100644 --- a/logstash-core/lib/logstash/environment.rb +++ b/logstash-core/lib/logstash/environment.rb @@ -85,6 +85,7 @@ module LogStash Setting::Boolean.new("queue.checkpoint.retry", false), Setting::Boolean.new("dead_letter_queue.enable", false), Setting::Bytes.new("dead_letter_queue.max_bytes", "1024mb"), + Setting::Numeric.new("dead_letter_queue.flush_interval", 5000), Setting::TimeValue.new("slowlog.threshold.warn", "-1"), Setting::TimeValue.new("slowlog.threshold.info", "-1"), Setting::TimeValue.new("slowlog.threshold.debug", "-1"), diff --git a/logstash-core/lib/logstash/settings.rb b/logstash-core/lib/logstash/settings.rb index 96270911c..94a0b6185 100644 --- a/logstash-core/lib/logstash/settings.rb +++ b/logstash-core/lib/logstash/settings.rb @@ -34,6 +34,7 @@ module LogStash "config.reload.interval", "config.string", "dead_letter_queue.enable", + "dead_letter_queue.flush_interval", "dead_letter_queue.max_bytes", "metric.collect", "pipeline.java_execution", diff --git a/logstash-core/src/main/java/org/logstash/common/DeadLetterQueueFactory.java b/logstash-core/src/main/java/org/logstash/common/DeadLetterQueueFactory.java index 0e07c80a4..88e817593 100644 --- a/logstash-core/src/main/java/org/logstash/common/DeadLetterQueueFactory.java +++ b/logstash-core/src/main/java/org/logstash/common/DeadLetterQueueFactory.java @@ -44,6 +44,7 @@ import org.logstash.common.io.DeadLetterQueueWriter; import java.io.IOException; import java.nio.file.Paths; +import java.time.Duration; import java.util.concurrent.ConcurrentHashMap; /** @@ -73,19 +74,20 @@ public class DeadLetterQueueFactory { * for each id * @param maxQueueSize Maximum size of the dead letter queue (in bytes). No entries will be written * that would make the size of this dlq greater than this value + * @param flushInterval Maximum duration between flushes of dead letter queue files if no data is sent. * @return The write manager for the specific id's dead-letter-queue context */ - public static DeadLetterQueueWriter getWriter(String id, String dlqPath, long maxQueueSize) { - return REGISTRY.computeIfAbsent(id, key -> newWriter(key, dlqPath, maxQueueSize)); + public static DeadLetterQueueWriter getWriter(String id, String dlqPath, long maxQueueSize, Duration flushInterval) { + return REGISTRY.computeIfAbsent(id, key -> newWriter(key, dlqPath, maxQueueSize, flushInterval)); } public static DeadLetterQueueWriter release(String id) { return REGISTRY.remove(id); } - private static DeadLetterQueueWriter newWriter(final String id, final String dlqPath, final long maxQueueSize) { + private static DeadLetterQueueWriter newWriter(final String id, final String dlqPath, final long maxQueueSize, final Duration flushInterval) { try { - return new DeadLetterQueueWriter(Paths.get(dlqPath, id), MAX_SEGMENT_SIZE_BYTES, maxQueueSize); + return new DeadLetterQueueWriter(Paths.get(dlqPath, id), MAX_SEGMENT_SIZE_BYTES, maxQueueSize, flushInterval); } catch (IOException e) { logger.error("unable to create dead letter queue writer", e); } diff --git a/logstash-core/src/main/java/org/logstash/common/io/DeadLetterQueueWriter.java b/logstash-core/src/main/java/org/logstash/common/io/DeadLetterQueueWriter.java index 3b9d665e6..588e58374 100644 --- a/logstash-core/src/main/java/org/logstash/common/io/DeadLetterQueueWriter.java +++ b/logstash-core/src/main/java/org/logstash/common/io/DeadLetterQueueWriter.java @@ -43,11 +43,19 @@ import java.io.IOException; import java.nio.channels.FileLock; import java.nio.file.Files; import java.nio.file.Path; -import java.nio.file.Paths; +import java.nio.file.StandardCopyOption; +import java.time.Duration; +import java.time.Instant; +import java.util.concurrent.Executors; +import java.util.concurrent.ScheduledExecutorService; +import java.util.concurrent.TimeUnit; import java.util.concurrent.atomic.AtomicBoolean; import java.util.concurrent.atomic.LongAdder; +import java.util.concurrent.locks.ReentrantLock; import java.util.stream.Collectors; import java.util.stream.Stream; + +import com.google.common.annotations.VisibleForTesting; import org.apache.logging.log4j.LogManager; import org.apache.logging.log4j.Logger; import org.logstash.DLQEntry; @@ -57,88 +65,106 @@ import org.logstash.FileLockFactory; import org.logstash.Timestamp; import static org.logstash.common.io.RecordIOWriter.RECORD_HEADER_SIZE; +import static org.logstash.common.io.RecordIOReader.SegmentStatus; public final class DeadLetterQueueWriter implements Closeable { - private static final Logger logger = LogManager.getLogger(DeadLetterQueueWriter.class); - private static final long MAX_SEGMENT_SIZE_BYTES = 10 * 1024 * 1024; - + @VisibleForTesting static final String SEGMENT_FILE_PATTERN = "%d.log"; - static final String LOCK_FILE = ".lock"; + private static final Logger logger = LogManager.getLogger(DeadLetterQueueWriter.class); + private enum FinalizeWhen {ALWAYS, ONLY_IF_STALE}; + private static final String TEMP_FILE_PATTERN = "%d.log.tmp"; + private static final String LOCK_FILE = ".lock"; + private final ReentrantLock lock = new ReentrantLock(); private static final FieldReference DEAD_LETTER_QUEUE_METADATA_KEY = FieldReference.from(String.format("%s[dead_letter_queue]", Event.METADATA_BRACKETS)); private final long maxSegmentSize; private final long maxQueueSize; private LongAdder currentQueueSize; private final Path queuePath; - private final FileLock lock; + private final FileLock fileLock; private volatile RecordIOWriter currentWriter; private int currentSegmentIndex; private Timestamp lastEntryTimestamp; + private Duration flushInterval; + private Instant lastWrite; private final AtomicBoolean open = new AtomicBoolean(true); + private ScheduledExecutorService flushScheduler; - public DeadLetterQueueWriter(Path queuePath, long maxSegmentSize, long maxQueueSize) throws IOException { - this.lock = FileLockFactory.obtainLock(queuePath, LOCK_FILE); + public DeadLetterQueueWriter(final Path queuePath, final long maxSegmentSize, final long maxQueueSize, final Duration flushInterval) throws IOException { + this.fileLock = FileLockFactory.obtainLock(queuePath, LOCK_FILE); this.queuePath = queuePath; this.maxSegmentSize = maxSegmentSize; this.maxQueueSize = maxQueueSize; + this.flushInterval = flushInterval; this.currentQueueSize = new LongAdder(); this.currentQueueSize.add(getStartupQueueSize()); + cleanupTempFiles(); currentSegmentIndex = getSegmentPaths(queuePath) .map(s -> s.getFileName().toString().split("\\.")[0]) .mapToInt(Integer::parseInt) .max().orElse(0); nextWriter(); this.lastEntryTimestamp = Timestamp.now(); + createFlushScheduler(); } - /** - * Constructor for Writer that uses defaults - * - * @param queuePath the path to the dead letter queue segments directory - * @throws IOException if the size of the file cannot be determined - */ - public DeadLetterQueueWriter(String queuePath) throws IOException { - this(Paths.get(queuePath), MAX_SEGMENT_SIZE_BYTES, Long.MAX_VALUE); + public boolean isOpen() { + return open.get(); } - private long getStartupQueueSize() throws IOException { - return getSegmentPaths(queuePath) - .mapToLong((p) -> { - try { - return Files.size(p); - } catch (IOException e) { - throw new IllegalStateException(e); - } - } ) - .sum(); + public Path getPath(){ + return queuePath; } - private void nextWriter() throws IOException { - currentWriter = new RecordIOWriter(queuePath.resolve(String.format(SEGMENT_FILE_PATTERN, ++currentSegmentIndex))); - currentQueueSize.increment(); + public long getCurrentQueueSize() { + return currentQueueSize.longValue(); + } + + public void writeEntry(Event event, String pluginName, String pluginId, String reason) throws IOException { + writeEntry(new DLQEntry(event, pluginName, pluginId, reason)); + } + + @Override + public void close() { + if (open.compareAndSet(true, false)) { + try { + finalizeSegment(FinalizeWhen.ALWAYS); + } catch (Exception e) { + logger.warn("Unable to close dlq writer, ignoring", e); + } + try { + releaseFileLock(); + } catch (Exception e) { + logger.warn("Unable to release fileLock, ignoring", e); + } + + try { + flushScheduler.shutdown(); + } catch (Exception e) { + logger.warn("Unable shutdown flush scheduler, ignoring", e); + } + } } static Stream getSegmentPaths(Path path) throws IOException { - try(final Stream files = Files.list(path)) { - return files.filter(p -> p.toString().endsWith(".log")) - .collect(Collectors.toList()).stream(); - } + return listFiles(path, ".log"); } - public synchronized void writeEntry(DLQEntry entry) throws IOException { - innerWriteEntry(entry); - } - - public synchronized void writeEntry(Event event, String pluginName, String pluginId, String reason) throws IOException { - Timestamp entryTimestamp = Timestamp.now(); - if (entryTimestamp.getTime().isBefore(lastEntryTimestamp.getTime())) { - entryTimestamp = lastEntryTimestamp; + @VisibleForTesting + void writeEntry(DLQEntry entry) throws IOException { + lock.lock(); + try { + Timestamp entryTimestamp = Timestamp.now(); + if (entryTimestamp.getTime().isBefore(lastEntryTimestamp.getTime())) { + entryTimestamp = lastEntryTimestamp; + } + innerWriteEntry(entry); + lastEntryTimestamp = entryTimestamp; + } finally { + lock.unlock(); } - DLQEntry entry = new DLQEntry(event, pluginName, pluginId, reason); - innerWriteEntry(entry); - lastEntryTimestamp = entryTimestamp; } private void innerWriteEntry(DLQEntry entry) throws IOException { @@ -154,10 +180,10 @@ public final class DeadLetterQueueWriter implements Closeable { logger.error("cannot write event to DLQ(path: " + this.queuePath + "): reached maxQueueSize of " + maxQueueSize); return; } else if (currentWriter.getPosition() + eventPayloadSize > maxSegmentSize) { - currentWriter.close(); - nextWriter(); + finalizeSegment(FinalizeWhen.ALWAYS); } currentQueueSize.add(currentWriter.writeEvent(record)); + lastWrite = Instant.now(); } /** @@ -172,42 +198,131 @@ public final class DeadLetterQueueWriter implements Closeable { return event.includes(DEAD_LETTER_QUEUE_METADATA_KEY); } - @Override - public void close() { - if (open.compareAndSet(true, false)) { - if (currentWriter != null) { - try { - currentWriter.close(); - } catch (Exception e) { - logger.debug("Unable to close dlq writer", e); - } - } - releaseLock(); + private void flushCheck() { + try{ + finalizeSegment(FinalizeWhen.ONLY_IF_STALE); + } catch (Exception e){ + logger.warn("unable to finalize segment", e); } } - private void releaseLock() { + /** + * Determines whether the current writer is stale. It is stale if writes have been performed, but the + * last time it was written is further in the past than the flush interval. + * @return + */ + private boolean isCurrentWriterStale(){ + return currentWriter.isStale(flushInterval); + } + + private void finalizeSegment(final FinalizeWhen finalizeWhen) throws IOException { + lock.lock(); try { - FileLockFactory.releaseLock(lock); + if (!isCurrentWriterStale() && finalizeWhen == FinalizeWhen.ONLY_IF_STALE) + return; + + if (currentWriter != null && currentWriter.hasWritten()) { + currentWriter.close(); + Files.move(queuePath.resolve(String.format(TEMP_FILE_PATTERN, currentSegmentIndex)), + queuePath.resolve(String.format(SEGMENT_FILE_PATTERN, currentSegmentIndex)), + StandardCopyOption.ATOMIC_MOVE); + if (isOpen()) { + nextWriter(); + } + } + } finally { + lock.unlock(); + } + } + + private void createFlushScheduler() { + flushScheduler = Executors.newScheduledThreadPool(1, r -> { + Thread t = new Thread(r); + //Allow this thread to die when the JVM dies + t.setDaemon(true); + //Set the name + t.setName("dlq-flush-check"); + return t; + }); + flushScheduler.scheduleAtFixedRate(this::flushCheck, 1L, 1L, TimeUnit.SECONDS); + } + + private long getStartupQueueSize() throws IOException { + return getSegmentPaths(queuePath) + .mapToLong((p) -> { + try { + return Files.size(p); + } catch (IOException e) { + throw new IllegalStateException(e); + } + } ) + .sum(); + } + + private void releaseFileLock() { + try { + FileLockFactory.releaseLock(fileLock); } catch (IOException e) { - logger.debug("Unable to release lock", e); + logger.debug("Unable to release fileLock", e); } try { Files.deleteIfExists(queuePath.resolve(LOCK_FILE)); } catch (IOException e){ - logger.debug("Unable to delete lock file", e); + logger.debug("Unable to delete fileLock file", e); } } - public boolean isOpen() { - return open.get(); + private void nextWriter() throws IOException { + currentWriter = new RecordIOWriter(queuePath.resolve(String.format(TEMP_FILE_PATTERN, ++currentSegmentIndex))); + currentQueueSize.increment(); } - public Path getPath(){ - return queuePath; + // Clean up existing temp files - files with an extension of .log.tmp. Either delete them if an existing + // segment file with the same base name exists, or rename the + // temp file to the segment file, which can happen when a process ends abnormally + private void cleanupTempFiles() throws IOException { + DeadLetterQueueWriter.listFiles(queuePath, ".log.tmp") + .forEach(this::cleanupTempFile); } - public long getCurrentQueueSize() { - return currentQueueSize.longValue(); + private static Stream listFiles(Path path, String suffix) throws IOException { + try(final Stream files = Files.list(path)) { + return files.filter(p -> p.toString().endsWith(suffix)) + .collect(Collectors.toList()).stream(); + } + } + + // check if there is a corresponding .log file - if yes delete the temp file, if no atomic move the + // temp file to be a new segment file.. + private void cleanupTempFile(final Path tempFile) { + String tempFilename = tempFile.getFileName().toString().split("\\.")[0]; + Path segmentFile = queuePath.resolve(String.format("%s.log", tempFilename)); + try { + if (Files.exists(segmentFile)) { + Files.delete(tempFile); + } + else { + SegmentStatus segmentStatus = RecordIOReader.getSegmentStatus(tempFile); + switch (segmentStatus){ + case VALID: + logger.debug("Moving temp file {} to segment file {}", tempFilename, segmentFile); + Files.move(tempFile, segmentFile, StandardCopyOption.ATOMIC_MOVE); + break; + case EMPTY: + logger.debug("Removing unused temp file {}", tempFilename); + Files.delete(tempFile); + break; + case INVALID: + Path errorFile = queuePath.resolve(String.format("%s.err", tempFilename)); + logger.warn("Segment file {} is in an error state, saving as {}", tempFilename, errorFile); + Files.move(tempFile, errorFile, StandardCopyOption.ATOMIC_MOVE); + break; + default: + throw new IllegalStateException("Unexpected value: " + RecordIOReader.getSegmentStatus(tempFile)); + } + } + } catch (IOException e){ + throw new IllegalStateException("Unable to clean up temp file: " + tempFile, e); + } } } diff --git a/logstash-core/src/main/java/org/logstash/common/io/RecordIOReader.java b/logstash-core/src/main/java/org/logstash/common/io/RecordIOReader.java index e10625ea1..583a3d306 100644 --- a/logstash-core/src/main/java/org/logstash/common/io/RecordIOReader.java +++ b/logstash-core/src/main/java/org/logstash/common/io/RecordIOReader.java @@ -38,6 +38,9 @@ */ package org.logstash.common.io; +import org.apache.logging.log4j.LogManager; +import org.apache.logging.log4j.Logger; + import java.io.Closeable; import java.io.IOException; import java.nio.ByteBuffer; @@ -60,12 +63,14 @@ import static org.logstash.common.io.RecordIOWriter.VERSION_SIZE; */ public final class RecordIOReader implements Closeable { + private static final Logger logger = LogManager.getLogger(RecordIOReader.class); private final FileChannel channel; private ByteBuffer currentBlock; private int currentBlockSizeReadFromChannel; private final Path path; private long channelPosition; private static final int UNSET = -1; + enum SegmentStatus { EMPTY, VALID, INVALID} public RecordIOReader(Path path) throws IOException { this.path = path; @@ -78,7 +83,7 @@ public final class RecordIOReader implements Closeable { byte versionInFile = versionBuffer.get(); if (versionInFile != VERSION) { this.channel.close(); - throw new RuntimeException(String.format( + throw new IllegalStateException(String.format( "Invalid version on DLQ data file %s. Expected version: %c. Version found on file: %c", path, VERSION, versionInFile)); } @@ -238,7 +243,7 @@ public final class RecordIOReader implements Closeable { computedChecksum.update(currentBlock.array(), currentBlock.position(), header.getSize()); if ((int) computedChecksum.getValue() != header.getChecksum()) { - throw new RuntimeException("invalid checksum of record"); + throw new IllegalStateException("invalid checksum of record"); } buffer.put(currentBlock.array(), currentBlock.position(), header.getSize()); @@ -343,4 +348,26 @@ public final class RecordIOReader implements Closeable { } } } + + /** + * Verify whether a segment is valid and non-empty. + * @param path Path to segment + * @return SegmentStatus EMPTY if the segment is empty, VALID if it is valid, INVALID otherwise + */ + static SegmentStatus getSegmentStatus(Path path) { + try (RecordIOReader ioReader = new RecordIOReader(path)) { + boolean moreEvents = true; + SegmentStatus segmentStatus = SegmentStatus.EMPTY; + while (moreEvents) { + // If all events in the segment can be read, then assume that this is a valid segment + moreEvents = (ioReader.readEvent() != null); + if (moreEvents) segmentStatus = SegmentStatus.VALID; + } + return segmentStatus; + } catch (IOException | IllegalStateException e){ + logger.warn("Error reading segment file {}", path, e); + return SegmentStatus.INVALID; + } + } + } diff --git a/logstash-core/src/main/java/org/logstash/common/io/RecordIOWriter.java b/logstash-core/src/main/java/org/logstash/common/io/RecordIOWriter.java index bbfb2b644..34d3b5024 100644 --- a/logstash-core/src/main/java/org/logstash/common/io/RecordIOWriter.java +++ b/logstash-core/src/main/java/org/logstash/common/io/RecordIOWriter.java @@ -44,7 +44,10 @@ import java.nio.ByteBuffer; import java.nio.channels.FileChannel; import java.nio.file.Path; import java.nio.file.StandardOpenOption; +import java.time.Duration; +import java.time.Instant; import java.util.OptionalInt; +import java.util.concurrent.atomic.AtomicBoolean; import java.util.zip.CRC32; import java.util.zip.Checksum; @@ -95,7 +98,11 @@ public final class RecordIOWriter implements Closeable { static final int VERSION_SIZE = 1; static final char VERSION = '1'; + private Path recordsFile; + private Instant lastWrite = null; + public RecordIOWriter(Path recordsFile) throws IOException { + this.recordsFile = recordsFile; this.posInBlock = 0; this.currentBlockIdx = 0; recordsFile.toFile().createNewFile(); @@ -133,6 +140,7 @@ public final class RecordIOWriter implements Closeable { } public long writeEvent(byte[] eventArray) throws IOException { + lastWrite = Instant.now(); ByteBuffer eventBuffer = ByteBuffer.wrap(eventArray); RecordType nextType = null; ByteBuffer slice = eventBuffer.slice(); @@ -160,6 +168,19 @@ public final class RecordIOWriter implements Closeable { return channel.position() - startPosition; } + + public boolean hasWritten(){ + return lastWrite != null; + } + + public boolean isStale(Duration flushPeriod){ + return hasWritten() && Instant.now().minus(flushPeriod).isAfter(lastWrite); + } + + public Path getPath(){ + return this.recordsFile; + } + @Override public void close() throws IOException { channel.close(); diff --git a/logstash-core/src/main/java/org/logstash/execution/AbstractPipelineExt.java b/logstash-core/src/main/java/org/logstash/execution/AbstractPipelineExt.java index 148378466..b36936ac7 100644 --- a/logstash-core/src/main/java/org/logstash/execution/AbstractPipelineExt.java +++ b/logstash-core/src/main/java/org/logstash/execution/AbstractPipelineExt.java @@ -27,6 +27,7 @@ import java.nio.file.Paths; import java.security.MessageDigest; import java.security.NoSuchAlgorithmException; import java.util.ArrayList; +import java.time.Duration; import java.util.Arrays; import java.util.List; import java.util.UUID; @@ -277,10 +278,9 @@ public class AbstractPipelineExt extends RubyBasicObject { DeadLetterQueueFactory.getWriter( pipelineId.asJavaString(), getSetting(context, "path.dead_letter_queue").asJavaString(), - getSetting(context, "dead_letter_queue.max_bytes").convertToInteger() - .getLongValue() - ) - ); + getSetting(context, "dead_letter_queue.max_bytes").convertToInteger().getLongValue(), + Duration.ofMillis(getSetting(context, "dead_letter_queue.flush_interval").convertToInteger().getLongValue())) + ); } else { dlqWriter = RubyUtil.DUMMY_DLQ_WRITER_CLASS.callMethod(context, "new"); } diff --git a/logstash-core/src/test/java/org/logstash/common/DeadLetterQueueFactoryTest.java b/logstash-core/src/test/java/org/logstash/common/DeadLetterQueueFactoryTest.java index 9072b2de7..12df8049b 100644 --- a/logstash-core/src/test/java/org/logstash/common/DeadLetterQueueFactoryTest.java +++ b/logstash-core/src/test/java/org/logstash/common/DeadLetterQueueFactoryTest.java @@ -47,6 +47,7 @@ import org.logstash.common.io.DeadLetterQueueWriter; import java.io.IOException; import java.nio.file.Path; +import java.time.Duration; import static junit.framework.TestCase.assertSame; import static org.junit.Assert.assertTrue; @@ -67,9 +68,9 @@ public class DeadLetterQueueFactoryTest { public void testSameBeforeRelease() throws IOException { try { Path pipelineA = dir.resolve(PIPELINE_NAME); - DeadLetterQueueWriter writer = DeadLetterQueueFactory.getWriter(PIPELINE_NAME, pipelineA.toString(), 10000); + DeadLetterQueueWriter writer = DeadLetterQueueFactory.getWriter(PIPELINE_NAME, pipelineA.toString(), 10000, Duration.ofSeconds(1)); assertTrue(writer.isOpen()); - DeadLetterQueueWriter writer2 = DeadLetterQueueFactory.getWriter(PIPELINE_NAME, pipelineA.toString(), 10000); + DeadLetterQueueWriter writer2 = DeadLetterQueueFactory.getWriter(PIPELINE_NAME, pipelineA.toString(), 10000, Duration.ofSeconds(1)); assertSame(writer, writer2); writer.close(); } finally { @@ -81,11 +82,11 @@ public class DeadLetterQueueFactoryTest { public void testOpenableAfterRelease() throws IOException { try { Path pipelineA = dir.resolve(PIPELINE_NAME); - DeadLetterQueueWriter writer = DeadLetterQueueFactory.getWriter(PIPELINE_NAME, pipelineA.toString(), 10000); + DeadLetterQueueWriter writer = DeadLetterQueueFactory.getWriter(PIPELINE_NAME, pipelineA.toString(), 10000, Duration.ofSeconds(1)); assertTrue(writer.isOpen()); writer.close(); DeadLetterQueueFactory.release(PIPELINE_NAME); - writer = DeadLetterQueueFactory.getWriter(PIPELINE_NAME, pipelineA.toString(), 10000); + writer = DeadLetterQueueFactory.getWriter(PIPELINE_NAME, pipelineA.toString(), 10000, Duration.ofSeconds(1)); assertTrue(writer.isOpen()); writer.close(); }finally{ diff --git a/logstash-core/src/test/java/org/logstash/common/io/DeadLetterQueueReaderTest.java b/logstash-core/src/test/java/org/logstash/common/io/DeadLetterQueueReaderTest.java index cea76f1e4..9c04397c0 100644 --- a/logstash-core/src/test/java/org/logstash/common/io/DeadLetterQueueReaderTest.java +++ b/logstash-core/src/test/java/org/logstash/common/io/DeadLetterQueueReaderTest.java @@ -1,23 +1,3 @@ -/* - * 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. - */ - - /* * Licensed to Elasticsearch under one or more contributor * license agreements. See the NOTICE file distributed with @@ -40,6 +20,7 @@ package org.logstash.common.io; +import org.junit.Assert; import org.junit.Before; import org.junit.Rule; import org.junit.Test; @@ -51,9 +32,13 @@ import org.logstash.ackedqueue.StringElement; import java.io.IOException; import java.nio.file.Path; +import java.time.Duration; import java.util.Arrays; import java.util.Collections; import java.util.Random; +import java.util.concurrent.ExecutorService; +import java.util.concurrent.Executors; +import java.util.concurrent.TimeUnit; import static org.hamcrest.CoreMatchers.equalTo; import static org.hamcrest.CoreMatchers.is; @@ -66,6 +51,8 @@ public class DeadLetterQueueReaderTest { private Path dir; private int defaultDlqSize = 100_000_000; // 100mb + private static final int PAD_FOR_BLOCK_SIZE_EVENT = 32490; + @Rule public TemporaryFolder temporaryFolder = new TemporaryFolder(); @@ -148,7 +135,7 @@ public class DeadLetterQueueReaderTest { event.setField("message", generateMessageContent(32500)); long startTime = System.currentTimeMillis(); int messageSize = 0; - try(DeadLetterQueueWriter writeManager = new DeadLetterQueueWriter(dir, 10 * 1024 * 1024, defaultDlqSize)) { + try(DeadLetterQueueWriter writeManager = new DeadLetterQueueWriter(dir, 10 * 1024 * 1024, defaultDlqSize, Duration.ofSeconds(1))) { for (int i = 0; i < 2; i++) { DLQEntry entry = new DLQEntry(event, "", "", "", new Timestamp(startTime++)); messageSize += entry.serialize().length; @@ -198,7 +185,7 @@ public class DeadLetterQueueReaderTest { int size = templateEntry.serialize().length + RecordIOWriter.RECORD_HEADER_SIZE + VERSION_SIZE; DeadLetterQueueWriter writeManager = null; try { - writeManager = new DeadLetterQueueWriter(dir, size, defaultDlqSize); + writeManager = new DeadLetterQueueWriter(dir, size, defaultDlqSize, Duration.ofSeconds(1)); for (int i = 1; i <= count; i++) { writeManager.writeEntry(new DLQEntry(event, "1", "1", String.valueOf(i))); } @@ -237,7 +224,7 @@ public class DeadLetterQueueReaderTest { event.setField("T", new String(field)); Timestamp timestamp = new Timestamp(); - try(DeadLetterQueueWriter writeManager = new DeadLetterQueueWriter(dir, 10 * 1024 * 1024, defaultDlqSize)) { + try(DeadLetterQueueWriter writeManager = new DeadLetterQueueWriter(dir, 10 * 1024 * 1024, defaultDlqSize, Duration.ofSeconds(1))) { for (int i = 0; i < 2; i++) { DLQEntry entry = new DLQEntry(event, "", "", "", timestamp); assertThat(entry.serialize().length + RecordIOWriter.RECORD_HEADER_SIZE, is(BLOCK_SIZE)); @@ -260,7 +247,7 @@ public class DeadLetterQueueReaderTest { event.setField("message", new String(field)); long startTime = System.currentTimeMillis(); int messageSize = 0; - try(DeadLetterQueueWriter writeManager = new DeadLetterQueueWriter(dir, 10 * 1024 * 1024, defaultDlqSize)) { + try(DeadLetterQueueWriter writeManager = new DeadLetterQueueWriter(dir, 10 * 1024 * 1024, defaultDlqSize, Duration.ofSeconds(1))) { for (int i = 1; i <= 5; i++) { DLQEntry entry = new DLQEntry(event, "", "", "", new Timestamp(startTime++)); messageSize += entry.serialize().length; @@ -277,15 +264,140 @@ public class DeadLetterQueueReaderTest { } } + @Test + public void testFlushAfterWriterClose() throws Exception { + Event event = new Event(); + event.setField("T", generateMessageContent(PAD_FOR_BLOCK_SIZE_EVENT/8)); + Timestamp timestamp = new Timestamp(); + + try(DeadLetterQueueWriter writeManager = new DeadLetterQueueWriter(dir, BLOCK_SIZE, defaultDlqSize, Duration.ofSeconds(1))) { + for (int i = 0; i < 6; i++) { + DLQEntry entry = new DLQEntry(event, "", "", Integer.toString(i), timestamp); + writeManager.writeEntry(entry); + } + } + try (DeadLetterQueueReader readManager = new DeadLetterQueueReader(dir)) { + for (int i = 0; i < 6;i++) { + DLQEntry entry = readManager.pollEntry(100); + assertThat(entry.getReason(), is(String.valueOf(i))); + } + } + } + + @Test + public void testFlushAfterSegmentComplete() throws Exception { + Event event = new Event(); + final int EVENTS_BEFORE_FLUSH = randomBetween(1, 32); + event.setField("T", generateMessageContent(PAD_FOR_BLOCK_SIZE_EVENT)); + Timestamp timestamp = new Timestamp(); + + try (DeadLetterQueueWriter writeManager = new DeadLetterQueueWriter(dir, BLOCK_SIZE * EVENTS_BEFORE_FLUSH, defaultDlqSize, Duration.ofHours(1))) { + for (int i = 1; i < EVENTS_BEFORE_FLUSH; i++) { + DLQEntry entry = new DLQEntry(event, "", "", Integer.toString(i), timestamp); + writeManager.writeEntry(entry); + } + + try (DeadLetterQueueReader readManager = new DeadLetterQueueReader(dir)) { + for (int i = 1; i < EVENTS_BEFORE_FLUSH; i++) { + DLQEntry entry = readManager.pollEntry(100); + assertThat(entry, is(nullValue())); + } + } + + writeManager.writeEntry(new DLQEntry(event, "", "", "flush event", timestamp)); + + try (DeadLetterQueueReader readManager = new DeadLetterQueueReader(dir)) { + for (int i = 1; i < EVENTS_BEFORE_FLUSH; i++) { + DLQEntry entry = readManager.pollEntry(100); + assertThat(entry.getReason(), is(String.valueOf(i))); + } + } + } + } + + @Test + public void testMultiFlushAfterSegmentComplete() throws Exception { + Event event = new Event(); + final int eventsInSegment = randomBetween(1, 32); + // Write enough events to not quite complete a second segment. + final int totalEventsToWrite = (2 * eventsInSegment) - 1; + event.setField("T", generateMessageContent(PAD_FOR_BLOCK_SIZE_EVENT)); + Timestamp timestamp = new Timestamp(); + + try (DeadLetterQueueWriter writeManager = new DeadLetterQueueWriter(dir, BLOCK_SIZE * eventsInSegment, defaultDlqSize, Duration.ofHours(1))) { + for (int i = 1; i < totalEventsToWrite; i++) { + DLQEntry entry = new DLQEntry(event, "", "", Integer.toString(i), timestamp); + writeManager.writeEntry(entry); + } + + try (DeadLetterQueueReader readManager = new DeadLetterQueueReader(dir)) { + + for (int i = 1; i < eventsInSegment; i++) { + DLQEntry entry = readManager.pollEntry(100); + assertThat(entry.getReason(), is(String.valueOf(i))); + } + + + for (int i = eventsInSegment + 1; i < totalEventsToWrite; i++) { + DLQEntry entry = readManager.pollEntry(100); + assertThat(entry, is(nullValue())); + } + } + + writeManager.writeEntry(new DLQEntry(event, "", "", "flush event", timestamp)); + + try (DeadLetterQueueReader readManager = new DeadLetterQueueReader(dir)) { + for (int i = 1; i < totalEventsToWrite; i++) { + DLQEntry entry = readManager.pollEntry(100); + assertThat(entry.getReason(), is(String.valueOf(i))); + } + } + } + } + + @Test + public void testFlushAfterDelay() throws Exception { + Event event = new Event(); + int eventsPerBlock = randomBetween(1,16); + int eventsToWrite = eventsPerBlock - 1; + event.setField("T", generateMessageContent(PAD_FOR_BLOCK_SIZE_EVENT/eventsPerBlock)); + Timestamp timestamp = new Timestamp(); + + System.out.println("events per block= " + eventsPerBlock); + + try(DeadLetterQueueWriter writeManager = new DeadLetterQueueWriter(dir, BLOCK_SIZE, defaultDlqSize, Duration.ofSeconds(1))) { + for (int i = 1; i < eventsToWrite; i++) { + DLQEntry entry = new DLQEntry(event, "", "", Integer.toString(i), timestamp); + writeManager.writeEntry(entry); + } + + try (DeadLetterQueueReader readManager = new DeadLetterQueueReader(dir)) { + for (int i = 1; i < eventsToWrite; i++) { + DLQEntry entry = readManager.pollEntry(100); + assertThat(entry, is(nullValue())); + } + } + + Thread.sleep(2000); + + try (DeadLetterQueueReader readManager = new DeadLetterQueueReader(dir)) { + for (int i = 1; i < eventsToWrite; i++) { + DLQEntry entry = readManager.pollEntry(100); + assertThat(entry.getReason(), is(String.valueOf(i))); + } + } + + } + } + // This test tests for a single event that ends on a block and segment boundary @Test public void testBlockAndSegmentBoundary() throws Exception { - final int PAD_FOR_BLOCK_SIZE_EVENT = 32490; Event event = new Event(); event.setField("T", generateMessageContent(PAD_FOR_BLOCK_SIZE_EVENT)); Timestamp timestamp = new Timestamp(); - try(DeadLetterQueueWriter writeManager = new DeadLetterQueueWriter(dir, BLOCK_SIZE, defaultDlqSize)) { + try(DeadLetterQueueWriter writeManager = new DeadLetterQueueWriter(dir, BLOCK_SIZE, defaultDlqSize, Duration.ofSeconds(1))) { for (int i = 0; i < 2; i++) { DLQEntry entry = new DLQEntry(event, "", "", "", timestamp); assertThat(entry.serialize().length + RecordIOWriter.RECORD_HEADER_SIZE, is(BLOCK_SIZE)); @@ -306,7 +418,7 @@ public class DeadLetterQueueReaderTest { int eventCount = 1024; // max = 1000 * 64kb = 64mb long startTime = System.currentTimeMillis(); - try(DeadLetterQueueWriter writeManager = new DeadLetterQueueWriter(dir, 10 * 1024 * 1024, defaultDlqSize)) { + try(DeadLetterQueueWriter writeManager = new DeadLetterQueueWriter(dir, 10 * 1024 * 1024, defaultDlqSize, Duration.ofSeconds(1))) { for (int i = 0; i < eventCount; i++) { event.setField("message", generateMessageContent((int)(Math.random() * (maxEventSize)))); DLQEntry entry = new DLQEntry(event, "", "", String.valueOf(i), new Timestamp(startTime++)); @@ -353,6 +465,63 @@ public class DeadLetterQueueReaderTest { String.valueOf(FIRST_WRITE_EVENT_COUNT)); } + /** + * Tests concurrently reading and writing from the DLQ. + * @throws Exception On Failure + */ + @Test + public void testConcurrentWriteReadRandomEventSize() throws Exception { + final ExecutorService exec = Executors.newSingleThreadExecutor(); + try { + final int maxEventSize = BLOCK_SIZE * 2; + final int eventCount = 300; + exec.submit(() -> { + final Event event = new Event(); + long startTime = System.currentTimeMillis(); + try (DeadLetterQueueWriter writeManager = new DeadLetterQueueWriter(dir, 10 * 1024 * 1024, defaultDlqSize, Duration.ofSeconds(10))) { + for (int i = 0; i < eventCount; i++) { + event.setField( + "message", + generateMessageContent((int) (Math.random() * (maxEventSize))) + ); + writeManager.writeEntry( + new DLQEntry( + event, "", "", String.valueOf(i), + new Timestamp(startTime++) + ) + ); + } + } catch (final IOException ex) { + throw new IllegalStateException(ex); + } + }); + + int i = 0; + try (DeadLetterQueueReader readManager = new DeadLetterQueueReader(dir)) { + while(i < eventCount) { + DLQEntry entry = readManager.pollEntry(10_000L); + if (entry != null){ + assertThat(entry.getReason(), is(String.valueOf(i))); + i++; + } + } + } catch (Exception e){ + throw new IllegalArgumentException("Failed to process entry number" + i, e); + } + } finally { + exec.shutdown(); + if (!exec.awaitTermination(2L, TimeUnit.MINUTES)) { + Assert.fail("Failed to shut down record writer"); + } + } + } + + + private int randomBetween(int from, int to){ + Random r = new Random(); + return r.nextInt((to - from) + 1) + from; + } + private String generateMessageContent(int size) { char[] valid = new char[RecordType.values().length + 1]; int j = 0; @@ -378,7 +547,7 @@ public class DeadLetterQueueReaderTest { } private void writeEntries(final Event event, int offset, final int numberOfEvents, long startTime) throws IOException { - try (DeadLetterQueueWriter writeManager = new DeadLetterQueueWriter(dir, 10 * 1024 * 1024, defaultDlqSize)) { + try (DeadLetterQueueWriter writeManager = new DeadLetterQueueWriter(dir, 10 * 1024 * 1024, defaultDlqSize, Duration.ofSeconds(1))) { for (int i = offset; i <= offset + numberOfEvents; i++) { DLQEntry entry = new DLQEntry(event, "foo", "bar", String.valueOf(i), new Timestamp(startTime++)); writeManager.writeEntry(entry); diff --git a/logstash-core/src/test/java/org/logstash/common/io/DeadLetterQueueWriterTest.java b/logstash-core/src/test/java/org/logstash/common/io/DeadLetterQueueWriterTest.java index ff352749c..5209dfb7b 100644 --- a/logstash-core/src/test/java/org/logstash/common/io/DeadLetterQueueWriterTest.java +++ b/logstash-core/src/test/java/org/logstash/common/io/DeadLetterQueueWriterTest.java @@ -1,23 +1,3 @@ -/* - * 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. - */ - - /* * Licensed to Elasticsearch under one or more contributor * license agreements. See the NOTICE file distributed with @@ -45,7 +25,10 @@ import java.nio.channels.OverlappingFileLockException; import java.nio.file.Files; import java.nio.file.Path; import java.nio.file.StandardOpenOption; +import java.time.Duration; import java.util.stream.Stream; + +import org.hamcrest.CoreMatchers; import org.junit.Before; import org.junit.Rule; import org.junit.Test; @@ -53,13 +36,16 @@ import org.junit.rules.TemporaryFolder; import org.logstash.DLQEntry; import org.logstash.Event; import org.logstash.LockException; +import org.logstash.Timestamp; import static junit.framework.TestCase.assertFalse; import static org.hamcrest.CoreMatchers.is; import static org.hamcrest.CoreMatchers.not; import static org.hamcrest.MatcherAssert.assertThat; +import static org.hamcrest.core.IsNull.nullValue; import static org.junit.Assert.assertTrue; import static org.junit.Assert.fail; +import static org.logstash.common.io.RecordIOWriter.BLOCK_SIZE; import static org.logstash.common.io.RecordIOWriter.RECORD_HEADER_SIZE; import static org.logstash.common.io.RecordIOWriter.VERSION_SIZE; @@ -79,7 +65,7 @@ public class DeadLetterQueueWriterTest { @Test public void testLockFileManagement() throws Exception { Path lockFile = dir.resolve(".lock"); - DeadLetterQueueWriter writer = new DeadLetterQueueWriter(dir, 1000, 100000); + DeadLetterQueueWriter writer = new DeadLetterQueueWriter(dir, 1000, 100000, Duration.ofSeconds(1)); assertTrue(Files.exists(lockFile)); writer.close(); assertFalse(Files.exists(lockFile)); @@ -87,9 +73,9 @@ public class DeadLetterQueueWriterTest { @Test public void testFileLocking() throws Exception { - DeadLetterQueueWriter writer = new DeadLetterQueueWriter(dir, 1000, 100000); + DeadLetterQueueWriter writer = new DeadLetterQueueWriter(dir, 1000, 100000, Duration.ofSeconds(1)); try { - new DeadLetterQueueWriter(dir, 100, 1000); + new DeadLetterQueueWriter(dir, 100, 1000, Duration.ofSeconds(1)); fail(); } catch (LockException e) { } finally { @@ -101,7 +87,7 @@ public class DeadLetterQueueWriterTest { public void testUncleanCloseOfPreviousWriter() throws Exception { Path lockFilePath = dir.resolve(".lock"); boolean created = lockFilePath.toFile().createNewFile(); - DeadLetterQueueWriter writer = new DeadLetterQueueWriter(dir, 1000, 100000); + DeadLetterQueueWriter writer = new DeadLetterQueueWriter(dir, 1000, 100000, Duration.ofSeconds(1)); FileChannel channel = FileChannel.open(lockFilePath, StandardOpenOption.WRITE); try { @@ -116,7 +102,7 @@ public class DeadLetterQueueWriterTest { @Test public void testWrite() throws Exception { - DeadLetterQueueWriter writer = new DeadLetterQueueWriter(dir, 1000, 100000); + DeadLetterQueueWriter writer = new DeadLetterQueueWriter(dir, 1000, 100000, Duration.ofSeconds(1)); DLQEntry entry = new DLQEntry(new Event(), "type", "id", "reason"); writer.writeEntry(entry); writer.close(); @@ -129,9 +115,9 @@ public class DeadLetterQueueWriterTest { DLQEntry entry = new DLQEntry(new Event(), "type", "id", "reason"); DLQEntry dlqEntry = new DLQEntry(dlqEvent, "type", "id", "reason"); - try (DeadLetterQueueWriter writer = new DeadLetterQueueWriter(dir, 1000, 100000);) { + try (DeadLetterQueueWriter writer = new DeadLetterQueueWriter(dir, 1000, 100000, Duration.ofSeconds(1));) { writer.writeEntry(entry); - long dlqLengthAfterEvent = dlqLength(); + long dlqLengthAfterEvent = dlqLength(); assertThat(dlqLengthAfterEvent, is(not(EMPTY_DLQ))); writer.writeEntry(dlqEntry); @@ -144,25 +130,76 @@ public class DeadLetterQueueWriterTest { DLQEntry entry = new DLQEntry(new Event(), "type", "id", "reason"); int payloadLength = RECORD_HEADER_SIZE + VERSION_SIZE + entry.serialize().length; - final int MESSAGE_COUNT= 5; + final int MESSAGE_COUNT = 5; long MAX_QUEUE_LENGTH = payloadLength * MESSAGE_COUNT; - DeadLetterQueueWriter writer = null; - try{ - writer = new DeadLetterQueueWriter(dir, payloadLength, MAX_QUEUE_LENGTH); + + try (DeadLetterQueueWriter writer = new DeadLetterQueueWriter(dir, payloadLength, MAX_QUEUE_LENGTH, Duration.ofSeconds(1))) { + for (int i = 0; i < MESSAGE_COUNT; i++) writer.writeEntry(entry); + // Sleep to allow flush to happen + Thread.sleep(2000); assertThat(dlqLength(), is(MAX_QUEUE_LENGTH)); writer.writeEntry(entry); + Thread.sleep(2000); assertThat(dlqLength(), is(MAX_QUEUE_LENGTH)); - } finally { - if (writer != null) { - writer.close(); + } + } + + @Test + public void testSlowFlush() throws Exception { + try (DeadLetterQueueWriter writer = new DeadLetterQueueWriter(dir, 1000, 1_000_000, Duration.ofSeconds(1))) { + DLQEntry entry = new DLQEntry(new Event(), "type", "id", "1"); + writer.writeEntry(entry); + entry = new DLQEntry(new Event(), "type", "id", "2"); + // Sleep to allow flush to happen\ + Thread.sleep(2000); + writer.writeEntry(entry); + Thread.sleep(2000); + // Do not close here - make sure that the slow write is processed + + try (DeadLetterQueueReader reader = new DeadLetterQueueReader(dir)) { + assertThat(reader.pollEntry(100).getReason(), is("1")); + assertThat(reader.pollEntry(100).getReason(), is("2")); } } } + + @Test + public void testNotFlushed() throws Exception { + try (DeadLetterQueueWriter writeManager = new DeadLetterQueueWriter(dir, BLOCK_SIZE, 1_000_000_000, Duration.ofSeconds(5))) { + for (int i = 0; i < 4; i++) { + DLQEntry entry = new DLQEntry(new Event(), "type", "id", "1"); + writeManager.writeEntry(entry); + } + + // Allow for time for scheduled flush check + Thread.sleep(1000); + + try (DeadLetterQueueReader readManager = new DeadLetterQueueReader(dir)) { + for (int i = 0; i < 4; i++) { + DLQEntry entry = readManager.pollEntry(100); + assertThat(entry, is(CoreMatchers.nullValue())); + } + } + } + } + + + @Test + public void testCloseFlush() throws Exception { + try (DeadLetterQueueWriter writer = new DeadLetterQueueWriter(dir, 1000, 1_000_000, Duration.ofHours(1))) { + DLQEntry entry = new DLQEntry(new Event(), "type", "id", "1"); + writer.writeEntry(entry); + } + try (DeadLetterQueueReader reader = new DeadLetterQueueReader(dir)) { + assertThat(reader.pollEntry(100).getReason(), is("1")); + } + } + private long dlqLength() throws IOException { try(final Stream files = Files.list(dir)) { return files.filter(p -> p.toString().endsWith(".log")) diff --git a/logstash-core/src/test/java/org/logstash/common/io/RecordIOReaderTest.java b/logstash-core/src/test/java/org/logstash/common/io/RecordIOReaderTest.java index e8537c9f8..4dacb14f1 100644 --- a/logstash-core/src/test/java/org/logstash/common/io/RecordIOReaderTest.java +++ b/logstash-core/src/test/java/org/logstash/common/io/RecordIOReaderTest.java @@ -33,6 +33,7 @@ import java.nio.file.Path; import java.nio.file.StandardOpenOption; import java.util.Arrays; import java.util.Comparator; +import java.util.OptionalInt; import java.util.function.Function; import static org.hamcrest.CoreMatchers.equalTo; @@ -174,6 +175,39 @@ public class RecordIOReaderTest { } } + @Test + public void testObviouslyInvalidSegment() throws Exception { + assertThat(RecordIOReader.getSegmentStatus(file), is(RecordIOReader.SegmentStatus.INVALID)); + } + + @Test + public void testPartiallyWrittenSegment() throws Exception { + try(RecordIOWriter writer = new RecordIOWriter(file)) { + writer.writeRecordHeader( + new RecordHeader(RecordType.COMPLETE, 100, OptionalInt.empty(), 0)); + } + assertThat(RecordIOReader.getSegmentStatus(file), is(RecordIOReader.SegmentStatus.INVALID)); + } + + @Test + public void testEmptySegment() throws Exception { + try(RecordIOWriter writer = new RecordIOWriter(file)){ + // Do nothing. Creating a new writer is the same behaviour as starting and closing + // This line avoids a compiler warning. + writer.toString(); + } + assertThat(RecordIOReader.getSegmentStatus(file), is(RecordIOReader.SegmentStatus.EMPTY)); + } + + @Test + public void testValidSegment() throws Exception { + try(RecordIOWriter writer = new RecordIOWriter(file)){ + writer.writeEvent(new byte[]{ 72, 101, 108, 108, 111}); + } + + assertThat(RecordIOReader.getSegmentStatus(file), is(RecordIOReader.SegmentStatus.VALID)); + } + @Test public void testReadWhileWriteAcrossBoundary() throws Exception { char[] tooBig = fillArray( BLOCK_SIZE/4); diff --git a/qa/integration/build.gradle b/qa/integration/build.gradle index bb618804b..7c60376d3 100644 --- a/qa/integration/build.gradle +++ b/qa/integration/build.gradle @@ -46,4 +46,13 @@ tasks.register("integrationTests", Test) { inputs.files fileTree("${projectDir}/specs") systemProperty 'logstash.core.root.dir', projectDir.absolutePath include '/org/logstash/integration/RSpecTests.class' + + outputs.upToDateWhen { + if (project.hasProperty('integrationTests.rerun')) { + println "Rerunning Integration Tests" + return false + } else { + return true + } + } } diff --git a/qa/integration/specs/dlq_spec.rb b/qa/integration/specs/dlq_spec.rb index ae6cc80c9..35e02c30c 100644 --- a/qa/integration/specs/dlq_spec.rb +++ b/qa/integration/specs/dlq_spec.rb @@ -23,6 +23,14 @@ require_relative 'spec_helper.rb' require "logstash/devutils/rspec/spec_helper" +def generate_message(number) + message = {} + number.times do |i| + message["field#{i}"] = "value#{i}" + end + message.to_json +end + describe "Test Dead Letter Queue" do before(:all) { @@ -58,7 +66,7 @@ describe "Test Dead Letter Queue" do let!(:settings_dir) { Stud::Temporary.directory } shared_examples_for "it can send 1000 documents to and index from the dlq" do - xit 'should index all documents' do + it 'should index all documents' do es_service = @fixture.get_service("elasticsearch") es_client = es_service.get_client # test if all data was indexed by ES, but first refresh manually @@ -91,13 +99,14 @@ describe "Test Dead Letter Queue" do end context 'with multiple pipelines' do + let(:message) { generate_message(100)} let(:pipelines) {[ { "pipeline.id" => "test", "pipeline.workers" => 1, "dead_letter_queue.enable" => true, "pipeline.batch.size" => 1, - "config.string" => "input { generator { message => '{\"test\":\"one\"}' codec => \"json\" count => 1000 } } filter { mutate { add_field => { \"geoip\" => \"somewhere\" } } } output { elasticsearch {} }" + "config.string" => "input { generator { message => '#{message}' codec => \"json\" count => 1000 } } filter { mutate { add_field => { \"geoip\" => \"somewhere\" } } } output { elasticsearch {} }" }, { "pipeline.id" => "test2", @@ -112,6 +121,7 @@ describe "Test Dead Letter Queue" do end context 'with a single pipeline' do + let(:message) { generate_message(100)} let(:pipelines) {[ { "pipeline.id" => "main", @@ -119,7 +129,7 @@ describe "Test Dead Letter Queue" do "dead_letter_queue.enable" => true, "pipeline.batch.size" => 1, "config.string" => " - input { generator{ message => '{\"test\":\"one\"}' codec => \"json\" count => 1000 } + input { generator{ message => '#{message}' codec => \"json\" count => 1000 } dead_letter_queue { path => \"#{dlq_dir}\" commit_offsets => true } } filter { @@ -135,7 +145,6 @@ describe "Test Dead Letter Queue" do end context 'using logstash.yml and separate config file' do - skip("This test fails Jenkins CI, tracked in https://github.com/elastic/logstash/issues/10275") let(:generator_config_file) { config_to_temp_file(@fixture.config("root",{ :dlq_dir => dlq_dir })) } before :each do diff --git a/qa/integration/specs/spec_helper.rb b/qa/integration/specs/spec_helper.rb index 71a1eb420..ef0e14da5 100644 --- a/qa/integration/specs/spec_helper.rb +++ b/qa/integration/specs/spec_helper.rb @@ -26,6 +26,10 @@ end RSpec::Matchers.define :have_hits do |expected| match do |actual| # For Elasticsearch versions 7+, the result is in a value field, just in total for > 6 - expected == actual['hits']['total'].is_a?(Hash) ? actual['hits']['total']['value'] : actual['hits']['total'] + if actual['hits']['total'].is_a?(Hash) + expected == actual['hits']['total']['value'] + else + expected == actual['hits']['total'] + end end end From 80db07d36d4e0e46a75142bfe20bb5e2a1d92275 Mon Sep 17 00:00:00 2001 From: Rob Bavey Date: Wed, 7 Oct 2020 14:46:53 -0400 Subject: [PATCH 0612/1126] [7x backport] env2yaml syntax error (#12322) Clean backport of #12320 `pipeline.ecs_compatibility` setting was missing a comma after its definition --- docker/data/logstash/env2yaml/env2yaml.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docker/data/logstash/env2yaml/env2yaml.go b/docker/data/logstash/env2yaml/env2yaml.go index cd3bf24f0..6b3bd346d 100644 --- a/docker/data/logstash/env2yaml/env2yaml.go +++ b/docker/data/logstash/env2yaml/env2yaml.go @@ -57,7 +57,7 @@ func normalizeSetting(setting string) (string, error) { "pipeline.batch.delay", "pipeline.unsafe_shutdown", "pipeline.java_execution", - "pipeline.ecs_compatibility" + "pipeline.ecs_compatibility", "pipeline.plugin_classloaders", "path.config", "config.string", From 0b18b79cceeb46dd1c170d19105a99311895b831 Mon Sep 17 00:00:00 2001 From: Karen Metts <35154725+karenzone@users.noreply.github.com> Date: Tue, 13 Oct 2020 15:38:15 -0400 Subject: [PATCH 0613/1126] Doc: Clarify use of queue max bytes setting (#12341) Queue max bytes only applies to persistent queues Forwardports: #12334 to 7.x Co-authored-by: rsdrakh <33121848+rsdrakh@users.noreply.github.com> --- docs/static/management/centralized-pipelines.asciidoc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/static/management/centralized-pipelines.asciidoc b/docs/static/management/centralized-pipelines.asciidoc index 1410119f2..77c98f0e6 100644 --- a/docs/static/management/centralized-pipelines.asciidoc +++ b/docs/static/management/centralized-pipelines.asciidoc @@ -77,7 +77,7 @@ The internal queueing model for event buffering. Options are *memory* for in-memory queueing, or *persisted* for disk-based acknowledged queueing. Queue max bytes:: -The total capacity of the queue. +The total capacity of the queue when persistent queues are enabled. Queue checkpoint writes:: The maximum number of events written before a checkpoint is forced when From 69e6200a7b1ca48d627e7eec3e37000dbfba4a10 Mon Sep 17 00:00:00 2001 From: Colin Surprenant Date: Tue, 13 Oct 2020 17:06:25 -0400 Subject: [PATCH 0614/1126] stop inputs upon a worker error before terminating the pipeline (#12342) This addresses an incomplete fix in #12019 starting in 7.8.1 where upon catching a worker exception (to avoid crashing the whole logstash per #12306) the input plugin(s) are not terminated prior to closing the pipeline leading to the input plugin(s) continuing execution and failing with IllegalStateException & Tried to write to a closed queue since closing the pipeline also correctly closes the queue. --- logstash-core/lib/logstash/java_pipeline.rb | 58 ++++++++++-- .../spec/logstash/java_pipeline_spec.rb | 88 ++++++++++++++++--- 2 files changed, 124 insertions(+), 22 deletions(-) diff --git a/logstash-core/lib/logstash/java_pipeline.rb b/logstash-core/lib/logstash/java_pipeline.rb index c20138e36..688018518 100644 --- a/logstash-core/lib/logstash/java_pipeline.rb +++ b/logstash-core/lib/logstash/java_pipeline.rb @@ -32,12 +32,15 @@ module LogStash; class JavaPipeline < JavaBasePipeline attr_reader \ :worker_threads, + :input_threads, :events_consumed, :events_filtered, :started_at, :thread MAX_INFLIGHT_WARN_THRESHOLD = 10_000 + SECOND = 1 + MEMORY = "memory".freeze def initialize(pipeline_config, namespaced_metric = nil, agent = nil) @logger = self.logger @@ -46,7 +49,7 @@ module LogStash; class JavaPipeline < JavaBasePipeline @worker_threads = [] - @drain_queue = settings.get_value("queue.drain") || settings.get("queue.type") == "memory" + @drain_queue = settings.get_value("queue.drain") || settings.get("queue.type") == MEMORY @events_filtered = java.util.concurrent.atomic.LongAdder.new @events_consumed = java.util.concurrent.atomic.LongAdder.new @@ -134,9 +137,7 @@ module LogStash; class JavaPipeline < JavaBasePipeline run @finished_run.make_true rescue => e - # no need to log at ERROR level since this log will be redundant to the log in - # the worker loop thread global rescue clause - logger.debug("Pipeline terminated by worker error", error_log_params.call(e)) + logger.error("Pipeline error", error_log_params.call(e)) ensure # we must trap any exception here to make sure the following @finished_execution # is always set to true regardless of any exception before in the close method call @@ -146,6 +147,7 @@ module LogStash; class JavaPipeline < JavaBasePipeline logger.error("Pipeline close error, ignoring", error_log_params.call(e)) end @finished_execution.make_true + @logger.info("Pipeline terminated", "pipeline.id" => pipeline_id) end end @@ -331,13 +333,38 @@ module LogStash; class JavaPipeline < JavaBasePipeline def monitor_inputs_and_workers twait = ThreadsWait.new(*(@input_threads + @worker_threads)) - while !@input_threads.empty? + loop do + break if @input_threads.empty? + terminated_thread = twait.next_wait + if @input_threads.delete(terminated_thread).nil? - # this is a worker thread termination - # delete it from @worker_threads so that wait_for_workers does not wait for it + # this is an abnormal worker thread termination, we need to terminate the pipeline + @worker_threads.delete(terminated_thread) - raise("Worker thread terminated in pipeline.id: #{pipeline_id}") + + # before terminating the pipeline we need to close the inputs + stop_inputs + + # wait 10 seconds for all input threads to terminate + wait_input_threads_termination(10 * SECOND) do + @logger.warn("Waiting for input plugin to close", default_logging_keys) + sleep(1) + end + + if inputs_running? && settings.get("queue.type") == MEMORY + # if there are still input threads alive they are probably blocked pushing on the memory queue + # because no worker is present to consume from the ArrayBlockingQueue + # if this is taking too long we have a problem + wait_input_threads_termination(10 * SECOND) do + dropped_batch = filter_queue_client.read_batch + @logger.error("Dropping events to unblock input plugin", default_logging_keys(:count => dropped_batch.filteredSize)) if dropped_batch.filteredSize > 0 + end + end + + raise("Unable to stop input plugin(s)") if inputs_running? + + break end end @@ -420,7 +447,6 @@ module LogStash; class JavaPipeline < JavaBasePipeline stop_inputs wait_for_shutdown clear_pipeline_metrics - @logger.info("Pipeline terminated", "pipeline.id" => pipeline_id) end # def shutdown def wait_for_shutdown @@ -581,4 +607,18 @@ module LogStash; class JavaPipeline < JavaBasePipeline false end + + def wait_input_threads_termination(timeout_seconds, &block) + start = Time.now + seconds = 0 + while inputs_running? && (seconds < timeout_seconds) + block.call + seconds = Time.now - start + end + end + + def inputs_running? + @input_threads.any?(&:alive?) + end + end; end diff --git a/logstash-core/spec/logstash/java_pipeline_spec.rb b/logstash-core/spec/logstash/java_pipeline_spec.rb index 9181dac67..df9ef0084 100644 --- a/logstash-core/spec/logstash/java_pipeline_spec.rb +++ b/logstash-core/spec/logstash/java_pipeline_spec.rb @@ -23,6 +23,7 @@ require_relative "../support/helpers" require 'support/pipeline/pipeline_helpers' require "stud/try" require 'timeout' +require "thread" class DummyInput < LogStash::Inputs::Base config_name "dummyinput" @@ -38,18 +39,31 @@ class DummyInput < LogStash::Inputs::Base end end -class DummyInputGenerator < LogStash::Inputs::Base - config_name "dummyinputgenerator" +class DummyManualInputGenerator < LogStash::Inputs::Base + config_name "dummymanualinputgenerator" milestone 2 + attr_accessor :keep_running + + def initialize(*args) + super(*args) + @keep_running = Concurrent::AtomicBoolean.new(false) + @queue = nil + end + def register end def run(queue) - queue << Logstash::Event.new while !stop? + @queue = queue + while !stop? || @keep_running.true? + queue << LogStash::Event.new + sleep(0.5) + end end - def close + def push_once + @queue << LogStash::Event.new end end @@ -237,37 +251,85 @@ describe LogStash::JavaPipeline do end end - context "a crashing worker" do + context "a crashing worker terminates the pipeline and all inputs and workers" do subject { mock_java_pipeline_from_string(config, pipeline_settings_obj) } - - let(:pipeline_settings) { { "pipeline.batch.size" => 1, "pipeline.workers" => 1 } } let(:config) do <<-EOS - input { generator {} } + input { dummymanualinputgenerator {} } filter { dummycrashingfilter {} } output { dummyoutput {} } EOS end let(:dummyoutput) { ::LogStash::Outputs::DummyOutput.new } + let(:dummyinput) { DummyManualInputGenerator.new } before :each do allow(::LogStash::Outputs::DummyOutput).to receive(:new).with(any_args).and_return(dummyoutput) - allow(LogStash::Plugin).to receive(:lookup).with("input", "generator").and_return(LogStash::Inputs::Generator) + allow(DummyManualInputGenerator).to receive(:new).with(any_args).and_return(dummyinput) + + allow(LogStash::Plugin).to receive(:lookup).with("input", "dummymanualinputgenerator").and_return(DummyManualInputGenerator) allow(LogStash::Plugin).to receive(:lookup).with("codec", "plain").and_return(LogStash::Codecs::Plain) allow(LogStash::Plugin).to receive(:lookup).with("filter", "dummycrashingfilter").and_return(DummyCrashingFilter) allow(LogStash::Plugin).to receive(:lookup).with("output", "dummyoutput").and_return(::LogStash::Outputs::DummyOutput) end - after :each do - subject.shutdown - end + context "a crashing worker using memory queue" do + let(:pipeline_settings) { { "pipeline.batch.size" => 1, "pipeline.workers" => 1, "queue.type" => "memory"} } it "does not raise in the main thread, terminates the run thread and finishes execution" do - expect { subject.start && subject.thread.join }.to_not raise_error + # first make sure we keep the input plugin in the run method for now + dummyinput.keep_running.make_true + + expect { subject.start }.to_not raise_error + + # wait until there is no more worker thread since we have a single worker that should have died + wait(5).for {subject.worker_threads.any?(&:alive?)}.to be_falsey + + # at this point the input plugin should have been asked to stop + wait(5).for {dummyinput.stop?}.to be_truthy + + # allow the input plugin to exit the run method now + dummyinput.keep_running.make_false + + # the pipeline thread should terminate normally + expect { subject.thread.join }.to_not raise_error expect(subject.finished_execution?).to be_truthy + + # when the pipeline has exited, no input threads should be alive + wait(5).for {subject.input_threads.any?(&:alive?)}.to be_falsey end end + context "a crashing worker using persisted queue" do + let(:pipeline_settings) { { "pipeline.batch.size" => 1, "pipeline.workers" => 1, "queue.type" => "persisted"} } + + it "does not raise in the main thread, terminates the run thread and finishes execution" do + # first make sure we keep the input plugin in the run method for now + dummyinput.keep_running.make_true + + expect { subject.start }.to_not raise_error + + # wait until there is no more worker thread since we have a single worker that should have died + wait(5).for {subject.worker_threads.any?(&:alive?)}.to be_falsey + + # at this point the input plugin should have been asked to stop + wait(5).for {dummyinput.stop?}.to be_truthy + + # allow the input plugin to exit the run method now + dummyinput.keep_running.make_false + + # the pipeline thread should terminate normally + expect { subject.thread.join }.to_not raise_error + expect(subject.finished_execution?).to be_truthy + + # when the pipeline has exited, no input threads should be alive + wait(5).for {subject.input_threads.any?(&:alive?)}.to be_falsey + + expect{dummyinput.push_once}.to raise_error(/Tried to write to a closed queue/) + end + end + end + describe "defaulting the pipeline workers based on thread safety" do before(:each) do allow(LogStash::Plugin).to receive(:lookup).with("input", "dummyinput").and_return(DummyInput) From 0727260c71bfc05321dc44b24df77ef6225ef718 Mon Sep 17 00:00:00 2001 From: Rob Bavey Date: Tue, 13 Oct 2020 17:11:58 -0400 Subject: [PATCH 0615/1126] [7x backport] Handle Windows delete pending files (#12337) Clean backport of #12335 When deleting temporary files created by the DLQ writer to store data before moving to their final location, Windows may leave these files in a "delete pending" state, where the files are somewhat in a state of limbo, where they result of `Files.exist(filename)` is `false`, but the result of `filename.toFile().exists()` is true. When files are in this state, a new file with the same name cannot be created, which causes the DLQ test used to ensure that closing and reopening the DLQ (in such events as a pipeline restart) to fail. This commit moves the temporary file to an alternative location before deletion, ensuring that the "pending delete" status does not interrupt with the DLQ startup --- .../common/io/DeadLetterQueueWriter.java | 34 +++++++++++++++---- 1 file changed, 27 insertions(+), 7 deletions(-) diff --git a/logstash-core/src/main/java/org/logstash/common/io/DeadLetterQueueWriter.java b/logstash-core/src/main/java/org/logstash/common/io/DeadLetterQueueWriter.java index 588e58374..54edca12f 100644 --- a/logstash-core/src/main/java/org/logstash/common/io/DeadLetterQueueWriter.java +++ b/logstash-core/src/main/java/org/logstash/common/io/DeadLetterQueueWriter.java @@ -295,8 +295,8 @@ public final class DeadLetterQueueWriter implements Closeable { // check if there is a corresponding .log file - if yes delete the temp file, if no atomic move the // temp file to be a new segment file.. private void cleanupTempFile(final Path tempFile) { - String tempFilename = tempFile.getFileName().toString().split("\\.")[0]; - Path segmentFile = queuePath.resolve(String.format("%s.log", tempFilename)); + String segmentName = tempFile.getFileName().toString().split("\\.")[0]; + Path segmentFile = queuePath.resolve(String.format("%s.log", segmentName)); try { if (Files.exists(segmentFile)) { Files.delete(tempFile); @@ -305,16 +305,15 @@ public final class DeadLetterQueueWriter implements Closeable { SegmentStatus segmentStatus = RecordIOReader.getSegmentStatus(tempFile); switch (segmentStatus){ case VALID: - logger.debug("Moving temp file {} to segment file {}", tempFilename, segmentFile); + logger.debug("Moving temp file {} to segment file {}", tempFile, segmentFile); Files.move(tempFile, segmentFile, StandardCopyOption.ATOMIC_MOVE); break; case EMPTY: - logger.debug("Removing unused temp file {}", tempFilename); - Files.delete(tempFile); + deleteTemporaryFile(tempFile, segmentName); break; case INVALID: - Path errorFile = queuePath.resolve(String.format("%s.err", tempFilename)); - logger.warn("Segment file {} is in an error state, saving as {}", tempFilename, errorFile); + Path errorFile = queuePath.resolve(String.format("%s.err", segmentName)); + logger.warn("Segment file {} is in an error state, saving as {}", segmentFile, errorFile); Files.move(tempFile, errorFile, StandardCopyOption.ATOMIC_MOVE); break; default: @@ -325,4 +324,25 @@ public final class DeadLetterQueueWriter implements Closeable { throw new IllegalStateException("Unable to clean up temp file: " + tempFile, e); } } + + // Windows can leave files in a "Delete pending" state, where the file presents as existing to certain + // methods, and not to others, and actively prevents a new file being created with the same file name, + // throwing AccessDeniedException. This method moves the temporary file to a .del file before + // deletion, enabling a new temp file to be created in its place. + private void deleteTemporaryFile(Path tempFile, String segmentName) throws IOException { + Path deleteTarget; + if (isWindows()) { + Path deletedFile = queuePath.resolve(String.format("%s.del", segmentName)); + logger.debug("Moving temp file {} to {}", tempFile, deletedFile); + deleteTarget = deletedFile; + Files.move(tempFile, deletedFile, StandardCopyOption.ATOMIC_MOVE); + } else { + deleteTarget = tempFile; + } + Files.delete(deleteTarget); + } + + private static boolean isWindows(){ + return System.getProperty("os.name").startsWith("Windows"); + } } From a693fa3bf4bfba8e149af589b63f2e9dbe12e40e Mon Sep 17 00:00:00 2001 From: Karol Bucek Date: Tue, 20 Oct 2020 09:00:01 +0200 Subject: [PATCH 0616/1126] Build: properly isolate integration (test) env setup (#12364) to avoid gems being resolved from the usual LS GEM_HOME this is problematic for gems such as jruby-openssl which are loaded during boot (by RGs/Bundler) and thus activated in Bundler from a different GEM_HOME. if such gem is updated it won't end up being install-ed in the --path location as it's found on the GEM_HOME! + Fix: gem conflict 1.3.6 required by core this is due now isolating GEM_HOME on `bundle install --path` + Refactor: we do not need LS_GEM_HOME/PATH + avoid pinning jruby-openssl to 0.10.4 resolves GH-12299 (reverting GH-12301) --- build.gradle | 9 +++++---- logstash-core/logstash-core.gemspec | 2 +- qa/integration/integration_tests.gemspec | 2 +- 3 files changed, 7 insertions(+), 6 deletions(-) diff --git a/build.gradle b/build.gradle index d895ebd80..9fcd11ff0 100644 --- a/build.gradle +++ b/build.gradle @@ -316,8 +316,9 @@ tasks.register("unpackTarDistribution", Copy) { into {buildDir} } -def qaVendorPath = "${buildDir}/qa/integration/vendor" -def qaBundledGemPath = "${qaVendorPath}/jruby/2.5.0" +def qaBuildPath = "${buildDir}/qa/integration" +def qaVendorPath = "${qaBuildPath}/vendor" +def qaBundledGemPath = "${qaVendorPath}/jruby/2.5.0".toString() def qaBundleBin = "${qaBundledGemPath}/bin/bundle" tasks.register("installIntegrationTestBundler"){ @@ -340,8 +341,8 @@ tasks.register("installIntegrationTestGems") { doLast { bundleWithEnv( projectDir, buildDir, - "${projectDir}/qa/integration", qaBundleBin, ['install', '--path', qaVendorPath], - [LS_GEM_PATH: qaBundledGemPath, LS_GEM_HOME: qaBundledGemPath] + qaBuildPath, qaBundleBin, ['install', '--path', qaVendorPath], + [ GEM_PATH: qaBundledGemPath, GEM_HOME: qaBundledGemPath ] ) } } diff --git a/logstash-core/logstash-core.gemspec b/logstash-core/logstash-core.gemspec index c43b1282e..03748524e 100644 --- a/logstash-core/logstash-core.gemspec +++ b/logstash-core/logstash-core.gemspec @@ -57,7 +57,7 @@ Gem::Specification.new do |gem| gem.add_runtime_dependency "mustermann", '~> 1.0.3' gem.add_runtime_dependency "sinatra", '~> 2' gem.add_runtime_dependency 'puma', '~> 4' - gem.add_runtime_dependency "jruby-openssl", "= 0.10.4" # >= 0.9.13 Required to support TLSv1.2; 0.10.5 is causing dependency issue in integration test #12299 + gem.add_runtime_dependency "jruby-openssl", "~> 0.10" # >= 0.9.13 Required to support TLSv1.2 gem.add_runtime_dependency "chronic_duration", "~> 0.10" gem.add_runtime_dependency "treetop", "~> 1" #(MIT license) diff --git a/qa/integration/integration_tests.gemspec b/qa/integration/integration_tests.gemspec index 039a53111..8740689ac 100644 --- a/qa/integration/integration_tests.gemspec +++ b/qa/integration/integration_tests.gemspec @@ -19,7 +19,7 @@ Gem::Specification.new do |s| s.add_development_dependency 'stud', '~> 0.0.22' s.add_development_dependency 'pry' s.add_development_dependency 'rspec', '~> 3.5' - s.add_development_dependency 'logstash-devutils', '= 1.3.5' + s.add_development_dependency 'logstash-devutils' s.add_development_dependency 'flores' s.add_development_dependency 'rubyzip' end From bf1238dec27acf9c5017fa3ce0a2c46c6a67015e Mon Sep 17 00:00:00 2001 From: Rob Bavey Date: Tue, 20 Oct 2020 11:00:05 -0400 Subject: [PATCH 0617/1126] [7x backport] Add optional sourceURL to license report CSV (#12362) Clean backport of #12346 This commit adds an extra optional column 'sourceURL' to the license report. This column contains a pointer to the source code, which is optional for most dependencies, but a requirement for some, such as the Red Hat Universal Base Image. This commit also populates the 'copyright' field, which previously was an used column in the CSV definition Relates #12297 --- .../lib/logstash/dependency_report.rb | 4 +- .../org/logstash/dependencies/Dependency.java | 21 +++++--- .../dependencies/ReportGenerator.java | 52 ++++++++++++------- .../src/main/resources/licenseMapping.csv | 4 +- .../dependencies/ReportGeneratorTest.java | 10 ++-- .../test/resources/expectedNoticeOutput.txt | 11 ++++ .../src/test/resources/expectedOutput.txt | 32 ++++++------ .../resources/licenseMapping-conflicting.csv | 2 + .../test/resources/licenseMapping-good.csv | 4 +- .../test/resources/licenseMapping-missing.csv | 4 +- .../licenseMapping-missingNotices.csv | 5 +- .../resources/licenseMapping-missingUrls.csv | 2 + .../resources/licenseMapping-unacceptable.csv | 2 + ...at Universal Base Image minimal-NOTICE.txt | 1 + .../test/resources/notices/tzinfo-NOTICE.txt | 1 + .../src/test/resources/rubyDependencies.csv | 32 ++++++------ 16 files changed, 120 insertions(+), 67 deletions(-) create mode 100644 tools/dependencies-report/src/test/resources/notices/Red Hat Universal Base Image minimal-NOTICE.txt create mode 100644 tools/dependencies-report/src/test/resources/notices/tzinfo-NOTICE.txt diff --git a/logstash-core/lib/logstash/dependency_report.rb b/logstash-core/lib/logstash/dependency_report.rb index 8d45b7641..5077d2b16 100644 --- a/logstash-core/lib/logstash/dependency_report.rb +++ b/logstash-core/lib/logstash/dependency_report.rb @@ -31,7 +31,7 @@ class LogStash::DependencyReport < Clamp::Command OTHER_DEPENDENCIES = [ ["jruby", "", "http://jruby.org", "EPL-2.0"], - ["Red Hat Universal Base Image minimal","8","https://catalog.redhat.com/software/containers/ubi8/ubi-minimal/5c359a62bed8bd75a2c3fba8","Custom;https://www.redhat.com/licenses/EULA_Red_Hat_Universal_Base_Image_English_20190422.pdf"] + ["Red Hat Universal Base Image minimal","8","https://catalog.redhat.com/software/containers/ubi8/ubi-minimal/5c359a62bed8bd75a2c3fba8","Custom;https://www.redhat.com/licenses/EULA_Red_Hat_Universal_Base_Image_English_20190422.pdf","","https://oss-dependencies.elastic.co/redhat/ubi/ubi-minimal-8-source.tar.gz"] ] def execute @@ -40,7 +40,7 @@ class LogStash::DependencyReport < Clamp::Command tmp_dir = java.lang.System.getProperty("java.io.tmpdir") ruby_output_path = File.join(tmp_dir, SecureRandom.uuid) # Write a CSV with just the ruby stuff - CSV.open(ruby_output_path, "wb", :headers => [ "name", "version", "url", "license" ], :write_headers => true) do |csv| + CSV.open(ruby_output_path, "wb", :headers => [ "name", "version", "url", "license","copyright","sourceURL" ], :write_headers => true) do |csv| puts "Finding gem dependencies" gems.each { |d| csv << d } puts "Finding gem embedded java/jar dependencies" diff --git a/tools/dependencies-report/src/main/java/org/logstash/dependencies/Dependency.java b/tools/dependencies-report/src/main/java/org/logstash/dependencies/Dependency.java index 5ba05a40c..d8c1c4ae2 100644 --- a/tools/dependencies-report/src/main/java/org/logstash/dependencies/Dependency.java +++ b/tools/dependencies-report/src/main/java/org/logstash/dependencies/Dependency.java @@ -23,15 +23,11 @@ package org.logstash.dependencies; import org.apache.commons.csv.CSVFormat; import org.apache.commons.csv.CSVRecord; -import java.io.BufferedReader; -import java.io.File; import java.io.IOException; import java.io.InputStream; import java.io.InputStreamReader; import java.io.Reader; import java.net.URL; -import java.nio.file.Path; -import java.nio.file.Paths; import java.util.Objects; import java.util.Scanner; import java.util.SortedSet; @@ -42,13 +38,15 @@ class Dependency implements Comparable { String version; String url; String spdxLicense; + String sourceURL; + String copyright; /** * Returns an object array representing this dependency as a CSV record according * to the format requested here: https://github.com/elastic/logstash/issues/8725 */ Object[] toCsvReportRecord() { - return new String[] {name, version, "", url, spdxLicense, ""}; + return new String[] {name, version, "", url, spdxLicense, copyright, sourceURL}; } /** @@ -78,10 +76,15 @@ class Dependency implements Comparable { private static Dependency fromRubyCsvRecord(CSVRecord record) { Dependency d = new Dependency(); - // name, version, url, license + // name, version, url, license, copyright, sourceURL d.name = record.get(0); d.version = record.get(1); - + if (record.size() > 4) { + d.copyright = record.get(4); + } + if (record.size() > 5) { + d.sourceURL = record.get(5); + } return d; } @@ -179,6 +182,10 @@ class Dependency implements Comparable { return version; } + public String getSourceURL() { + return sourceURL; + } + @Override public String toString() { return ""; diff --git a/tools/dependencies-report/src/main/java/org/logstash/dependencies/ReportGenerator.java b/tools/dependencies-report/src/main/java/org/logstash/dependencies/ReportGenerator.java index 6343706fb..78f1f651d 100644 --- a/tools/dependencies-report/src/main/java/org/logstash/dependencies/ReportGenerator.java +++ b/tools/dependencies-report/src/main/java/org/logstash/dependencies/ReportGenerator.java @@ -49,7 +49,7 @@ public class ReportGenerator { final String UNKNOWN_LICENSE = "UNKNOWN"; final Collection UNKNOWN_LICENSES = new ArrayList<>(); - final String[] CSV_HEADERS = {"name", "version", "revision", "url", "license", "copyright"}; + final String[] CSV_HEADERS = {"name", "version", "revision", "url", "license", "copyright","sourceURL"}; final Collection MISSING_NOTICE = new ArrayList<>(); boolean generateReport( @@ -65,7 +65,7 @@ public class ReportGenerator { Dependency.addDependenciesFromRubyReport(rubyDependenciesStream, dependencies); addJavaDependencies(javaDependenciesStreams, dependencies); - Map licenseMapping = new HashMap<>(); + Map licenseMapping = new HashMap<>(); checkDependencyLicenses(licenseMappingStream, acceptableLicensesStream, licenseMapping, dependencies); checkDependencyNotices(noticeOutput, dependencies); @@ -91,7 +91,7 @@ public class ReportGenerator { } private void checkDependencyLicenses(InputStream licenseMappingStream, InputStream acceptableLicensesStream, - Map licenseMapping, SortedSet dependencies) throws IOException { + Map licenseMapping, SortedSet dependencies) throws IOException { readLicenseMapping(licenseMappingStream, licenseMapping); List acceptableLicenses = new ArrayList<>(); readAcceptableLicenses(acceptableLicensesStream, acceptableLicenses); @@ -134,10 +134,10 @@ public class ReportGenerator { } } - private void reportUnusedLicenseMappings(Writer unusedLicenseWriter, Map licenseMapping) throws IOException { + private void reportUnusedLicenseMappings(Writer unusedLicenseWriter, Map licenseMapping) throws IOException { SortedSet unusedDependencies = new TreeSet<>(); - for (Map.Entry entry : licenseMapping.entrySet()) { + for (Map.Entry entry : licenseMapping.entrySet()) { if (entry.getValue().isUnused) { unusedDependencies.add(entry.getKey()); } @@ -177,13 +177,13 @@ public class ReportGenerator { } } - private void checkDependencyLicense(Map licenseMapping, List acceptableLicenses, Dependency dependency) { + private void checkDependencyLicense(Map licenseMapping, List acceptableLicenses, Dependency dependency) { if (licenseMapping.containsKey(dependency.name)) { - LicenseUrlPair pair = licenseMapping.get(dependency.name); + LicenseInfo licenseInfo = licenseMapping.get(dependency.name); - String[] dependencyLicenses = pair.license.split("\\|"); + String[] dependencyLicenses = licenseInfo.license.split("\\|"); boolean hasAcceptableLicense = false; - if (pair.url != null && !pair.url.equals("")) { + if (licenseInfo.url != null && !licenseInfo.url.equals("")) { for (int k = 0; k < dependencyLicenses.length && !hasAcceptableLicense; k++) { if (acceptableLicenses.stream().anyMatch(dependencyLicenses[k]::equalsIgnoreCase)) { hasAcceptableLicense = true; @@ -192,9 +192,11 @@ public class ReportGenerator { } if (hasAcceptableLicense) { - dependency.spdxLicense = pair.license; - dependency.url = pair.url; - pair.isUnused = false; + dependency.spdxLicense = licenseInfo.license; + dependency.url = licenseInfo.url; + dependency.sourceURL = licenseInfo.sourceURL; + dependency.copyright = licenseInfo.copyright; + licenseInfo.isUnused = false; } else { // unacceptable license or missing URL UNKNOWN_LICENSES.add(dependency); @@ -216,7 +218,7 @@ public class ReportGenerator { } } - private void readLicenseMapping(InputStream stream, Map licenseMapping) + private void readLicenseMapping(InputStream stream, Map licenseMapping) throws IOException { Reader in = new InputStreamReader(stream); for (CSVRecord record : CSVFormat.DEFAULT.withFirstRecordAsHeader().parse(in)) { @@ -226,14 +228,15 @@ public class ReportGenerator { String depName = lastIndex < 0 ? dependencyNameAndVersion : dependencyNameAndVersion.substring(0, lastIndex); - validateAndAdd(licenseMapping, depName, new LicenseUrlPair(record.get(2), record.get(1))); + + validateAndAdd(licenseMapping, depName, LicenseInfo.fromCSVRecord(record)); } } } - private static void validateAndAdd(Map licenses, String depName, LicenseUrlPair lup) { + private static void validateAndAdd(Map licenses, String depName, LicenseInfo lup) { if (licenses.containsKey(depName)) { - LicenseUrlPair existingLicense = licenses.get(depName); + LicenseInfo existingLicense = licenses.get(depName); // Because dependency versions are not treated independently, if dependencies with different versions // have different licenses, we cannot distinguish between them @@ -249,13 +252,26 @@ public class ReportGenerator { } -class LicenseUrlPair { +class LicenseInfo { String license; String url; + String sourceURL; + String copyright; boolean isUnused = true; - LicenseUrlPair(String license, String url) { + LicenseInfo(String license, String url) { this.license = license; this.url = url; } + + static LicenseInfo fromCSVRecord(CSVRecord record){ + LicenseInfo info = new LicenseInfo(record.get(2), record.get(1)); + if (record.size() > 3){ + info.copyright = record.get(3); + } + if (record.size() > 4){ + info.sourceURL = record.get(4); + } + return info; + } } diff --git a/tools/dependencies-report/src/main/resources/licenseMapping.csv b/tools/dependencies-report/src/main/resources/licenseMapping.csv index 419e93113..98e2c636c 100644 --- a/tools/dependencies-report/src/main/resources/licenseMapping.csv +++ b/tools/dependencies-report/src/main/resources/licenseMapping.csv @@ -1,4 +1,4 @@ -dependency,dependencyUrl,licenseOverride +dependency,dependencyUrl,licenseOverride,copyright,sourceURL "addressable:",https://github.com/sporkmonger/addressable,Apache-2.0 "atomic:",http://github.com/ruby-concurrency/atomic,Apache-2.0 "avl_tree:",https://github.com/nahi/avl_tree,BSD-2-Clause-FreeBSD @@ -121,7 +121,7 @@ dependency,dependencyUrl,licenseOverride "rack-protection:",http://github.com/rkh/rack-protection,MIT "rack:",http://rack.github.io/,MIT "rake:",https://github.com/ruby/rake,MIT -"Red Hat Universal Base Image minimal:",https://catalog.redhat.com/software/containers/ubi8/ubi-minimal/5c359a62bed8bd75a2c3fba8,Custom;https://www.redhat.com/licenses/EULA_Red_Hat_Universal_Base_Image_English_20190422.pdf +"Red Hat Universal Base Image minimal:",https://catalog.redhat.com/software/containers/ubi8/ubi-minimal/5c359a62bed8bd75a2c3fba8,Custom;https://www.redhat.com/licenses/EULA_Red_Hat_Universal_Base_Image_English_20190422.pdf,,https://oss-dependencies.elastic.co/redhat/ubi/ubi-minimal-8-source.tar.gz "redis:",https://github.com/redis/redis-rb,MIT "ruby-progressbar:",https://github.com/jfelchner/ruby-progressbar,MIT "rubyzip:",https://github.com/rubyzip/rubyzip,BSD-2-Clause-FreeBSD diff --git a/tools/dependencies-report/src/test/java/org/logstash/dependencies/ReportGeneratorTest.java b/tools/dependencies-report/src/test/java/org/logstash/dependencies/ReportGeneratorTest.java index a7e53d57c..4e71d68ec 100644 --- a/tools/dependencies-report/src/test/java/org/logstash/dependencies/ReportGeneratorTest.java +++ b/tools/dependencies-report/src/test/java/org/logstash/dependencies/ReportGeneratorTest.java @@ -77,8 +77,8 @@ public class ReportGeneratorTest { // verify that the two components in the test input with missing licenses are // listed in the output with no license, i.e., an empty license field followed by CR/LF - assertTrue(csvOutput.toString().contains("commons-io:commons-io,2.5,,,,\r\n")); - assertTrue(csvOutput.toString().contains("filesize,0.0.4,,,,\r\n")); + assertTrue(csvOutput.toString().contains("commons-io:commons-io,2.5,,,,,\r\n")); + assertTrue(csvOutput.toString().contains("filesize,0.0.4,,,,,\r\n")); String unusedLicenses = unusedLicenseWriter.toString(); assertThat(unusedLicenses, containsString("43 license mappings were specified but unused")); } @@ -103,7 +103,7 @@ public class ReportGeneratorTest { // verify that the two components in the test input with unacceptable licenses are // listed in the output with no license, i.e., an empty license field followed by CR/LF String csvString = csvOutput.toString(); - assertThat(csvString, containsString("com.fasterxml.jackson.core:jackson-core,2.7.3,,,,\r\n")); + assertThat(csvString, containsString("com.fasterxml.jackson.core:jackson-core,2.7.3,,,,,\r\n")); Pattern bundlerPattern = Pattern.compile(".*bundler,1\\.16\\.[0-1],,,,.*"); assertThat(bundlerPattern.matcher(csvString).find(), is(true)); @@ -119,8 +119,8 @@ public class ReportGeneratorTest { // verify that the two components in the test input with missing URLs are // listed in the output with no license, i.e., an empty license field followed by CR/LF - assertTrue(csvOutput.toString().contains("org.codehaus.janino:commons-compiler,3.0.8,,,,\r\n")); - assertTrue(csvOutput.toString().contains("json-parser,,,,,\r\n")); + assertTrue(csvOutput.toString().contains("org.codehaus.janino:commons-compiler,3.0.8,,,,,\r\n")); + assertTrue(csvOutput.toString().contains("json-parser,,,,,,\r\n")); String unusedLicenses = unusedLicenseWriter.toString(); assertThat(unusedLicenses, containsString("43 license mappings were specified but unused")); } diff --git a/tools/dependencies-report/src/test/resources/expectedNoticeOutput.txt b/tools/dependencies-report/src/test/resources/expectedNoticeOutput.txt index 64ed0605e..112223333 100644 --- a/tools/dependencies-report/src/test/resources/expectedNoticeOutput.txt +++ b/tools/dependencies-report/src/test/resources/expectedNoticeOutput.txt @@ -1,4 +1,9 @@ +========== +Notice for: Red Hat Universal Base Image minimal-8 +---------- + +TEST ========== Notice for: bundler-1.16.1 ---------- @@ -81,3 +86,9 @@ Notice for: org.codehaus.janino:commons-compiler-3.0.8 ---------- TEST + +========== +Notice for: tzinfo- +---------- + +TEST \ No newline at end of file diff --git a/tools/dependencies-report/src/test/resources/expectedOutput.txt b/tools/dependencies-report/src/test/resources/expectedOutput.txt index 2557edfe6..24bf61b01 100644 --- a/tools/dependencies-report/src/test/resources/expectedOutput.txt +++ b/tools/dependencies-report/src/test/resources/expectedOutput.txt @@ -1,15 +1,17 @@ -name,version,revision,url,license,copyright -bundler,1.16.1,,https://rubygems.org/gems/bundler/versions/1.16.0,UnacceptableLicense|MIT, -com.fasterxml.jackson.core:jackson-core,2.7.3,,https://github.com/FasterXML/jackson-core/tree/jackson-core-2.7.3,Apache-2.0, -com.google.errorprone:javac-shaded,9-dev-r4023-3,,http://repo1.maven.org/maven2/com/google/errorprone/javac-shaded/9-dev-r4023-3/,EPL-1.0, -commons-io:commons-io,2.5,,https://commons.apache.org/proper/commons-io/index.html,Apache-2.0, -control.js,,,https://github.com/zombieleet/control,MIT, -filesize,0.0.4,,https://rubygems.org/gems/filesize/versions/0.0.4,MIT, -gradle.plugin.com.github.jk1:gradle-license-report,0.7.1,,https://github.com/jk1/Gradle-License-Report,Apache-2.0, -jar-dependencies,0.3.12,,https://rubygems.org/gems/jar-dependencies/versions/0.3.11,MIT, -jruby-openssl,0.9.21,,https://rubygems.org/gems/jruby-openssl/versions/0.9.20-java,Apache-2.0, -jruby-readline,1.1.1,,https://rubygems.org/gems/jruby-readline/versions/1.1.1-java,Apache-2.0, -json-generator,,,https://github.com/flori/json,Ruby, -json-parser,,,https://rubygems.org/gems/json-parser/versions/0.0.1,Apache-2.0, -junit:junit,4.12,,https://github.com/junit-team/junit4,Apache-2.0, -org.codehaus.janino:commons-compiler,3.0.8,,https://github.com/janino-compiler/janino,BSD-3-Clause-Attribution, +name,version,revision,url,license,copyright,sourceURL +Red Hat Universal Base Image minimal,8,,https://catalog.redhat.com/software/containers/ubi8/ubi-minimal/5c359a62bed8bd75a2c3fba8,Custom;https://www.redhat.com/licenses/EULA_Red_Hat_Universal_Base_Image_English_20190422.pdf,,https://oss-dependencies.elastic.co/redhat/ubi/ubi-minimal-8-source.tar.gz +bundler,1.16.1,,https://rubygems.org/gems/bundler/versions/1.16.0,UnacceptableLicense|MIT,, +com.fasterxml.jackson.core:jackson-core,2.7.3,,https://github.com/FasterXML/jackson-core/tree/jackson-core-2.7.3,Apache-2.0,, +com.google.errorprone:javac-shaded,9-dev-r4023-3,,http://repo1.maven.org/maven2/com/google/errorprone/javac-shaded/9-dev-r4023-3/,EPL-1.0,, +commons-io:commons-io,2.5,,https://commons.apache.org/proper/commons-io/index.html,Apache-2.0,, +control.js,,,https://github.com/zombieleet/control,MIT,, +filesize,0.0.4,,https://rubygems.org/gems/filesize/versions/0.0.4,MIT,, +gradle.plugin.com.github.jk1:gradle-license-report,0.7.1,,https://github.com/jk1/Gradle-License-Report,Apache-2.0,, +jar-dependencies,0.3.12,,https://rubygems.org/gems/jar-dependencies/versions/0.3.11,MIT,, +jruby-openssl,0.9.21,,https://rubygems.org/gems/jruby-openssl/versions/0.9.20-java,Apache-2.0,, +jruby-readline,1.1.1,,https://rubygems.org/gems/jruby-readline/versions/1.1.1-java,Apache-2.0,, +json-generator,,,https://github.com/flori/json,Ruby,, +json-parser,,,https://rubygems.org/gems/json-parser/versions/0.0.1,Apache-2.0,, +junit:junit,4.12,,https://github.com/junit-team/junit4,Apache-2.0,, +org.codehaus.janino:commons-compiler,3.0.8,,https://github.com/janino-compiler/janino,BSD-3-Clause-Attribution,, +tzinfo,,,https://github.com/tzinfo/tzinfo,MIT,Philip Ross, diff --git a/tools/dependencies-report/src/test/resources/licenseMapping-conflicting.csv b/tools/dependencies-report/src/test/resources/licenseMapping-conflicting.csv index d94844c31..c1d9ef949 100644 --- a/tools/dependencies-report/src/test/resources/licenseMapping-conflicting.csv +++ b/tools/dependencies-report/src/test/resources/licenseMapping-conflicting.csv @@ -60,3 +60,5 @@ dependency,dependencyUrl,licenseOverride "json-parser:",https://rubygems.org/gems/json-parser/versions/0.0.1,Apache-2.0 "junit:junit:4.12",https://github.com/junit-team/junit4,Apache-2.0 "json-generator",https://github.com/flori/json,Ruby +"tzinfo:",https://github.com/tzinfo/tzinfo,MIT,Philip Ross +"Red Hat Universal Base Image minimal:8",https://catalog.redhat.com/software/containers/ubi8/ubi-minimal/5c359a62bed8bd75a2c3fba8,Custom;https://www.redhat.com/licenses/EULA_Red_Hat_Universal_Base_Image_English_20190422.pdf,,https://oss-dependencies.elastic.co/redhat/ubi/ubi-minimal-8-source.tar.gz diff --git a/tools/dependencies-report/src/test/resources/licenseMapping-good.csv b/tools/dependencies-report/src/test/resources/licenseMapping-good.csv index b3cf57c4d..bffbd8b09 100644 --- a/tools/dependencies-report/src/test/resources/licenseMapping-good.csv +++ b/tools/dependencies-report/src/test/resources/licenseMapping-good.csv @@ -1,4 +1,4 @@ -dependency,dependencyUrl,licenseOverride +dependency,dependencyUrl,licenseOverride,copyright,sourceURL "webrick:1.3.1",,BSD-2-Clause-FreeBSD "bundler:1.16.0",https://rubygems.org/gems/bundler/versions/1.16.0,UnacceptableLicense|MIT "webhdfs:0.8.0",,Apache-2.0 @@ -58,3 +58,5 @@ dependency,dependencyUrl,licenseOverride "json-parser:",https://rubygems.org/gems/json-parser/versions/0.0.1,Apache-2.0 "junit:junit:4.12",https://github.com/junit-team/junit4,Apache-2.0 "json-generator",https://github.com/flori/json,Ruby +"tzinfo:",https://github.com/tzinfo/tzinfo,MIT,Philip Ross +"Red Hat Universal Base Image minimal:8",https://catalog.redhat.com/software/containers/ubi8/ubi-minimal/5c359a62bed8bd75a2c3fba8,Custom;https://www.redhat.com/licenses/EULA_Red_Hat_Universal_Base_Image_English_20190422.pdf,,https://oss-dependencies.elastic.co/redhat/ubi/ubi-minimal-8-source.tar.gz diff --git a/tools/dependencies-report/src/test/resources/licenseMapping-missing.csv b/tools/dependencies-report/src/test/resources/licenseMapping-missing.csv index a31a46863..6a4e5cdbc 100644 --- a/tools/dependencies-report/src/test/resources/licenseMapping-missing.csv +++ b/tools/dependencies-report/src/test/resources/licenseMapping-missing.csv @@ -1,4 +1,4 @@ -dependency,dependencyUrl,licenseOverride +dependency,dependencyUrl,licenseOverride,copyright,sourceURL "webrick:1.3.1",,BSD-2-Clause-FreeBSD "bundler:1.16.0",https://rubygems.org/gems/bundler/versions/1.16.0,MIT "webhdfs:0.8.0",,Apache-2.0 @@ -59,3 +59,5 @@ dependency,dependencyUrl,licenseOverride "json-parser:",https://rubygems.org/gems/json-parser/versions/0.0.1,Apache-2.0 "junit:junit:4.12",https://github.com/junit-team/junit4,Apache-2.0 "json-generator",https://github.com/flori/json,Ruby +"tzinfo:",https://github.com/tzinfo/tzinfo,MIT,Philip Ross +"Red Hat Universal Base Image minimal:8",https://catalog.redhat.com/software/containers/ubi8/ubi-minimal/5c359a62bed8bd75a2c3fba8,Custom;https://www.redhat.com/licenses/EULA_Red_Hat_Universal_Base_Image_English_20190422.pdf,,https://oss-dependencies.elastic.co/redhat/ubi/ubi-minimal-8-source.tar.gz diff --git a/tools/dependencies-report/src/test/resources/licenseMapping-missingNotices.csv b/tools/dependencies-report/src/test/resources/licenseMapping-missingNotices.csv index c4c53d411..138517a88 100644 --- a/tools/dependencies-report/src/test/resources/licenseMapping-missingNotices.csv +++ b/tools/dependencies-report/src/test/resources/licenseMapping-missingNotices.csv @@ -1,4 +1,4 @@ -dependency,dependencyUrl,licenseOverride +dependency,dependencyUrl,licenseOverride,copyright,sourceURL "co.elastic:noNoticeDep:0.0.1",,MIT "webrick:1.3.1",,BSD-2-Clause-FreeBSD "bundler:1.16.0",https://rubygems.org/gems/bundler/versions/1.16.0,MIT @@ -61,3 +61,6 @@ dependency,dependencyUrl,licenseOverride "junit:junit:4.12",https://github.com/junit-team/junit4,Apache-2.0 "junit:junit:4.12",https://github.com/junit-team/junit4,Apache-2.0 "json-generator",https://github.com/flori/json,Ruby +"tzinfo:",https://github.com/tzinfo/tzinfo,MIT,Philip Ross +"Red Hat Universal Base Image minimal:8",https://catalog.redhat.com/software/containers/ubi8/ubi-minimal/5c359a62bed8bd75a2c3fba8,Custom;https://www.redhat.com/licenses/EULA_Red_Hat_Universal_Base_Image_English_20190422.pdf,,https://oss-dependencies.elastic.co/redhat/ubi/ubi-minimal-8-source.tar.gz + diff --git a/tools/dependencies-report/src/test/resources/licenseMapping-missingUrls.csv b/tools/dependencies-report/src/test/resources/licenseMapping-missingUrls.csv index 5e6fe4a3c..a08d135df 100644 --- a/tools/dependencies-report/src/test/resources/licenseMapping-missingUrls.csv +++ b/tools/dependencies-report/src/test/resources/licenseMapping-missingUrls.csv @@ -59,3 +59,5 @@ dependency,dependencyUrl,licenseOverride "json-parser:",,Apache-2.0 "junit:junit:4.12",https://github.com/junit-team/junit4,Apache-2.0 "json-generator",https://github.com/flori/json,Ruby +"tzinfo:",https://github.com/tzinfo/tzinfo,MIT,Philip Ross +"Red Hat Universal Base Image minimal:8",https://catalog.redhat.com/software/containers/ubi8/ubi-minimal/5c359a62bed8bd75a2c3fba8,Custom;https://www.redhat.com/licenses/EULA_Red_Hat_Universal_Base_Image_English_20190422.pdf,,https://oss-dependencies.elastic.co/redhat/ubi/ubi-minimal-8-source.tar.gz diff --git a/tools/dependencies-report/src/test/resources/licenseMapping-unacceptable.csv b/tools/dependencies-report/src/test/resources/licenseMapping-unacceptable.csv index e9a06cbbf..495d3b830 100644 --- a/tools/dependencies-report/src/test/resources/licenseMapping-unacceptable.csv +++ b/tools/dependencies-report/src/test/resources/licenseMapping-unacceptable.csv @@ -56,3 +56,5 @@ dependency,dependencyUrl,licenseOverride "json-parser:",https://rubygems.org/gems/json-parser/versions/0.0.1,Apache-2.0 "junit:junit:4.12",https://github.com/junit-team/junit4,Apache-2.0 "json-generator",https://github.com/flori/json,Ruby +"tzinfo:",https://github.com/tzinfo/tzinfo,MIT,Philip Ross +"Red Hat Universal Base Image minimal:8",https://catalog.redhat.com/software/containers/ubi8/ubi-minimal/5c359a62bed8bd75a2c3fba8,Custom;https://www.redhat.com/licenses/EULA_Red_Hat_Universal_Base_Image_English_20190422.pdf,,https://oss-dependencies.elastic.co/redhat/ubi/ubi-minimal-8-source.tar.gz diff --git a/tools/dependencies-report/src/test/resources/notices/Red Hat Universal Base Image minimal-NOTICE.txt b/tools/dependencies-report/src/test/resources/notices/Red Hat Universal Base Image minimal-NOTICE.txt new file mode 100644 index 000000000..3b1246497 --- /dev/null +++ b/tools/dependencies-report/src/test/resources/notices/Red Hat Universal Base Image minimal-NOTICE.txt @@ -0,0 +1 @@ +TEST \ No newline at end of file diff --git a/tools/dependencies-report/src/test/resources/notices/tzinfo-NOTICE.txt b/tools/dependencies-report/src/test/resources/notices/tzinfo-NOTICE.txt new file mode 100644 index 000000000..3b1246497 --- /dev/null +++ b/tools/dependencies-report/src/test/resources/notices/tzinfo-NOTICE.txt @@ -0,0 +1 @@ +TEST \ No newline at end of file diff --git a/tools/dependencies-report/src/test/resources/rubyDependencies.csv b/tools/dependencies-report/src/test/resources/rubyDependencies.csv index 1ac0913d9..4ac926f7b 100644 --- a/tools/dependencies-report/src/test/resources/rubyDependencies.csv +++ b/tools/dependencies-report/src/test/resources/rubyDependencies.csv @@ -1,15 +1,17 @@ -name,version,url,license -bundler,1.16.1,http://bundler.io,MIT -bundler,1.16.0,http://bundler.io,MIT -filesize,0.0.4,http://filesize.rubyforge.org/,UNKNOWN -jar-dependencies,0.3.12,https://github.com/mkristian/jar-dependencies,MIT -jar-dependencies,0.3.11,https://github.com/mkristian/jar-dependencies,MIT -jar-dependencies,0.3.10,https://github.com/mkristian/jar-dependencies,MIT -jruby-openssl,0.9.21,https://github.com/jruby/jruby-openssl,EPL-1.0|GPL-2.0|LGPL-2.1 -jruby-openssl,0.9.20,https://github.com/jruby/jruby-openssl,EPL-1.0|GPL-2.0|LGPL-2.1 -jruby-readline,1.1.1,https://github.com/jruby/jruby,EPL-1.0|GPL-2.0|LGPL-2.1 -com.fasterxml.jackson.core:jackson-core,2.7.3,https://github.com/FasterXML/jackson-core,Apache-2.0 -com.fasterxml.jackson.core:jackson-core,2.9.1,https://github.com/FasterXML/jackson-core,Apache-2.0 -control.js,,,MIT -json-generator,,https://github.com/flori/json,Ruby -json-parser,,https://github.com/flori/json,Ruby +name,version,url,license,copyright,sourceURL +bundler,1.16.1,http://bundler.io,MIT,, +bundler,1.16.0,http://bundler.io,MIT,, +filesize,0.0.4,http://filesize.rubyforge.org/,UNKNOWN,, +jar-dependencies,0.3.12,https://github.com/mkristian/jar-dependencies,MIT,, +jar-dependencies,0.3.11,https://github.com/mkristian/jar-dependencies,MIT,, +jar-dependencies,0.3.10,https://github.com/mkristian/jar-dependencies,MIT,, +jruby-openssl,0.9.21,https://github.com/jruby/jruby-openssl,EPL-1.0|GPL-2.0|LGPL-2.1,, +jruby-openssl,0.9.20,https://github.com/jruby/jruby-openssl,EPL-1.0|GPL-2.0|LGPL-2.1,, +jruby-readline,1.1.1,https://github.com/jruby/jruby,EPL-1.0|GPL-2.0|LGPL-2.1,, +com.fasterxml.jackson.core:jackson-core,2.7.3,https://github.com/FasterXML/jackson-core,Apache-2.0,, +com.fasterxml.jackson.core:jackson-core,2.9.1,https://github.com/FasterXML/jackson-core,Apache-2.0,, +control.js,,,MIT,, +json-generator,,https://github.com/flori/json,Ruby,, +json-parser,,https://github.com/flori/json,Ruby,, +tzinfo,,https://github.com/tzinfo/tzinfo,MIT,Philip Ross, +Red Hat Universal Base Image minimal,8,https://catalog.redhat.com/software/containers/ubi8/ubi-minimal/5c359a62bed8bd75a2c3fba8,Custom;https://www.redhat.com/licenses/EULA_Red_Hat_Universal_Base_Image_English_20190422.pdf,,https://oss-dependencies.elastic.co/redhat/ubi/ubi-minimal-8-source.tar.gz \ No newline at end of file From 582f886276f5289076e40228efc17fd6d4a4976f Mon Sep 17 00:00:00 2001 From: andsel Date: Wed, 21 Oct 2020 15:42:32 +0200 Subject: [PATCH 0618/1126] Forward of 7.9.3 release notes --- docs/static/releasenotes.asciidoc | 27 +++++++++++++++++++++++++++ 1 file changed, 27 insertions(+) diff --git a/docs/static/releasenotes.asciidoc b/docs/static/releasenotes.asciidoc index 6aac4ada4..ff4dbef60 100644 --- a/docs/static/releasenotes.asciidoc +++ b/docs/static/releasenotes.asciidoc @@ -3,6 +3,7 @@ This section summarizes the changes in the following releases: +* <> * <> * <> * <> @@ -34,6 +35,32 @@ This section summarizes the changes in the following releases: * <> * <> +[[logstash-7-9-3]] +=== Logstash 7.9.3 Release Notes + +==== Notable issues fixed + +===== Pipeline execution fixes to flushing and shutdown +Fix to stop inputs upon a worker error before terminating the pipeline https://github.com/elastic/logstash/pull/12336[#12336] + +==== Plugins + +*File Input - 4.2.2* + +* Fix: sincedb_clean_after not being respected https://github.com/logstash-plugins/logstash-input-file/pull/276[#276] + +*Snmp Input - 1.2.7* + +* Added integration tests to ensure SNMP server and IPv6 connections https://github.com/logstash-plugins/logstash-input-snmp/pull/87[#87] + +* Docs: example on setting IPv6 hosts https://github.com/logstash-plugins/logstash-input-snmp/pull/89[#89] + +*Twitter Input - 4.0.3* + +* Fix: broken proxy configuration https://github.com/logstash-plugins/logstash-input-twitter/pull/69[#69] + +* Fix: user rest api call + proxy configuration https://github.com/logstash-plugins/logstash-input-twitter/pull/68[#68] + [[logstash-7-9-2]] === Logstash 7.9.2 Release Notes From 350bb28b06fa7980bbcdb8f3830869989c3c8297 Mon Sep 17 00:00:00 2001 From: andsel Date: Wed, 21 Oct 2020 13:06:39 +0200 Subject: [PATCH 0619/1126] In QA test, when Logstash package with bundled JDK is installed on RedHat it has to check also the architecture (cherry picked from commit a6fbc6c260342ba890d3a7a57cff582d98c4849f) --- qa/rspec/commands/redhat.rb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/qa/rspec/commands/redhat.rb b/qa/rspec/commands/redhat.rb index 5929f982b..5de3255cb 100644 --- a/qa/rspec/commands/redhat.rb +++ b/qa/rspec/commands/redhat.rb @@ -29,7 +29,7 @@ module ServiceTester stdout = cmd.stdout end stdout.match(/^Installed Packages$/) - stdout.match(/^logstash.noarch/) + stdout.match(/^logstash.noarch/) || stdout.match(/^logstash.#{architecture_extension}/) end def package_extension From a02b7e13c5dc3e7f9e0a34c487be1ad177ec2e03 Mon Sep 17 00:00:00 2001 From: Rob Bavey Date: Mon, 26 Oct 2020 15:00:26 -0400 Subject: [PATCH 0620/1126] [7x backport] Update jrjackon and databind versions Clean backport of #12385 --- versions.yml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/versions.yml b/versions.yml index df3eaa86d..99ba28f1b 100644 --- a/versions.yml +++ b/versions.yml @@ -27,6 +27,6 @@ jruby: # Note: this file is copied to the root of logstash-core because its gemspec needs it when # bundler evaluates the gemspec via bin/logstash # Ensure Jackson version here is kept in sync with version used by jrjackson gem -jrjackson: 0.4.12 +jrjackson: 0.4.13 jackson: 2.9.10 -jackson-databind: 2.9.10.4 +jackson-databind: 2.9.10.6 From c96543b0102c2808da2754c795c7d7820162f83a Mon Sep 17 00:00:00 2001 From: kaisecheng <69120390+kaisecheng@users.noreply.github.com> Date: Thu, 29 Oct 2020 09:49:52 +0100 Subject: [PATCH 0621/1126] [7x backport] document system indices api privilege (#12393) backport #12388 #12391 --- docs/static/security/logstash.asciidoc | 11 ++--------- .../configuration-management-settings.asciidoc | 8 +++++--- 2 files changed, 7 insertions(+), 12 deletions(-) diff --git a/docs/static/security/logstash.asciidoc b/docs/static/security/logstash.asciidoc index 8771304bd..d6526fba6 100644 --- a/docs/static/security/logstash.asciidoc +++ b/docs/static/security/logstash.asciidoc @@ -123,16 +123,9 @@ privileges for the Logstash indices. You can create roles from the --------------------------------------------------------------- POST _xpack/security/role/logstash_reader { - "indices": [ - { - "names": [ "logstash-*" ], <1> - "privileges": ["read","view_index_metadata"] - } - ] + "cluster": ["manage_logstash_pipelines"] } --------------------------------------------------------------- -<1> If you use a custom Logstash index pattern, specify that pattern -instead of the default `logstash-*` pattern. . Assign your Logstash users the `logstash_reader` role. If the Logstash user will be using @@ -149,7 +142,7 @@ POST _xpack/security/user/logstash_user "full_name" : "Kibana User for Logstash" } --------------------------------------------------------------- -<1> `logstash_admin` is a built-in role that provides access to `.logstash-*` +<1> `logstash_admin` is a built-in role that provides access to system indices for managing configurations. [float] diff --git a/docs/static/settings/configuration-management-settings.asciidoc b/docs/static/settings/configuration-management-settings.asciidoc index 893daac7c..2292899af 100644 --- a/docs/static/settings/configuration-management-settings.asciidoc +++ b/docs/static/settings/configuration-management-settings.asciidoc @@ -53,8 +53,10 @@ section in your Logstash configuration, or a different one. Defaults to If your {es} cluster is protected with basic authentication, these settings provide the username and password that the Logstash instance uses to authenticate for accessing the configuration data. The username you specify here -should have the built-in `logstash_admin` role and the customized `logstash_writer` role, which provides access to `.logstash-*` -indices for managing configurations. +should have the built-in `logstash_admin` role and the customized `logstash_writer` role, which provides access to system +indices for managing configurations. Starting with Elasticsearch version 7.10.0, the +`logstash_admin` role inherits the `manage_logstash_pipelines` cluster privilege for centralized pipeline management. +If a user has created their own roles and granted them access to the .logstash index, those roles will continue to work in 7.x but will need to be updated for 8.0. `xpack.management.elasticsearch.proxy`:: @@ -98,7 +100,7 @@ This setting is an alternative to both `xpack.management.elasticsearch.username` and `xpack.management.elasticsearch.password`. If `cloud_auth` is configured, those settings should not be used. The credentials you specify here should be for a user with the `logstash_admin` role, which -provides access to `.logstash-*` indices for managing configurations. +provides access to system indices for managing configurations. `xpack.management.elasticsearch.api_key`:: From 50428785cfea06d6a2cfe4f634a6794c728f5ab4 Mon Sep 17 00:00:00 2001 From: Karen Metts <35154725+karenzone@users.noreply.github.com> Date: Fri, 30 Oct 2020 16:23:58 -0400 Subject: [PATCH 0622/1126] [Backport][Doc]Relocate logstash-to-cloud info for increased visibility (#12400) Moves Cloud info to Configuration section to make it more obvious and easier to find Expands content for using cloud id and cloud auth outside of modules Moves module-specific info into modules section Backports #11884 to 7.x --- docs/index.asciidoc | 5 ++- docs/static/ls-to-cloud.asciidoc | 54 ++++++++++++++++++++++++++++++++ docs/static/modules.asciidoc | 49 +++++++++-------------------- 3 files changed, 73 insertions(+), 35 deletions(-) create mode 100644 docs/static/ls-to-cloud.asciidoc diff --git a/docs/index.asciidoc b/docs/index.asciidoc index 742a11f9a..3ee1a547f 100644 --- a/docs/index.asciidoc +++ b/docs/index.asciidoc @@ -105,7 +105,10 @@ include::static/configuration.asciidoc[] :edit_url!: include::static/security/logstash.asciidoc[] -// Advanced Logstash Configurion +:edit_url!: +include::static/ls-to-cloud.asciidoc[] + +// Advanced Logstash Configuration :edit_url!: include::static/configuration-advanced.asciidoc[] diff --git a/docs/static/ls-to-cloud.asciidoc b/docs/static/ls-to-cloud.asciidoc new file mode 100644 index 000000000..1c1e31d78 --- /dev/null +++ b/docs/static/ls-to-cloud.asciidoc @@ -0,0 +1,54 @@ +[[connecting-to-cloud]] +=== Sending data to Elasticsearch Service + +Our hosted Elasticsearch Service is available on AWS, GCP, and Azure. +{ess-trial}[You can try the Elasticsearch Service for free]. + +Logstash comes with two settings that simplify sending data to +https://cloud.elastic.co/[Elastic Cloud]: Cloud ID and Cloud Auth. + +[[cloud-id]] +==== Cloud ID + +{ls} uses the Cloud ID, found in the Elastic Cloud web console, to build the +Elasticsearch and Kibana hosts settings. It is a base64 encoded text value of +about 120 characters made up of upper and lower case letters and numbers. +If you have several Cloud IDs, you can add a label, which is ignored +internally, to help you tell them apart. To add a label you should prefix your +Cloud ID with a label and a `:` separator in this format "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

_HrE+{ttEL*ybd=5S868 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 diff --git a/docs/static/settings/configuration-management-settings.asciidoc b/docs/static/settings/configuration-management-settings.asciidoc index 2292899af..82d6d6ace 100644 --- a/docs/static/settings/configuration-management-settings.asciidoc +++ b/docs/static/settings/configuration-management-settings.asciidoc @@ -40,6 +40,7 @@ The default is 5s. Specify a comma-separated list of pipeline IDs to register for centralized pipeline management. After changing this setting, you need to restart Logstash to pick up changes. +Pipeline IDs support `*` as a <> for matching multiple IDs `xpack.management.elasticsearch.hosts`:: diff --git a/docs/static/settings/configuration-wildcard-pipeline-id.asciidoc b/docs/static/settings/configuration-wildcard-pipeline-id.asciidoc new file mode 100644 index 000000000..0304f7ba6 --- /dev/null +++ b/docs/static/settings/configuration-wildcard-pipeline-id.asciidoc @@ -0,0 +1,19 @@ +[role="xpack"] +[[wildcard-in-pipeline-id]] +==== Wildcard support in pipeline ID +++++ +Wildcard support in pipeline ID +++++ +Pipeline IDs must begin with a letter or underscore and contain only letters, underscores, dashes, and numbers. +You can use `*` in `xpack.management.pipeline.id` to match any number of letters, underscores, dashes, and numbers. + +[source,shell] +----- +xpack.management.pipeline.id: ["*logs", "*apache*", "tomcat_log"] +----- + +In this example, `"*logs"` matches all IDs ending in `logs`. `"*apache*"` matches any IDs with `apache` in the name. + +Wildcard in pipeline IDs is available starting with Elasticsearch 7.10. Logstash can pick up new pipeline without a restart if the new pipeline ID matches the wildcard pattern. + + From 5037fd23e9d5fb20013f8297eff3554d605a5214 Mon Sep 17 00:00:00 2001 From: Karen Metts <35154725+karenzone@users.noreply.github.com> Date: Thu, 5 Nov 2020 12:45:57 -0500 Subject: [PATCH 0627/1126] [Backport] Doc: Add bundled JDK info (#12417) Document options and impacts of bundled JDK Backports: #12369 --- docs/static/jvm.asciidoc | 18 +++++++++++++++--- 1 file changed, 15 insertions(+), 3 deletions(-) diff --git a/docs/static/jvm.asciidoc b/docs/static/jvm.asciidoc index 38a142cfe..4f6a09bfa 100644 --- a/docs/static/jvm.asciidoc +++ b/docs/static/jvm.asciidoc @@ -8,13 +8,25 @@ * Java 11 * Java 14 -See the https://www.elastic.co/support/matrix#matrix_jvm[Elastic Support Matrix] -for the official word on supported versions across releases. - Use the http://www.oracle.com/technetwork/java/javase/downloads/index.html[official Oracle distribution] or an open-source distribution, such as http://openjdk.java.net/[OpenJDK]. +See the https://www.elastic.co/support/matrix#matrix_jvm[Elastic Support Matrix] +for the official word on supported versions across releases. + +.Bundled JDK +[NOTE] +===== +{ls} offers architecture-specific +https://staging-website.elastic.co/downloads/logstash[downloads] that include +AdoptOpenJDK 11, the latest long term support (LTS) release of JDK. + +Use the JAVA_HOME environment variable if you want to use a JDK other than the +version that is bundled. +If you have the JAVA_HOME environment variable set to use a custom JDK, Logstash +will continue to use the JDK version you have specified, even after you upgrade. +===== [float] [[check-jvm]] From 1ea4837b71858f8706c353c9f1fbd5e05caa798c Mon Sep 17 00:00:00 2001 From: kaisecheng <69120390+kaisecheng@users.noreply.github.com> Date: Mon, 9 Nov 2020 13:21:40 +0100 Subject: [PATCH 0628/1126] [backport 7x] delete pipeline in registry (#12419) deletes the pipeline in the pipelines_registry if it is terminated and is removed in the source Fixed: #12414 --- logstash-core/lib/logstash/pipeline_action.rb | 4 +- .../lib/logstash/pipeline_action/delete.rb | 38 +++++++++++++++++ .../lib/logstash/pipelines_registry.rb | 27 +++++++++++- logstash-core/lib/logstash/state_resolver.rb | 7 +++- .../spec/logstash/pipelines_registry_spec.rb | 42 +++++++++++++++++++ .../spec/logstash/state_resolver_spec.rb | 40 ++++++++++++++++++ 6 files changed, 155 insertions(+), 3 deletions(-) create mode 100644 logstash-core/lib/logstash/pipeline_action/delete.rb diff --git a/logstash-core/lib/logstash/pipeline_action.rb b/logstash-core/lib/logstash/pipeline_action.rb index f4c1ba9d9..910ce66bf 100644 --- a/logstash-core/lib/logstash/pipeline_action.rb +++ b/logstash-core/lib/logstash/pipeline_action.rb @@ -19,11 +19,13 @@ require "logstash/pipeline_action/base" require "logstash/pipeline_action/create" require "logstash/pipeline_action/stop" require "logstash/pipeline_action/reload" +require "logstash/pipeline_action/delete" module LogStash module PipelineAction ORDERING = { LogStash::PipelineAction::Create => 100, LogStash::PipelineAction::Reload => 200, - LogStash::PipelineAction::Stop => 300 + LogStash::PipelineAction::Stop => 300, + LogStash::PipelineAction::Delete => 400 } end end diff --git a/logstash-core/lib/logstash/pipeline_action/delete.rb b/logstash-core/lib/logstash/pipeline_action/delete.rb new file mode 100644 index 000000000..1a19509ba --- /dev/null +++ b/logstash-core/lib/logstash/pipeline_action/delete.rb @@ -0,0 +1,38 @@ +# 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 "logstash/pipeline_action/base" + +module LogStash module PipelineAction + class Delete < Base + attr_reader :pipeline_id + + def initialize(pipeline_id) + @pipeline_id = pipeline_id + end + + def execute(agent, pipelines_registry) + success = pipelines_registry.delete_pipeline(@pipeline_id) + + LogStash::ConvergeResult::ActionResult.create(self, success) + end + + def to_s + "PipelineAction::Delete<#{pipeline_id}>" + end + end +end end diff --git a/logstash-core/lib/logstash/pipelines_registry.rb b/logstash-core/lib/logstash/pipelines_registry.rb index 6143f3ee3..5fc67e086 100644 --- a/logstash-core/lib/logstash/pipelines_registry.rb +++ b/logstash-core/lib/logstash/pipelines_registry.rb @@ -76,7 +76,6 @@ module LogStash def remove(pipeline_id) @lock.synchronize do @states.delete(pipeline_id) - @locks.delete(pipeline_id) end end @@ -209,6 +208,32 @@ module LogStash lock.unlock end + # Delete the pipeline that is terminated + # @param pipeline_id [String, Symbol] the pipeline id + # @return [Boolean] pipeline delete success + def delete_pipeline(pipeline_id) + lock = @states.get_lock(pipeline_id) + lock.lock + + state = @states.get(pipeline_id) + + if state.nil? + logger.error("Attempted to delete a pipeline that does not exists", :pipeline_id => pipeline_id) + return false + end + + if state.terminated? + @states.remove(pipeline_id) + logger.info("Removed pipeline from registry successfully", :pipeline_id => pipeline_id) + return true + else + logger.info("Attempted to delete a pipeline that is not terminated", :pipeline_id => pipeline_id) + return false + end + ensure + lock.unlock + end + # @param pipeline_id [String, Symbol] the pipeline id # @return [Pipeline] the pipeline object or nil if none for pipeline_id def get_pipeline(pipeline_id) diff --git a/logstash-core/lib/logstash/state_resolver.rb b/logstash-core/lib/logstash/state_resolver.rb index 386921b1f..8045c4b0b 100644 --- a/logstash-core/lib/logstash/state_resolver.rb +++ b/logstash-core/lib/logstash/state_resolver.rb @@ -41,7 +41,7 @@ module LogStash end end - configured_pipelines = pipeline_configs.map { |config| config.pipeline_id.to_sym } + configured_pipelines = pipeline_configs.each_with_object(Set.new) { |config, set| set.add(config.pipeline_id.to_sym) } # If one of the running pipeline is not in the pipeline_configs, we assume that we need to # stop it. @@ -49,6 +49,11 @@ module LogStash .select { |pipeline_id| !configured_pipelines.include?(pipeline_id) } .each { |pipeline_id| actions << LogStash::PipelineAction::Stop.new(pipeline_id) } + # If one of the terminated pipeline is not in the pipeline_configs, delete it in registry. + pipelines_registry.non_running_pipelines.keys + .select { |pipeline_id| !configured_pipelines.include?(pipeline_id) } + .each { |pipeline_id| actions << LogStash::PipelineAction::Delete.new(pipeline_id)} + actions.sort # See logstash/pipeline_action.rb end end diff --git a/logstash-core/spec/logstash/pipelines_registry_spec.rb b/logstash-core/spec/logstash/pipelines_registry_spec.rb index 3af1ff78a..b068a4e5a 100644 --- a/logstash-core/spec/logstash/pipelines_registry_spec.rb +++ b/logstash-core/spec/logstash/pipelines_registry_spec.rb @@ -228,6 +228,48 @@ describe LogStash::PipelinesRegistry do end end + context "deleting a pipeline" do + context "when pipeline is in registry" do + before :each do + subject.create_pipeline(pipeline_id, pipeline) { true } + end + + it "should not delete pipeline if pipeline is not terminated" do + expect(pipeline).to receive(:finished_execution?).and_return(false) + expect(LogStash::PipelinesRegistry).to receive(:logger).and_return(logger) + expect(logger).to receive(:info) + expect(subject.delete_pipeline(pipeline_id)).to be_falsey + expect(subject.get_pipeline(pipeline_id)).not_to be_nil + end + + it "should delete pipeline if pipeline is terminated" do + expect(pipeline).to receive(:finished_execution?).and_return(true) + expect(LogStash::PipelinesRegistry).to receive(:logger).and_return(logger) + expect(logger).to receive(:info) + expect(subject.delete_pipeline(pipeline_id)).to be_truthy + expect(subject.get_pipeline(pipeline_id)).to be_nil + end + + it "should recreate pipeline if pipeline is delete and create again" do + expect(pipeline).to receive(:finished_execution?).and_return(true) + expect(LogStash::PipelinesRegistry).to receive(:logger).and_return(logger) + expect(logger).to receive(:info) + expect(subject.delete_pipeline(pipeline_id)).to be_truthy + expect(subject.get_pipeline(pipeline_id)).to be_nil + subject.create_pipeline(pipeline_id, pipeline) { true } + expect(subject.get_pipeline(pipeline_id)).not_to be_nil + end + end + + context "when pipeline is not in registry" do + it "should log error" do + expect(LogStash::PipelinesRegistry).to receive(:logger).and_return(logger) + expect(logger).to receive(:error) + expect(subject.delete_pipeline(pipeline_id)).to be_falsey + end + end + end + context "pipelines collections" do context "with a non terminated pipelines" do before :each do diff --git a/logstash-core/spec/logstash/state_resolver_spec.rb b/logstash-core/spec/logstash/state_resolver_spec.rb index 8775bc3ac..350832797 100644 --- a/logstash-core/spec/logstash/state_resolver_spec.rb +++ b/logstash-core/spec/logstash/state_resolver_spec.rb @@ -172,5 +172,45 @@ describe LogStash::StateResolver do end end end + + context "when a pipeline stops" do + let(:main_pipeline) { mock_pipeline(:main) } + let(:main_pipeline_config) { main_pipeline.pipeline_config } + let(:pipelines) do + r = LogStash::PipelinesRegistry.new + r.create_pipeline(:main, main_pipeline) { true } + r + end + + before do + expect(main_pipeline).to receive(:finished_execution?).at_least(:once).and_return(true) + end + + context "when pipeline config contains a new one and the existing" do + let(:pipeline_configs) { [mock_pipeline_config(:hello_world), main_pipeline_config ] } + + it "creates the new one and keep the other one stop" do + expect(subject.resolve(pipelines, pipeline_configs)).to have_actions([:create, :hello_world]) + expect(pipelines.non_running_pipelines.size).to eq(1) + end + end + + context "when pipeline config contains an updated pipeline" do + let(:pipeline_configs) { [mock_pipeline_config(:main, "input { generator {}}")] } + + it "should reload the stopped pipeline" do + expect(subject.resolve(pipelines, pipeline_configs)).to have_actions([:reload, :main]) + end + end + + context "when pipeline config contains no pipeline" do + let(:pipeline_configs) { [] } + + it "should delete the stopped one" do + expect(subject.resolve(pipelines, pipeline_configs)).to have_actions([:delete, :main]) + end + end + end + end end From aba562e8873210c2aac5e7fd29d62954a7217f3b Mon Sep 17 00:00:00 2001 From: kaisecheng <69120390+kaisecheng@users.noreply.github.com> Date: Mon, 9 Nov 2020 15:36:50 +0100 Subject: [PATCH 0629/1126] [backport 7x] hash function of pipeline config with metadata (#12425) add metadata in the hash function Fixed #12387 --- .../logstash/common/SourceWithMetadata.java | 19 ++++++++++--- .../logstash/config/ir/PipelineConfig.java | 14 +++++++++- .../config/ir/PipelineConfigTest.java | 19 ++++++------- .../config_management/elasticsearch_source.rb | 3 ++- .../management/multiple_pipelines_spec.rb | 23 ++++++++++++++++ x-pack/qa/integration/support/helpers.rb | 27 ++++++++++++------- 6 files changed, 81 insertions(+), 24 deletions(-) diff --git a/logstash-core/src/main/java/org/logstash/common/SourceWithMetadata.java b/logstash-core/src/main/java/org/logstash/common/SourceWithMetadata.java index f8fba5614..1063dfd58 100644 --- a/logstash-core/src/main/java/org/logstash/common/SourceWithMetadata.java +++ b/logstash-core/src/main/java/org/logstash/common/SourceWithMetadata.java @@ -39,6 +39,7 @@ public class SourceWithMetadata implements HashableWithSource { private final Integer column; private final String text; private int linesCount; + private final String metadata; public String getProtocol() { return this.protocol; @@ -60,14 +61,17 @@ public class SourceWithMetadata implements HashableWithSource { return text; } + public String getMetadata() { return metadata; } + private static final Pattern emptyString = Pattern.compile("^\\s*$"); - public SourceWithMetadata(String protocol, String id, Integer line, Integer column, String text) throws IncompleteSourceWithMetadataException { + public SourceWithMetadata(String protocol, String id, Integer line, Integer column, String text, String metadata) throws IncompleteSourceWithMetadataException { this.protocol = protocol; this.id = id; this.line = line; this.column = column; this.text = text; + this.metadata = metadata; List badAttributes = this.attributes().stream().filter(a -> { if (a == null) return true; @@ -82,8 +86,7 @@ public class SourceWithMetadata implements HashableWithSource { } if (!badAttributes.isEmpty()) { - String message = "Missing attributes in SourceWithMetadata: (" + badAttributes + ") " - + this.toString(); + String message = "Missing attributes in SourceWithMetadata: (" + badAttributes + ") " + this.toString(); throw new IncompleteSourceWithMetadataException(message); } @@ -91,7 +94,15 @@ public class SourceWithMetadata implements HashableWithSource { } public SourceWithMetadata(String protocol, String id, String text) throws IncompleteSourceWithMetadataException { - this(protocol, id, 0, 0, text); + this(protocol, id, 0, 0, text, ""); + } + + public SourceWithMetadata(String protocol, String id, String text, String metadata) throws IncompleteSourceWithMetadataException { + this(protocol, id, 0, 0, text, metadata); + } + + public SourceWithMetadata(String protocol, String id, Integer line, Integer column, String text) throws IncompleteSourceWithMetadataException { + this(protocol, id, line, column, text, ""); } public int hashCode() { diff --git a/logstash-core/src/main/java/org/logstash/config/ir/PipelineConfig.java b/logstash-core/src/main/java/org/logstash/config/ir/PipelineConfig.java index dba86cb70..8767064c5 100644 --- a/logstash-core/src/main/java/org/logstash/config/ir/PipelineConfig.java +++ b/logstash-core/src/main/java/org/logstash/config/ir/PipelineConfig.java @@ -60,6 +60,7 @@ public final class PipelineConfig { private LocalDateTime readAt; private String configHash; private volatile String configString; + private volatile String metadata; private List sourceRefs; private static final String NEWLINE = "\n"; @@ -104,7 +105,7 @@ public final class PipelineConfig { public String configHash() { if (configHash == null) { - configHash = DigestUtils.sha1Hex(configString()); + configHash = DigestUtils.sha1Hex(configString() + metadataString()); } return configHash; } @@ -129,6 +130,17 @@ public final class PipelineConfig { return this.configString; } + public String metadataString() { + if (this.metadata == null) { + synchronized(this) { + if (this.metadata == null) { + this.metadata = confParts.stream().map(SourceWithMetadata::getMetadata).collect(Collectors.joining()); + } + } + } + return this.metadata; + } + public boolean isSystem() { return this.settings.callMethod(RUBY.getCurrentContext(), "get_value", RubyString.newString(RUBY, "pipeline.system")) diff --git a/logstash-core/src/test/java/org/logstash/config/ir/PipelineConfigTest.java b/logstash-core/src/test/java/org/logstash/config/ir/PipelineConfigTest.java index b26d3656f..8bd2fb98e 100644 --- a/logstash-core/src/test/java/org/logstash/config/ir/PipelineConfigTest.java +++ b/logstash-core/src/test/java/org/logstash/config/ir/PipelineConfigTest.java @@ -81,8 +81,8 @@ public class PipelineConfigTest extends RubyEnvTestCase { private final StringBuilder compositeSource = new StringBuilder(); private final List orderedConfigParts = new ArrayList<>(); - void appendSource(final String protocol, final String id, final int line, final int column, final String text) throws IncompleteSourceWithMetadataException { - orderedConfigParts.add(new SourceWithMetadata(protocol, id, line, column, text)); + void appendSource(final String protocol, final String id, final int line, final int column, final String text, final String metadata) throws IncompleteSourceWithMetadataException { + orderedConfigParts.add(new SourceWithMetadata(protocol, id, line, column, text, metadata)); if (compositeSource.length() > 0 && !compositeSource.toString().endsWith("\n")) { compositeSource.append("\n"); @@ -106,13 +106,13 @@ public class PipelineConfigTest extends RubyEnvTestCase { pipelineIdSym = RubySymbol.newSymbol(RubyUtil.RUBY, PIPELINE_ID); final SourceCollector sourceCollector = new SourceCollector(); - sourceCollector.appendSource("file", "/tmp/1", 0, 0, "input { generator1 }\n"); - sourceCollector.appendSource("file", "/tmp/2", 0, 0, "input { generator2 }"); - sourceCollector.appendSource("file", "/tmp/3", 0, 0, "input { generator3 }\n"); - sourceCollector.appendSource("file", "/tmp/4", 0, 0, "input { generator4 }"); - sourceCollector.appendSource("file", "/tmp/5", 0, 0, "input { generator5 }\n"); - sourceCollector.appendSource("file", "/tmp/6", 0, 0, "input { generator6 }"); - sourceCollector.appendSource("string", "config_string", 0, 0, "input { generator1 }"); + sourceCollector.appendSource("file", "/tmp/1", 0, 0, "input { generator1 }\n", "{\"version\": \"1\"}"); + sourceCollector.appendSource("file", "/tmp/2", 0, 0, "input { generator2 }", "{\"version\": \"1\"}"); + sourceCollector.appendSource("file", "/tmp/3", 0, 0, "input { generator3 }\n", "{\"version\": \"1\"}"); + sourceCollector.appendSource("file", "/tmp/4", 0, 0, "input { generator4 }", "{\"version\": \"1\"}"); + sourceCollector.appendSource("file", "/tmp/5", 0, 0, "input { generator5 }\n", "{\"version\": \"1\"}"); + sourceCollector.appendSource("file", "/tmp/6", 0, 0, "input { generator6 }", "{\"version\": \"1\"}"); + sourceCollector.appendSource("string", "config_string", 0, 0, "input { generator1 }", "{\"version\": \"1\"}"); orderedConfigParts = sourceCollector.orderedConfigParts(); configMerged = sourceCollector.compositeSource(); @@ -129,6 +129,7 @@ public class PipelineConfigTest extends RubyEnvTestCase { assertEquals("returns the source", source, sut.getSource()); assertEquals("returns the pipeline id", PIPELINE_ID, sut.getPipelineId()); assertNotNull("returns the config_hash", sut.configHash()); + assertNotNull("returns the config_hash", sut.metadataString()); assertEquals("returns the merged `ConfigPart#config_string`", configMerged, sut.configString()); assertThat("records when the config was read", sut.getReadAt(), isBeforeOrSame(LocalDateTime.now())); } diff --git a/x-pack/lib/config_management/elasticsearch_source.rb b/x-pack/lib/config_management/elasticsearch_source.rb index 50f4597e7..84b569541 100644 --- a/x-pack/lib/config_management/elasticsearch_source.rb +++ b/x-pack/lib/config_management/elasticsearch_source.rb @@ -87,10 +87,11 @@ module LogStash def get_pipeline(pipeline_id, fetcher) config_string = fetcher.get_single_pipeline_setting(pipeline_id)["pipeline"] + pipeline_metadata_str = (fetcher.get_single_pipeline_setting(pipeline_id)["pipeline_metadata"] || "").to_s raise RemoteConfigError, "Empty configuration for pipeline_id: #{pipeline_id}" if config_string.nil? || config_string.empty? - config_part = org.logstash.common.SourceWithMetadata.new("x-pack-config-management", pipeline_id.to_s, config_string) + config_part = org.logstash.common.SourceWithMetadata.new("x-pack-config-management", pipeline_id.to_s, config_string, pipeline_metadata_str) # We don't support multiple pipelines, so use the global settings from the logstash.yml file settings = @settings.clone diff --git a/x-pack/qa/integration/management/multiple_pipelines_spec.rb b/x-pack/qa/integration/management/multiple_pipelines_spec.rb index 51507223c..470448d73 100644 --- a/x-pack/qa/integration/management/multiple_pipelines_spec.rb +++ b/x-pack/qa/integration/management/multiple_pipelines_spec.rb @@ -177,6 +177,29 @@ describe "Read configuration from elasticsearch" do end end + it "should pick up recreated pipeline with the same config string and different metadata" do + elasticsearch_client.indices.refresh + + pipeline_id = @pipelines.keys[0] + config = @pipelines.values[0] + file = File.join(@temporary_directory, pipeline_id) + + Stud.try(max_retry.times, [RSpec::Expectations::ExpectationNotMetError]) do + expect(File.exist?(file)).to be_truthy + end + + cleanup_system_indices([pipeline_id]) + File.delete(file) + expect(File.exist?(file)).to be_falsey + + push_elasticsearch_config(pipeline_id, config, "2") + elasticsearch_client.indices.refresh + + Stud.try(max_retry.times, [RSpec::Expectations::ExpectationNotMetError]) do + expect(File.exist?(file)).to be_truthy + end + end + after :each do @logstash_service.stop if !!@logstash_service @elasticsearch_service.stop if !!@elasticsearch_service diff --git a/x-pack/qa/integration/support/helpers.rb b/x-pack/qa/integration/support/helpers.rb index bdc75ef73..a8cf72296 100644 --- a/x-pack/qa/integration/support/helpers.rb +++ b/x-pack/qa/integration/support/helpers.rb @@ -97,13 +97,15 @@ end def es_version response = elasticsearch_client.perform_request(:get, "") - response.body["version"]["number"].gsub(/(\d+\.\d+)\..+/, '\1').to_f + major, minor = response.body["version"]["number"].split(".") + [major.to_i, minor.to_i] end -def push_elasticsearch_config(pipeline_id, config) - if es_version >= 7.10 +def push_elasticsearch_config(pipeline_id, config, version="1") + major, minor = es_version + if major >= 8 || (major == 7 && minor >= 10) elasticsearch_client.perform_request(:put, "_logstash/pipeline/#{pipeline_id}", {}, - { :pipeline => config, :username => "log.stash", :pipeline_metadata => {:version => "1" }, + { :pipeline => config, :username => "log.stash", :pipeline_metadata => {:version => version }, :pipeline_settings => {"pipeline.batch.delay": "50"}, :last_modified => Time.now.utc.iso8601}) else elasticsearch_client.index :index => '.logstash', :type => "_doc", id: pipeline_id, :body => { :pipeline => config } @@ -116,13 +118,20 @@ def cleanup_elasticsearch(index = MONITORING_INDEXES) end def cleanup_system_indices(pipeline_ids) - pipeline_ids.each do |id| - begin - elasticsearch_client.perform_request(:delete, "_logstash/pipeline/#{id}") - rescue Elasticsearch::Transport::Transport::Errors::NotFound => e - puts ".logstash can be empty #{e.message}" + major, minor = es_version + + if major >= 8 || (major == 7 && minor >= 10) + pipeline_ids.each do |id| + begin + elasticsearch_client.perform_request(:delete, "_logstash/pipeline/#{id}") + rescue Elasticsearch::Transport::Transport::Errors::NotFound => e + puts ".logstash can be empty #{e.message}" + end end + else + cleanup_elasticsearch(".logstash*") end + elasticsearch_client.indices.refresh end From 68f9ba899ca0da1d3f2d179a909d8977aa8efa0e Mon Sep 17 00:00:00 2001 From: Rob Bavey Date: Tue, 10 Nov 2020 10:35:29 -0500 Subject: [PATCH 0630/1126] [7x backport] Add more information to UnexpectedTypeException (#12429) Clean backport of #12426 Where available, this commit adds information from getSourceWithMetadata to the error message of UnexpectedTypeException, dropping down to `toString` if not, giving more context to find where the issue is caused in the configuration. --- .../config/ir/compiler/EventCondition.java | 24 +++++++++++++++---- 1 file changed, 19 insertions(+), 5 deletions(-) diff --git a/logstash-core/src/main/java/org/logstash/config/ir/compiler/EventCondition.java b/logstash-core/src/main/java/org/logstash/config/ir/compiler/EventCondition.java index 0b2848d8d..c3338f8ee 100644 --- a/logstash-core/src/main/java/org/logstash/config/ir/compiler/EventCondition.java +++ b/logstash-core/src/main/java/org/logstash/config/ir/compiler/EventCondition.java @@ -665,21 +665,35 @@ public interface EventCondition { UnexpectedTypeException(final Expression left, final Expression right) { super( - String.format("Unexpected input types %s %s", left.getClass(), right.getClass()) + String.format( + "Unexpected input types left: %s, right: %s", getUnexpectedTypeDetails(left), getUnexpectedTypeDetails(right) + ) ); } UnexpectedTypeException(final Object inner) { - super(String.format("Unexpected input type %s", inner.getClass())); + super(String.format("Unexpected input type %s", getUnexpectedTypeDetails(inner))); } UnexpectedTypeException(final Object left, final Object right) { super( - String.format( - "Unexpected input type combination %s %s", left.getClass(), right.getClass() - ) + String.format( + "Unexpected input type combination left %s, right %s", getUnexpectedTypeDetails(left), getUnexpectedTypeDetails(right) + ) ); } + + private static String getUnexpectedTypeDetails(Object unexpected) { + String details; + if (unexpected instanceof Expression) { + Expression expression = (Expression)unexpected; + details = (expression.getSourceWithMetadata() != null) ? expression.getSourceWithMetadata().toString() + : expression.toString(); + } else { + details = unexpected.toString(); + } + return String.format("%s:%s", unexpected.getClass(), details); + } } } } From 88ceb5ccfcdab032534c5e65013b63f8fa2e3901 Mon Sep 17 00:00:00 2001 From: andsel Date: Tue, 10 Nov 2020 14:47:41 +0100 Subject: [PATCH 0631/1126] Added console prints in ingest-converter for not recognized processor definitions. Adds console output for - 'if' condition in 'set' processor - unrecognized processor, like join (cherry picked from commit 690bade81f9f013d0629df61414fd46336feb362) --- .../src/main/resources/ingest-pipeline.js | 13 +++++++++++++ .../src/main/resources/ingest-set.js | 4 ++++ 2 files changed, 17 insertions(+) diff --git a/tools/ingest-converter/src/main/resources/ingest-pipeline.js b/tools/ingest-converter/src/main/resources/ingest-pipeline.js index 2056c034c..1d2c0f088 100644 --- a/tools/ingest-converter/src/main/resources/ingest-pipeline.js +++ b/tools/ingest-converter/src/main/resources/ingest-pipeline.js @@ -26,50 +26,63 @@ function ingest_pipeline_to_logstash(json, append_stdio) { ); } } + var processed = false; if (IngestDate.has_date(processor)) { filter_blocks.push( IngestConverter.create_hash("date", IngestDate.date_hash(processor)) ) + processed = true; } if (IngestGeoIp.has_geoip(processor)) { filter_blocks.push( IngestConverter.create_hash("geoip", IngestGeoIp.geoip_hash(processor)) ) + processed = true; } if (IngestConvert.has_convert(processor)) { filter_blocks.push( IngestConverter.create_hash("mutate", IngestConvert.convert_hash(processor)) ); + processed = true; } if (IngestGsub.has_gsub(processor)) { filter_blocks.push( IngestConverter.create_hash("mutate", IngestGsub.gsub_hash(processor)) ); + processed = true; } if (IngestAppend.has_append(processor)) { filter_blocks.push( IngestConverter.create_hash("mutate", IngestAppend.append_hash(processor)) ); + processed = true; } if (IngestJson.has_json(processor)) { filter_blocks.push( IngestConverter.create_hash("json", IngestJson.json_hash(processor)) ); + processed = true; } if (IngestRename.has_rename(processor)) { filter_blocks.push( IngestConverter.create_hash("mutate", IngestRename.rename_hash(processor)) ); + processed = true; } if (IngestLowercase.has_lowercase(processor)) { filter_blocks.push( IngestConverter.create_hash("mutate", IngestLowercase.lowercase_hash(processor)) ); + processed = true; } if (IngestSet.has_set(processor)) { filter_blocks.push( IngestConverter.create_hash("mutate", IngestSet.set_hash(processor)) ); + processed = true; + } + if (!processed) { + print("WARN Found unrecognized processor named: " + Object.keys(processor)[0]); } return IngestConverter.join_hash_fields(filter_blocks); } diff --git a/tools/ingest-converter/src/main/resources/ingest-set.js b/tools/ingest-converter/src/main/resources/ingest-set.js index c5982b044..122dc44a5 100644 --- a/tools/ingest-converter/src/main/resources/ingest-set.js +++ b/tools/ingest-converter/src/main/resources/ingest-set.js @@ -11,6 +11,10 @@ var IngestSet = { } else { value_contents = value; } + var painless_condition = set_json["if"]; + if (!!painless_condition) { + print("WARN Found in 'set' processor an 'if' painless condition not translated: " + painless_condition); + } var mutate_contents = IngestConverter.create_field( IngestConverter.quote_string(IngestConverter.dots_to_square_brackets(set_json["field"])), value_contents); From cf7e2e308ef80aecf01d4257f8b58da296283fd2 Mon Sep 17 00:00:00 2001 From: Karen Metts <35154725+karenzone@users.noreply.github.com> Date: Thu, 12 Nov 2020 14:02:30 -0500 Subject: [PATCH 0632/1126] [Forward] Doc:Release notes 7.10.0 to 7.x (#12433) Co-authored-by: andsel --- docs/static/releasenotes.asciidoc | 115 +++++++++++++++++++++++++++++- 1 file changed, 114 insertions(+), 1 deletion(-) diff --git a/docs/static/releasenotes.asciidoc b/docs/static/releasenotes.asciidoc index ff4dbef60..a1d5d6816 100644 --- a/docs/static/releasenotes.asciidoc +++ b/docs/static/releasenotes.asciidoc @@ -3,6 +3,7 @@ This section summarizes the changes in the following releases: +* <> * <> * <> * <> @@ -35,6 +36,116 @@ This section summarizes the changes in the following releases: * <> * <> +[[logstash-7-10-0]] +=== Logstash 7.10.0 Release Notes + +==== New features and enhancements + +===== Architecture-specific artifacts with bundled JDK + +Logstash 7.10.0 offers new architecture-specific download and installation +options that include a bundled Java Development Kit (JDK). AdoptOpenJDK 11, the +latest long term support (LTS) release, is the bundled version. Before Logstash +included the JDK, users had to install a JDK before they could install Logstash. +Logstash with AdoptOpenJDK 11 makes installation and setup easier, especially +for first time users. + +**Upgrade impacts** + +* If you have JAVA_HOME set to use a custom JDK, Logstash will continue to use the +JDK version you have specified. + +* If you are using the system's JDK (from Ubuntu/Debian/CentOS archives, for +example) and have not set JAVA_HOME, Logstash will default to the bundled +version of Java after you upgrade. Set JAVA_HOME to use your system's JDK if +that is the version you prefer. + +===== Elastic Common Schema (ECS) compatibility + +As we continue to add opt-in ECS compatibility modes in Logstash plugins, +Release 7.10.0 introduces a new pipeline-level setting in +<>. The `pipeline.ecs_compatibility` +setting allows users to control the ECS compatibility of all plugins in a +pipeline at once instead of configuring each instance manually. While ECS +compatibility in these plugins is off-by-default in Logstash 7.x, we plan to +make them on-by-default in Logstash 8.0. This setting allows users to lock in a +specific behavior in advance of their next major version upgrade. + +===== New Docker images and improvements + +* This release adds RedHat Universal Base Images (UBIs). We have updated license +information and added fixes that enable images to pass RedHat docker image +certification. https://github.com/elastic/logstash/pull/12248[#12248], +https://github.com/elastic/logstash/pull/12296[#12296]. +* We have given users more security options by exposing proxy and ssl verification +modes for management and monitoring of a Docker image. +https://github.com/elastic/logstash/pull/12201[#12201], +https://github.com/elastic/logstash/pull/12151[#12151], +https://github.com/elastic/logstash/pull/12205[#12205] + + +==== Performance improvements and notable issues fixed + +**Java pipeline execution and management** + +* We have addressed an issue with the aggregate filter in the Java execution. +The issue prevented events from being generated (when the amount of time for an +aggregation event timed out), preventing a pipeline from effectively summing +events. https://github.com/elastic/logstash/pull/12204[#12204] + +* We have made pipelines more stable by calling `close` on input plugins when a pipeline is +terminated or reloaded. https://github.com/elastic/logstash/pull/12195[#12195] + +**Keystore thread safety.** +After a https://github.com/elastic/logstash/pull/10794[recent performance +improvement], Logstash could fail to start reliably in certain configurations +involving parameter expansion and multiple pipelines. Access to the shared +keystore has since been made thread-safe and is no longer a source of errors. +https://github.com/elastic/logstash/pull/12233[#12233] + +**Dead letter queue (DLQ).** +We changed the DLQ writer policy to avoid the possibility of the DLQ reader processing +an incomplete DLQ segment. Logstash now writes to a temporary file that is +renamed upon completion. https://github.com/elastic/logstash/pull/12304[#12304] + +**Persistent queues (PQ).** +We have addressed PQ issues in which exceptions were impacting pipeline +execution and causing Logstash to crash or to fail to reload. +https://github.com/elastic/logstash/pull/12019[#12019] + +**Updates to dependencies** + +* Update jruby to 9.2.13.0 +* Pinned open-ssl version to 0.10.4 to avoid "Gem not found" error with +jruby-openssl-0.10.5 https://github.com/elastic/logstash/pull/12300[#12300] + +==== Plugin releases + +*Elasticsearch Input - 4.8.1* + +* Fixed connection error when using multiple `slices` https://github.com/logstash-plugins/logstash-input-elasticsearch/issues/133[#133] +* Added the ability to configure connection-, request-, and socket-timeouts with `connect_timeout_seconds`, `request_timeout_seconds`, and `socket_timeout_seconds` https://github.com/logstash-plugins/logstash-input-elasticsearch/issues/121[#121] + +*Kafka Integration - 10.5.1* + +* [DOC]Replaced plugin_header file with plugin_header-integration file https://github.com/logstash-plugins/logstash-integration-kafka/pull/46[#46] +* [DOC]Update kafka client version across kafka integration docs https://github.com/logstash-plugins/logstash-integration-kafka/pull/47[#47] +* [DOC]Replace hard-coded kafka client and doc path version numbers with attributes to simplify doc maintenance https://github.com/logstash-plugins/logstash-integration-kafka/pull/48[#48] +* Changed: retry sending messages only for retriable exceptions https://github.com/logstash-plugins/logstash-integration-kafka/pull/29[#27] +* [DOC] Fixed formatting issues and made minor content edits https://github.com/logstash-plugins/logstash-integration-kafka/pull/43[#43] + +*Aws Mixin - 4.4.1* + +* Fix: proxy with assumed role (properly) https://github.com/logstash-plugins/logstash-mixin-aws/pull/50[#50] +* Fix: credentials/proxy with assumed role. Plugin no longer assumes +`access_key_id`/`secret_access_key` credentials not to be set when `role_arn` +specified. https://github.com/logstash-plugins/logstash-mixin-aws/pull/48[#48] + +*Elasticsearch Output - 10.7.0* + +* Changed: don't set the pipeline parameter if the value resolves to an empty string https://github.com/logstash-plugins/logstash-output-elasticsearch/pull/962[#962] + + [[logstash-7-9-3]] === Logstash 7.9.3 Release Notes @@ -61,6 +172,7 @@ Fix to stop inputs upon a worker error before terminating the pipeline https://g * Fix: user rest api call + proxy configuration https://github.com/logstash-plugins/logstash-input-twitter/pull/68[#68] + [[logstash-7-9-2]] === Logstash 7.9.2 Release Notes @@ -73,6 +185,7 @@ Since `7.8.0`, a change to optimise the speed of loading variables from the Logs ===== App Search output startup failure Since `7.9.0`, a regression was introduced which prevented pipelines using the Elastic App Search output from starting. This release fixes support for this plugin, you can read the details here: https://github.com/logstash-plugins/logstash-output-elastic_app_search/pull/18[#18], https://github.com/elastic/logstash/pull/12251[#12251] + [[jdk15-compat]] ==== Compatibility notice: {ls} and JDK 15 @@ -1883,4 +1996,4 @@ Here are the plugin changes. - Tweaked logging statements to reduce verbosity - Fixed numerous issues relating to builds on Travis https://github.com/logstash-plugins/logstash-output-elasticsearch/pull/799[#799] * logstash-output-s3 - - Fixed issue where on restart, 0 byte files could erroneously be uploaded to s3 https://github.com/logstash-plugins/logstash-output-s3/issues/195[#195] + - Fixed issue where on restart, 0 byte files could erroneously be uploaded to s3 https://github.com/logstash-plugins/logstash-output-s3/issues/195[#195] \ No newline at end of file From b1e5c4f25793f68dee937f3383f3c951fd013bde Mon Sep 17 00:00:00 2001 From: andsel Date: Wed, 11 Nov 2020 13:56:55 +0100 Subject: [PATCH 0633/1126] Moved CloudSettingId class and tests to Java (cherry picked from commit 2545fa45ba0eca9adec2e8ce87bc428d80a342ab) --- .../lib/logstash/util/cloud_setting_id.rb | 89 +------ .../spec/logstash/settings/modules_spec.rb | 8 +- .../logstash/util/cloud_setting_id_spec.rb | 218 ------------------ .../org/logstash/util/CloudSettingId.java | 191 +++++++++++++++ .../org/logstash/util/CloudSettingIdTest.java | 194 ++++++++++++++++ 5 files changed, 392 insertions(+), 308 deletions(-) delete mode 100644 logstash-core/spec/logstash/util/cloud_setting_id_spec.rb create mode 100644 logstash-core/src/main/java/org/logstash/util/CloudSettingId.java create mode 100644 logstash-core/src/test/java/org/logstash/util/CloudSettingIdTest.java diff --git a/logstash-core/lib/logstash/util/cloud_setting_id.rb b/logstash-core/lib/logstash/util/cloud_setting_id.rb index 0a47bdbc8..5fb35c3d3 100644 --- a/logstash-core/lib/logstash/util/cloud_setting_id.rb +++ b/logstash-core/lib/logstash/util/cloud_setting_id.rb @@ -17,89 +17,6 @@ require "base64" -module LogStash module Util class CloudSettingId - - def self.cloud_id_encode(*args) - Base64.urlsafe_encode64(args.join("$")) - end - DOT_SEPARATOR = "." - CLOUD_PORT = "443" - - attr_reader :original, :decoded, :label - attr_reader :elasticsearch_host, :elasticsearch_scheme, :elasticsearch_port - attr_reader :kibana_host, :kibana_scheme, :kibana_port - attr_reader :other_identifiers - - # The constructor is expecting a 'cloud.id', a string in 2 variants. - # 1 part example: 'dXMtZWFzdC0xLmF3cy5mb3VuZC5pbyRub3RhcmVhbCRpZGVudGlmaWVy' - # 2 part example: 'foobar:dXMtZWFzdC0xLmF3cy5mb3VuZC5pbyRub3RhcmVhbCRpZGVudGlmaWVy' - # The two part variant has a 'label' prepended with a colon separator. The label is not encoded. - # The 1 part (or second section of the 2 part variant) is base64 encoded. - # The original string before encoding has three segments separated by a dollar sign. - # e.g. 'us-east-1.aws.found.io$notareal$identifier' - # The first segment is the cloud base url, e.g. 'us-east-1.aws.found.io' - # The second segment is the elasticsearch host identifier, e.g. 'notareal' - # The third segment is the kibana host identifier, e.g. 'identifier' - # The 'cloud.id' value decoded into the #attr_reader ivars. - def initialize(value) - return if value.nil? - - unless value.is_a?(String) - raise ArgumentError.new("Cloud Id must be String. Received: #{value.class}") - end - @original = value - @label, colon, encoded = @original.partition(":") - if encoded.empty? - @decoded = Base64.urlsafe_decode64(@label) rescue "" - @label = "" - else - @decoded = Base64.urlsafe_decode64(encoded) rescue "" - end - - @decoded = @decoded.encode(Encoding::UTF_8, :invalid => :replace, :undef => :replace) - - if @decoded.count("$") < 2 - raise ArgumentError.new("Cloud Id, after decoding, is invalid. Format: '$$'. Received: \"#{@decoded}\".") - end - - segments = @decoded.split("$") - if segments.any?(&:empty?) - raise ArgumentError.new("Cloud Id, after decoding, is invalid. Format: '$$'. Received: \"#{@decoded}\".") - end - cloud_base = segments.shift - cloud_host = "#{DOT_SEPARATOR}#{cloud_base}" - cloud_host, cloud_port = cloud_host.split(":") - cloud_port ||= CLOUD_PORT - - @elasticsearch_host, @kibana_host, *@other_identifiers = segments - @elasticsearch_host, @elasticsearch_port = @elasticsearch_host.split(":") - @kibana_host, @kibana_port = @kibana_host.split(":") if @kibana_host - @elasticsearch_port ||= cloud_port - @kibana_port ||= cloud_port - @other_identifiers ||= [] - - if @elasticsearch_host == "undefined" - raise ArgumentError.new("Cloud Id, after decoding, elasticsearch segment is 'undefined', literally.") - end - @elasticsearch_scheme = "https" - @elasticsearch_host.concat(cloud_host) - @elasticsearch_host.concat(":#{@elasticsearch_port}") - - if @kibana_host == "undefined" - raise ArgumentError.new("Cloud Id, after decoding, the kibana segment is 'undefined', literally. You may need to enable Kibana in the Cloud UI.") - end - - @kibana_scheme = "https" - @kibana_host ||= String.new # non-sense really to have '.my-host:443' but we're mirroring others - @kibana_host.concat(cloud_host) - @kibana_host.concat(":#{@kibana_port}") - end - - def to_s - @decoded.to_s - end - - def inspect - to_s - end -end end end +module LogStash; module Util + java_import org.logstash.util.CloudSettingId +end; end diff --git a/logstash-core/spec/logstash/settings/modules_spec.rb b/logstash-core/spec/logstash/settings/modules_spec.rb index dd3404c64..1999e7232 100644 --- a/logstash-core/spec/logstash/settings/modules_spec.rb +++ b/logstash-core/spec/logstash/settings/modules_spec.rb @@ -50,26 +50,26 @@ describe LogStash::Setting::Modules do subject { described_class.new("mycloudid", LogStash::Util::CloudSettingId) } context "when given a string which is not a cloud id" do it "should raise an exception" do - expect { subject.set("foobarbaz") }.to raise_error(ArgumentError, /Cloud Id.*is invalid/) + expect { subject.set("foobarbaz") }.to raise_error(IllegalArgumentException, /Cloud Id.*is invalid/) end end context "when given a string which is empty" do it "should raise an exception" do - expect { subject.set("") }.to raise_error(ArgumentError, /Cloud Id.*is invalid/) + expect { subject.set("") }.to raise_error(IllegalArgumentException, /Cloud Id.*is invalid/) end end context "when given a string which is has environment prefix only" do it "should raise an exception" do - expect { subject.set("testing:") }.to raise_error(ArgumentError, /Cloud Id.*is invalid/) + expect { subject.set("testing:") }.to raise_error(IllegalArgumentException, /Cloud Id.*is invalid/) end end context "when given a badly formatted encoded id" do it "should not raise an error" do encoded = Base64.urlsafe_encode64("foo$$bal") - expect { subject.set(encoded) }.to raise_error(ArgumentError, "Cloud Id, after decoding, is invalid. Format: '$$'. Received: \"foo$$bal\".") + expect { subject.set(encoded) }.to raise_error(IllegalArgumentException, "Cloud Id, after decoding, is invalid. Format: '$$'. Received: \"foo$$bal\".") end end diff --git a/logstash-core/spec/logstash/util/cloud_setting_id_spec.rb b/logstash-core/spec/logstash/util/cloud_setting_id_spec.rb deleted file mode 100644 index 9f2d397cc..000000000 --- a/logstash-core/spec/logstash/util/cloud_setting_id_spec.rb +++ /dev/null @@ -1,218 +0,0 @@ -# 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 "spec_helper" -require "logstash/util/cloud_setting_id" - -describe LogStash::Util::CloudSettingId do - let(:input) { "foobar:dXMtZWFzdC0xLmF3cy5mb3VuZC5pbyRub3RhcmVhbCRpZGVudGlmaWVy" } - subject { described_class.new(input) } - - describe "when given unacceptable input" do - it "a nil input does not raise an exception" do - expect{described_class.new(nil)}.not_to raise_exception - end - it "when given a nil input, the accessors are all nil" do - cloud_id = described_class.new(nil) - expect(cloud_id.original).to be_nil - expect(cloud_id.decoded).to be_nil - expect(cloud_id.label).to be_nil - expect(cloud_id.elasticsearch_host).to be_nil - expect(cloud_id.kibana_host).to be_nil - expect(cloud_id.elasticsearch_scheme).to be_nil - expect(cloud_id.kibana_scheme).to be_nil - end - - context "when a malformed value is given" do - let(:raw) {%w(first second)} - let(:input) { described_class.cloud_id_encode(*raw) } - it "raises an error" do - expect{subject}.to raise_exception(ArgumentError, "Cloud Id, after decoding, is invalid. Format: '$$'. Received: \"#{raw[0]}$#{raw[1]}\".") - end - end - - context "when at least one segment is empty" do - let(:raw) {["first", "", "third"]} - let(:input) { described_class.cloud_id_encode(*raw) } - it "raises an error" do - expect{subject}.to raise_exception(ArgumentError, "Cloud Id, after decoding, is invalid. Format: '$$'. Received: \"#{raw[0]}$#{raw[1]}$#{raw[2]}\".") - end - end - - context "when elasticsearch segment is undefined" do - let(:raw) {%w(us-east-1.aws.found.io undefined my-kibana)} - let(:input) { described_class.cloud_id_encode(*raw) } - it "raises an error" do - expect{subject}.to raise_exception(ArgumentError, "Cloud Id, after decoding, elasticsearch segment is 'undefined', literally.") - end - end - - context "when kibana segment is undefined" do - let(:raw) {%w(us-east-1.aws.found.io my-elastic-cluster undefined)} - let(:input) { described_class.cloud_id_encode(*raw) } - it "raises an error" do - expect{subject}.to raise_exception(ArgumentError, "Cloud Id, after decoding, the kibana segment is 'undefined', literally. You may need to enable Kibana in the Cloud UI.") - end - end - end - - describe "without a label" do - let(:input) { "dXMtZWFzdC0xLmF3cy5mb3VuZC5pbyRub3RhcmVhbCRpZGVudGlmaWVy" } - it "#label is empty" do - expect(subject.label).to be_empty - end - it "#decode is set" do - expect(subject.decoded).to eq("us-east-1.aws.found.io$notareal$identifier") - end - end - - describe "when given acceptable input, the accessors:" do - it '#original has a value' do - expect(subject.original).to eq(input) - end - it '#decoded has a value' do - expect(subject.decoded).to eq("us-east-1.aws.found.io$notareal$identifier") - end - it '#label has a value' do - expect(subject.label).to eq("foobar") - end - it '#elasticsearch_host has a value' do - expect(subject.elasticsearch_host).to eq("notareal.us-east-1.aws.found.io:443") - end - it '#elasticsearch_scheme has a value' do - expect(subject.elasticsearch_scheme).to eq("https") - end - it '#kibana_host has a value' do - expect(subject.kibana_host).to eq("identifier.us-east-1.aws.found.io:443") - end - it '#kibana_scheme has a value' do - expect(subject.kibana_scheme).to eq("https") - end - it '#to_s has a value of #decoded' do - expect(subject.to_s).to eq(subject.decoded) - end - end - context "when cloud id contains port descriptions for ES and Kibana" do - let(:input) { "different-es-kb-port:dXMtY2VudHJhbDEuZ2NwLmNsb3VkLmVzLmlvJGFjMzFlYmI5MDI0MTc3MzE1NzA0M2MzNGZkMjZmZDQ2OjkyNDMkYTRjMDYyMzBlNDhjOGZjZTdiZTg4YTA3NGEzYmIzZTA6OTI0NA==" } - - it "decodes the elasticsearch port corretly" do - expect(subject.elasticsearch_host).to eq("ac31ebb90241773157043c34fd26fd46.us-central1.gcp.cloud.es.io:9243") - end - it "decodes the kibana port corretly" do - expect(subject.kibana_host).to eq("a4c06230e48c8fce7be88a074a3bb3e0.us-central1.gcp.cloud.es.io:9244") - end - end - context "when cloud id contains cloud port" do - let(:input) { "custom-port:dXMtY2VudHJhbDEuZ2NwLmNsb3VkLmVzLmlvOjkyNDMkYWMzMWViYjkwMjQxNzczMTU3MDQzYzM0ZmQyNmZkNDYkYTRjMDYyMzBlNDhjOGZjZTdiZTg4YTA3NGEzYmIzZTA=" } - - it "decodes the elasticsearch port corretly" do - expect(subject.elasticsearch_host).to eq("ac31ebb90241773157043c34fd26fd46.us-central1.gcp.cloud.es.io:9243") - end - it "decodes the kibana port corretly" do - expect(subject.kibana_host).to eq("a4c06230e48c8fce7be88a074a3bb3e0.us-central1.gcp.cloud.es.io:9243") - end - end - context "when cloud id only defines kibana port" do - let(:input) { "only-kb-set:dXMtY2VudHJhbDEuZ2NwLmNsb3VkLmVzLmlvJGFjMzFlYmI5MDI0MTc3MzE1NzA0M2MzNGZkMjZmZDQ2JGE0YzA2MjMwZTQ4YzhmY2U3YmU4OGEwNzRhM2JiM2UwOjkyNDQ=" } - - it "defaults the elasticsearch port to 443" do - expect(subject.elasticsearch_host).to eq("ac31ebb90241773157043c34fd26fd46.us-central1.gcp.cloud.es.io:443") - end - it "decodes the kibana port corretly" do - expect(subject.kibana_host).to eq("a4c06230e48c8fce7be88a074a3bb3e0.us-central1.gcp.cloud.es.io:9244") - end - end - context "when cloud id defines cloud port and kibana port" do - let(:input) { "host-and-kb-set:dXMtY2VudHJhbDEuZ2NwLmNsb3VkLmVzLmlvOjkyNDMkYWMzMWViYjkwMjQxNzczMTU3MDQzYzM0ZmQyNmZkNDYkYTRjMDYyMzBlNDhjOGZjZTdiZTg4YTA3NGEzYmIzZTA6OTI0NA==" } - - it "sets the elasticsearch port to cloud port" do - expect(subject.elasticsearch_host).to eq("ac31ebb90241773157043c34fd26fd46.us-central1.gcp.cloud.es.io:9243") - end - it "overrides cloud port with the kibana port" do - expect(subject.kibana_host).to eq("a4c06230e48c8fce7be88a074a3bb3e0.us-central1.gcp.cloud.es.io:9244") - end - end - context "when cloud id defines extra data" do - let(:input) { "extra-items:dXMtY2VudHJhbDEuZ2NwLmNsb3VkLmVzLmlvJGFjMzFlYmI5MDI0MTc3MzE1NzA0M2MzNGZkMjZmZDQ2JGE0YzA2MjMwZTQ4YzhmY2U3YmU4OGEwNzRhM2JiM2UwJGFub3RoZXJpZCRhbmRhbm90aGVy" } - - it "captures the elasticsearch host" do - expect(subject.elasticsearch_host).to eq("ac31ebb90241773157043c34fd26fd46.us-central1.gcp.cloud.es.io:443") - end - it "captures the kibana host" do - expect(subject.kibana_host).to eq("a4c06230e48c8fce7be88a074a3bb3e0.us-central1.gcp.cloud.es.io:443") - end - it "captures the remaining identifiers" do - expect(subject.other_identifiers).to eq(["anotherid", "andanother"]) - end - end - - describe "when given acceptable input (with empty kibana uuid), the accessors:" do - let(:input) { "a-test:ZWNlLmhvbWUubGFuJHRlc3Qk" } # ece.home.lan$test$ - - it '#original has a value' do - expect(subject.original).to eq(input) - end - it '#decoded has a value' do - expect(subject.decoded).to eq("ece.home.lan$test$") - end - it '#label has a value' do - expect(subject.label).to eq("a-test") - end - it '#elasticsearch_host has a value' do - expect(subject.elasticsearch_host).to eq("test.ece.home.lan:443") - end - it '#elasticsearch_scheme has a value' do - expect(subject.elasticsearch_scheme).to eq("https") - end - it '#kibana_host has a value' do - # NOTE: kibana part is not relevant -> this is how python/beats(go) code behaves - expect(subject.kibana_host).to eq(".ece.home.lan:443") - end - it '#kibana_scheme has a value' do - expect(subject.kibana_scheme).to eq("https") - end - it '#to_s has a value of #decoded' do - expect(subject.to_s).to eq(subject.decoded) - end - end - - describe "a lengthy real-world input, the accessors:" do - let(:input) do - "ZWFzdHVzMi5henVyZS5lbGFzdGljLWNsb3VkLmNvbTo5MjQzJDQwYjM0MzExNmNmYTRlYmNiNzZjMTFlZTIzMjlmOTJkJDQzZDA5MjUyNTAyYzQxODlhMzc2ZmQwY2YyY2QwODQ4" - # eastus2.azure.elastic-cloud.com:9243$40b343116cfa4ebcb76c11ee2329f92d$43d09252502c4189a376fd0cf2cd0848 - end - - it '#original has a value' do - expect(subject.original).to eq(input) - end - it '#decoded has a value' do - expect(subject.decoded).to eq("eastus2.azure.elastic-cloud.com:9243$40b343116cfa4ebcb76c11ee2329f92d$43d09252502c4189a376fd0cf2cd0848") - end - it '#label has a value' do - expect(subject.label).to eq("") - end - it '#elasticsearch_host has a value' do - expect(subject.elasticsearch_host).to eq("40b343116cfa4ebcb76c11ee2329f92d.eastus2.azure.elastic-cloud.com:9243") - end - it '#kibana_host has a value' do - expect(subject.kibana_host).to eq("43d09252502c4189a376fd0cf2cd0848.eastus2.azure.elastic-cloud.com:9243") - end - it '#to_s has a value of #decoded' do - expect(subject.to_s).to eq(subject.decoded) - end - end -end diff --git a/logstash-core/src/main/java/org/logstash/util/CloudSettingId.java b/logstash-core/src/main/java/org/logstash/util/CloudSettingId.java new file mode 100644 index 000000000..c51104908 --- /dev/null +++ b/logstash-core/src/main/java/org/logstash/util/CloudSettingId.java @@ -0,0 +1,191 @@ +/* + * 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. + */ + +package org.logstash.util; + +import java.nio.charset.StandardCharsets; +import java.util.Arrays; +import java.util.Base64; + +/* + * The constructor is expecting a 'cloud.id', a string in 2 variants. + * 1 part example: 'dXMtZWFzdC0xLmF3cy5mb3VuZC5pbyRub3RhcmVhbCRpZGVudGlmaWVy' + * 2 part example: 'foobar:dXMtZWFzdC0xLmF3cy5mb3VuZC5pbyRub3RhcmVhbCRpZGVudGlmaWVy' + * The two part variant has a 'label' prepended with a colon separator. The label is not encoded. + * The 1 part (or second section of the 2 part variant) is base64 encoded. + * The original string before encoding has three segments separated by a dollar sign. + * e.g. 'us-east-1.aws.found.io$notareal$identifier' + * The first segment is the cloud base url, e.g. 'us-east-1.aws.found.io' + * The second segment is the elasticsearch host identifier, e.g. 'notareal' + * The third segment is the kibana host identifier, e.g. 'identifier' + * The 'cloud.id' value decoded into the various fields. + */ +public class CloudSettingId { + + private static class HostAndPort { + static final HostAndPort NO_HOST = new HostAndPort("", null); + private final String host; + private final String port; + + private HostAndPort(String host, String port) { + this.host = host; + this.port = port; + } + + String portOrDefault(String defaultPort) { + return port == null ? defaultPort : port; + } + + static HostAndPort parseHostAndPort(String part, String guidanceMessageWhenHostEqualsUndefined) { + final String[] hostParts = part.split(":"); + String host = hostParts[0]; + if ("undefined".equals(host)) { + throw new IllegalArgumentException(guidanceMessageWhenHostEqualsUndefined); + } + String port = null; + if (hostParts.length > 1) { + port = hostParts[1]; + } + return new HostAndPort(host, port); + } + } + + public static final String DOT_SEPARATOR = "."; + public static final String CLOUD_PORT = "443"; + + private String original; + private String decoded; + private String label; + private String elasticsearchScheme; + private String elasticsearchHost; + private String elasticsearchPort; + private String kibanaScheme; + private String kibanaHost; + private String kibanaPort; + private String[] otherIdentifiers = new String[0]; + + public CloudSettingId(String value) { + if (value == null) { + return; + } + original = value; + final String[] parts = original.split(":"); + label = parts[0]; + String encoded = null; + if (parts.length > 1) { + encoded = parts[1]; + } + if (encoded == null || encoded.isEmpty()) { + try { + decoded = new String(Base64.getUrlDecoder().decode(label), StandardCharsets.UTF_8); + } catch (IllegalArgumentException iaex) { + decoded = ""; + } + label = ""; + } else { + try { + decoded = new String(Base64.getUrlDecoder().decode(encoded), StandardCharsets.UTF_8); + } catch (IllegalArgumentException iaex) { + decoded = ""; + } + } + long separatorCount = decoded.chars().filter(c -> c == '$').count(); + if (separatorCount < 2) { + throw new IllegalArgumentException("Cloud Id, after decoding, is invalid. Format: '$$'. Received: \"" + decoded + "\"."); + } + final String[] segments = decoded.split("\\$"); + if (Arrays.stream(segments).anyMatch(String::isEmpty)) { + throw new IllegalArgumentException("Cloud Id, after decoding, is invalid. Format: '$$'. Received: \"" + decoded + "\"."); + } + String cloudBase = segments[0]; + String cloudHost = DOT_SEPARATOR + cloudBase; + final String[] hostParts = cloudHost.split(":"); + final HostAndPort cloud = new HostAndPort(hostParts[0], hostParts.length > 1 ? hostParts[1] : CLOUD_PORT); + + final HostAndPort elasticsearch = HostAndPort.parseHostAndPort(segments[1], "Cloud Id, after decoding, elasticsearch segment is 'undefined', literally."); + elasticsearchPort = elasticsearch.portOrDefault(cloud.port); + elasticsearchHost = elasticsearch.host + cloud.host + ":" + elasticsearchPort; + elasticsearchScheme = "https"; + + final HostAndPort kibana; + if (segments.length > 2) { + kibana = HostAndPort.parseHostAndPort(segments[2], "Cloud Id, after decoding, the kibana segment is 'undefined', literally. You may need to enable Kibana in the Cloud UI."); + } else { + // non-sense really to have '.my-host:443' but we're mirroring others + kibana = HostAndPort.NO_HOST; + } + kibanaPort = kibana.portOrDefault(cloud.port); + kibanaHost = kibana.host + cloud.host + ":" + kibanaPort; + kibanaScheme = "https"; + + if (segments.length > 3) { + otherIdentifiers = Arrays.copyOfRange(segments, 3, segments.length); + } + } + + public String getOriginal() { + return original; + } + + public String getDecoded() { + return decoded; + } + + public String getLabel() { + return label; + } + + public String getElasticsearchScheme() { + return elasticsearchScheme; + } + + public String getElasticsearchHost() { + return elasticsearchHost; + } + + public String getElasticsearchPort() { + return elasticsearchPort; + } + + public String getKibanaScheme() { + return kibanaScheme; + } + + public String getKibanaHost() { + return kibanaHost; + } + + public String getKibanaPort() { + return kibanaPort; + } + + public String[] getOtherIdentifiers() { + return otherIdentifiers; + } + + @Override + public String toString() { + return decoded; + } + + public static String cloudIdEncode(String... args) { + final String joinedArgs = String.join("$", args); + return Base64.getUrlEncoder().encodeToString(joinedArgs.getBytes()); + } +} diff --git a/logstash-core/src/test/java/org/logstash/util/CloudSettingIdTest.java b/logstash-core/src/test/java/org/logstash/util/CloudSettingIdTest.java new file mode 100644 index 000000000..0525d6bbe --- /dev/null +++ b/logstash-core/src/test/java/org/logstash/util/CloudSettingIdTest.java @@ -0,0 +1,194 @@ +/* + * 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. + */ + +package org.logstash.util; + +import org.junit.Before; +import org.junit.Rule; +import org.junit.Test; +import org.junit.rules.ExpectedException; + +import static org.junit.Assert.*; + +public class CloudSettingIdTest { + + private String input = "foobar:dXMtZWFzdC0xLmF3cy5mb3VuZC5pbyRub3RhcmVhbCRpZGVudGlmaWVy"; + private CloudSettingId sut; + + @Rule + public ExpectedException exceptionRule = ExpectedException.none(); + + @Before + public void setUp() { + sut = new CloudSettingId(input); + } + + // when given unacceptable input + @Test + public void testNullInputDoenstThrowAnException() { + new CloudSettingId(null); + } + + @Test + public void testNullInputMakesAllGettersReturnNull() { + sut = new CloudSettingId(null); + assertNull(sut.getOriginal()); + assertNull(sut.getDecoded()); + assertNull(sut.getLabel()); + assertNull(sut.getElasticsearchHost()); + assertNull(sut.getKibanaHost()); + assertNull(sut.getElasticsearchScheme()); + assertNull(sut.getKibanaScheme()); + } + + @Test + public void testThrowExceptionWhenMalformedValueIsGiven() { + String[] raw = new String[] {"first", "second"}; + String encoded = CloudSettingId.cloudIdEncode(raw); + exceptionRule.expect(IllegalArgumentException.class); + exceptionRule.expectMessage("Cloud Id, after decoding, is invalid. Format: '$$'. Received: \"" + String.join("$", raw) + "\"."); + + new CloudSettingId(encoded); + } + + @Test + public void testThrowExceptionWhenAtLeatOneSegmentIsEmpty() { + String[] raw = new String[] {"first", "", "third"}; + String encoded = CloudSettingId.cloudIdEncode(raw); + exceptionRule.expect(IllegalArgumentException.class); + exceptionRule.expectMessage("Cloud Id, after decoding, is invalid. Format: '$$'. Received: \"" + String.join("$", raw) + "\"."); + + new CloudSettingId(encoded); + } + + @Test + public void testThrowExceptionWhenElasticSegmentSegmentIsUndefined() { + String[] raw = new String[] {"us-east-1.aws.found.io", "undefined", "my-kibana"}; + String encoded = CloudSettingId.cloudIdEncode(raw); + exceptionRule.expect(IllegalArgumentException.class); + exceptionRule.expectMessage("Cloud Id, after decoding, elasticsearch segment is 'undefined', literally."); + + new CloudSettingId(encoded); + } + + @Test + public void testThrowExceptionWhenKibanaSegmentSegmentIsUndefined() { + String[] raw = new String[] {"us-east-1.aws.found.io", "my-elastic-cluster", "undefined"}; + String encoded = CloudSettingId.cloudIdEncode(raw); + exceptionRule.expect(IllegalArgumentException.class); + exceptionRule.expectMessage("Cloud Id, after decoding, the kibana segment is 'undefined', literally. You may need to enable Kibana in the Cloud UI."); + + new CloudSettingId(encoded); + } + + // without a label + @Test + public void testDecodingWithoutLabelSegment() { + sut = new CloudSettingId("dXMtZWFzdC0xLmF3cy5mb3VuZC5pbyRub3RhcmVhbCRpZGVudGlmaWVy"); + + assertEquals("#label is empty", "", sut.getLabel()); + assertEquals("#decode is set", "us-east-1.aws.found.io$notareal$identifier", sut.getDecoded()); + } + + // when given acceptable input, the accessors: + @Test + public void testAccessorsWithAcceptableInput() { + assertEquals("#original has a value", input, sut.getOriginal()); + assertEquals("#decoded has a value", "us-east-1.aws.found.io$notareal$identifier", sut.getDecoded()); + assertEquals("#label has a value", "foobar", sut.getLabel()); + assertEquals("#elasticsearch_host has a value", "notareal.us-east-1.aws.found.io:443", sut.getElasticsearchHost()); + assertEquals("#elasticsearch_scheme has a value", "https", sut.getElasticsearchScheme()); + assertEquals("#kibana_host has a value", "identifier.us-east-1.aws.found.io:443", sut.getKibanaHost()); + assertEquals("#kibana_scheme has a value", "https", sut.getKibanaScheme()); + assertEquals("#to_s has a value of #decoded", sut.toString(), sut.getDecoded()); + } + + @Test + public void testWhenCloudIdContainsPortDescriptionForESAndKibana() { + sut = new CloudSettingId("different-es-kb-port:dXMtY2VudHJhbDEuZ2NwLmNsb3VkLmVzLmlvJGFjMzFlYmI5MDI0MTc3MzE1NzA0M2MzNGZkMjZmZDQ2OjkyNDMkYTRjMDYyMzBlNDhjOGZjZTdiZTg4YTA3NGEzYmIzZTA6OTI0NA=="); + + assertEquals("decodes the elasticsearch port corretly", "ac31ebb90241773157043c34fd26fd46.us-central1.gcp.cloud.es.io:9243", sut.getElasticsearchHost()); + assertEquals("decodes the kibana port corretly", "a4c06230e48c8fce7be88a074a3bb3e0.us-central1.gcp.cloud.es.io:9244", sut.getKibanaHost()); + } + + @Test + public void testWhenCloudIdContainsCloudPort() { + sut = new CloudSettingId("custom-port:dXMtY2VudHJhbDEuZ2NwLmNsb3VkLmVzLmlvOjkyNDMkYWMzMWViYjkwMjQxNzczMTU3MDQzYzM0ZmQyNmZkNDYkYTRjMDYyMzBlNDhjOGZjZTdiZTg4YTA3NGEzYmIzZTA="); + + assertEquals("decodes the elasticsearch port corretly", "ac31ebb90241773157043c34fd26fd46.us-central1.gcp.cloud.es.io:9243", sut.getElasticsearchHost()); + assertEquals("decodes the kibana port corretly", "a4c06230e48c8fce7be88a074a3bb3e0.us-central1.gcp.cloud.es.io:9243", sut.getKibanaHost()); + } + + @Test + public void testWhenCloudIdOnlyDefinesKibanaPort() { + sut = new CloudSettingId("only-kb-set:dXMtY2VudHJhbDEuZ2NwLmNsb3VkLmVzLmlvJGFjMzFlYmI5MDI0MTc3MzE1NzA0M2MzNGZkMjZmZDQ2JGE0YzA2MjMwZTQ4YzhmY2U3YmU4OGEwNzRhM2JiM2UwOjkyNDQ="); + + assertEquals("defaults the elasticsearch port to 443", "ac31ebb90241773157043c34fd26fd46.us-central1.gcp.cloud.es.io:443", sut.getElasticsearchHost()); + assertEquals("decodes the kibana port corretly", "a4c06230e48c8fce7be88a074a3bb3e0.us-central1.gcp.cloud.es.io:9244", sut.getKibanaHost()); + } + + @Test + public void testWhenCloudIdDefinesCloudPortAndKibanaPort() { + sut = new CloudSettingId("host-and-kb-set:dXMtY2VudHJhbDEuZ2NwLmNsb3VkLmVzLmlvOjkyNDMkYWMzMWViYjkwMjQxNzczMTU3MDQzYzM0ZmQyNmZkNDYkYTRjMDYyMzBlNDhjOGZjZTdiZTg4YTA3NGEzYmIzZTA6OTI0NA=="); + + assertEquals("sets the elasticsearch port to cloud port", "ac31ebb90241773157043c34fd26fd46.us-central1.gcp.cloud.es.io:9243", sut.getElasticsearchHost()); + assertEquals("overrides cloud port with the kibana port", "a4c06230e48c8fce7be88a074a3bb3e0.us-central1.gcp.cloud.es.io:9244", sut.getKibanaHost()); + } + + @Test + public void testWhenCloudIdDefinesExtraData() { + sut = new CloudSettingId("extra-items:dXMtY2VudHJhbDEuZ2NwLmNsb3VkLmVzLmlvJGFjMzFlYmI5MDI0MTc3MzE1NzA0M2MzNGZkMjZmZDQ2JGE0YzA2MjMwZTQ4YzhmY2U3YmU4OGEwNzRhM2JiM2UwJGFub3RoZXJpZCRhbmRhbm90aGVy"); + + assertEquals("captures the elasticsearch host", "ac31ebb90241773157043c34fd26fd46.us-central1.gcp.cloud.es.io:443", sut.getElasticsearchHost()); + assertEquals("captures the kibana host", "a4c06230e48c8fce7be88a074a3bb3e0.us-central1.gcp.cloud.es.io:443", sut.getKibanaHost()); + assertArrayEquals("captures the remaining identifiers", new String[] {"anotherid", "andanother"}, sut.getOtherIdentifiers()); + } + + // when given acceptable input (with empty kibana uuid), the accessors: + @Test + public void testGivenAcceptableInputEmptyKibanaUUID() { + input = "a-test:ZWNlLmhvbWUubGFuJHRlc3Qk"; + sut = new CloudSettingId(input); // ece.home.lan$test$ + + assertEquals("#original has a value", input, sut.getOriginal()); + assertEquals("#decoded has a value", "ece.home.lan$test$", sut.getDecoded()); + assertEquals("#label has a value", "a-test", sut.getLabel()); + assertEquals("#elasticsearch_host has a value", "test.ece.home.lan:443", sut.getElasticsearchHost()); + assertEquals("#elasticsearch_scheme has a value", "https", sut.getElasticsearchScheme()); + // NOTE: kibana part is not relevant -> this is how python/beats(go) code behaves + assertEquals("#kibana_host has a value", ".ece.home.lan:443", sut.getKibanaHost()); + assertEquals("#kibana_scheme has a value", "https", sut.getKibanaScheme()); + assertEquals("#toString has a value of #decoded", sut.getDecoded(), sut.toString()); + } + + // a lengthy real-world input, the accessors: + @Test + public void testWithRealWorldInput() { + //eastus2.azure.elastic-cloud.com:9243$40b343116cfa4ebcb76c11ee2329f92d$43d09252502c4189a376fd0cf2cd0848 + input = "ZWFzdHVzMi5henVyZS5lbGFzdGljLWNsb3VkLmNvbTo5MjQzJDQwYjM0MzExNmNmYTRlYmNiNzZjMTFlZTIzMjlmOTJkJDQzZDA5MjUyNTAyYzQxODlhMzc2ZmQwY2YyY2QwODQ4"; + sut = new CloudSettingId(input); + + assertEquals("#original has a value", input, sut.getOriginal()); + assertEquals("#decoded has a value", "eastus2.azure.elastic-cloud.com:9243$40b343116cfa4ebcb76c11ee2329f92d$43d09252502c4189a376fd0cf2cd0848", sut.getDecoded()); + assertEquals("#label has a value", "", sut.getLabel()); + assertEquals("#elasticsearch_host has a value", "40b343116cfa4ebcb76c11ee2329f92d.eastus2.azure.elastic-cloud.com:9243", sut.getElasticsearchHost()); + assertEquals("#kibana_host has a value", "43d09252502c4189a376fd0cf2cd0848.eastus2.azure.elastic-cloud.com:9243", sut.getKibanaHost()); + assertEquals("#toString has a value of #decoded", sut.getDecoded(), sut.toString()); + } +} From 44fa8498529e4c2649220e304c82196625167f1c Mon Sep 17 00:00:00 2001 From: Rob Bavey Date: Wed, 18 Nov 2020 16:10:48 -0500 Subject: [PATCH 0634/1126] [7x backport] Fix docker image metadata (#12450) Clean backport of #12447, #12452 This commit fixes two issues with the docker metadata: Removes non-OCI compliant freeform metadata labels Uses a consistent build date for all the docker images and dockerfiles Additionally, this commit adds a `build_docker_ubi8` rake task to enable `ci/docker_acceptance_tests.sh` to run with no options to build all docker images for the architecture. Removing the freeform description labels left the container metadata without a description label. This commit adds a description under the "org.opencontainers.image.description" label --- docker/Makefile | 9 ++++----- docker/templates/Dockerfile.j2 | 9 ++------- qa/docker/shared_examples/image_metadata.rb | 22 ++++++--------------- rakelib/artifacts.rake | 15 +++++++++++--- 4 files changed, 24 insertions(+), 31 deletions(-) diff --git a/docker/Makefile b/docker/Makefile index d2533058a..9c7671ae1 100644 --- a/docker/Makefile +++ b/docker/Makefile @@ -27,7 +27,6 @@ HTTPD ?= logstash-docker-artifact-server FIGLET := pyfiglet -w 160 -f puffy all: build-from-local-artifacts build-from-local-oss-artifacts public-dockerfiles -DATE:= $(shell date -u +'%Y-%m-%dT%H:%M:%S.%sZ') lint: venv flake8 tests @@ -89,7 +88,7 @@ public-dockerfiles: public-dockerfiles_oss public_dockerfiles_full public_docker public-dockerfiles_full: venv templates/Dockerfile.j2 docker_paths $(COPY_FILES) jinja2 \ - -D created_date='$(DATE)' \ + -D created_date='$(BUILD_DATE)' \ -D elastic_version='$(ELASTIC_VERSION)' \ -D arch='${ARCHITECTURE}' \ -D version_tag='$(VERSION_TAG)' \ @@ -103,7 +102,7 @@ public-dockerfiles_full: venv templates/Dockerfile.j2 docker_paths $(COPY_FILES) public-dockerfiles_oss: venv templates/Dockerfile.j2 docker_paths $(COPY_FILES) jinja2 \ - -D created_date='$(DATE)' \ + -D created_date='$(BUILD_DATE)' \ -D elastic_version='$(ELASTIC_VERSION)' \ -D arch='${ARCHITECTURE}' \ -D version_tag='$(VERSION_TAG)' \ @@ -117,7 +116,7 @@ public-dockerfiles_oss: venv templates/Dockerfile.j2 docker_paths $(COPY_FILES) public-dockerfiles_ubi8: venv templates/Dockerfile.j2 docker_paths $(COPY_FILES) jinja2 \ - -D created_date='$(DATE)' \ + -D created_date='$(BUILD_DATE)' \ -D elastic_version='$(ELASTIC_VERSION)' \ -D arch='${ARCHITECTURE}' \ -D version_tag='$(VERSION_TAG)' \ @@ -173,7 +172,7 @@ env2yaml: golang dockerfile: venv templates/Dockerfile.j2 $(foreach FLAVOR, $(IMAGE_FLAVORS), \ jinja2 \ - -D created_date='$(DATE)' \ + -D created_date='$(BUILD_DATE)' \ -D elastic_version='$(ELASTIC_VERSION)' \ -D arch='${ARCHITECTURE}' \ -D version_tag='$(VERSION_TAG)' \ diff --git a/docker/templates/Dockerfile.j2 b/docker/templates/Dockerfile.j2 index ee48872c5..a3423bf1a 100644 --- a/docker/templates/Dockerfile.j2 +++ b/docker/templates/Dockerfile.j2 @@ -92,16 +92,11 @@ LABEL org.label-schema.schema-version="1.0" \ org.opencontainers.image.version="{{ elastic_version }}" \ org.label-schema.url="https://www.elastic.co/products/logstash" \ org.label-schema.vcs-url="https://github.com/elastic/logstash" \ - license="{{ license }}" \ org.label-schema.license="{{ license }}" \ org.opencontainers.image.licenses="{{ license }}" \ + org.opencontainers.image.description="Logstash is a free and open server-side data processing pipeline that ingests data from a multitude of sources, transforms it, and then sends it to your favorite 'stash.'" \ org.label-schema.build-date={{ created_date }} \ - org.opencontainers.image.created={{ created_date }} \ - description="Logstash is a free and open server-side data processing pipeline that ingests data from a multitude of sources, transforms it, and then sends it to your favorite 'stash.'" \ - name="logstash" \ - maintainer="info@elastic.co" \ - summary="Logstash is a free and open server-side data processing pipeline that ingests data from a multitude of sources, transforms it, and then sends it to your favorite 'stash.'" \ - vendor="Elastic" + org.opencontainers.image.created={{ created_date }} ENTRYPOINT ["/usr/local/bin/docker-entrypoint"] diff --git a/qa/docker/shared_examples/image_metadata.rb b/qa/docker/shared_examples/image_metadata.rb index 10dccd329..5839a6e8d 100644 --- a/qa/docker/shared_examples/image_metadata.rb +++ b/qa/docker/shared_examples/image_metadata.rb @@ -13,34 +13,24 @@ shared_examples_for 'the metadata is set correctly' do |flavor| expect(@image.json['Architecture']).to have_correct_architecture end - %w(license org.label-schema.license org.opencontainers.image.licenses).each do |label| + %w(org.label-schema.license org.opencontainers.image.licenses).each do |label| it "should set the license label #{label} correctly" do expect(@labels[label]).to have_correct_license_label(flavor) end end - %w(name org.label-schema.name org.opencontainers.image.title).each do |label| + %w(org.label-schema.name org.opencontainers.image.title).each do |label| it "should set the name label #{label} correctly" do expect(@labels[label]).to eql "logstash" end end - %w(maintainer).each do |label| - it "should set the name label #{label} correctly" do - expect(@labels[label]).to eql "info@elastic.co" - end + it "should set the vendor label org.opencontainers.image.vendor correctly" do + expect(@labels['org.opencontainers.image.vendor']).to eql "Elastic" end - %w(description summary).each do |label| - it "should set the name label #{label} correctly" do - expect(@labels[label]).to eql "Logstash is a free and open server-side data processing pipeline that ingests data from a multitude of sources, transforms it, and then sends it to your favorite 'stash.'" - end - end - - %w(vendor org.opencontainers.image.vendor).each do |label| - it "should set the vendor label #{label} correctly" do - expect(@labels[label]).to eql "Elastic" - end + it "should set the description label org.opencontainers.image.description correctly" do + expect(@labels['org.opencontainers.image.description']).to eql "Logstash is a free and open server-side data processing pipeline that ingests data from a multitude of sources, transforms it, and then sends it to your favorite 'stash.'" end %w(org.label-schema.version org.opencontainers.image.version).each do |label| diff --git a/rakelib/artifacts.rake b/rakelib/artifacts.rake index 575dc9128..b98f0b480 100644 --- a/rakelib/artifacts.rake +++ b/rakelib/artifacts.rake @@ -336,14 +336,21 @@ namespace "artifact" do Rake::Task["artifact:dockerfile_oss"].invoke end + task "build_docker_ubi8" => [:generate_build_metadata] do + Rake::Task["artifact:docker_ubi8"].invoke + Rake::Task["artifact:dockerfile_ubi8"].invoke + end + task "generate_build_metadata" do return if defined?(BUILD_METADATA_FILE) BUILD_METADATA_FILE = Tempfile.new('build.rb') + BUILD_DATE=Time.now.iso8601 build_info = { - "build_date" => Time.now.iso8601, + "build_date" => BUILD_DATE, "build_sha" => `git rev-parse HEAD`.chomp, "build_snapshot" => SNAPSHOT_BUILD } + metadata = [ "# encoding: utf-8", "BUILD_INFO = #{build_info}" ] IO.write(BUILD_METADATA_FILE.path, metadata.join("\n")) end @@ -690,7 +697,8 @@ namespace "artifact" do env = { "ARTIFACTS_DIR" => ::File.join(Dir.pwd, "build"), "RELEASE" => ENV["RELEASE"], - "VERSION_QUALIFIER" => VERSION_QUALIFIER + "VERSION_QUALIFIER" => VERSION_QUALIFIER, + "BUILD_DATE" => BUILD_DATE } Dir.chdir("docker") do |dir| system(env, "make build-from-local-#{flavor}-artifacts") @@ -701,7 +709,8 @@ namespace "artifact" do env = { "ARTIFACTS_DIR" => ::File.join(Dir.pwd, "build"), "RELEASE" => ENV["RELEASE"], - "VERSION_QUALIFIER" => VERSION_QUALIFIER + "VERSION_QUALIFIER" => VERSION_QUALIFIER, + "BUILD_DATE" => BUILD_DATE } Dir.chdir("docker") do |dir| system(env, "make public-dockerfiles_#{flavor}") From 747c38d6dbc70c1da62ea62668505eb7b5a23bfa Mon Sep 17 00:00:00 2001 From: andsel Date: Mon, 16 Nov 2020 11:38:23 +0100 Subject: [PATCH 0635/1126] Move code of CloudSettingAuth to Java - moved the class's code - moved spec tests to JUnit tests (cherry picked from commit b0920eb6fff9bee21a9c2fd54c452adfe229ad71) --- .../lib/logstash/util/cloud_setting_auth.rb | 30 +------ .../spec/logstash/settings/modules_spec.rb | 42 ---------- .../co/elastic/logstash/api/Password.java | 4 + .../org/logstash/util/CloudSettingAuth.java | 60 ++++++++++++++ .../logstash/util/CloudSettingAuthTest.java | 79 +++++++++++++++++++ 5 files changed, 146 insertions(+), 69 deletions(-) create mode 100644 logstash-core/src/main/java/org/logstash/util/CloudSettingAuth.java create mode 100644 logstash-core/src/test/java/org/logstash/util/CloudSettingAuthTest.java diff --git a/logstash-core/lib/logstash/util/cloud_setting_auth.rb b/logstash-core/lib/logstash/util/cloud_setting_auth.rb index c36672dd4..1ff525287 100644 --- a/logstash-core/lib/logstash/util/cloud_setting_auth.rb +++ b/logstash-core/lib/logstash/util/cloud_setting_auth.rb @@ -15,30 +15,6 @@ # specific language governing permissions and limitations # under the License. -require "logstash/util/password" - -module LogStash module Util class CloudSettingAuth - attr_reader :original, :username, :password - - def initialize(value) - return if value.nil? - - unless value.is_a?(String) - raise ArgumentError.new("Cloud Auth must be String. Received: #{value.class}") - end - @original = value - @username, sep, password = @original.partition(":") - if @username.empty? || sep.empty? || password.empty? - raise ArgumentError.new("Cloud Auth username and password format should be \":\".") - end - @password = LogStash::Util::Password.new(password) - end - - def to_s - "#{@username}:#{@password}" - end - - def inspect - to_s - end -end end end +module LogStash; module Util + java_import org.logstash.util.CloudSettingAuth +end; end diff --git a/logstash-core/spec/logstash/settings/modules_spec.rb b/logstash-core/spec/logstash/settings/modules_spec.rb index 1999e7232..8d1a64b95 100644 --- a/logstash-core/spec/logstash/settings/modules_spec.rb +++ b/logstash-core/spec/logstash/settings/modules_spec.rb @@ -97,46 +97,4 @@ describe LogStash::Setting::Modules do end end end - - describe "Cloud.Auth" do - subject { described_class.new("mycloudauth", LogStash::Util::CloudSettingAuth) } - context "when given a string without a separator or a password" do - it "should raise an exception" do - expect { subject.set("foobarbaz") }.to raise_error(ArgumentError, /Cloud Auth username and password format should be/) - end - end - - context "when given a string without a password" do - it "should raise an exception" do - expect { subject.set("foo:") }.to raise_error(ArgumentError, /Cloud Auth username and password format should be/) - end - end - - context "when given a string without a username" do - it "should raise an exception" do - expect { subject.set(":bar") }.to raise_error(ArgumentError, /Cloud Auth username and password format should be/) - end - end - - context "when given a string which is empty" do - it "should raise an exception" do - expect { subject.set("") }.to raise_error(ArgumentError, /Cloud Auth username and password format should be/) - end - end - - context "when given a nil" do - it "should not raise an error" do - expect { subject.set(nil) }.to_not raise_error - end - end - - context "when given a string which is a cloud auth" do - it "should set the string" do - expect { subject.set("frodo:baggins") }.to_not raise_error - expect(subject.value.username).to eq("frodo") - expect(subject.value.password.value).to eq("baggins") - expect(subject.value.to_s).to eq("frodo:") - end - end - end end diff --git a/logstash-core/src/main/java/co/elastic/logstash/api/Password.java b/logstash-core/src/main/java/co/elastic/logstash/api/Password.java index a80ae6378..535a745fc 100644 --- a/logstash-core/src/main/java/co/elastic/logstash/api/Password.java +++ b/logstash-core/src/main/java/co/elastic/logstash/api/Password.java @@ -39,4 +39,8 @@ public class Password { public String toString() { return ""; } + + public String getValue() { + return getPassword(); + } } diff --git a/logstash-core/src/main/java/org/logstash/util/CloudSettingAuth.java b/logstash-core/src/main/java/org/logstash/util/CloudSettingAuth.java new file mode 100644 index 000000000..c7e41383f --- /dev/null +++ b/logstash-core/src/main/java/org/logstash/util/CloudSettingAuth.java @@ -0,0 +1,60 @@ +/* + * 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. + */ + +package org.logstash.util; + +import co.elastic.logstash.api.Password; + +public class CloudSettingAuth { + + private String original; + private String username; + private Password password; + + public CloudSettingAuth(String value) { + if (value == null) { + return; + } + this.original = value; + final String[] parts = this.original.split(":"); + if (parts.length != 2 || parts[0].isEmpty() || parts[1].isEmpty()) { + throw new IllegalArgumentException("Cloud Auth username and password format should be \":\"."); + } + + this.username = parts[0]; + this.password = new Password(parts[1]); + } + + public String getOriginal() { + return original; + } + + public String getUsername() { + return username; + } + + public Password getPassword() { + return password; + } + + @Override + public String toString() { + return String.join(":", username, password.toString()); + } +} diff --git a/logstash-core/src/test/java/org/logstash/util/CloudSettingAuthTest.java b/logstash-core/src/test/java/org/logstash/util/CloudSettingAuthTest.java new file mode 100644 index 000000000..28bc97ce8 --- /dev/null +++ b/logstash-core/src/test/java/org/logstash/util/CloudSettingAuthTest.java @@ -0,0 +1,79 @@ +/* + * 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. + */ + +package org.logstash.util; + +import org.junit.Rule; +import org.junit.Test; +import org.junit.rules.ExpectedException; + +import static org.junit.Assert.*; + +public class CloudSettingAuthTest { + + @Rule + public ExpectedException exceptionRule = ExpectedException.none(); + + @Test + public void testThrowExceptionWhenGivenStringWithoutSeparatorOrPassword() { + exceptionRule.expect(IllegalArgumentException.class); + exceptionRule.expectMessage("Cloud Auth username and password format should be"); + + new CloudSettingAuth("foobarbaz"); + } + + @Test + public void testThrowExceptionWhenGivenStringWithoutPassword() { + exceptionRule.expect(IllegalArgumentException.class); + exceptionRule.expectMessage("Cloud Auth username and password format should be"); + + new CloudSettingAuth("foo:"); + } + + @Test + public void testThrowExceptionWhenGivenStringWithoutUsername() { + exceptionRule.expect(IllegalArgumentException.class); + exceptionRule.expectMessage("Cloud Auth username and password format should be"); + + new CloudSettingAuth(":bar"); + } + + @Test + public void testThrowExceptionWhenGivenStringWhichIsEmpty() { + exceptionRule.expect(IllegalArgumentException.class); + exceptionRule.expectMessage("Cloud Auth username and password format should be"); + + new CloudSettingAuth(""); + } + + @Test + public void testNullInputDoenstThrowAnException() { + new CloudSettingAuth(null); + } + + + @Test + public void testWhenGivenStringWhichIsCloudAuthSetTheString() { + final CloudSettingAuth sut = new CloudSettingAuth("frodo:baggins"); + assertEquals("frodo", sut.getUsername()); + assertEquals("baggins", sut.getPassword().getValue()); + assertEquals("frodo:", sut.toString()); + } + +} \ No newline at end of file From f37d9a462c6393035c328e3d266501d4f7d6d9c5 Mon Sep 17 00:00:00 2001 From: andsel Date: Thu, 19 Nov 2020 11:27:00 +0100 Subject: [PATCH 0636/1126] Drop Password Ruby class to use only the Java version There is two Password classes that almost does the same thing. One in Ruby (LogStash::Util::Password) and one in Java (co.elastic.logstash.api.Password). This commit drop the the Ruby implementation to import the Java version in the LogStash::Util so that existing Ruby code haven't to be changed, works as it is. (cherry picked from commit ca81a8f4a32457a7c100a4712c7c5a4c9b5c2faa) --- logstash-core/lib/logstash/util/password.rb | 20 +++---------------- .../co/elastic/logstash/api/Password.java | 12 ++++++++++- 2 files changed, 14 insertions(+), 18 deletions(-) diff --git a/logstash-core/lib/logstash/util/password.rb b/logstash-core/lib/logstash/util/password.rb index bb55ff1d0..f1f4dd2d4 100644 --- a/logstash-core/lib/logstash/util/password.rb +++ b/logstash-core/lib/logstash/util/password.rb @@ -17,21 +17,7 @@ # This class exists to quietly wrap a password string so that, when printed or # logged, you don't accidentally print the password itself. -module LogStash module Util class Password - attr_reader :value - public - def initialize(password) - @value = password - end # def initialize - - public - def to_s - return "" - end # def to_s - - public - def inspect - return to_s - end # def inspect -end end end # class LogStash::Util::Password +module LogStash; module Util + java_import "co.elastic.logstash.api.Password" +end; end # class LogStash::Util::Password diff --git a/logstash-core/src/main/java/co/elastic/logstash/api/Password.java b/logstash-core/src/main/java/co/elastic/logstash/api/Password.java index 535a745fc..c89c31557 100644 --- a/logstash-core/src/main/java/co/elastic/logstash/api/Password.java +++ b/logstash-core/src/main/java/co/elastic/logstash/api/Password.java @@ -20,10 +20,14 @@ package co.elastic.logstash.api; +import java.io.Serializable; + /** * Wraps a password string so that it is not inadvertently printed or logged. */ -public class Password { +public class Password implements Serializable { + + private static final long serialVersionUID = -8683271728417419530L; private String password; @@ -40,7 +44,13 @@ public class Password { return ""; } + // Ruby code compatibility, value attribute public String getValue() { return getPassword(); } + + // Ruby code compatibility, inspect method + public String inspect() { + return toString(); + } } From 45099c1b54c0ef4b5e2d165536bcc52fbc308542 Mon Sep 17 00:00:00 2001 From: Colin Surprenant Date: Fri, 20 Nov 2020 10:40:26 -0500 Subject: [PATCH 0637/1126] remove evaluation dir from JRuby bundled did_you_mean gem --- rubyUtils.gradle | 1 + 1 file changed, 1 insertion(+) diff --git a/rubyUtils.gradle b/rubyUtils.gradle index b81762d51..8f55a8e92 100644 --- a/rubyUtils.gradle +++ b/rubyUtils.gradle @@ -276,6 +276,7 @@ tasks.register("downloadAndInstallJRuby", Copy) { exclude "**/stdlib/bundler.rb" exclude "**/bundler-1.16.6/**" exclude "**/bundler-1.16.6.*" + exclude "**/did_you_mean-*/evaluation/**" // licensing issue https://github.com/jruby/jruby/issues/6471 includeEmptyDirs = false into "${projectDir}/vendor/jruby" From e9aabdc3f171d1c6e285da8b4efc9685d3292db4 Mon Sep 17 00:00:00 2001 From: andsel Date: Fri, 20 Nov 2020 19:20:42 +0100 Subject: [PATCH 0638/1126] Fix an API break in CloudSettingsAuth, a Ruby's ArgumentError should be raised. Bring back Ruby specs to double check the change also in Ruby context. (cherry picked from commit 14570d5d86348924906fa09fdbb731d7b6bf557c) --- .../spec/logstash/settings/modules_spec.rb | 42 +++++++++++++++++++ .../org/logstash/util/CloudSettingAuth.java | 3 +- .../logstash/util/CloudSettingAuthTest.java | 8 ++-- 3 files changed, 48 insertions(+), 5 deletions(-) diff --git a/logstash-core/spec/logstash/settings/modules_spec.rb b/logstash-core/spec/logstash/settings/modules_spec.rb index 8d1a64b95..1999e7232 100644 --- a/logstash-core/spec/logstash/settings/modules_spec.rb +++ b/logstash-core/spec/logstash/settings/modules_spec.rb @@ -97,4 +97,46 @@ describe LogStash::Setting::Modules do end end end + + describe "Cloud.Auth" do + subject { described_class.new("mycloudauth", LogStash::Util::CloudSettingAuth) } + context "when given a string without a separator or a password" do + it "should raise an exception" do + expect { subject.set("foobarbaz") }.to raise_error(ArgumentError, /Cloud Auth username and password format should be/) + end + end + + context "when given a string without a password" do + it "should raise an exception" do + expect { subject.set("foo:") }.to raise_error(ArgumentError, /Cloud Auth username and password format should be/) + end + end + + context "when given a string without a username" do + it "should raise an exception" do + expect { subject.set(":bar") }.to raise_error(ArgumentError, /Cloud Auth username and password format should be/) + end + end + + context "when given a string which is empty" do + it "should raise an exception" do + expect { subject.set("") }.to raise_error(ArgumentError, /Cloud Auth username and password format should be/) + end + end + + context "when given a nil" do + it "should not raise an error" do + expect { subject.set(nil) }.to_not raise_error + end + end + + context "when given a string which is a cloud auth" do + it "should set the string" do + expect { subject.set("frodo:baggins") }.to_not raise_error + expect(subject.value.username).to eq("frodo") + expect(subject.value.password.value).to eq("baggins") + expect(subject.value.to_s).to eq("frodo:") + end + end + end end diff --git a/logstash-core/src/main/java/org/logstash/util/CloudSettingAuth.java b/logstash-core/src/main/java/org/logstash/util/CloudSettingAuth.java index c7e41383f..9d89e3e94 100644 --- a/logstash-core/src/main/java/org/logstash/util/CloudSettingAuth.java +++ b/logstash-core/src/main/java/org/logstash/util/CloudSettingAuth.java @@ -20,6 +20,7 @@ package org.logstash.util; import co.elastic.logstash.api.Password; +import org.logstash.RubyUtil; public class CloudSettingAuth { @@ -34,7 +35,7 @@ public class CloudSettingAuth { this.original = value; final String[] parts = this.original.split(":"); if (parts.length != 2 || parts[0].isEmpty() || parts[1].isEmpty()) { - throw new IllegalArgumentException("Cloud Auth username and password format should be \":\"."); + throw RubyUtil.RUBY.newArgumentError("Cloud Auth username and password format should be \":\"."); } this.username = parts[0]; diff --git a/logstash-core/src/test/java/org/logstash/util/CloudSettingAuthTest.java b/logstash-core/src/test/java/org/logstash/util/CloudSettingAuthTest.java index 28bc97ce8..67217d3dc 100644 --- a/logstash-core/src/test/java/org/logstash/util/CloudSettingAuthTest.java +++ b/logstash-core/src/test/java/org/logstash/util/CloudSettingAuthTest.java @@ -32,7 +32,7 @@ public class CloudSettingAuthTest { @Test public void testThrowExceptionWhenGivenStringWithoutSeparatorOrPassword() { - exceptionRule.expect(IllegalArgumentException.class); + exceptionRule.expect(org.jruby.exceptions.ArgumentError.class); exceptionRule.expectMessage("Cloud Auth username and password format should be"); new CloudSettingAuth("foobarbaz"); @@ -40,7 +40,7 @@ public class CloudSettingAuthTest { @Test public void testThrowExceptionWhenGivenStringWithoutPassword() { - exceptionRule.expect(IllegalArgumentException.class); + exceptionRule.expect(org.jruby.exceptions.ArgumentError.class); exceptionRule.expectMessage("Cloud Auth username and password format should be"); new CloudSettingAuth("foo:"); @@ -48,7 +48,7 @@ public class CloudSettingAuthTest { @Test public void testThrowExceptionWhenGivenStringWithoutUsername() { - exceptionRule.expect(IllegalArgumentException.class); + exceptionRule.expect(org.jruby.exceptions.ArgumentError.class); exceptionRule.expectMessage("Cloud Auth username and password format should be"); new CloudSettingAuth(":bar"); @@ -56,7 +56,7 @@ public class CloudSettingAuthTest { @Test public void testThrowExceptionWhenGivenStringWhichIsEmpty() { - exceptionRule.expect(IllegalArgumentException.class); + exceptionRule.expect(org.jruby.exceptions.ArgumentError.class); exceptionRule.expectMessage("Cloud Auth username and password format should be"); new CloudSettingAuth(""); From fee5c72022d61f232fab7a6db031bf06a66df335 Mon Sep 17 00:00:00 2001 From: andsel Date: Fri, 20 Nov 2020 19:14:26 +0100 Subject: [PATCH 0639/1126] Fix an API break, a Ruby's ArgumentError should be raised. Reestablished Ruby specs to test moved code. (cherry picked from commit 09f995776e930e823f1e3e37eaf1029ba1e72139) --- .../spec/logstash/settings/modules_spec.rb | 8 +- .../logstash/util/cloud_setting_id_spec.rb | 218 ++++++++++++++++++ .../org/logstash/util/CloudSettingId.java | 8 +- .../org/logstash/util/CloudSettingIdTest.java | 8 +- 4 files changed, 231 insertions(+), 11 deletions(-) create mode 100644 logstash-core/spec/logstash/util/cloud_setting_id_spec.rb diff --git a/logstash-core/spec/logstash/settings/modules_spec.rb b/logstash-core/spec/logstash/settings/modules_spec.rb index 1999e7232..dd3404c64 100644 --- a/logstash-core/spec/logstash/settings/modules_spec.rb +++ b/logstash-core/spec/logstash/settings/modules_spec.rb @@ -50,26 +50,26 @@ describe LogStash::Setting::Modules do subject { described_class.new("mycloudid", LogStash::Util::CloudSettingId) } context "when given a string which is not a cloud id" do it "should raise an exception" do - expect { subject.set("foobarbaz") }.to raise_error(IllegalArgumentException, /Cloud Id.*is invalid/) + expect { subject.set("foobarbaz") }.to raise_error(ArgumentError, /Cloud Id.*is invalid/) end end context "when given a string which is empty" do it "should raise an exception" do - expect { subject.set("") }.to raise_error(IllegalArgumentException, /Cloud Id.*is invalid/) + expect { subject.set("") }.to raise_error(ArgumentError, /Cloud Id.*is invalid/) end end context "when given a string which is has environment prefix only" do it "should raise an exception" do - expect { subject.set("testing:") }.to raise_error(IllegalArgumentException, /Cloud Id.*is invalid/) + expect { subject.set("testing:") }.to raise_error(ArgumentError, /Cloud Id.*is invalid/) end end context "when given a badly formatted encoded id" do it "should not raise an error" do encoded = Base64.urlsafe_encode64("foo$$bal") - expect { subject.set(encoded) }.to raise_error(IllegalArgumentException, "Cloud Id, after decoding, is invalid. Format: '$$'. Received: \"foo$$bal\".") + expect { subject.set(encoded) }.to raise_error(ArgumentError, "Cloud Id, after decoding, is invalid. Format: '$$'. Received: \"foo$$bal\".") end end diff --git a/logstash-core/spec/logstash/util/cloud_setting_id_spec.rb b/logstash-core/spec/logstash/util/cloud_setting_id_spec.rb new file mode 100644 index 000000000..8217327dd --- /dev/null +++ b/logstash-core/spec/logstash/util/cloud_setting_id_spec.rb @@ -0,0 +1,218 @@ +# 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 "spec_helper" +require "logstash/util/cloud_setting_id" + +describe LogStash::Util::CloudSettingId do + let(:input) { "foobar:dXMtZWFzdC0xLmF3cy5mb3VuZC5pbyRub3RhcmVhbCRpZGVudGlmaWVy" } + subject { described_class.new(input) } + + describe "when given unacceptable input" do + it "a nil input does not raise an exception" do + expect{described_class.new(nil)}.not_to raise_exception + end + it "when given a nil input, the accessors are all nil" do + cloud_id = described_class.new(nil) + expect(cloud_id.original).to be_nil + expect(cloud_id.decoded).to be_nil + expect(cloud_id.label).to be_nil + expect(cloud_id.elasticsearch_host).to be_nil + expect(cloud_id.kibana_host).to be_nil + expect(cloud_id.elasticsearch_scheme).to be_nil + expect(cloud_id.kibana_scheme).to be_nil + end + + context "when a malformed value is given" do + let(:raw) {%w(first second)} + let(:input) { described_class.cloud_id_encode(*raw) } + it "raises an error" do + expect{subject}.to raise_exception(ArgumentError, "Cloud Id, after decoding, is invalid. Format: '$$'. Received: \"#{raw[0]}$#{raw[1]}\".") + end + end + + context "when at least one segment is empty" do + let(:raw) {["first", "", "third"]} + let(:input) { described_class.cloud_id_encode(*raw) } + it "raises an error" do + expect{subject}.to raise_exception(ArgumentError, "Cloud Id, after decoding, is invalid. Format: '$$'. Received: \"#{raw[0]}$#{raw[1]}$#{raw[2]}\".") + end + end + + context "when elasticsearch segment is undefined" do + let(:raw) {%w(us-east-1.aws.found.io undefined my-kibana)} + let(:input) { described_class.cloud_id_encode(*raw) } + it "raises an error" do + expect{subject}.to raise_exception(ArgumentError, "Cloud Id, after decoding, elasticsearch segment is 'undefined', literally.") + end + end + + context "when kibana segment is undefined" do + let(:raw) {%w(us-east-1.aws.found.io my-elastic-cluster undefined)} + let(:input) { described_class.cloud_id_encode(*raw) } + it "raises an error" do + expect{subject}.to raise_exception(ArgumentError, "Cloud Id, after decoding, the kibana segment is 'undefined', literally. You may need to enable Kibana in the Cloud UI.") + end + end + end + + describe "without a label" do + let(:input) { "dXMtZWFzdC0xLmF3cy5mb3VuZC5pbyRub3RhcmVhbCRpZGVudGlmaWVy" } + it "#label is empty" do + expect(subject.label).to be_empty + end + it "#decode is set" do + expect(subject.decoded).to eq("us-east-1.aws.found.io$notareal$identifier") + end + end + + describe "when given acceptable input, the accessors:" do + it '#original has a value' do + expect(subject.original).to eq(input) + end + it '#decoded has a value' do + expect(subject.decoded).to eq("us-east-1.aws.found.io$notareal$identifier") + end + it '#label has a value' do + expect(subject.label).to eq("foobar") + end + it '#elasticsearch_host has a value' do + expect(subject.elasticsearch_host).to eq("notareal.us-east-1.aws.found.io:443") + end + it '#elasticsearch_scheme has a value' do + expect(subject.elasticsearch_scheme).to eq("https") + end + it '#kibana_host has a value' do + expect(subject.kibana_host).to eq("identifier.us-east-1.aws.found.io:443") + end + it '#kibana_scheme has a value' do + expect(subject.kibana_scheme).to eq("https") + end + it '#to_s has a value of #decoded' do + expect(subject.to_s).to eq(subject.decoded) + end + end + context "when cloud id contains port descriptions for ES and Kibana" do + let(:input) { "different-es-kb-port:dXMtY2VudHJhbDEuZ2NwLmNsb3VkLmVzLmlvJGFjMzFlYmI5MDI0MTc3MzE1NzA0M2MzNGZkMjZmZDQ2OjkyNDMkYTRjMDYyMzBlNDhjOGZjZTdiZTg4YTA3NGEzYmIzZTA6OTI0NA==" } + + it "decodes the elasticsearch port corretly" do + expect(subject.elasticsearch_host).to eq("ac31ebb90241773157043c34fd26fd46.us-central1.gcp.cloud.es.io:9243") + end + it "decodes the kibana port corretly" do + expect(subject.kibana_host).to eq("a4c06230e48c8fce7be88a074a3bb3e0.us-central1.gcp.cloud.es.io:9244") + end + end + context "when cloud id contains cloud port" do + let(:input) { "custom-port:dXMtY2VudHJhbDEuZ2NwLmNsb3VkLmVzLmlvOjkyNDMkYWMzMWViYjkwMjQxNzczMTU3MDQzYzM0ZmQyNmZkNDYkYTRjMDYyMzBlNDhjOGZjZTdiZTg4YTA3NGEzYmIzZTA=" } + + it "decodes the elasticsearch port corretly" do + expect(subject.elasticsearch_host).to eq("ac31ebb90241773157043c34fd26fd46.us-central1.gcp.cloud.es.io:9243") + end + it "decodes the kibana port corretly" do + expect(subject.kibana_host).to eq("a4c06230e48c8fce7be88a074a3bb3e0.us-central1.gcp.cloud.es.io:9243") + end + end + context "when cloud id only defines kibana port" do + let(:input) { "only-kb-set:dXMtY2VudHJhbDEuZ2NwLmNsb3VkLmVzLmlvJGFjMzFlYmI5MDI0MTc3MzE1NzA0M2MzNGZkMjZmZDQ2JGE0YzA2MjMwZTQ4YzhmY2U3YmU4OGEwNzRhM2JiM2UwOjkyNDQ=" } + + it "defaults the elasticsearch port to 443" do + expect(subject.elasticsearch_host).to eq("ac31ebb90241773157043c34fd26fd46.us-central1.gcp.cloud.es.io:443") + end + it "decodes the kibana port corretly" do + expect(subject.kibana_host).to eq("a4c06230e48c8fce7be88a074a3bb3e0.us-central1.gcp.cloud.es.io:9244") + end + end + context "when cloud id defines cloud port and kibana port" do + let(:input) { "host-and-kb-set:dXMtY2VudHJhbDEuZ2NwLmNsb3VkLmVzLmlvOjkyNDMkYWMzMWViYjkwMjQxNzczMTU3MDQzYzM0ZmQyNmZkNDYkYTRjMDYyMzBlNDhjOGZjZTdiZTg4YTA3NGEzYmIzZTA6OTI0NA==" } + + it "sets the elasticsearch port to cloud port" do + expect(subject.elasticsearch_host).to eq("ac31ebb90241773157043c34fd26fd46.us-central1.gcp.cloud.es.io:9243") + end + it "overrides cloud port with the kibana port" do + expect(subject.kibana_host).to eq("a4c06230e48c8fce7be88a074a3bb3e0.us-central1.gcp.cloud.es.io:9244") + end + end + context "when cloud id defines extra data" do + let(:input) { "extra-items:dXMtY2VudHJhbDEuZ2NwLmNsb3VkLmVzLmlvJGFjMzFlYmI5MDI0MTc3MzE1NzA0M2MzNGZkMjZmZDQ2JGE0YzA2MjMwZTQ4YzhmY2U3YmU4OGEwNzRhM2JiM2UwJGFub3RoZXJpZCRhbmRhbm90aGVy" } + + it "captures the elasticsearch host" do + expect(subject.elasticsearch_host).to eq("ac31ebb90241773157043c34fd26fd46.us-central1.gcp.cloud.es.io:443") + end + it "captures the kibana host" do + expect(subject.kibana_host).to eq("a4c06230e48c8fce7be88a074a3bb3e0.us-central1.gcp.cloud.es.io:443") + end + it "captures the remaining identifiers" do + expect(subject.other_identifiers).to eq(["anotherid", "andanother"]) + end + end + + describe "when given acceptable input (with empty kibana uuid), the accessors:" do + let(:input) { "a-test:ZWNlLmhvbWUubGFuJHRlc3Qk" } # ece.home.lan$test$ + + it '#original has a value' do + expect(subject.original).to eq(input) + end + it '#decoded has a value' do + expect(subject.decoded).to eq("ece.home.lan$test$") + end + it '#label has a value' do + expect(subject.label).to eq("a-test") + end + it '#elasticsearch_host has a value' do + expect(subject.elasticsearch_host).to eq("test.ece.home.lan:443") + end + it '#elasticsearch_scheme has a value' do + expect(subject.elasticsearch_scheme).to eq("https") + end + it '#kibana_host has a value' do + # NOTE: kibana part is not relevant -> this is how python/beats(go) code behaves + expect(subject.kibana_host).to eq(".ece.home.lan:443") + end + it '#kibana_scheme has a value' do + expect(subject.kibana_scheme).to eq("https") + end + it '#to_s has a value of #decoded' do + expect(subject.to_s).to eq(subject.decoded) + end + end + + describe "a lengthy real-world input, the accessors:" do + let(:input) do + "ZWFzdHVzMi5henVyZS5lbGFzdGljLWNsb3VkLmNvbTo5MjQzJDQwYjM0MzExNmNmYTRlYmNiNzZjMTFlZTIzMjlmOTJkJDQzZDA5MjUyNTAyYzQxODlhMzc2ZmQwY2YyY2QwODQ4" + # eastus2.azure.elastic-cloud.com:9243$40b343116cfa4ebcb76c11ee2329f92d$43d09252502c4189a376fd0cf2cd0848 + end + + it '#original has a value' do + expect(subject.original).to eq(input) + end + it '#decoded has a value' do + expect(subject.decoded).to eq("eastus2.azure.elastic-cloud.com:9243$40b343116cfa4ebcb76c11ee2329f92d$43d09252502c4189a376fd0cf2cd0848") + end + it '#label has a value' do + expect(subject.label).to eq("") + end + it '#elasticsearch_host has a value' do + expect(subject.elasticsearch_host).to eq("40b343116cfa4ebcb76c11ee2329f92d.eastus2.azure.elastic-cloud.com:9243") + end + it '#kibana_host has a value' do + expect(subject.kibana_host).to eq("43d09252502c4189a376fd0cf2cd0848.eastus2.azure.elastic-cloud.com:9243") + end + it '#to_s has a value of #decoded' do + expect(subject.to_s).to eq(subject.decoded) + end + end +end \ No newline at end of file diff --git a/logstash-core/src/main/java/org/logstash/util/CloudSettingId.java b/logstash-core/src/main/java/org/logstash/util/CloudSettingId.java index c51104908..4b432df1d 100644 --- a/logstash-core/src/main/java/org/logstash/util/CloudSettingId.java +++ b/logstash-core/src/main/java/org/logstash/util/CloudSettingId.java @@ -19,6 +19,8 @@ package org.logstash.util; +import org.logstash.RubyUtil; + import java.nio.charset.StandardCharsets; import java.util.Arrays; import java.util.Base64; @@ -56,7 +58,7 @@ public class CloudSettingId { final String[] hostParts = part.split(":"); String host = hostParts[0]; if ("undefined".equals(host)) { - throw new IllegalArgumentException(guidanceMessageWhenHostEqualsUndefined); + throw RubyUtil.RUBY.newArgumentError(guidanceMessageWhenHostEqualsUndefined); } String port = null; if (hostParts.length > 1) { @@ -107,11 +109,11 @@ public class CloudSettingId { } long separatorCount = decoded.chars().filter(c -> c == '$').count(); if (separatorCount < 2) { - throw new IllegalArgumentException("Cloud Id, after decoding, is invalid. Format: '$$'. Received: \"" + decoded + "\"."); + throw RubyUtil.RUBY.newArgumentError("Cloud Id, after decoding, is invalid. Format: '$$'. Received: \"" + decoded + "\"."); } final String[] segments = decoded.split("\\$"); if (Arrays.stream(segments).anyMatch(String::isEmpty)) { - throw new IllegalArgumentException("Cloud Id, after decoding, is invalid. Format: '$$'. Received: \"" + decoded + "\"."); + throw RubyUtil.RUBY.newArgumentError("Cloud Id, after decoding, is invalid. Format: '$$'. Received: \"" + decoded + "\"."); } String cloudBase = segments[0]; String cloudHost = DOT_SEPARATOR + cloudBase; diff --git a/logstash-core/src/test/java/org/logstash/util/CloudSettingIdTest.java b/logstash-core/src/test/java/org/logstash/util/CloudSettingIdTest.java index 0525d6bbe..118d6bd7b 100644 --- a/logstash-core/src/test/java/org/logstash/util/CloudSettingIdTest.java +++ b/logstash-core/src/test/java/org/logstash/util/CloudSettingIdTest.java @@ -61,7 +61,7 @@ public class CloudSettingIdTest { public void testThrowExceptionWhenMalformedValueIsGiven() { String[] raw = new String[] {"first", "second"}; String encoded = CloudSettingId.cloudIdEncode(raw); - exceptionRule.expect(IllegalArgumentException.class); + exceptionRule.expect(org.jruby.exceptions.ArgumentError.class); exceptionRule.expectMessage("Cloud Id, after decoding, is invalid. Format: '$$'. Received: \"" + String.join("$", raw) + "\"."); new CloudSettingId(encoded); @@ -71,7 +71,7 @@ public class CloudSettingIdTest { public void testThrowExceptionWhenAtLeatOneSegmentIsEmpty() { String[] raw = new String[] {"first", "", "third"}; String encoded = CloudSettingId.cloudIdEncode(raw); - exceptionRule.expect(IllegalArgumentException.class); + exceptionRule.expect(org.jruby.exceptions.ArgumentError.class); exceptionRule.expectMessage("Cloud Id, after decoding, is invalid. Format: '$$'. Received: \"" + String.join("$", raw) + "\"."); new CloudSettingId(encoded); @@ -81,7 +81,7 @@ public class CloudSettingIdTest { public void testThrowExceptionWhenElasticSegmentSegmentIsUndefined() { String[] raw = new String[] {"us-east-1.aws.found.io", "undefined", "my-kibana"}; String encoded = CloudSettingId.cloudIdEncode(raw); - exceptionRule.expect(IllegalArgumentException.class); + exceptionRule.expect(org.jruby.exceptions.ArgumentError.class); exceptionRule.expectMessage("Cloud Id, after decoding, elasticsearch segment is 'undefined', literally."); new CloudSettingId(encoded); @@ -91,7 +91,7 @@ public class CloudSettingIdTest { public void testThrowExceptionWhenKibanaSegmentSegmentIsUndefined() { String[] raw = new String[] {"us-east-1.aws.found.io", "my-elastic-cluster", "undefined"}; String encoded = CloudSettingId.cloudIdEncode(raw); - exceptionRule.expect(IllegalArgumentException.class); + exceptionRule.expect(org.jruby.exceptions.ArgumentError.class); exceptionRule.expectMessage("Cloud Id, after decoding, the kibana segment is 'undefined', literally. You may need to enable Kibana in the Cloud UI."); new CloudSettingId(encoded); From f50cc38ea6d29ed8b2af9799791f286482b6a710 Mon Sep 17 00:00:00 2001 From: andsel Date: Tue, 24 Nov 2020 15:02:36 +0100 Subject: [PATCH 0640/1126] [Doc] expanded the description of how to obtain the logger's names form Java and Ruby class names (cherry picked from commit 7db4692044213f1b5d464712b1d73400be143583) --- docs/static/logging.asciidoc | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/docs/static/logging.asciidoc b/docs/static/logging.asciidoc index 5fd497795..574c0f8c0 100644 --- a/docs/static/logging.asciidoc +++ b/docs/static/logging.asciidoc @@ -42,6 +42,12 @@ logger.elasticsearchoutput.name = logstash.outputs.elasticsearch logger.elasticsearchoutput.level = debug -------------------------------------------------- +The previous example defines a name and level for the logger `logstash.outputs.elasticsearch`. +The logger is usually identified by a Java class name, such as +`org.logstash.dissect.Dissector`, for example. It can also be a partial package +path as in `org.logstash.dissect`. For Ruby classes, like `LogStash::Outputs::Elasticsearch`, +the logger name is obtained by lowercasing the full class name and replacing double colons with a single dot. + ==== Logging APIs For temporary logging changes, modifying the `log4j2.properties` file and restarting Logstash leads to unnecessary From 872d25b9f64e22dcbf24492454bdca0c4d7d296f Mon Sep 17 00:00:00 2001 From: andsel Date: Wed, 18 Nov 2020 16:04:59 +0100 Subject: [PATCH 0641/1126] Moved ModulesSettingArray from Ruby to Java. The ModulesSettingArray is responsible to obfuscate password in arrays of settings. The test are still in Ruby to proove the interoperability with Ruby code that used the previous version. Added method to mimic .first and .last methods of Ruby Array (cherry picked from commit fa3891953d37353e75a0fdc85b5a98ae1926a72a) --- .../lib/logstash/modules/settings_merger.rb | 3 + .../logstash/util/modules_setting_array.rb | 30 +------- .../logstash/modules/settings_merger_spec.rb | 3 +- .../spec/logstash/settings/modules_spec.rb | 9 ++- .../logstash/util/ModulesSettingArray.java | 77 +++++++++++++++++++ 5 files changed, 90 insertions(+), 32 deletions(-) create mode 100644 logstash-core/src/main/java/org/logstash/util/ModulesSettingArray.java diff --git a/logstash-core/lib/logstash/modules/settings_merger.rb b/logstash-core/lib/logstash/modules/settings_merger.rb index ccf854bc1..8f32680d2 100644 --- a/logstash-core/lib/logstash/modules/settings_merger.rb +++ b/logstash-core/lib/logstash/modules/settings_merger.rb @@ -21,6 +21,8 @@ module LogStash module Modules module SettingsMerger include LogStash::Util::Loggable extend self + # cli_settings Array or LogStash::Util::ModulesSettingArray + # yml_settings Array or LogStash::Util::ModulesSettingArray def merge(cli_settings, yml_settings) # both args are arrays of hashes, e.g. # [{"name"=>"mod1", "var.input.tcp.port"=>"3333"}, {"name"=>"mod2"}] @@ -28,6 +30,7 @@ module LogStash module Modules module SettingsMerger merged = [] # union and group_by preserves order # union will also coalesce identical hashes + # this "|" operator is provided to Java List by RubyJavaIntegration union_of_settings = (cli_settings | yml_settings) grouped_by_name = union_of_settings.group_by{|e| e["name"]} grouped_by_name.each do |_, array| diff --git a/logstash-core/lib/logstash/util/modules_setting_array.rb b/logstash-core/lib/logstash/util/modules_setting_array.rb index 84be32fc5..854cdca5f 100644 --- a/logstash-core/lib/logstash/util/modules_setting_array.rb +++ b/logstash-core/lib/logstash/util/modules_setting_array.rb @@ -15,30 +15,6 @@ # specific language governing permissions and limitations # under the License. -require "forwardable" -require "logstash/util/password" - -module LogStash module Util class ModulesSettingArray - extend Forwardable - DELEGATED_METHODS = [].public_methods.reject{|symbol| symbol.to_s.end_with?('__')} - - def_delegators :@original, *DELEGATED_METHODS - - attr_reader :original - def initialize(value) - unless value.is_a?(Array) - raise ArgumentError.new("Module Settings must be an Array. Received: #{value.class}") - end - @original = value - # wrap passwords - @original.each do |hash| - hash.keys.select{|key| key.to_s.end_with?('password') && !hash[key].is_a?(LogStash::Util::Password)}.each do |key| - hash[key] = LogStash::Util::Password.new(hash[key]) - end - end - end - - def __class__ - LogStash::Util::ModulesSettingArray - end -end end end +module LogStash; module Util + java_import org.logstash.util.ModulesSettingArray +end; end diff --git a/logstash-core/spec/logstash/modules/settings_merger_spec.rb b/logstash-core/spec/logstash/modules/settings_merger_spec.rb index 4f0792901..5612ac419 100644 --- a/logstash-core/spec/logstash/modules/settings_merger_spec.rb +++ b/logstash-core/spec/logstash/modules/settings_merger_spec.rb @@ -20,6 +20,7 @@ require "logstash/util/cloud_setting_id" require "logstash/util/cloud_setting_auth" require "logstash/modules/settings_merger" require "logstash/util/password" +require "logstash/util/modules_setting_array" class SubstituteSettingsForRSpec def initialize(hash = {}) @hash = hash; end @@ -29,7 +30,7 @@ end describe LogStash::Modules::SettingsMerger do describe "#merge" do - let(:cli) {[{"name"=>"mod1", "var.input.tcp.port"=>"3333"}, {"name"=>"mod2"}]} + let(:cli) { LogStash::Util::ModulesSettingArray.new [{"name"=>"mod1", "var.input.tcp.port"=>"3333"}, {"name"=>"mod2"}] } let(:yml) {[{"name"=>"mod1", "var.input.tcp.port"=>2222, "var.kibana.username"=>"rupert", "var.kibana.password"=>"fotherington"}, {"name"=>"mod3", "var.input.tcp.port"=>4445}]} subject(:results) { described_class.merge(cli, yml) } it "merges cli overwriting any common fields in yml" do diff --git a/logstash-core/spec/logstash/settings/modules_spec.rb b/logstash-core/spec/logstash/settings/modules_spec.rb index dd3404c64..b0ae29298 100644 --- a/logstash-core/spec/logstash/settings/modules_spec.rb +++ b/logstash-core/spec/logstash/settings/modules_spec.rb @@ -20,6 +20,7 @@ require "logstash/settings" require "logstash/util/cloud_setting_id" require "logstash/util/cloud_setting_auth" require "logstash/util/modules_setting_array" +require "java" describe LogStash::Setting::Modules do describe "Modules.Cli" do @@ -29,8 +30,8 @@ describe LogStash::Setting::Modules do it "should convert password Strings to Password" do source = [{"var.kibana.password" => secret}] setting = subject.set(source) - expect(setting).to be_a(Array) - expect(setting.__class__).to eq(LogStash::Util::ModulesSettingArray) + expect(setting).to be_a(java.util.ArrayList) + expect(setting.class).to eq(LogStash::Util::ModulesSettingArray) expect(setting.first.fetch("var.kibana.password")).to be_a(LogStash::Util::Password) expect(setting.first.fetch("var.kibana.password").value).to eq(secret) end @@ -38,8 +39,8 @@ describe LogStash::Setting::Modules do it 'should not wrap values that are already passwords' do source = [{"var.kibana.password" => LogStash::Util::Password.new(secret)}] setting = subject.set(source) - expect(setting).to be_a(Array) - expect(setting.__class__).to eq(LogStash::Util::ModulesSettingArray) + expect(setting).to be_a(java.util.ArrayList) + expect(setting.class).to eq(LogStash::Util::ModulesSettingArray) expect(setting.first.fetch("var.kibana.password")).to be_a(LogStash::Util::Password) expect(setting.first.fetch("var.kibana.password").value).to eq(secret) end diff --git a/logstash-core/src/main/java/org/logstash/util/ModulesSettingArray.java b/logstash-core/src/main/java/org/logstash/util/ModulesSettingArray.java new file mode 100644 index 000000000..f4f49c97b --- /dev/null +++ b/logstash-core/src/main/java/org/logstash/util/ModulesSettingArray.java @@ -0,0 +1,77 @@ +/* + * 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. + */ + +package org.logstash.util; + +import co.elastic.logstash.api.Password; + +import java.util.ArrayList; +import java.util.Collection; +import java.util.HashMap; +import java.util.LinkedHashMap; +import java.util.Map; +import java.util.TreeMap; +import java.util.stream.Collectors; + +public final class ModulesSettingArray extends ArrayList> { + + private static final long serialVersionUID = 4094949366274116593L; + + public ModulesSettingArray(Collection> original) { + super(wrapPasswords(original)); + } + + private static Collection> wrapPasswords(Collection> original) { + return original.stream() + .map(ModulesSettingArray::wrapPasswordsInSettings) + .collect(Collectors.toList()); + } + + private static Map wrapPasswordsInSettings(Map settings) { + // Insertion order is important. The Map object passed into is usually a org.jruby.RubyHash, which preserves + // the insertion order, during the scan. Here we need to keep the same order, because tests on modules + // expects a precise order of keys. It's important to have stable tests. + final Map acc = new LinkedHashMap<>(); + for (Map.Entry entry : settings.entrySet()) { + if (entry.getKey().endsWith("password") && !(entry.getValue() instanceof Password)) { + acc.put(entry.getKey(), new Password((String) entry.getValue())); + } else { + acc.put(entry.getKey(), entry.getValue()); + } + } + return acc; + } + + public Map getFirst() { + try { + return get(0); + } catch (IndexOutOfBoundsException ex) { + return null; + } + } + + public Map getLast() { + try { + return get(size() - 1); + } catch (IndexOutOfBoundsException ex) { + return null; + } + } + +} From 8539d3fb9b588df5f6cf69d76e3d8a18937cae6f Mon Sep 17 00:00:00 2001 From: andsel Date: Thu, 26 Nov 2020 14:56:00 +0100 Subject: [PATCH 0642/1126] Moved LogStash::Util::TimeValue to Java (cherry picked from commit 1a62dc79e02d3bd327dfd2b77841fac9384eb507) --- logstash-core/lib/logstash/util/time_value.rb | 72 +--------- .../spec/logstash/util/time_value_spec.rb | 2 +- .../java/org/logstash/util/TimeValue.java | 126 ++++++++++++++++++ 3 files changed, 128 insertions(+), 72 deletions(-) create mode 100644 logstash-core/src/main/java/org/logstash/util/TimeValue.java diff --git a/logstash-core/lib/logstash/util/time_value.rb b/logstash-core/lib/logstash/util/time_value.rb index b2814d22f..85094c417 100644 --- a/logstash-core/lib/logstash/util/time_value.rb +++ b/logstash-core/lib/logstash/util/time_value.rb @@ -17,76 +17,6 @@ module LogStash module Util - class TimeValue - def initialize(duration, time_unit) - @duration = duration - @time_unit = time_unit - end - - def self.from_value(value) - case value - when TimeValue - return value # immutable - when ::String - normalized = value.downcase.strip - if normalized.end_with?("nanos") - TimeValue.new(parse(normalized, 5), :nanosecond) - elsif normalized.end_with?("micros") - TimeValue.new(parse(normalized, 6), :microsecond) - elsif normalized.end_with?("ms") - TimeValue.new(parse(normalized, 2), :millisecond) - elsif normalized.end_with?("s") - TimeValue.new(parse(normalized, 1), :second) - elsif normalized.end_with?("m") - TimeValue.new(parse(normalized, 1), :minute) - elsif normalized.end_with?("h") - TimeValue.new(parse(normalized, 1), :hour) - elsif normalized.end_with?("d") - TimeValue.new(parse(normalized, 1), :day) - elsif normalized =~ /^-0*1/ - TimeValue.new(-1, :nanosecond) - else - raise ArgumentError.new("invalid time unit: \"#{value}\"") - end - else - raise ArgumentError.new("value is not a string: #{value} [#{value.class}]") - end - end - - def to_nanos - case @time_unit - when :day - 86400000000000 * @duration - when :hour - 3600000000000 * @duration - when :minute - 60000000000 * @duration - when :second - 1000000000 * @duration - when :millisecond - 1000000 * @duration - when :microsecond - 1000 * @duration - when :nanosecond - @duration - end - end - - def to_seconds - self.to_nanos / 1_000_000_000.0 - end - - def ==(other) - (self.duration == other.duration && self.time_unit == other.time_unit) || self.to_nanos == other.to_nanos - end - - def self.parse(value, suffix) - Integer(value[0..(value.size - suffix - 1)].strip) - end - - private_class_method :parse - attr_reader :duration - attr_reader :time_unit - end + java_import org.logstash.util.TimeValue end end diff --git a/logstash-core/spec/logstash/util/time_value_spec.rb b/logstash-core/spec/logstash/util/time_value_spec.rb index 79b4a0229..312a91ec6 100644 --- a/logstash-core/spec/logstash/util/time_value_spec.rb +++ b/logstash-core/spec/logstash/util/time_value_spec.rb @@ -67,7 +67,7 @@ describe TimeValue do a = TimeValue.from_value(32) fail "should not parse" rescue ArgumentError => e - expect(e.message).to eq("value is not a string: 32 [Integer]") + expect(e.message).to start_with("value is not a string: 32 ") end end end diff --git a/logstash-core/src/main/java/org/logstash/util/TimeValue.java b/logstash-core/src/main/java/org/logstash/util/TimeValue.java new file mode 100644 index 000000000..8ce4fcf88 --- /dev/null +++ b/logstash-core/src/main/java/org/logstash/util/TimeValue.java @@ -0,0 +1,126 @@ +/* + * 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. + */ +package org.logstash.util; + +import org.logstash.RubyUtil; + +import java.util.Objects; +import java.util.concurrent.TimeUnit; + +public class TimeValue { + + public static TimeValue fromValue(Object value) { + if (value instanceof TimeValue) { + return (TimeValue) value; + } + if (value instanceof String) { + final String normalized = ((String) value).toLowerCase().trim(); + if (normalized.endsWith("nanos")) { + return new TimeValue(parse(normalized, 5), TimeUnit.NANOSECONDS); + } + if (normalized.endsWith("micros")) { + return new TimeValue(parse(normalized, 6), TimeUnit.MICROSECONDS); + } + if (normalized.endsWith("ms")) { + return new TimeValue(parse(normalized, 2), TimeUnit.MILLISECONDS); + } + if (normalized.endsWith("s")) { + return new TimeValue(parse(normalized, 1), TimeUnit.SECONDS); + } + if (normalized.endsWith("m")) { + return new TimeValue(parse(normalized, 1), TimeUnit.MINUTES); + } + if (normalized.endsWith("h")) { + return new TimeValue(parse(normalized, 1), TimeUnit.HOURS); + } + if (normalized.endsWith("d")) { + return new TimeValue(parse(normalized, 1), TimeUnit.DAYS); + } + if (normalized.matches("^-0*1")) { + return new TimeValue(-1, TimeUnit.NANOSECONDS); + } + throw RubyUtil.RUBY.newArgumentError("invalid time unit: \"" + value + "\""); + } + throw RubyUtil.RUBY.newArgumentError("value is not a string: " + value + " [" + value.getClass().getName() + "]"); + } + + private static int parse(String value, int suffix) { + final String numericPart = value.substring(0, value.length() - suffix).trim(); + try { + return Integer.parseInt(numericPart); + } catch (NumberFormatException ex) { + throw RubyUtil.RUBY.newArgumentError("invalid value for Integer(): \"" + numericPart + "\""); + } + } + + private final long duration; + private final TimeUnit timeUnit; + + /** + * @param duration number of timeUnit + * @param timeUnit could be one of nanosecond, microsecond, millisecond, second, minute, hour, day, nanosecond + * */ + public TimeValue(int duration, String timeUnit) { + this(duration, TimeUnit.valueOf((timeUnit + "s").toUpperCase())); + } + + protected TimeValue(long duration, TimeUnit timeUnit) { + this.duration = duration; + this.timeUnit = timeUnit; + } + + public long getDuration() { + return duration; + } + + public String getTimeUnit() { + final String value = timeUnit.toString(); + return value.substring(0, value.length() - 1); // remove last "s" + } + + public long toNanos() { + return timeUnit.toNanos(duration); + } + + public long toSeconds() { + return timeUnit.toSeconds(duration); + } + + @Override + public boolean equals(Object o) { + if (this == o) return true; + if (o == null || getClass() != o.getClass()) return false; + TimeValue timeValue = (TimeValue) o; + return (duration == timeValue.duration && + timeUnit == timeValue.timeUnit) || (this.toNanos() == timeValue.toNanos()); + } + + @Override + public int hashCode() { + return Objects.hash(duration, timeUnit); + } + + @Override + public String toString() { + return "TimeValue{" + + "duration=" + duration + + ", timeUnit=" + timeUnit + + '}'; + } +} From 7457bc903821fd8482f964db32db62f245112af4 Mon Sep 17 00:00:00 2001 From: Ry Biesemeyer Date: Wed, 2 Dec 2020 18:15:46 +0000 Subject: [PATCH 0643/1126] REE: output reload interval as nanos instead of object fixes a warning about an unsupported gauge type, matches the behaviour on JEE. --- logstash-core/lib/logstash/pipeline.rb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/logstash-core/lib/logstash/pipeline.rb b/logstash-core/lib/logstash/pipeline.rb index 6b3ec1733..70feff385 100644 --- a/logstash-core/lib/logstash/pipeline.rb +++ b/logstash-core/lib/logstash/pipeline.rb @@ -320,7 +320,7 @@ module LogStash; class Pipeline < BasePipeline config_metric.gauge(:batch_size, batch_size) config_metric.gauge(:batch_delay, batch_delay) config_metric.gauge(:config_reload_automatic, settings.get("config.reload.automatic")) - config_metric.gauge(:config_reload_interval, settings.get("config.reload.interval")) + config_metric.gauge(:config_reload_interval, settings.get("config.reload.interval").to_nanos) config_metric.gauge(:dead_letter_queue_enabled, dlq_enabled?) config_metric.gauge(:dead_letter_queue_path, dlq_writer.get_path.to_absolute_path.to_s) if dlq_enabled? From 0588d510564a4d5d21a3e766b3d84316829077cf Mon Sep 17 00:00:00 2001 From: Rob Bavey Date: Fri, 4 Dec 2020 16:12:39 -0500 Subject: [PATCH 0644/1126] [7x_backport] Add UBI8 image specific labels back to the docker image (#12502) Clean backport of #12498 these labels are required for redhat openshift certification. These commit reintroduces the labels for the ubi8 image only, and adds acceptance tests to ensure these labels are correct and not inherited --- docker/templates/Dockerfile.j2 | 8 ++++++++ qa/docker/spec/ubi8/image_spec.rb | 32 +++++++++++++++++++++++++++++++ 2 files changed, 40 insertions(+) diff --git a/docker/templates/Dockerfile.j2 b/docker/templates/Dockerfile.j2 index a3423bf1a..c6f522f16 100644 --- a/docker/templates/Dockerfile.j2 +++ b/docker/templates/Dockerfile.j2 @@ -96,6 +96,14 @@ LABEL org.label-schema.schema-version="1.0" \ org.opencontainers.image.licenses="{{ license }}" \ org.opencontainers.image.description="Logstash is a free and open server-side data processing pipeline that ingests data from a multitude of sources, transforms it, and then sends it to your favorite 'stash.'" \ org.label-schema.build-date={{ created_date }} \ +{% if image_flavor == 'ubi8' -%} + license="{{ license }}" \ + description="Logstash is a free and open server-side data processing pipeline that ingests data from a multitude of sources, transforms it, and then sends it to your favorite 'stash.'" \ + name="logstash" \ + maintainer="info@elastic.co" \ + summary="Logstash is a free and open server-side data processing pipeline that ingests data from a multitude of sources, transforms it, and then sends it to your favorite 'stash.'" \ + vendor="Elastic" \ +{% endif -%} org.opencontainers.image.created={{ created_date }} diff --git a/qa/docker/spec/ubi8/image_spec.rb b/qa/docker/spec/ubi8/image_spec.rb index 562f4aef4..3f880c29b 100644 --- a/qa/docker/spec/ubi8/image_spec.rb +++ b/qa/docker/spec/ubi8/image_spec.rb @@ -3,4 +3,36 @@ require_relative '../../shared_examples/image_metadata' describe 'An image with the full distribution' do it_behaves_like 'the metadata is set correctly', 'ubi8' + + context 'the ubi8 image should set its specific labels correctly' do + before do + @image = find_image('ubi8') + @image_config = @image.json['Config'] + @labels = @image_config['Labels'] + end + + %w(license org.label-schema.license org.opencontainers.image.licenses).each do |label| + it "should set the license label #{label} correctly" do + expect(@labels[label]).to have_correct_license_label('ubi8') + end + end + + it 'should set the name label correctly' do + expect(@labels['name']).to eql "logstash" + end + + it 'should set the maintainer label correctly' do + expect(@labels["maintainer"]).to eql "info@elastic.co" + end + + %w(description summary).each do |label| + it "should set the name label #{label} correctly" do + expect(@labels[label]).to eql "Logstash is a free and open server-side data processing pipeline that ingests data from a multitude of sources, transforms it, and then sends it to your favorite 'stash.'" + end + end + + it 'should set the vendor label correctly' do + expect(@labels["vendor"]).to eql "Elastic" + end + end end \ No newline at end of file From 8550059a2a4dd10d663c8cffe63331c191c3472d Mon Sep 17 00:00:00 2001 From: andsel Date: Mon, 7 Dec 2020 09:55:45 +0100 Subject: [PATCH 0645/1126] Forward port of 7.10.1 release notes to 7.x --- docs/static/releasenotes.asciidoc | 35 +++++++++++++++++++++++++++++++ 1 file changed, 35 insertions(+) diff --git a/docs/static/releasenotes.asciidoc b/docs/static/releasenotes.asciidoc index a1d5d6816..0d7052ebf 100644 --- a/docs/static/releasenotes.asciidoc +++ b/docs/static/releasenotes.asciidoc @@ -3,6 +3,7 @@ This section summarizes the changes in the following releases: +* <> * <> * <> * <> @@ -36,6 +37,40 @@ This section summarizes the changes in the following releases: * <> * <> +[[logstash-7-10-1]] +=== Logstash 7.10.1 Release Notes + +==== Notable issues fixed + +===== Support recreation of same pipeline through centralized pipeline management +When users attempted to delete and recreate a pipeline with the same identifier and configuration, Logstash was unable +to pick up the new pipeline. https://github.com/elastic/logstash/issues/12387[#12387] + +==== Plugins + +*Azure_event_hubs Input - 1.2.3* + +* Fixed missing configuration of `prefetch_count` and `receive_timeout` https://github.com/logstash-plugins/logstash-input-azure_event_hubs/pull/61[#61] + +*Http Input - 3.3.6* + +* Fixes a regression introduced in **3.1.0** with the migration to the Netty back-end that broke +browser-based workflows for some users. When a plugin that is configured to require Basic authentication receives a request that does not +include authentication, it now appropriately includes an `WWW-Authenticate` header in its `401 Unauthorized` response, +allowing the browser to collect credentials before retrying the request. https://github.com/logstash-plugins/logstash-input-http/pull/129[#129] + +*Sqs Input - 3.1.3* + +* Fix: retry networking errors (with backoff) https://github.com/logstash-plugins/logstash-input-sqs/pull/57[#57] + +*Kafka Integration - 10.5.3* + +* Fix: set (optional) truststore when endpoint id check disabled. Since **10.1.0** disabling server host-name +verification (`ssl_endpoint_identification_algorithm => ""`) did not allow the (output) plugin to set +`ssl_truststore_location => "..."` https://github.com/logstash-plugins/logstash-integration-kafka/pull/60[#60] +* Docs: explain group_id in case of multiple inputs https://github.com/logstash-plugins/logstash-integration-kafka/pull/59[#59] + + [[logstash-7-10-0]] === Logstash 7.10.0 Release Notes From 06418b8631feb009c2b75821076d4b8b879563b2 Mon Sep 17 00:00:00 2001 From: andsel Date: Thu, 10 Dec 2020 11:42:23 +0100 Subject: [PATCH 0646/1126] Fix error due to missing variable when listitng tasks and no architecture is externally specified with -Pos_arch= (cherry picked from commit 7144a3f7cf9628a2ce397b29cbf6f65dcbf3e334) --- build.gradle | 19 ++++++++++++++++++- 1 file changed, 18 insertions(+), 1 deletion(-) diff --git a/build.gradle b/build.gradle index 9fcd11ff0..32a90eb6e 100644 --- a/build.gradle +++ b/build.gradle @@ -532,6 +532,23 @@ def selectOsType() { } } +def selectArch() { + if (project.ext.has("jdk_arch")) { + return project.ext.jdk_arch + } + String cpu_arch = System.properties["os.arch"] + switch (cpu_arch) { + case "amd64": + case "x86_64": + return "x86_64" + case "aarch64": + case "arm64": + return "arm64" + default: + throw new IllegalArgumentException("Can't handle os.arch of type $cpu_arch") + } +} + class JDKDetails { final String revision final String build @@ -602,7 +619,7 @@ tasks.register("downloadJdk", Download) { String osName = selectOsType() def versionYml = new Yaml().load(new File("$projectDir/versions.yml").text) - String jdkArch = project.ext.jdk_arch + String jdkArch = selectArch() def jdkDetails = new JDKDetails(versionYml, osName, jdkArch) description "Download JDK ${jdkDetails.major}, OS: ${osName}" From 8746cdeda4680e422f4a386c09f3d3e8b9a9d0de Mon Sep 17 00:00:00 2001 From: Ry Biesemeyer Date: Tue, 15 Dec 2020 07:13:46 -0800 Subject: [PATCH 0647/1126] plugin: adds `:validate => :field_reference` (#12459) (#12521) * plugin: adds `:validate => :field_reference` Provide plugins a way of validating that an input is a literal field-reference. This is useful for input plugins that implement a `target` or other non-interpolated directive, and allows these plugins to reject invalid configuration before start-up instead of at run-time. Plugins should not use this named validator directly, as doing so would cause validation to fail with "Unknown validator" when the plugin is run on older releases of Logstash. Instead, plugins should use the `validator_support` adapter mixin that provides back-ports when necessary. Co-authored-by: Karen Metts <35154725+karenzone@users.noreply.github.com> --- docs/static/configuration.asciidoc | 8 ++++ logstash-core/lib/logstash/config/mixin.rb | 44 +++++++++++++++++++ .../spec/logstash/config/mixin_spec.rb | 35 +++++++++++++++ .../java/org/logstash/FieldReference.java | 9 ++++ 4 files changed, 96 insertions(+) diff --git a/docs/static/configuration.asciidoc b/docs/static/configuration.asciidoc index bc86f24eb..fd4c71af8 100644 --- a/docs/static/configuration.asciidoc +++ b/docs/static/configuration.asciidoc @@ -278,6 +278,14 @@ Example: name => 'It\'s a beautiful day' ---------------------------------- +[[field-reference]] +[float] +==== Field Reference + +A Field Reference is a special <> value representing the path to a field in an event, such as `@timestamp` or `[@timestamp]` to reference a top-level field, or `[client][ip]` to access a nested field. +The <> provides detailed information about the structure of Field References. +When provided as a configuration option, Field References need to be quoted and special characters must be escaped following the same rules as <>. + [float] [[comments]] === Comments diff --git a/logstash-core/lib/logstash/config/mixin.rb b/logstash-core/lib/logstash/config/mixin.rb index 38ef99b9d..c4d204025 100644 --- a/logstash-core/lib/logstash/config/mixin.rb +++ b/logstash-core/lib/logstash/config/mixin.rb @@ -195,6 +195,15 @@ module LogStash::Config::Mixin end # Define a new configuration setting + # + # @param name [String, Symbol, Regexp] + # @param opts [Hash]: the options for this config parameter + # @option opts [Array,Symbol] :validate + # When `Array`, the expanded form of the given directive MUST exist in the Array. + # When `Symbol`, the named validator matching the provided `Symbol` is used. + # @option opts [Boolean] :list + # @option opts [Object] :default + # @option opts [Boolean] :required def config(name, opts={}) @config ||= Hash.new # TODO(sissel): verify 'name' is of type String, Symbol, or Regexp @@ -412,6 +421,32 @@ module LogStash::Config::Mixin return nil end + ## + # Performs deep replacement of the provided value, then performs validation and coercion. + # + # The provided validator can be nil, an Array of acceptable values, or a Symbol + # representing a named validator, and is the result of a configuration parameter's `:validate` option (@see DSL#config) + # + # @overload validate_value(value, validator) + # Validation occurs with the named validator. + # @param value [Object] + # @param validator [Symbol] + # @overload validate_value(value, validator) + # The value must exist in the provided Array. + # @param value [Object] + # @param validator [Array] + # @overload validate_value(value, validator) + # The value is always considered valid + # @param value [Object] + # @param validator [nil] + # + # @return [Array<(true, Object)>]: when value is valid, a tuple containing true and a coerced form of the value is returned + # @return [Array<(false, String)>]: when value is not valid, a tuple containing false and an error string is returned. + # + # @api private + # + # WARNING: validators added here must be back-ported to the Validation Support plugin mixin so that plugins + # that use them are not constrained to the version of Logstash that introduced the validator. def validate_value(value, validator) # Validator comes from the 'config' pieces of plugins. # They look like this @@ -578,6 +613,15 @@ module LogStash::Config::Mixin rescue ArgumentError return false, "Unparseable filesize: #{value.first}. possible units (KiB, MiB, ...) e.g. '10 KiB'. doc reference: http://www.elastic.co/guide/en/logstash/current/configuration.html#bytes" end + when :field_reference # @since 7.11 + return [false, "Expected exactly one field reference, got `#{value.inspect}`"] unless value.kind_of?(Array) && value.size <= 1 + return [true, nil] if value.empty? || value.first.nil? || value.first.empty? + + candidate = value.first + + return [false, "Expected a valid field reference, got `#{candidate.inspect}`"] unless org.logstash.FieldReference.isValid(candidate) + + return [true, candidate] else return false, "Unknown validator symbol #{validator}" end # case validator diff --git a/logstash-core/spec/logstash/config/mixin_spec.rb b/logstash-core/spec/logstash/config/mixin_spec.rb index 60c261136..7928409bb 100644 --- a/logstash-core/spec/logstash/config/mixin_spec.rb +++ b/logstash-core/spec/logstash/config/mixin_spec.rb @@ -72,6 +72,41 @@ describe LogStash::Config::Mixin do end end + context "validating :field_reference" do + let(:plugin_class) do + Class.new(LogStash::Filters::Base) do + config :target, :validate => :field_reference + end + end + let(:params) do + { "target" => target_param } + end + + before(:each) do + allow(plugin_class).to receive(:logger).and_return(double('Logger').as_null_object) + end + + context "when input is valid" do + let(:target_param) { "[@metadata][target]" } + it 'successfully initializes the plugin' do + expect(plugin_class.new(params)).to be_a_kind_of plugin_class + end + it 'coerces the value' do + instance = plugin_class.new(params) + expect(instance.target).to_not be_nil + expect(instance.target).to eq(target_param) + end + end + + context "when input is invalid" do + let(:target_param) { "][Nv@l][d" } + it 'does not initialize the plugin' do + expect { plugin_class.new(params) }.to raise_exception(LogStash::ConfigurationError) + expect(plugin_class.logger).to have_received(:error).with(/must be a field_reference/) + end + end + end + context "when validating :bytes successfully" do subject do local_num_bytes = num_bytes # needs to be locally scoped :( diff --git a/logstash-core/src/main/java/org/logstash/FieldReference.java b/logstash-core/src/main/java/org/logstash/FieldReference.java index 03a476dd2..e7b58b074 100644 --- a/logstash-core/src/main/java/org/logstash/FieldReference.java +++ b/logstash-core/src/main/java/org/logstash/FieldReference.java @@ -127,6 +127,15 @@ public final class FieldReference { return parseToCache(reference); } + public static boolean isValid(final String reference) { + try { + FieldReference.from(reference); + return true; + } catch (IllegalSyntaxException ise) { + return false; + } + } + /** * Returns the type of this instance to allow for fast switch operations in * {@link Event#getUnconvertedField(FieldReference)} and From 7704bc78d0db6aefabe72bf25b1447530f02c9d9 Mon Sep 17 00:00:00 2001 From: Ry Biesemeyer Date: Wed, 16 Dec 2020 06:59:28 -0800 Subject: [PATCH 0648/1126] Bump 7.12 (#12525) --- README.md | 16 ++++++++-------- versions.yml | 4 ++-- 2 files changed, 10 insertions(+), 10 deletions(-) diff --git a/README.md b/README.md index 375590c2f..e2cd603f4 100644 --- a/README.md +++ b/README.md @@ -28,14 +28,14 @@ These builds are created nightly and have undergone no formal QA, so they should | [deb-complete][] | [deb-oss][] | | [rpm-complete][] | [rpm-oss][] | -[tar-complete]: https://snapshots.elastic.co/downloads/logstash/logstash-7.11.0-SNAPSHOT.tar.gz -[zip-complete]: https://snapshots.elastic.co/downloads/logstash/logstash-7.11.0-SNAPSHOT.zip -[deb-complete]: https://snapshots.elastic.co/downloads/logstash/logstash-7.11.0-SNAPSHOT.deb -[rpm-complete]: https://snapshots.elastic.co/downloads/logstash/logstash-7.11.0-SNAPSHOT.rpm -[tar-oss]: https://snapshots.elastic.co/downloads/logstash/logstash-oss-7.11.0-SNAPSHOT.tar.gz -[zip-oss]: https://snapshots.elastic.co/downloads/logstash/logstash-oss-7.11.0-SNAPSHOT.zip -[deb-oss]: https://snapshots.elastic.co/downloads/logstash/logstash-oss-7.11.0-SNAPSHOT.deb -[rpm-oss]: https://snapshots.elastic.co/downloads/logstash/logstash-oss-7.11.0-SNAPSHOT.rpm +[tar-complete]: https://snapshots.elastic.co/downloads/logstash/logstash-7.12.0-SNAPSHOT.tar.gz +[zip-complete]: https://snapshots.elastic.co/downloads/logstash/logstash-7.12.0-SNAPSHOT.zip +[deb-complete]: https://snapshots.elastic.co/downloads/logstash/logstash-7.12.0-SNAPSHOT.deb +[rpm-complete]: https://snapshots.elastic.co/downloads/logstash/logstash-7.12.0-SNAPSHOT.rpm +[tar-oss]: https://snapshots.elastic.co/downloads/logstash/logstash-oss-7.12.0-SNAPSHOT.tar.gz +[zip-oss]: https://snapshots.elastic.co/downloads/logstash/logstash-oss-7.12.0-SNAPSHOT.zip +[deb-oss]: https://snapshots.elastic.co/downloads/logstash/logstash-oss-7.12.0-SNAPSHOT.deb +[rpm-oss]: https://snapshots.elastic.co/downloads/logstash/logstash-oss-7.12.0-SNAPSHOT.rpm ## Need Help? diff --git a/versions.yml b/versions.yml index 99ba28f1b..2839e611b 100644 --- a/versions.yml +++ b/versions.yml @@ -1,7 +1,7 @@ --- # alpha and beta qualifiers are now added via VERSION_QUALIFIER environment var -logstash: 7.11.0 -logstash-core: 7.11.0 +logstash: 7.12.0 +logstash-core: 7.12.0 logstash-core-plugin-api: 2.1.16 bundled_jdk: From 05ec149b3938d290c9d50826685c54cc17c20017 Mon Sep 17 00:00:00 2001 From: andsel Date: Wed, 16 Dec 2020 10:19:23 +0100 Subject: [PATCH 0649/1126] Enable javadoc lint only for files that contains javadoc comments, avoid warning for missing javadoc comments on everything else (cherry picked from commit d176e608bdd20a3221bdbb8b3fc84fc3f1085229) --- build.gradle | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/build.gradle b/build.gradle index 32a90eb6e..c7993592f 100644 --- a/build.gradle +++ b/build.gradle @@ -59,7 +59,13 @@ allprojects { } tasks.withType(Javadoc).configureEach { - options.addStringOption("Xwerror", "-quiet") + if (JavaVersion.current().compareTo(JavaVersion.VERSION_14) > 0) { + // with JDK 15 the -Xwerror undocumented feature becomes official with switch -Werror + options.addBooleanOption("Werror", true) + } else { + options.addBooleanOption("Xwerror", true) + } + options.addBooleanOption("Xdoclint:all,-missing", true) if (JavaVersion.current().compareTo(JavaVersion.VERSION_1_9) > 0) { options.addBooleanOption("html5", true) } From a5dbc8d2a2ab7e9cd0763d8e4d95d8010e39f072 Mon Sep 17 00:00:00 2001 From: Rob Bavey Date: Mon, 4 Jan 2021 15:59:21 -0500 Subject: [PATCH 0650/1126] Update license dependency information (#12544) This commit updates the license information for the license dependency report. Specifically, this adds a notice for racc, a different version of which is now pulled in by nokogiri from the version included with jruby. --- NOTICE.TXT | 65 ++++++++++++++----- .../src/main/resources/licenseMapping.csv | 1 + .../main/resources/notices/racc-NOTICE.txt | 24 +++++++ 3 files changed, 72 insertions(+), 18 deletions(-) create mode 100644 tools/dependencies-report/src/main/resources/notices/racc-NOTICE.txt diff --git a/NOTICE.TXT b/NOTICE.TXT index 68c48fb6c..2900d52b4 100644 --- a/NOTICE.TXT +++ b/NOTICE.TXT @@ -298,7 +298,7 @@ See the License for the specific language governing permissions and limitations under the License. ========== -Notice for: amazing_print-1.2.1 +Notice for: amazing_print-1.2.2 ---------- MIT License @@ -504,7 +504,7 @@ THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. ========== -Notice for: avro-1.10.0 +Notice for: avro-1.10.1 ---------- Apache Avro @@ -522,7 +522,7 @@ AWS SDK for Ruby Copyright 2015 Amazon.com, Inc. or its affiliates. All Rights Reserved. ========== -Notice for: aws-sdk-2.11.596 +Notice for: aws-sdk-2.11.632 ---------- copyright 2013. amazon web services, inc. all rights reserved. @@ -730,7 +730,7 @@ copyright 2013. amazon web services, inc. all rights reserved. limitations under the License. ========== -Notice for: aws-sdk-core-2.11.596 +Notice for: aws-sdk-core-2.11.632 ---------- copyright 2013. amazon web services, inc. all rights reserved. @@ -938,7 +938,7 @@ copyright 2013. amazon web services, inc. all rights reserved. limitations under the License. ========== -Notice for: aws-sdk-resources-2.11.596 +Notice for: aws-sdk-resources-2.11.632 ---------- copyright 2013. amazon web services, inc. all rights reserved. @@ -2069,7 +2069,7 @@ from the source code management (SCM) system project uses. See the License for the specific language governing permissions and limitations under the License. ========== -Notice for: com.fasterxml.jackson.core:jackson-databind-2.9.10.4 +Notice for: com.fasterxml.jackson.core:jackson-databind-2.9.10.6 ---------- # Jackson JSON processor @@ -3255,7 +3255,7 @@ The above copyright notice and this permission notice shall be included in all c THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. ========== -Notice for: ffi-1.13.1 +Notice for: ffi-1.14.2 ---------- source: https://github.com/ffi/ffi/blob/1.9.23/LICENSE @@ -3507,7 +3507,7 @@ FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. ========== -Notice for: i18n-1.8.5 +Notice for: i18n-1.8.7 ---------- source: https://github.com/svenfuchs/i18n/blob/v0.6.9/MIT-LICENSE @@ -3992,7 +3992,7 @@ TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION of your accepting any such warranty or additional liability. ========== -Notice for: jrjackson-0.4.12 +Notice for: jrjackson-0.4.13 ---------- https://github.com/guyboertje/jrjackson/blob/v0.4.6/README.md @@ -6484,7 +6484,7 @@ See the License for the specific language governing permissions and limitations under the License. ========== -Notice for: jruby-openssl-0.10.4 +Notice for: jruby-openssl-0.10.5 ---------- source: https://github.com/jruby/jruby-openssl/blob/v0.9.21/LICENSE.txt @@ -7014,7 +7014,7 @@ The above copyright notice and this permission notice shall be included in all c THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. ========== -Notice for: nokogiri-1.10.10 +Notice for: nokogiri-1.11.0 ---------- source: https://github.com/sparklemotion/nokogiri/blob/v1.8.2/LICENSE.md @@ -7194,7 +7194,7 @@ OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. ========== -Notice for: puma-4.3.6 +Notice for: puma-4.3.7 ---------- Some code copyright (c) 2005, Zed Shaw @@ -7224,6 +7224,35 @@ CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +========== +Notice for: racc-1.5.2 +---------- + +source: https://github.com/ruby/racc/blob/master/COPYING + +Copyright (C) 2019 Yukihiro Matsumoto. All rights reserved. + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions +are met: +1. Redistributions of source code must retain the above copyright +notice, this list of conditions and the following disclaimer. +2. Redistributions in binary form must reproduce the above copyright +notice, this list of conditions and the following disclaimer in the +documentation and/or other materials provided with the distribution. + +THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND +ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE +FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL +DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS +OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) +HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT +LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY +OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF +SUCH DAMAGE. + ========== Notice for: rack-2.2.3 ---------- @@ -7302,7 +7331,7 @@ WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. ========== -Notice for: redis-4.2.2 +Notice for: redis-4.2.5 ---------- Copyright (c) 2009 Ezra Zygmuntowicz @@ -7326,7 +7355,7 @@ LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. ========== -Notice for: ruby-progressbar-1.10.1 +Notice for: ruby-progressbar-1.11.0 ---------- Copyright (c) 2010-2016 The Kompanee, Ltd @@ -7465,7 +7494,7 @@ See the License for the specific language governing permissions and limitations under the License. ========== -Notice for: sequel-5.36.0 +Notice for: sequel-5.40.0 ---------- Copyright (c) 2007-2008 Sharon Rosner @@ -8001,7 +8030,7 @@ OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. ========== -Notice for: tzinfo-2.0.2 +Notice for: tzinfo-2.0.4 ---------- Copyright (c) 2005-2018 Philip Ross @@ -8025,7 +8054,7 @@ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. ========== -Notice for: tzinfo-data-1.2020.1 +Notice for: tzinfo-data-1.2020.6 ---------- Copyright (c) 2005-2018 Philip Ross @@ -8096,7 +8125,7 @@ Copyright (C) 2012 Fluentd Project limitations under the License. ========== -Notice for: xml-simple-1.1.5 +Notice for: xml-simple-1.1.8 ---------- Readme.md: diff --git a/tools/dependencies-report/src/main/resources/licenseMapping.csv b/tools/dependencies-report/src/main/resources/licenseMapping.csv index 98e2c636c..1504ffde3 100644 --- a/tools/dependencies-report/src/main/resources/licenseMapping.csv +++ b/tools/dependencies-report/src/main/resources/licenseMapping.csv @@ -118,6 +118,7 @@ dependency,dependencyUrl,licenseOverride,copyright,sourceURL "pry:",http://pryrepl.org,MIT "public_suffix:",https://simonecarletti.com/code/publicsuffix-ruby,MIT "puma:",http://puma.io,BSD-3-Clause +"racc:",https://github.com/ruby/rake,Ruby "rack-protection:",http://github.com/rkh/rack-protection,MIT "rack:",http://rack.github.io/,MIT "rake:",https://github.com/ruby/rake,MIT diff --git a/tools/dependencies-report/src/main/resources/notices/racc-NOTICE.txt b/tools/dependencies-report/src/main/resources/notices/racc-NOTICE.txt new file mode 100644 index 000000000..c6ce0a915 --- /dev/null +++ b/tools/dependencies-report/src/main/resources/notices/racc-NOTICE.txt @@ -0,0 +1,24 @@ +source: https://github.com/ruby/racc/blob/master/COPYING + +Copyright (C) 2019 Yukihiro Matsumoto. All rights reserved. + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions +are met: +1. Redistributions of source code must retain the above copyright +notice, this list of conditions and the following disclaimer. +2. Redistributions in binary form must reproduce the above copyright +notice, this list of conditions and the following disclaimer in the +documentation and/or other materials provided with the distribution. + +THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND +ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE +FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL +DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS +OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) +HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT +LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY +OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF +SUCH DAMAGE. From c5941e6340f1a8a182787b4e2ddf5d7b085601e9 Mon Sep 17 00:00:00 2001 From: Karen Metts <35154725+karenzone@users.noreply.github.com> Date: Mon, 4 Jan 2021 16:09:59 -0500 Subject: [PATCH 0651/1126] Doc: Add info on contributor program Backports #12543 to 7.x --- CONTRIBUTING.md | 2 ++ 1 file changed, 2 insertions(+) diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index f9b2c4470..3295219d8 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -3,6 +3,8 @@ All contributions are welcome: ideas, patches, documentation, bug reports, complaints, etc! +If you want to be rewarded for your contributions, sign up for the [Elastic Contributor Program](https://www.elastic.co/community/contributor). Each time you make a valid contribution, you’ll earn points that increase your chances of winning prizes and being recognized as a top contributor. + Programming is not a required skill, and there are many ways to help out! It is more important to us that you are able to contribute. From e2f2255fa56c7056c814a3e1ce089cb0ca037eaa Mon Sep 17 00:00:00 2001 From: Ry Biesemeyer Date: Thu, 7 Jan 2021 17:44:23 +0000 Subject: [PATCH 0652/1126] pq: eliminate corruption by forcing version byte to be persisted When the PQ creates a new page and allocates a memory-mapped buffer, the underlying file is zero'd out to full page capacity and the version byte is written to the buffer. If Logstash crashes or is shut down before any elements have been pushed into the queue page, we have no guarantees that the version marker has been persisted to the storage device. A subsequent attempt to load an all-zeros queue page will result in an obscure error message and failure to load: ~~~ AbstractPipelineExt - Logstash failed to create queue. org.logstash.ackedqueue.io.MmapPageIOV2$PageIOInvalidVersionException: Expected page version=2 but found version=0 ~~~ By sending `MappedByteBuffer#force()` immediately after the version has been added to the buffer, we can shrink the window in which a crash can leave the queue on disk in a corrupt state. --- .../src/main/java/org/logstash/ackedqueue/io/MmapPageIOV2.java | 1 + 1 file changed, 1 insertion(+) diff --git a/logstash-core/src/main/java/org/logstash/ackedqueue/io/MmapPageIOV2.java b/logstash-core/src/main/java/org/logstash/ackedqueue/io/MmapPageIOV2.java index 2c8dd403a..ecb4ee170 100644 --- a/logstash-core/src/main/java/org/logstash/ackedqueue/io/MmapPageIOV2.java +++ b/logstash-core/src/main/java/org/logstash/ackedqueue/io/MmapPageIOV2.java @@ -190,6 +190,7 @@ public final class MmapPageIOV2 implements PageIO { } buffer.position(0); buffer.put(VERSION_TWO); + buffer.force(); this.head = 1; this.minSeqNum = 0L; this.elementCount = 0; From 98d3ac9d003ad2178e6e27c28ae67cb67aa09bb8 Mon Sep 17 00:00:00 2001 From: andsel Date: Tue, 15 Dec 2020 17:39:02 +0100 Subject: [PATCH 0653/1126] Moved ingest-converter tool from Javascript to Java, preserving the same behaviour (#12524) (cherry picked from commit aa3576d74d02f909aff7fa6348f57d43d6e3192d) --- tools/ingest-converter/build.gradle | 1 + .../org/logstash/ingest/IngestAppend.java | 72 ++++++ .../org/logstash/ingest/IngestConvert.java | 66 +++++ .../org/logstash/ingest/IngestConverter.java | 231 ++++++++++++++++++ .../java/org/logstash/ingest/IngestDate.java | 97 ++++++++ .../java/org/logstash/ingest/IngestGeoIp.java | 85 +++++++ .../java/org/logstash/ingest/IngestGrok.java | 99 ++++++++ .../java/org/logstash/ingest/IngestGsub.java | 67 +++++ .../java/org/logstash/ingest/IngestJson.java | 79 ++++++ .../org/logstash/ingest/IngestLowercase.java | 67 +++++ .../org/logstash/ingest/IngestPipeline.java | 136 +++++++++++ .../org/logstash/ingest/IngestRename.java | 66 +++++ .../java/org/logstash/ingest/IngestSet.java | 80 ++++++ .../main/java/org/logstash/ingest/JsUtil.java | 89 ++++++- .../src/main/resources/ingest-append.js | 40 --- .../src/main/resources/ingest-convert.js | 34 --- .../src/main/resources/ingest-date.js | 60 ----- .../src/main/resources/ingest-geoip.js | 50 ---- .../src/main/resources/ingest-grok.js | 68 ------ .../src/main/resources/ingest-gsub.js | 33 --- .../src/main/resources/ingest-json.js | 48 ---- .../src/main/resources/ingest-lowercase.js | 34 --- .../src/main/resources/ingest-pipeline.js | 97 -------- .../src/main/resources/ingest-rename.js | 34 --- .../src/main/resources/ingest-set.js | 44 ---- .../src/main/resources/ingest-shared.js | 184 -------------- 26 files changed, 1228 insertions(+), 733 deletions(-) create mode 100644 tools/ingest-converter/src/main/java/org/logstash/ingest/IngestAppend.java create mode 100644 tools/ingest-converter/src/main/java/org/logstash/ingest/IngestConvert.java create mode 100644 tools/ingest-converter/src/main/java/org/logstash/ingest/IngestConverter.java create mode 100644 tools/ingest-converter/src/main/java/org/logstash/ingest/IngestDate.java create mode 100644 tools/ingest-converter/src/main/java/org/logstash/ingest/IngestGeoIp.java create mode 100644 tools/ingest-converter/src/main/java/org/logstash/ingest/IngestGrok.java create mode 100644 tools/ingest-converter/src/main/java/org/logstash/ingest/IngestGsub.java create mode 100644 tools/ingest-converter/src/main/java/org/logstash/ingest/IngestJson.java create mode 100644 tools/ingest-converter/src/main/java/org/logstash/ingest/IngestLowercase.java create mode 100644 tools/ingest-converter/src/main/java/org/logstash/ingest/IngestPipeline.java create mode 100644 tools/ingest-converter/src/main/java/org/logstash/ingest/IngestRename.java create mode 100644 tools/ingest-converter/src/main/java/org/logstash/ingest/IngestSet.java delete mode 100644 tools/ingest-converter/src/main/resources/ingest-append.js delete mode 100644 tools/ingest-converter/src/main/resources/ingest-convert.js delete mode 100644 tools/ingest-converter/src/main/resources/ingest-date.js delete mode 100644 tools/ingest-converter/src/main/resources/ingest-geoip.js delete mode 100644 tools/ingest-converter/src/main/resources/ingest-grok.js delete mode 100644 tools/ingest-converter/src/main/resources/ingest-gsub.js delete mode 100644 tools/ingest-converter/src/main/resources/ingest-json.js delete mode 100644 tools/ingest-converter/src/main/resources/ingest-lowercase.js delete mode 100644 tools/ingest-converter/src/main/resources/ingest-pipeline.js delete mode 100644 tools/ingest-converter/src/main/resources/ingest-rename.js delete mode 100644 tools/ingest-converter/src/main/resources/ingest-set.js delete mode 100644 tools/ingest-converter/src/main/resources/ingest-shared.js diff --git a/tools/ingest-converter/build.gradle b/tools/ingest-converter/build.gradle index b30a0e7c5..1e9699116 100644 --- a/tools/ingest-converter/build.gradle +++ b/tools/ingest-converter/build.gradle @@ -43,6 +43,7 @@ buildscript { dependencies { implementation 'net.sf.jopt-simple:jopt-simple:4.6' + implementation 'com.fasterxml.jackson.core:jackson-databind:2.11.3' testImplementation "junit:junit:4.12" testImplementation 'commons-io:commons-io:2.5' } diff --git a/tools/ingest-converter/src/main/java/org/logstash/ingest/IngestAppend.java b/tools/ingest-converter/src/main/java/org/logstash/ingest/IngestAppend.java new file mode 100644 index 000000000..eee5d8dfb --- /dev/null +++ b/tools/ingest-converter/src/main/java/org/logstash/ingest/IngestAppend.java @@ -0,0 +1,72 @@ +/* + * 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. + */ + +package org.logstash.ingest; + +import com.fasterxml.jackson.core.JsonProcessingException; +import com.fasterxml.jackson.core.type.TypeReference; +import com.fasterxml.jackson.databind.ObjectMapper; + +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import java.util.stream.Collectors; + +public class IngestAppend { + + /** + * Converts Ingest Append JSON to LS mutate filter. + */ + @SuppressWarnings({"rawtypes", "unchecked"}) + public static String toLogstash(String json, boolean appendStdio) throws JsonProcessingException { + ObjectMapper mapper = new ObjectMapper(); + TypeReference> typeRef = new TypeReference>() {}; + final HashMap jsonDefinition = mapper.readValue(json, typeRef); + final List processors = (List) jsonDefinition.get("processors"); + List filters_pipeline = processors.stream().map(IngestAppend::mapProcessor).collect(Collectors.toList()); + + return IngestConverter.filtersToFile( + IngestConverter.appendIoPlugins(filters_pipeline, appendStdio)); + } + + @SuppressWarnings({"rawtypes", "unchecked"}) + private static String mapProcessor(Map processor) { + return IngestConverter.filterHash(IngestConverter.createHash("mutate", appendHash(processor))); + } + + @SuppressWarnings({"rawtypes", "unchecked"}) + static String appendHash(Map processor) { + Map append_json = processor.get("append"); + Object value = append_json.get("value"); + Object value_contents; + if (value instanceof List) { + value_contents = IngestConverter.createArray((List) value); + } else { + value_contents = IngestConverter.quoteString((String) value); + } + Object mutate_contents = IngestConverter.createField( + IngestConverter.quoteString(IngestConverter.dotsToSquareBrackets((String) append_json.get("field"))), + (String) value_contents); + return IngestConverter.createField("add_field", IngestConverter.wrapInCurly((String) mutate_contents)); + } + + public static boolean has_append(Map processor) { + return processor.containsKey("append"); + } +} diff --git a/tools/ingest-converter/src/main/java/org/logstash/ingest/IngestConvert.java b/tools/ingest-converter/src/main/java/org/logstash/ingest/IngestConvert.java new file mode 100644 index 000000000..6c1128264 --- /dev/null +++ b/tools/ingest-converter/src/main/java/org/logstash/ingest/IngestConvert.java @@ -0,0 +1,66 @@ +/* + * 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. + */ + +package org.logstash.ingest; + +import com.fasterxml.jackson.core.JsonProcessingException; +import com.fasterxml.jackson.core.type.TypeReference; +import com.fasterxml.jackson.databind.ObjectMapper; + +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import java.util.stream.Collectors; + +public class IngestConvert { + + /** + * Converts Ingest Convert JSON to LS Date filter. + */ + @SuppressWarnings({"rawtypes", "unchecked"}) + public static String toLogstash(String json, boolean appendStdio) throws JsonProcessingException { + ObjectMapper mapper = new ObjectMapper(); + TypeReference> typeRef = new TypeReference>() {}; + final HashMap jsonDefinition = mapper.readValue(json, typeRef); + final List processors = (List) jsonDefinition.get("processors"); + List filters_pipeline = processors.stream().map(IngestConvert::mapProcessor).collect(Collectors.toList()); + + return IngestConverter.filtersToFile( + IngestConverter.appendIoPlugins(filters_pipeline, appendStdio)); + } + + @SuppressWarnings({"rawtypes", "unchecked"}) + private static String mapProcessor(Map processor) { + return IngestConverter.filterHash(IngestConverter.createHash("mutate", convertHash(processor))); + } + + @SuppressWarnings({"rawtypes", "unchecked"}) + static String convertHash(Map processor) { + Map convert_json = processor.get("convert"); + + Object mutate_contents = IngestConverter.createField( + IngestConverter.quoteString(IngestConverter.dotsToSquareBrackets((String) convert_json.get("field"))), + IngestConverter.quoteString((String) convert_json.get("type"))); + return IngestConverter.createField("convert", IngestConverter.wrapInCurly((String) mutate_contents)); + } + + public static boolean has_convert(Map processor) { + return processor.containsKey("convert"); + } +} diff --git a/tools/ingest-converter/src/main/java/org/logstash/ingest/IngestConverter.java b/tools/ingest-converter/src/main/java/org/logstash/ingest/IngestConverter.java new file mode 100644 index 000000000..16bc91e3c --- /dev/null +++ b/tools/ingest-converter/src/main/java/org/logstash/ingest/IngestConverter.java @@ -0,0 +1,231 @@ +/* + * 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. + */ +package org.logstash.ingest; + +import java.util.ArrayList; +import java.util.Arrays; +import java.util.List; +import java.util.Map; +import java.util.regex.Matcher; +import java.util.regex.Pattern; +import java.util.stream.Collectors; + +public class IngestConverter { + + /** + * Translates the JSON naming pattern (`name.qualifier.sub`) into the LS pattern + * [name][qualifier][sub] for all applicable tokens in the given string. + * This function correctly identifies and omits renaming of string literals. + * @param content to replace naming pattern in + * @returns {string} with Json naming translated into grok naming + */ + public static String dotsToSquareBrackets(String content) { + final Pattern pattern = Pattern.compile("\\(\\?:%\\{.*\\|-\\)"); + final Matcher matcher = pattern.matcher(content); + List tokens = new ArrayList<>(); + String right = content; + while (matcher.find()) { + final int start = matcher.start(); + final int end = matcher.end(); + final String matchContent = content.substring(start, end); + right = content.substring(end); + tokens.add(tokenDotsToSquareBrackets(content.substring(0, start))); + tokens.add(matchContent); + } + tokens.add(tokenDotsToSquareBrackets(right)); + return String.join("", tokens); + } + + private static String tokenDotsToSquareBrackets(String content) { + //Break out if this is not a naming pattern we convert + final String adjusted; + if (Pattern.compile("([\\w_]+\\.)+[\\w_]+").matcher(content).find()) { + adjusted = content.replaceAll("(\\w*)\\.(\\w*)", "$1][$2") + .replaceAll("\\[(\\w+)(}|$)", "[$1]$2") + .replaceAll("\\{(\\w+):(\\w+)]", "{$1:[$2]") + .replaceAll("^(\\w+)]\\[", "[$1]["); + } else { + adjusted = content; + } + return adjusted; + } + + public static String quoteString(String content) { + return "\"" + content.replace("\"", "\\\"") + "\""; + } + + public static String wrapInCurly(String content) { + return "{\n" + content + "\n}"; + } + + public static String createField(String fieldName, String content) { + return fieldName + " => " + content; + } + + public static String createHash(String fieldName, String content) { + return fieldName + " " + wrapInCurly(content); + } + + /** + * All hash fields in LS start on a new line. + * @param fields Array of Strings of Serialized Hash Fields + * @returns {string} Joined Serialization of Hash Fields + */ + public static String joinHashFields(String... fields) { + return String.join("\n", fields); + } + + /** + * Fixes indentation in LS string. + * @param content LS string to fix indentation in, that has no indentation intentionally with + * all lines starting on a token without preceding spaces. + * @return LS string indented by 3 spaces per level + */ + public static String fixIndent(String content) { + final String[] lines = content.split("\n"); + int count = 0; + for (int i = 0; i < lines.length; i++) { + if (Pattern.compile("(\\{|\\[)$").matcher(lines[i]).find()) { + lines[i] = indent(lines[i], count); + ++count; + } else if (Pattern.compile("(\\}|\\])$").matcher(lines[i]).find()) { + --count; + lines[i] = indent(lines[i], count); + // Only indent line if previous line ended on relevant control char. + } else if (i > 0 && Pattern.compile("(=>\\s+\".+\"|,|\\{|\\}|\\[|\\])$").matcher(lines[i - 1]).find()) { + lines[i] = indent(lines[i], count); + } + } + + return String.join("\n", lines); + } + + private static String indent(String content, int shifts) { + StringBuilder spacing = new StringBuilder(); + for (int i = 0; i < shifts * 3; i++) { + spacing.append(" "); + } + return spacing.append(content).toString(); + } + + /** + * Converts Ingest/JSON style pattern array to LS pattern array, performing necessary variable + * name and quote escaping adjustments. + * @param patterns Pattern Array in JSON formatting + * @return Pattern array in LS formatting + */ + public static String createPatternArray(String... patterns) { + final String body = Arrays.stream(patterns) + .map(IngestConverter::dotsToSquareBrackets) + .map(IngestConverter::quoteString) + .collect(Collectors.joining(",\n")); + return "[\n" + body + "\n]"; + } + + public static String createArray(List ingestArray) { + final String body = ingestArray.stream() + .map(IngestConverter::quoteString) + .collect(Collectors.joining(",\n")); + return "[\n" + body + "\n]"; + } + + + /** + * Converts Ingest/JSON style pattern array to LS pattern array or string if the given array + * contains a single element only, performing necessary variable name and quote escaping + * adjustments. + * @param patterns Pattern Array in JSON formatting + * @return Pattern array or string in LS formatting + */ + public static String createPatternArrayOrField(String... patterns) { + return patterns.length == 1 + ? quoteString(dotsToSquareBrackets(patterns[0])) + : createPatternArray(patterns); + } + + public static String filterHash(String contents) { + return fixIndent(createHash("filter", contents)); + } + + public static String filtersToFile(String... filters) { + return String.join("\n\n", filters) + "\n"; + } + + /** + * Does it have an on_failure field? + * @param processor Json + * @param name Name of the processor + * @return true if has on failure + */ + @SuppressWarnings("rawtypes") + public static boolean hasOnFailure(Map processor, String name) { + final List onFailure = (List) processor.get(name).get("on_failure"); + return onFailure != null && !onFailure.isEmpty(); + } + + @SuppressWarnings({"rawtypes", "unchecked"}) + public static List> getOnFailure(Map processor, String name) { + return (List>) processor.get(name).get("on_failure"); + } + + /** + * Creates an if clause with the tag name + * @param tag String tag name to find in [tags] field + * @param onFailurePipeline The on failure pipeline converted to LS to tack on in the conditional + * @return a string representing a conditional logic + */ + public static String createTagConditional(String tag, String onFailurePipeline) { + return "if " + quoteString(tag) + " in [tags] {\n" + + onFailurePipeline + "\n" + + "}"; + } + + public static String getElasticsearchOutput() { + return fixIndent("output {\n" + + "elasticsearch {\n" + + "hosts => \"localhost\"\n" + + "}\n" + + "}"); + } + + public static String getStdinInput() { + return fixIndent("input {\n" + + "stdin {\n" + + "}\n" + + "}"); + } + + public static String getStdoutOutput() { + return fixIndent("output {\n" + + "stdout {\n" + + "codec => \"rubydebug\"\n" + + "}\n" + + "}"); + } + + public static String appendIoPlugins(List filtersPipeline, boolean appendStdio) { + // TODO create unique list to join all + String filtersPipelineStr = String.join("\n", filtersPipeline); + if (appendStdio) { + return String.join("\n", IngestConverter.getStdinInput(), filtersPipelineStr, IngestConverter.getStdoutOutput()); + } else { + return String.join("\n", filtersPipelineStr, IngestConverter.getElasticsearchOutput()); + } + } +} diff --git a/tools/ingest-converter/src/main/java/org/logstash/ingest/IngestDate.java b/tools/ingest-converter/src/main/java/org/logstash/ingest/IngestDate.java new file mode 100644 index 000000000..6aea685e8 --- /dev/null +++ b/tools/ingest-converter/src/main/java/org/logstash/ingest/IngestDate.java @@ -0,0 +1,97 @@ +/* + * 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. + */ + +package org.logstash.ingest; + +import com.fasterxml.jackson.core.JsonProcessingException; +import com.fasterxml.jackson.core.type.TypeReference; +import com.fasterxml.jackson.databind.ObjectMapper; + +import java.util.ArrayList; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import java.util.stream.Collectors; + +public class IngestDate { + + /** + * Converts Ingest Date JSON to LS Date filter. + */ + @SuppressWarnings({"rawtypes", "unchecked"}) + public static String toLogstash(String json, boolean appendStdio) throws JsonProcessingException { + ObjectMapper mapper = new ObjectMapper(); + TypeReference> typeRef = new TypeReference>() {}; + final HashMap jsonDefinition = mapper.readValue(json, typeRef); + final List processors = (List) jsonDefinition.get("processors"); + List filters_pipeline = processors.stream().map(IngestDate::mapProcessor).collect(Collectors.toList()); + + return IngestConverter.filtersToFile( + IngestConverter.appendIoPlugins(filters_pipeline, appendStdio)); + } + + @SuppressWarnings({"rawtypes", "unchecked"}) + private static String mapProcessor(Map processor) { + return IngestConverter.filterHash(IngestConverter.createHash("date", dateHash(processor))); + } + + @SuppressWarnings({"rawtypes", "unchecked"}) + static String dateHash(Map processor) { + Map date_json = processor.get("date"); + List formats = (List) date_json.get("formats"); + + final String firstElem = IngestConverter.dotsToSquareBrackets((String) date_json.get("field")); + List match_contents = new ArrayList<>(); + match_contents.add(firstElem); + for (String f : formats) { + match_contents.add(f); + } + String date_contents = IngestConverter.createField( + "match", + IngestConverter.createPatternArray(match_contents.toArray(new String[0]))); + if (JsUtil.isNotEmpty((String) date_json.get("target_field"))) { + String target = IngestConverter.createField( + "target", + IngestConverter.quoteString( + IngestConverter.dotsToSquareBrackets((String) date_json.get("target_field")) + ) + ); + date_contents = IngestConverter.joinHashFields(date_contents, target); + } + if (JsUtil.isNotEmpty((String) date_json.get("timezone"))) { + String timezone = IngestConverter.createField( + "timezone", + IngestConverter.quoteString((String) date_json.get("timezone")) + ); + date_contents = IngestConverter.joinHashFields(date_contents, timezone); + } + if (JsUtil.isNotEmpty((String) date_json.get("locale"))) { + String locale = IngestConverter.createField( + "locale", + IngestConverter.quoteString((String) date_json.get("locale")) + ); + date_contents = IngestConverter.joinHashFields(date_contents, locale); + } + return date_contents; + } + + public static boolean has_date(Map processor) { + return processor.containsKey("date"); + } +} diff --git a/tools/ingest-converter/src/main/java/org/logstash/ingest/IngestGeoIp.java b/tools/ingest-converter/src/main/java/org/logstash/ingest/IngestGeoIp.java new file mode 100644 index 000000000..3394ba52d --- /dev/null +++ b/tools/ingest-converter/src/main/java/org/logstash/ingest/IngestGeoIp.java @@ -0,0 +1,85 @@ +/* + * 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. + */ + +package org.logstash.ingest; + +import com.fasterxml.jackson.core.JsonProcessingException; +import com.fasterxml.jackson.core.type.TypeReference; +import com.fasterxml.jackson.databind.ObjectMapper; + +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import java.util.stream.Collectors; + +public class IngestGeoIp { + + + /** + * Converts Ingest Date JSON to LS Date filter. + */ + @SuppressWarnings({"rawtypes", "unchecked"}) + public static String toLogstash(String json, boolean appendStdio) throws JsonProcessingException { + ObjectMapper mapper = new ObjectMapper(); + TypeReference> typeRef = new TypeReference>() {}; + final HashMap jsonDefinition = mapper.readValue(json, typeRef); + final List processors = (List) jsonDefinition.get("processors"); + List filters_pipeline = processors.stream().map(IngestGeoIp::mapProcessor).collect(Collectors.toList()); + + return IngestConverter.filtersToFile( + IngestConverter.appendIoPlugins(filters_pipeline, appendStdio)); + } + + @SuppressWarnings({"rawtypes", "unchecked"}) + private static String mapProcessor(Map processor) { + return IngestConverter.filterHash(IngestConverter.createHash("geoip", geoIpHash(processor))); + } + + @SuppressWarnings({"rawtypes", "unchecked"}) + static String geoIpHash(Map processor) { + Map geoip_data = processor.get("geoip"); + final String sourceField = IngestConverter.createField( + "source", + IngestConverter.quoteString( + IngestConverter.dotsToSquareBrackets((String) geoip_data.get("field")) + ) + ); + + final String targetField = IngestConverter.createField( + "target", + IngestConverter.quoteString( + IngestConverter.dotsToSquareBrackets((String) geoip_data.get("target_field")) + ) + ); + + if (geoip_data.containsKey("properties")) { + String fields = IngestConverter.createField( + "fields", + IngestConverter.createPatternArray(((List) geoip_data.get("properties")).toArray(new String[0]) + )); + return IngestConverter.joinHashFields(sourceField, targetField, fields); + } else { + return IngestConverter.joinHashFields(sourceField, targetField); + } + } + + public static boolean has_geoip(Map processor) { + return processor.containsKey("geoip"); + } +} diff --git a/tools/ingest-converter/src/main/java/org/logstash/ingest/IngestGrok.java b/tools/ingest-converter/src/main/java/org/logstash/ingest/IngestGrok.java new file mode 100644 index 000000000..9c8c8067b --- /dev/null +++ b/tools/ingest-converter/src/main/java/org/logstash/ingest/IngestGrok.java @@ -0,0 +1,99 @@ +/* + * 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. + */ + +package org.logstash.ingest; + +import com.fasterxml.jackson.core.JsonProcessingException; +import com.fasterxml.jackson.core.type.TypeReference; +import com.fasterxml.jackson.databind.ObjectMapper; + +import java.util.ArrayList; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import java.util.stream.Collectors; + +public class IngestGrok { + + /** + * Converts Ingest JSON to LS Grok. + */ + @SuppressWarnings({"rawtypes", "unchecked"}) + public static String toLogstash(String json, boolean appendStdio) throws JsonProcessingException { + ObjectMapper mapper = new ObjectMapper(); + TypeReference> typeRef = new TypeReference>() {}; + final HashMap jsonDefinition = mapper.readValue(json, typeRef); + final List processors = (List) jsonDefinition.get("processors"); + List filters_pipeline = processors.stream().map(IngestGrok::mapProcessor).collect(Collectors.toList()); + + return IngestConverter.filtersToFile( + IngestConverter.appendIoPlugins(filters_pipeline, appendStdio)); + } + + @SuppressWarnings({"rawtypes", "unchecked"}) + private static String mapProcessor(Map processor) { + return IngestConverter.filterHash(IngestConverter.createHash("grok", grokHash(processor))); + } + + @SuppressWarnings({"rawtypes", "unchecked"}) + static String grokHash(Map processor) { + Map grok_data = processor.get("grok"); + String grok_contents = createHashField("match", + IngestConverter.createField( + IngestConverter.quoteString((String) grok_data.get("field")), + IngestConverter.createPatternArrayOrField(((List) grok_data.get("patterns")).toArray(new String[0])) + )); + if (grok_data.containsKey("pattern_definitions")) { + grok_contents = IngestConverter.joinHashFields( + grok_contents, + createPatternDefinitionHash((Map) grok_data.get("pattern_definitions")) + ); + } + return grok_contents; + } + + private static String createHashField(String name, String content) { + return IngestConverter.createField(name, IngestConverter.wrapInCurly(content)); + } + + private static String createPatternDefinitionHash(Map definitions) { + List content = new ArrayList<>(); + for(Map.Entry entry : definitions.entrySet()) { + content.add(IngestConverter.createField( + IngestConverter.quoteString(entry.getKey()), + IngestConverter.quoteString(entry.getValue()))); + } + + final String patternDefs = content.stream().map(IngestConverter::dotsToSquareBrackets) + .collect(Collectors.joining("\n")); + + return createHashField( + "pattern_definitions", + patternDefs + ); + } + + public static boolean has_grok(Map processor) { + return processor.containsKey(get_name()); + } + + public static String get_name() { + return "grok"; + } +} diff --git a/tools/ingest-converter/src/main/java/org/logstash/ingest/IngestGsub.java b/tools/ingest-converter/src/main/java/org/logstash/ingest/IngestGsub.java new file mode 100644 index 000000000..1ff3e3b51 --- /dev/null +++ b/tools/ingest-converter/src/main/java/org/logstash/ingest/IngestGsub.java @@ -0,0 +1,67 @@ +/* + * 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. + */ + +package org.logstash.ingest; + +import com.fasterxml.jackson.core.JsonProcessingException; +import com.fasterxml.jackson.core.type.TypeReference; +import com.fasterxml.jackson.databind.ObjectMapper; + +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import java.util.stream.Collectors; + +public class IngestGsub { + + /** + * Converts Ingest JSON to LS Grok. + */ + @SuppressWarnings({"rawtypes", "unchecked"}) + public static String toLogstash(String json, boolean appendStdio) throws JsonProcessingException { + ObjectMapper mapper = new ObjectMapper(); + TypeReference> typeRef = new TypeReference>() {}; + final HashMap jsonDefinition = mapper.readValue(json, typeRef); + final List processors = (List) jsonDefinition.get("processors"); + List filters_pipeline = processors.stream().map(IngestGsub::mapProcessor).collect(Collectors.toList()); + + return IngestConverter.filtersToFile( + IngestConverter.appendIoPlugins(filters_pipeline, appendStdio)); + } + + @SuppressWarnings({"rawtypes", "unchecked"}) + private static String mapProcessor(Map processor) { + return IngestConverter.filterHash(IngestConverter.createHash("mutate", gsubHash(processor))); + } + + @SuppressWarnings({"rawtypes", "unchecked"}) + static String gsubHash(Map processor) { + Map gsub_data = processor.get("gsub"); + final String body = String.join(", ", + IngestConverter.quoteString(IngestConverter.dotsToSquareBrackets((String) gsub_data.get("field"))), + IngestConverter.quoteString((String) gsub_data.get("pattern")), + IngestConverter.quoteString((String) gsub_data.get("replacement"))); + + return IngestConverter.createField("gsub", "[\n" + body + "\n]"); + } + + public static boolean has_gsub(Map processor) { + return processor.containsKey("gsub"); + } +} diff --git a/tools/ingest-converter/src/main/java/org/logstash/ingest/IngestJson.java b/tools/ingest-converter/src/main/java/org/logstash/ingest/IngestJson.java new file mode 100644 index 000000000..77a9b37df --- /dev/null +++ b/tools/ingest-converter/src/main/java/org/logstash/ingest/IngestJson.java @@ -0,0 +1,79 @@ +/* + * 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. + */ + +package org.logstash.ingest; + +import com.fasterxml.jackson.core.JsonProcessingException; +import com.fasterxml.jackson.core.type.TypeReference; +import com.fasterxml.jackson.databind.ObjectMapper; + +import java.util.ArrayList; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import java.util.stream.Collectors; + +public class IngestJson { + + /** + * Converts Ingest json processor to LS json filter. + */ + @SuppressWarnings({"rawtypes", "unchecked"}) + public static String toLogstash(String json, boolean appendStdio) throws JsonProcessingException { + ObjectMapper mapper = new ObjectMapper(); + TypeReference> typeRef = new TypeReference>() {}; + final HashMap jsonDefinition = mapper.readValue(json, typeRef); + final List processors = (List) jsonDefinition.get("processors"); + List filters_pipeline = processors.stream().map(IngestJson::mapProcessor).collect(Collectors.toList()); + + return IngestConverter.filtersToFile( + IngestConverter.appendIoPlugins(filters_pipeline, appendStdio)); + } + + @SuppressWarnings({"rawtypes", "unchecked"}) + private static String mapProcessor(Map processor) { + return IngestConverter.filterHash(IngestConverter.createHash("json", jsonHash(processor))); + } + + @SuppressWarnings({"rawtypes", "unchecked"}) + static String jsonHash(Map processor) { + Map json_data = processor.get("json"); + + List parts = new ArrayList(); + parts.add(IngestConverter.createField("source", + IngestConverter.quoteString( + IngestConverter.dotsToSquareBrackets((String) json_data.get("field")) + ) + )); + + if (json_data.containsKey("target_field")) { + parts.add(IngestConverter.createField( + "target", + IngestConverter.quoteString( + IngestConverter.dotsToSquareBrackets((String) json_data.get("target_field")) + ) + )); + } + return IngestConverter.joinHashFields(parts.toArray(new String[0])); + } + + public static boolean has_json(Map processor) { + return processor.containsKey("json"); + } +} diff --git a/tools/ingest-converter/src/main/java/org/logstash/ingest/IngestLowercase.java b/tools/ingest-converter/src/main/java/org/logstash/ingest/IngestLowercase.java new file mode 100644 index 000000000..09b3c703a --- /dev/null +++ b/tools/ingest-converter/src/main/java/org/logstash/ingest/IngestLowercase.java @@ -0,0 +1,67 @@ +/* + * 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. + */ + +package org.logstash.ingest; + +import com.fasterxml.jackson.core.JsonProcessingException; +import com.fasterxml.jackson.core.type.TypeReference; +import com.fasterxml.jackson.databind.ObjectMapper; + +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import java.util.stream.Collectors; + +public class IngestLowercase { + + /** + * Converts Ingest Lowercase JSON to LS mutate filter. + */ + @SuppressWarnings({"rawtypes", "unchecked"}) + public static String toLogstash(String json, boolean appendStdio) throws JsonProcessingException { + ObjectMapper mapper = new ObjectMapper(); + TypeReference> typeRef = new TypeReference>() {}; + final HashMap jsonDefinition = mapper.readValue(json, typeRef); + final List processors = (List) jsonDefinition.get("processors"); + List filters_pipeline = processors.stream().map(IngestLowercase::mapProcessor).collect(Collectors.toList()); + + return IngestConverter.filtersToFile( + IngestConverter.appendIoPlugins(filters_pipeline, appendStdio)); + } + + @SuppressWarnings({"rawtypes", "unchecked"}) + private static String mapProcessor(Map processor) { + return IngestConverter.filterHash(IngestConverter.createHash("mutate", lowercaseHash(processor))); + } + + @SuppressWarnings({"rawtypes", "unchecked"}) + static String lowercaseHash(Map processor) { + Map lowercase_data = processor.get("lowercase"); + return IngestConverter.createField( + "lowercase", + IngestConverter.quoteString( + IngestConverter.dotsToSquareBrackets((String) lowercase_data.get("field")) + ) + ); + } + + public static boolean has_lowercase(Map processor) { + return processor.containsKey("lowercase"); + } +} diff --git a/tools/ingest-converter/src/main/java/org/logstash/ingest/IngestPipeline.java b/tools/ingest-converter/src/main/java/org/logstash/ingest/IngestPipeline.java new file mode 100644 index 000000000..1084f680c --- /dev/null +++ b/tools/ingest-converter/src/main/java/org/logstash/ingest/IngestPipeline.java @@ -0,0 +1,136 @@ +/* + * 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. + */ + +package org.logstash.ingest; + +import com.fasterxml.jackson.core.JsonProcessingException; +import com.fasterxml.jackson.core.type.TypeReference; +import com.fasterxml.jackson.databind.ObjectMapper; + +import java.util.ArrayList; +import java.util.Collections; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import java.util.stream.Collectors; + +public class IngestPipeline { + + /** + * Converts Ingest JSON to LS. + */ + @SuppressWarnings({"rawtypes", "unchecked"}) + public static String toLogstash(String json, boolean appendStdio) throws JsonProcessingException { + ObjectMapper mapper = new ObjectMapper(); + TypeReference> typeRef = new TypeReference>() {}; + final HashMap jsonDefinition = mapper.readValue(json, typeRef); + final List processors = (List) jsonDefinition.get("processors"); + List filters_pipeline = processors.stream().map(IngestPipeline::mapProcessor).collect(Collectors.toList()); + + String logstash_pipeline = IngestConverter.filterHash( + IngestConverter.joinHashFields(filters_pipeline.toArray(new String[0]))); + + return IngestConverter.filtersToFile( + IngestConverter.appendIoPlugins(Collections.singletonList(logstash_pipeline), appendStdio)); + } + + @SuppressWarnings({"rawtypes", "unchecked"}) + private static String mapProcessor(Map processor) { + List filter_blocks = new ArrayList<>(); + if (IngestGrok.has_grok(processor)) { + filter_blocks.add(IngestConverter.createHash(IngestGrok.get_name(), IngestGrok.grokHash(processor))); + + if (IngestConverter.hasOnFailure(processor, IngestGrok.get_name())) { + filter_blocks.add( + handle_on_failure_pipeline( + IngestConverter.getOnFailure(processor, IngestGrok.get_name()), + "_grokparsefailure" + ) + ); + } + } + boolean processed = false; + if (IngestDate.has_date(processor)) { + filter_blocks.add( + IngestConverter.createHash("date", IngestDate.dateHash(processor)) + ); + processed = true; + } + if (IngestGeoIp.has_geoip(processor)) { + filter_blocks.add( + IngestConverter.createHash("geoip", IngestGeoIp.geoIpHash(processor)) + ); + processed = true; + } + if (IngestConvert.has_convert(processor)) { + filter_blocks.add( + IngestConverter.createHash("mutate", IngestConvert.convertHash(processor)) + ); + processed = true; + } + if (IngestGsub.has_gsub(processor)) { + filter_blocks.add( + IngestConverter.createHash("mutate", IngestGsub.gsubHash(processor)) + ); + processed = true; + } + if (IngestAppend.has_append(processor)) { + filter_blocks.add( + IngestConverter.createHash("mutate", IngestAppend.appendHash(processor)) + ); + processed = true; + } + if (IngestJson.has_json(processor)) { + filter_blocks.add( + IngestConverter.createHash("json", IngestJson.jsonHash(processor)) + ); + processed = true; + } + if (IngestRename.has_rename(processor)) { + filter_blocks.add( + IngestConverter.createHash("mutate", IngestRename.renameHash(processor)) + ); + processed = true; + } + if (IngestLowercase.has_lowercase(processor)) { + filter_blocks.add( + IngestConverter.createHash("mutate", IngestLowercase.lowercaseHash(processor)) + ); + processed = true; + } + if (IngestSet.has_set(processor)) { + filter_blocks.add( + IngestConverter.createHash("mutate", IngestSet.setHash(processor)) + ); + processed = true; + } + if (!processed) { + System.out.println("WARN Found unrecognized processor named: " + processor.keySet().iterator().next()); + } + return IngestConverter.joinHashFields(filter_blocks.toArray(new String[0])); + } + + @SuppressWarnings({"rawtypes", "unchecked"}) + public static String handle_on_failure_pipeline(List on_failure_json, String tag_name) { + final List mapped = on_failure_json.stream().map(IngestPipeline::mapProcessor).collect(Collectors.toList()); + return IngestConverter.createTagConditional(tag_name, + IngestConverter.joinHashFields(mapped.toArray(new String[0])) + ); + } +} diff --git a/tools/ingest-converter/src/main/java/org/logstash/ingest/IngestRename.java b/tools/ingest-converter/src/main/java/org/logstash/ingest/IngestRename.java new file mode 100644 index 000000000..a21c81f53 --- /dev/null +++ b/tools/ingest-converter/src/main/java/org/logstash/ingest/IngestRename.java @@ -0,0 +1,66 @@ +/* + * 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. + */ + +package org.logstash.ingest; + +import com.fasterxml.jackson.core.JsonProcessingException; +import com.fasterxml.jackson.core.type.TypeReference; +import com.fasterxml.jackson.databind.ObjectMapper; + +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import java.util.stream.Collectors; + +public class IngestRename { + + /** + * Converts Ingest Rename JSON to LS mutate filter. + */ + @SuppressWarnings({"rawtypes", "unchecked"}) + public static String toLogstash(String json, boolean appendStdio) throws JsonProcessingException { + ObjectMapper mapper = new ObjectMapper(); + TypeReference> typeRef = new TypeReference>() {}; + final HashMap jsonDefinition = mapper.readValue(json, typeRef); + final List processors = (List) jsonDefinition.get("processors"); + List filters_pipeline = processors.stream().map(IngestRename::mapProcessor).collect(Collectors.toList()); + + return IngestConverter.filtersToFile( + IngestConverter.appendIoPlugins(filters_pipeline, appendStdio)); + } + + @SuppressWarnings({"rawtypes", "unchecked"}) + private static String mapProcessor(Map processor) { + return IngestConverter.filterHash(IngestConverter.createHash("mutate", renameHash(processor))); + } + + @SuppressWarnings({"rawtypes", "unchecked"}) + static String renameHash(Map processor) { + Map rename_json = processor.get("rename"); + final String mutateContents = IngestConverter.createField( + IngestConverter.quoteString(IngestConverter.dotsToSquareBrackets((String) rename_json.get("field"))), + IngestConverter.quoteString(IngestConverter.dotsToSquareBrackets((String) rename_json.get("target_field"))) + ); + return IngestConverter.createField("rename", IngestConverter.wrapInCurly(mutateContents)); + } + + public static boolean has_rename(Map processor) { + return processor.containsKey("rename"); + } +} diff --git a/tools/ingest-converter/src/main/java/org/logstash/ingest/IngestSet.java b/tools/ingest-converter/src/main/java/org/logstash/ingest/IngestSet.java new file mode 100644 index 000000000..044d787ed --- /dev/null +++ b/tools/ingest-converter/src/main/java/org/logstash/ingest/IngestSet.java @@ -0,0 +1,80 @@ +/* + * 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. + */ + +package org.logstash.ingest; + +import com.fasterxml.jackson.core.JsonProcessingException; +import com.fasterxml.jackson.core.type.TypeReference; +import com.fasterxml.jackson.databind.ObjectMapper; + +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import java.util.stream.Collectors; + +public class IngestSet { + + /** + * Converts Ingest Set JSON to LS mutate filter. + */ + @SuppressWarnings({"rawtypes", "unchecked"}) + public static String toLogstash(String json, boolean appendStdio) throws JsonProcessingException { + ObjectMapper mapper = new ObjectMapper(); + TypeReference> typeRef = new TypeReference>() {}; + final HashMap jsonDefinition = mapper.readValue(json, typeRef); + final List processors = (List) jsonDefinition.get("processors"); + List filters_pipeline = processors.stream().map(IngestSet::mapProcessor).collect(Collectors.toList()); + + return IngestConverter.filtersToFile( + IngestConverter.appendIoPlugins(filters_pipeline, appendStdio)); + } + + @SuppressWarnings({"rawtypes", "unchecked"}) + private static String mapProcessor(Map processor) { + return IngestConverter.filterHash(IngestConverter.createHash("mutate", setHash(processor))); + } + + @SuppressWarnings({"rawtypes", "unchecked"}) + static String setHash(Map processor) { + Map set_json = processor.get("set"); + final Object value = set_json.get("value"); + final Object value_contents; + if (value instanceof String) { + value_contents = IngestConverter.quoteString((String) value); + } else { + value_contents = value; + } + if (set_json.containsKey("if") && set_json.get("if") != null) { + String painless_condition = (String) set_json.get("if"); + if (!painless_condition.isEmpty()) { + System.out.println("WARN Found in 'set' processor an 'if' painless condition not translated: " + painless_condition); + } + + } + + String mutate_contents = IngestConverter.createField( + IngestConverter.quoteString(IngestConverter.dotsToSquareBrackets((String) set_json.get("field"))), + value_contents.toString()); + return IngestConverter.createField("add_field", IngestConverter.wrapInCurly(mutate_contents)); + } + + public static boolean has_set(Map processor) { + return processor.containsKey("set"); + } +} diff --git a/tools/ingest-converter/src/main/java/org/logstash/ingest/JsUtil.java b/tools/ingest-converter/src/main/java/org/logstash/ingest/JsUtil.java index fd71da88a..806c2f36f 100644 --- a/tools/ingest-converter/src/main/java/org/logstash/ingest/JsUtil.java +++ b/tools/ingest-converter/src/main/java/org/logstash/ingest/JsUtil.java @@ -98,13 +98,79 @@ final class JsUtil { parser.printHelpOn(System.out); throw ex; } - final ScriptEngine engine = JsUtil.engine(); - Files.write( - Paths.get(options.valueOf(output)), - ((String) ((Invocable) engine).invokeFunction( - jsFunc, input(options.valueOf(input)), options.has(appendStdio) - )).getBytes(StandardCharsets.UTF_8) - ); + switch (jsFunc) { + case "ingest_append_to_logstash": + Files.write( + Paths.get(options.valueOf(output)), + IngestAppend.toLogstash(input(options.valueOf(input)), options.has(appendStdio)).getBytes(StandardCharsets.UTF_8) + ); + break; + case "ingest_convert_to_logstash": + Files.write( + Paths.get(options.valueOf(output)), + IngestConvert.toLogstash(input(options.valueOf(input)), options.has(appendStdio)).getBytes(StandardCharsets.UTF_8) + ); + break; + case "ingest_to_logstash_date": + Files.write( + Paths.get(options.valueOf(output)), + IngestDate.toLogstash(input(options.valueOf(input)), options.has(appendStdio)).getBytes(StandardCharsets.UTF_8) + ); + break; + case "ingest_to_logstash_geoip": + Files.write( + Paths.get(options.valueOf(output)), + IngestGeoIp.toLogstash(input(options.valueOf(input)), options.has(appendStdio)).getBytes(StandardCharsets.UTF_8) + ); + break; + case "ingest_to_logstash_grok": + Files.write( + Paths.get(options.valueOf(output)), + IngestGrok.toLogstash(input(options.valueOf(input)), options.has(appendStdio)).getBytes(StandardCharsets.UTF_8) + ); + break; + case "ingest_to_logstash_gsub": + Files.write( + Paths.get(options.valueOf(output)), + IngestGsub.toLogstash(input(options.valueOf(input)), options.has(appendStdio)).getBytes(StandardCharsets.UTF_8) + ); + break; + case "ingest_json_to_logstash": + Files.write( + Paths.get(options.valueOf(output)), + IngestJson.toLogstash(input(options.valueOf(input)), options.has(appendStdio)).getBytes(StandardCharsets.UTF_8) + ); + break; + case "ingest_lowercase_to_logstash": + Files.write( + Paths.get(options.valueOf(output)), + IngestLowercase.toLogstash(input(options.valueOf(input)), options.has(appendStdio)).getBytes(StandardCharsets.UTF_8) + ); + break; + case "ingest_rename_to_logstash": + Files.write( + Paths.get(options.valueOf(output)), + IngestRename.toLogstash(input(options.valueOf(input)), options.has(appendStdio)).getBytes(StandardCharsets.UTF_8) + ); + break; + case "ingest_set_to_logstash": + Files.write( + Paths.get(options.valueOf(output)), + IngestSet.toLogstash(input(options.valueOf(input)), options.has(appendStdio)).getBytes(StandardCharsets.UTF_8) + ); + break; + case "ingest_pipeline_to_logstash": + Files.write( + Paths.get(options.valueOf(output)), + IngestPipeline.toLogstash(input(options.valueOf(input)), options.has(appendStdio)).getBytes(StandardCharsets.UTF_8) + ); + break; + + default: { + throw new IllegalArgumentException("Can't recognize " + jsFunc + " processor"); + } + } + } catch (final IOException ex) { throw new IllegalStateException(ex); } @@ -132,4 +198,13 @@ final class JsUtil { engine.eval(reader); } } + + /*** + * Not empty check with nullability + * @param s string to check + * @return true iff s in not null and not empty + */ + static boolean isNotEmpty(String s) { + return s != null && !s.isEmpty(); + } } diff --git a/tools/ingest-converter/src/main/resources/ingest-append.js b/tools/ingest-converter/src/main/resources/ingest-append.js deleted file mode 100644 index 191d7fdd8..000000000 --- a/tools/ingest-converter/src/main/resources/ingest-append.js +++ /dev/null @@ -1,40 +0,0 @@ -var IngestAppend = { - has_append: function (processor) { - return !!processor["append"]; - }, - append_hash: function (processor) { - var append_json = processor["append"]; - var value_contents; - var value = append_json["value"]; - if (Array.isArray(value)) { - value_contents = IngestConverter.create_array(value); - } else { - value_contents = IngestConverter.quote_string(value); - } - var mutate_contents = IngestConverter.create_field( - IngestConverter.quote_string(IngestConverter.dots_to_square_brackets(append_json["field"])), - value_contents); - return IngestConverter.create_field("add_field", IngestConverter.wrap_in_curly(mutate_contents)); - } -}; - -/** - * Converts Ingest Append JSON to LS mutate filter. - */ -function ingest_append_to_logstash(json, append_stdio) { - - function map_processor(processor) { - - return IngestConverter.filter_hash( - IngestConverter.create_hash( - "mutate", IngestAppend.append_hash(processor) - ) - ); - } - - var filters_pipeline = JSON.parse(json)["processors"].map(map_processor); - return IngestConverter.filters_to_file([ - IngestConverter.append_io_plugins(filters_pipeline, append_stdio) - ] - ); -} diff --git a/tools/ingest-converter/src/main/resources/ingest-convert.js b/tools/ingest-converter/src/main/resources/ingest-convert.js deleted file mode 100644 index 977a48049..000000000 --- a/tools/ingest-converter/src/main/resources/ingest-convert.js +++ /dev/null @@ -1,34 +0,0 @@ -var IngestConvert = { - has_convert: function (processor) { - return !!processor["convert"]; - }, - convert_hash: function (processor) { - var convert_json = processor["convert"]; - var mutate_contents = IngestConverter.create_field( - IngestConverter.quote_string(IngestConverter.dots_to_square_brackets(convert_json["field"])), - IngestConverter.quote_string(convert_json["type"]) - ); - return IngestConverter.create_field("convert", IngestConverter.wrap_in_curly(mutate_contents)); - } -}; - -/** - * Converts Ingest Convert JSON to LS Date filter. - */ -function ingest_convert_to_logstash(json, append_stdio) { - - function map_processor(processor) { - - return IngestConverter.filter_hash( - IngestConverter.create_hash( - "mutate", IngestConvert.convert_hash(processor) - ) - ); - } - - var filters_pipeline = JSON.parse(json)["processors"].map(map_processor); - return IngestConverter.filters_to_file([ - IngestConverter.append_io_plugins(filters_pipeline, append_stdio) - ] - ); -} diff --git a/tools/ingest-converter/src/main/resources/ingest-date.js b/tools/ingest-converter/src/main/resources/ingest-date.js deleted file mode 100644 index b007ae918..000000000 --- a/tools/ingest-converter/src/main/resources/ingest-date.js +++ /dev/null @@ -1,60 +0,0 @@ -var IngestDate = { - has_date: function (processor) { - return !!processor["date"]; - }, - date_hash: function (processor) { - var date_json = processor["date"]; - var formats = date_json["formats"]; - var match_contents = [IngestConverter.dots_to_square_brackets(date_json["field"])]; - for (var f in formats) { - match_contents.push(formats[f]); - } - var date_contents = IngestConverter.create_field( - "match", - IngestConverter.create_pattern_array(match_contents) - ); - if (date_json["target_field"]) { - var target = IngestConverter.create_field( - "target", - IngestConverter.quote_string( - IngestConverter.dots_to_square_brackets(date_json["target_field"]) - ) - ); - date_contents = IngestConverter.join_hash_fields([date_contents, target]); - } - if (date_json["timezone"]) { - var timezone = IngestConverter.create_field( - "timezone", - IngestConverter.quote_string(date_json["timezone"]) - ); - date_contents = IngestConverter.join_hash_fields([date_contents, timezone]); - } - if (date_json["locale"]) { - var locale = IngestConverter.create_field( - "locale", IngestConverter.quote_string(date_json["locale"])); - date_contents = IngestConverter.join_hash_fields([date_contents, locale]); - } - return date_contents; - } -}; - -/** - * Converts Ingest Date JSON to LS Date filter. - */ -function ingest_to_logstash_date(json, append_stdio) { - - function map_processor(processor) { - - return IngestConverter.filter_hash( - IngestConverter.create_hash( - "date", IngestDate.date_hash(processor) - ) - ); - } - - var filters_pipeline = JSON.parse(json)["processors"].map(map_processor); - return IngestConverter.filters_to_file([ - IngestConverter.append_io_plugins(filters_pipeline, append_stdio) - ] - ); -} diff --git a/tools/ingest-converter/src/main/resources/ingest-geoip.js b/tools/ingest-converter/src/main/resources/ingest-geoip.js deleted file mode 100644 index fcaa81640..000000000 --- a/tools/ingest-converter/src/main/resources/ingest-geoip.js +++ /dev/null @@ -1,50 +0,0 @@ -var IngestGeoIp = { - has_geoip: function (processor) { - return !!processor["geoip"]; - }, - geoip_hash: function (processor) { - var geoip_data = processor["geoip"]; - var parts = [ - IngestConverter.create_field( - "source", - IngestConverter.quote_string( - IngestConverter.dots_to_square_brackets(geoip_data["field"]) - ) - ), - IngestConverter.create_field( - "target", - IngestConverter.quote_string( - IngestConverter.dots_to_square_brackets(geoip_data["target_field"]) - ) - ) - ]; - if (geoip_data["properties"]) { - parts.push( - IngestConverter.create_field( - "fields", - IngestConverter.create_pattern_array(geoip_data["properties"]) - ) - ); - } - return IngestConverter.join_hash_fields(parts); - } -}; - -/** - * Converts Ingest JSON to LS Grok. - */ -function ingest_to_logstash_geoip(json, append_stdio) { - - function map_processor(processor) { - - return IngestConverter.filter_hash( - IngestConverter.create_hash("geoip", IngestGeoIp.geoip_hash(processor)) - ) - } - - var filters_pipeline = JSON.parse(json)["processors"].map(map_processor); - return IngestConverter.filters_to_file([ - IngestConverter.append_io_plugins(filters_pipeline, append_stdio) - ] - ); -} diff --git a/tools/ingest-converter/src/main/resources/ingest-grok.js b/tools/ingest-converter/src/main/resources/ingest-grok.js deleted file mode 100644 index 94e37903b..000000000 --- a/tools/ingest-converter/src/main/resources/ingest-grok.js +++ /dev/null @@ -1,68 +0,0 @@ -var IngestGrok = { - has_grok: function (processor) { - return !!processor[this.get_name()]; - }, - get_name: function () { - return "grok"; - }, - grok_hash: function (processor) { - - function create_hash_field(name, content) { - return IngestConverter.create_field( - name, IngestConverter.wrap_in_curly(content) - ); - } - - function create_pattern_definition_hash(definitions) { - var content = []; - for (var key in definitions) { - if (definitions.hasOwnProperty(key)) { - content.push( - IngestConverter.create_field( - IngestConverter.quote_string(key), - IngestConverter.quote_string(definitions[key])) - ); - } - } - return create_hash_field( - "pattern_definitions", - content.map(IngestConverter.dots_to_square_brackets).join("\n") - ); - } - - var grok_data = processor["grok"]; - var grok_contents = create_hash_field( - "match", - IngestConverter.create_field( - IngestConverter.quote_string(grok_data["field"]), - IngestConverter.create_pattern_array_or_field(grok_data["patterns"]) - ) - ); - if (grok_data["pattern_definitions"]) { - grok_contents = IngestConverter.join_hash_fields([ - grok_contents, - create_pattern_definition_hash(grok_data["pattern_definitions"]) - ]) - } - return grok_contents; - } -}; - -/** - * Converts Ingest JSON to LS Grok. - */ -function ingest_to_logstash_grok(json, append_stdio) { - - function map_processor(processor) { - - return IngestConverter.filter_hash( - IngestConverter.create_hash("grok", IngestGrok.grok_hash(processor)) - ) - } - - var filters_pipeline = JSON.parse(json)["processors"].map(map_processor); - return IngestConverter.filters_to_file([ - IngestConverter.append_io_plugins(filters_pipeline, append_stdio) - ] - ); -} diff --git a/tools/ingest-converter/src/main/resources/ingest-gsub.js b/tools/ingest-converter/src/main/resources/ingest-gsub.js deleted file mode 100644 index 488649869..000000000 --- a/tools/ingest-converter/src/main/resources/ingest-gsub.js +++ /dev/null @@ -1,33 +0,0 @@ -var IngestGsub = { - has_gsub: function (processor) { - return !!processor["gsub"]; - }, - gsub_hash: function (processor) { - var gsub_data = processor["gsub"]; - return IngestConverter.create_field( - "gsub", - "[\n" + [IngestConverter.dots_to_square_brackets(gsub_data["field"]), - gsub_data["pattern"], gsub_data["replacement"]].map(IngestConverter.quote_string) - .join(", ") + "\n]" - ); - } -}; - -/** - * Converts Ingest JSON to LS Grok. - */ -function ingest_to_logstash_gsub(json, append_stdio) { - - function map_processor(processor) { - - return IngestConverter.filter_hash( - IngestConverter.create_hash("mutate", IngestGsub.gsub_hash(processor)) - ) - } - - var filters_pipeline = JSON.parse(json)["processors"].map(map_processor); - return IngestConverter.filters_to_file([ - IngestConverter.append_io_plugins(filters_pipeline, append_stdio) - ] - ); -} diff --git a/tools/ingest-converter/src/main/resources/ingest-json.js b/tools/ingest-converter/src/main/resources/ingest-json.js deleted file mode 100644 index ad2a71bc8..000000000 --- a/tools/ingest-converter/src/main/resources/ingest-json.js +++ /dev/null @@ -1,48 +0,0 @@ -var IngestJson = { - has_json: function (processor) { - return !!processor["json"]; - }, - json_hash: function (processor) { - var json_data = processor["json"]; - var parts = [ - IngestConverter.create_field( - "source", - IngestConverter.quote_string( - IngestConverter.dots_to_square_brackets(json_data["field"]) - ) - ) - ]; - - if (json_data["target_field"]) { - parts.push( - IngestConverter.create_field( - "target", - IngestConverter.quote_string( - IngestConverter.dots_to_square_brackets(json_data["target_field"]) - ) - ) - ); - } - - return IngestConverter.join_hash_fields(parts); - } -}; - -/** - * Converts Ingest json processor to LS json filter. - */ -function ingest_json_to_logstash(json, append_stdio) { - - function map_processor(processor) { - - return IngestConverter.filter_hash( - IngestConverter.create_hash("json", IngestJson.json_hash(processor)) - ) - } - - var filters_pipeline = JSON.parse(json)["processors"].map(map_processor); - return IngestConverter.filters_to_file([ - IngestConverter.append_io_plugins(filters_pipeline, append_stdio) - ] - ); -} diff --git a/tools/ingest-converter/src/main/resources/ingest-lowercase.js b/tools/ingest-converter/src/main/resources/ingest-lowercase.js deleted file mode 100644 index aae5a9087..000000000 --- a/tools/ingest-converter/src/main/resources/ingest-lowercase.js +++ /dev/null @@ -1,34 +0,0 @@ -var IngestLowercase = { - has_lowercase: function (processor) { - return !!processor["lowercase"]; - }, - lowercase_hash: function (processor) { - return IngestConverter.create_field( - "lowercase", - IngestConverter.quote_string( - IngestConverter.dots_to_square_brackets(processor["lowercase"]["field"]) - ) - ); - } -}; - -/** - * Converts Ingest Lowercase JSON to LS mutate filter. - */ -function ingest_lowercase_to_logstash(json, append_stdio) { - - function map_processor(processor) { - - return IngestConverter.filter_hash( - IngestConverter.create_hash( - "mutate", IngestLowercase.lowercase_hash(processor) - ) - ); - } - - var filters_pipeline = JSON.parse(json)["processors"].map(map_processor); - return IngestConverter.filters_to_file([ - IngestConverter.append_io_plugins(filters_pipeline, append_stdio) - ] - ); -} diff --git a/tools/ingest-converter/src/main/resources/ingest-pipeline.js b/tools/ingest-converter/src/main/resources/ingest-pipeline.js deleted file mode 100644 index 1d2c0f088..000000000 --- a/tools/ingest-converter/src/main/resources/ingest-pipeline.js +++ /dev/null @@ -1,97 +0,0 @@ -/** - * Converts Ingest JSON to LS Grok. - */ -function ingest_pipeline_to_logstash(json, append_stdio) { - - function handle_on_failure_pipeline(on_failure_json, tag_name) { - - return IngestConverter.create_tag_conditional(tag_name, - IngestConverter.join_hash_fields(on_failure_json.map(map_processor)) - ); - } - - function map_processor(processor) { - - var filter_blocks = []; - if (IngestGrok.has_grok(processor)) { - filter_blocks.push( - IngestConverter.create_hash(IngestGrok.get_name(), IngestGrok.grok_hash(processor)) - ); - if (IngestConverter.has_on_failure(processor, IngestGrok.get_name())) { - filter_blocks.push( - handle_on_failure_pipeline( - IngestConverter.get_on_failure(processor, IngestGrok.get_name()), - "_grokparsefailure" - ) - ); - } - } - var processed = false; - if (IngestDate.has_date(processor)) { - filter_blocks.push( - IngestConverter.create_hash("date", IngestDate.date_hash(processor)) - ) - processed = true; - } - if (IngestGeoIp.has_geoip(processor)) { - filter_blocks.push( - IngestConverter.create_hash("geoip", IngestGeoIp.geoip_hash(processor)) - ) - processed = true; - } - if (IngestConvert.has_convert(processor)) { - filter_blocks.push( - IngestConverter.create_hash("mutate", IngestConvert.convert_hash(processor)) - ); - processed = true; - } - if (IngestGsub.has_gsub(processor)) { - filter_blocks.push( - IngestConverter.create_hash("mutate", IngestGsub.gsub_hash(processor)) - ); - processed = true; - } - if (IngestAppend.has_append(processor)) { - filter_blocks.push( - IngestConverter.create_hash("mutate", IngestAppend.append_hash(processor)) - ); - processed = true; - } - if (IngestJson.has_json(processor)) { - filter_blocks.push( - IngestConverter.create_hash("json", IngestJson.json_hash(processor)) - ); - processed = true; - } - if (IngestRename.has_rename(processor)) { - filter_blocks.push( - IngestConverter.create_hash("mutate", IngestRename.rename_hash(processor)) - ); - processed = true; - } - if (IngestLowercase.has_lowercase(processor)) { - filter_blocks.push( - IngestConverter.create_hash("mutate", IngestLowercase.lowercase_hash(processor)) - ); - processed = true; - } - if (IngestSet.has_set(processor)) { - filter_blocks.push( - IngestConverter.create_hash("mutate", IngestSet.set_hash(processor)) - ); - processed = true; - } - if (!processed) { - print("WARN Found unrecognized processor named: " + Object.keys(processor)[0]); - } - return IngestConverter.join_hash_fields(filter_blocks); - } - - var logstash_pipeline = IngestConverter.filter_hash( - IngestConverter.join_hash_fields(JSON.parse(json)["processors"].map(map_processor)) - ); - return IngestConverter.filters_to_file([ - IngestConverter.append_io_plugins(logstash_pipeline, append_stdio) - ] - ); -} diff --git a/tools/ingest-converter/src/main/resources/ingest-rename.js b/tools/ingest-converter/src/main/resources/ingest-rename.js deleted file mode 100644 index e861dbed5..000000000 --- a/tools/ingest-converter/src/main/resources/ingest-rename.js +++ /dev/null @@ -1,34 +0,0 @@ -var IngestRename = { - has_rename: function (processor) { - return !!processor["rename"]; - }, - rename_hash: function (processor) { - var rename_json = processor["rename"]; - var mutate_contents = IngestConverter.create_field( - IngestConverter.quote_string(IngestConverter.dots_to_square_brackets(rename_json["field"])), - IngestConverter.quote_string(IngestConverter.dots_to_square_brackets(rename_json["target_field"])) - ); - return IngestConverter.create_field("rename", IngestConverter.wrap_in_curly(mutate_contents)); - } -}; - -/** - * Converts Ingest Rename JSON to LS mutate filter. - */ -function ingest_rename_to_logstash(json, append_stdio) { - - function map_processor(processor) { - - return IngestConverter.filter_hash( - IngestConverter.create_hash( - "mutate", IngestRename.rename_hash(processor) - ) - ); - } - - var filters_pipeline = JSON.parse(json)["processors"].map(map_processor); - return IngestConverter.filters_to_file([ - IngestConverter.append_io_plugins(filters_pipeline, append_stdio) - ] - ); -} diff --git a/tools/ingest-converter/src/main/resources/ingest-set.js b/tools/ingest-converter/src/main/resources/ingest-set.js deleted file mode 100644 index 122dc44a5..000000000 --- a/tools/ingest-converter/src/main/resources/ingest-set.js +++ /dev/null @@ -1,44 +0,0 @@ -var IngestSet = { - has_set: function (processor) { - return !!processor["set"]; - }, - set_hash: function (processor) { - var set_json = processor["set"]; - var value_contents; - var value = set_json["value"]; - if (typeof value === 'string' || value instanceof String) { - value_contents = IngestConverter.quote_string(value); - } else { - value_contents = value; - } - var painless_condition = set_json["if"]; - if (!!painless_condition) { - print("WARN Found in 'set' processor an 'if' painless condition not translated: " + painless_condition); - } - var mutate_contents = IngestConverter.create_field( - IngestConverter.quote_string(IngestConverter.dots_to_square_brackets(set_json["field"])), - value_contents); - return IngestConverter.create_field("add_field", IngestConverter.wrap_in_curly(mutate_contents)); - } -}; - -/** - * Converts Ingest Set JSON to LS mutate filter. - */ -function ingest_set_to_logstash(json, append_stdio) { - - function map_processor(processor) { - - return IngestConverter.filter_hash( - IngestConverter.create_hash( - "mutate", IngestSet.set_hash(processor) - ) - ); - } - - var filters_pipeline = JSON.parse(json)["processors"].map(map_processor); - return IngestConverter.filters_to_file([ - IngestConverter.append_io_plugins(filters_pipeline, append_stdio) - ] - ); -} diff --git a/tools/ingest-converter/src/main/resources/ingest-shared.js b/tools/ingest-converter/src/main/resources/ingest-shared.js deleted file mode 100644 index 4f36ccafc..000000000 --- a/tools/ingest-converter/src/main/resources/ingest-shared.js +++ /dev/null @@ -1,184 +0,0 @@ -var IngestConverter = { - /** - * Translates the JSON naming pattern (`name.qualifier.sub`) into the LS pattern - * [name][qualifier][sub] for all applicable tokens in the given string. - * This function correctly identifies and omits renaming of string literals. - * @param string to replace naming pattern in - * @returns {string} with Json naming translated into grok naming - */ - dots_to_square_brackets: function (string) { - - function token_dots_to_square_brackets(string) { - var adjusted; - //Break out if this is not a naming pattern we convert - if (string.match(/([\w_]+\.)+[\w_]+/)) { - adjusted = string.replace(/(\w*)\.(\w*)/g, "$1][$2") - .replace(/\[(\w+)(}|$)/g, "[$1]$2") - .replace(/{(\w+):(\w+)]/g, "{$1:[$2]") - .replace(/^(\w+)]\[/g, "[$1]["); - } else { - adjusted = string; - } - return adjusted; - } - - var literals = string.match(/\(\?:%{.*\|-\)/); - var i; - var tokens = []; - // Copy String before Manipulation - var right = string; - if (literals) { - for (i = 0; i < literals.length; ++i) { - var parts = right.split(literals[i], 2); - right = parts[1]; - tokens.push(token_dots_to_square_brackets(parts[0])); - tokens.push(literals[i]); - } - } - tokens.push(token_dots_to_square_brackets(right)); - return tokens.join(""); - }, quote_string: function (string) { - return "\"" + string.replace(/"/g, "\\\"") + "\""; - }, wrap_in_curly: function (string) { - return "{\n" + string + "\n}"; - }, create_field: function (name, content) { - return name + " => " + content; - }, create_hash: function (name, content) { - return name + " " + this.wrap_in_curly(content); - }, - - /** - * All hash fields in LS start on a new line. - * @param fields Array of Strings of Serialized Hash Fields - * @returns {string} Joined Serialization of Hash Fields - */ - join_hash_fields: function (fields) { - return fields.join("\n"); - }, - - /** - * Fixes indentation in LS string. - * @param string LS string to fix indentation in, that has no indentation intentionally with - * all lines starting on a token without preceding spaces. - * @returns {string} LS string indented by 3 spaces per level - */ - fix_indent: function (string) { - - function indent(string, shifts) { - return new Array(shifts * 3 + 1).join(" ") + string; - } - - var lines = string.split("\n"); - var count = 0; - var i; - for (i = 0; i < lines.length; ++i) { - if (lines[i].match(/(\{|\[)$/)) { - lines[i] = indent(lines[i], count); - ++count; - } else if (lines[i].match(/(\}|\])$/)) { - --count; - lines[i] = indent(lines[i], count); - // Only indent line if previous line ended on relevant control char. - } else if (i > 0 && lines[i - 1].match(/(=>\s+".+"|,|\{|\}|\[|\])$/)) { - lines[i] = indent(lines[i], count); - } - } - return lines.join("\n"); - }, - - /** - * Converts Ingest/JSON style pattern array to LS pattern array, performing necessary variable - * name and quote escaping adjustments. - * @param patterns Pattern Array in JSON formatting - * @returns {string} Pattern array in LS formatting - */ - create_pattern_array: function (patterns) { - return "[\n" - + patterns.map(this.dots_to_square_brackets).map(this.quote_string).join(",\n") - + "\n]"; - }, - - create_array: function (ingest_array) { - return "[\n" - + ingest_array.map(this.quote_string).join(",\n") - + "\n]"; - }, - - /** - * Converts Ingest/JSON style pattern array to LS pattern array or string if the given array - * contains a single element only, performing necessary variable name and quote escaping - * adjustments. - * @param patterns Pattern Array in JSON formatting - * @returns {string} Pattern array or string in LS formatting - */ - create_pattern_array_or_field: function (patterns) { - return patterns.length === 1 - ? this.quote_string(this.dots_to_square_brackets(patterns[0])) - : this.create_pattern_array(patterns); - }, - - filter_hash: function(contents) { - return this.fix_indent(this.create_hash("filter", contents)) - }, - - filters_to_file: function(filters) { - return filters.join("\n\n") + "\n"; - }, - - /** - * Does it have an on_failure field? - * @param processor Json - * @param name Name of the processor - * @returns {boolean} True if has on failure - */ - has_on_failure: function (processor, name) { - return !!processor[name]["on_failure"]; - }, - - get_on_failure: function (processor, name) { - return processor[name]["on_failure"]; - }, - - /** - * Creates an if clause with the tag name - * @param tag String tag name to find in [tags] field - * @param on_failure_pipeline The on failure pipeline converted to LS to tack on in the conditional - * @returns {string} a string representing a conditional logic - */ - create_tag_conditional: function (tag, on_failure_pipeline) { - return "if " + this.quote_string(tag) + " in [tags] {\n" + - on_failure_pipeline + "\n" + - "}"; - }, - - get_elasticsearch_output: function () { - return this.fix_indent("output {\n" + - "elasticsearch {\n" + - "hosts => \"localhost\"\n" + - "}\n" + - "}"); - }, - - get_stdin_input: function () { - return this.fix_indent("input {\n" + - "stdin {\n" + - "}\n" + - "}"); - }, - - get_stdout_output: function () { - return this.fix_indent("output {\n" + - "stdout {\n" + - "codec => \"rubydebug\"\n" + - "}\n" + - "}"); - }, - - append_io_plugins: function(filters_pipeline, append_stdio) { - if (append_stdio === true) { - return [IngestConverter.get_stdin_input(), filters_pipeline, IngestConverter.get_stdout_output()].join("\n"); - } else { - return [filters_pipeline, IngestConverter.get_elasticsearch_output()].join("\n"); - } - } -}; From 53e73e9ccce91f39f728bab31d272c48f022b401 Mon Sep 17 00:00:00 2001 From: Karol Bucek Date: Wed, 13 Jan 2021 06:45:16 +0100 Subject: [PATCH 0654/1126] Fix: make sure LS exits when running into fatal errors (#12559) Currently, LS does not respect fatal errors such as java.lang.OutOfMemoryError and continues executing. This is dangerous since JVM errors are a legitimate reason to halt the process and not continue processing. Additionally: - make sure we log the full stack-trace on fatal errors - halt the JVM wout executing finalizers/hook (scissors on how ES handles uncaught exceptions) - also, we should now be aware of a potentially unexpectedly dying thread Back-port of #12470 --- .../src/main/java/org/logstash/Logstash.java | 101 ++++++++++++++---- qa/integration/fixtures/fatal_error_spec.yml | 3 + qa/integration/specs/fatal_error_spec.rb | 74 +++++++++++++ 3 files changed, 155 insertions(+), 23 deletions(-) create mode 100644 qa/integration/fixtures/fatal_error_spec.yml create mode 100644 qa/integration/specs/fatal_error_spec.rb diff --git a/logstash-core/src/main/java/org/logstash/Logstash.java b/logstash-core/src/main/java/org/logstash/Logstash.java index 4acf602db..7d387bfd5 100644 --- a/logstash-core/src/main/java/org/logstash/Logstash.java +++ b/logstash-core/src/main/java/org/logstash/Logstash.java @@ -20,17 +20,21 @@ package org.logstash; +import java.io.IOError; import java.io.IOException; import java.io.InputStream; import java.io.PrintStream; import java.nio.file.Path; import java.nio.file.Paths; +import java.security.AccessController; +import java.security.PrivilegedAction; + import org.apache.logging.log4j.LogManager; import org.apache.logging.log4j.Logger; import org.jruby.Ruby; import org.jruby.RubyException; import org.jruby.RubyInstanceConfig; -import org.jruby.RubyNumeric; +import org.jruby.RubySystemExit; import org.jruby.exceptions.RaiseException; import org.jruby.runtime.builtin.IRubyObject; @@ -59,6 +63,7 @@ public final class Logstash implements Runnable, AutoCloseable { ); } configureNashornDeprecationSwitchForJavaAbove11(); + installGlobalUncaughtExceptionHandler(); final Path home = Paths.get(lsHome).toAbsolutePath(); try ( @@ -66,20 +71,25 @@ public final class Logstash implements Runnable, AutoCloseable { ) { logstash.run(); } catch (final IllegalStateException e) { - String errorMessage[] = null; - if (e.getMessage().contains("Could not load FFI Provider")) { - errorMessage = new String[]{ - "\nError accessing temp directory: " + System.getProperty("java.io.tmpdir"), - "This often occurs because the temp directory has been mounted with NOEXEC or", - "the Logstash user has insufficient permissions on the directory. Possible", - "workarounds include setting the -Djava.io.tmpdir property in the jvm.options", - "file to an alternate directory or correcting the Logstash user's permissions." - }; + Throwable t = e; + String message = e.getMessage(); + if (message != null) { + if (message.startsWith(UNCLEAN_SHUTDOWN_PREFIX)) { + t = e.getCause(); // be less verbose with uncleanShutdown's wrapping exception + } else if (message.contains("Could not load FFI Provider")) { + message = + "Error accessing temp directory: " + System.getProperty("java.io.tmpdir") + + " this often occurs because the temp directory has been mounted with NOEXEC or" + + " the Logstash user has insufficient permissions on the directory. \n" + + "Possible workarounds include setting the -Djava.io.tmpdir property in the jvm.options" + + "file to an alternate directory or correcting the Logstash user's permissions."; + } } - handleCriticalError(e, errorMessage); + handleFatalError(message, t); } catch (final Throwable t) { - handleCriticalError(t, null); + handleFatalError("", t); } + System.exit(0); } @@ -92,16 +102,59 @@ public final class Logstash implements Runnable, AutoCloseable { } } - private static void handleCriticalError(Throwable t, String[] errorMessage) { - LOGGER.error(t); - if (errorMessage != null) { - for (String err : errorMessage) { - System.err.println(err); + private static void installGlobalUncaughtExceptionHandler() { + Thread.setDefaultUncaughtExceptionHandler((thread, e) -> { + if (e instanceof Error) { + handleFatalError("uncaught error (in thread " + thread.getName() + ")", e); + } else { + LOGGER.error("uncaught exception (in thread " + thread.getName() + ")", e); } + }); + } + + private static void handleFatalError(String message, Throwable t) { + LOGGER.fatal(message, t); + + if (t instanceof InternalError) { + halt(128); + } else if (t instanceof OutOfMemoryError) { + halt(127); + } else if (t instanceof StackOverflowError) { + halt(126); + } else if (t instanceof UnknownError) { + halt(125); + } else if (t instanceof IOError) { + halt(124); + } else if (t instanceof LinkageError) { + halt(123); + } else if (t instanceof Error) { + halt(120); } + System.exit(1); } + private static void halt(final int status) { + AccessController.doPrivileged(new PrivilegedHaltAction(status)); + } + + private static class PrivilegedHaltAction implements PrivilegedAction { + + private final int status; + + private PrivilegedHaltAction(final int status) { + this.status = status; + } + + @Override + public Void run() { + // we halt to prevent shutdown hooks from running + Runtime.getRuntime().halt(status); + return null; + } + + } + /** * Ctor. * @param home Logstash Root Directory @@ -132,11 +185,10 @@ public final class Logstash implements Runnable, AutoCloseable { Thread.currentThread().setContextClassLoader(ruby.getJRubyClassLoader()); ruby.runFromMain(script, config.displayedFileName()); } catch (final RaiseException ex) { - final RubyException rexep = ex.getException(); - if (ruby.getSystemExit().isInstance(rexep)) { - final IRubyObject status = - rexep.callMethod(ruby.getCurrentContext(), "status"); - if (status != null && !status.isNil() && RubyNumeric.fix2int(status) != 0) { + final RubyException re = ex.getException(); + if (re instanceof RubySystemExit) { + IRubyObject success = ((RubySystemExit) re).success_p(); + if (!success.isTrue()) { uncleanShutdown(ex); } } else { @@ -190,7 +242,10 @@ public final class Logstash implements Runnable, AutoCloseable { return resolved.toString(); } + private static final String UNCLEAN_SHUTDOWN_PREFIX = "Logstash stopped processing because of an error: "; + private static void uncleanShutdown(final Exception ex) { - throw new IllegalStateException("Logstash stopped processing because of an error: " + ex.getMessage(), ex); + throw new IllegalStateException(UNCLEAN_SHUTDOWN_PREFIX + ex.getMessage(), ex); } + } diff --git a/qa/integration/fixtures/fatal_error_spec.yml b/qa/integration/fixtures/fatal_error_spec.yml new file mode 100644 index 000000000..cbfc784af --- /dev/null +++ b/qa/integration/fixtures/fatal_error_spec.yml @@ -0,0 +1,3 @@ +--- +services: + - logstash diff --git a/qa/integration/specs/fatal_error_spec.rb b/qa/integration/specs/fatal_error_spec.rb new file mode 100644 index 000000000..910f921a4 --- /dev/null +++ b/qa/integration/specs/fatal_error_spec.rb @@ -0,0 +1,74 @@ +# 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/helpers' +require_relative '../framework/settings' +require_relative '../services/logstash_service' +require "logstash/devutils/rspec/spec_helper" + +describe "uncaught exception" do + + before(:all) do + @fixture = Fixture.new(__FILE__) + @logstash = @fixture.get_service("logstash") + end + + after(:each) { @logstash.teardown } + + let(:timeout) { 90 } # seconds + let(:temp_dir) { Stud::Temporary.directory("logstash-error-test") } + + it "halts LS on fatal error" do + config = "input { generator { count => 1 message => 'a fatal error' } } " + # inline Ruby filter seems to catch everything (including java.lang.Error) so we exercise a thread throwing + config += "filter { ruby { code => 'Thread.start { raise java.lang.AssertionError.new event.get(\"message\") }' } }" + + spawn_logstash_and_wait_for_exit! config, timeout + + expect(@logstash.exit_code).to be 120 + + log_file = "#{temp_dir}/logstash-plain.log" + expect( File.exists?(log_file) ).to be true + expect( File.read(log_file) ).to match /\[FATAL\]\[org.logstash.Logstash.*?java.lang.AssertionError: a fatal error/m + end + + it "logs unexpected exception (from Java thread)" do + config = "input { generator { count => 1 message => 'unexpected' } } " + config += "filter { ruby { code => 'java.lang.Thread.new { raise java.io.EOFException.new event.get(\"message\") }.start; sleep(1.5)' } }" + + spawn_logstash_and_wait_for_exit! config, timeout + + expect(@logstash.exit_code).to be 0 # normal exit + + log_file = "#{temp_dir}/logstash-plain.log" + expect( File.exists?(log_file) ).to be true + expect( File.read(log_file) ).to match /\[ERROR\]\[org.logstash.Logstash.*?uncaught exception \(in thread .*?java.io.EOFException: unexpected/m + end + + def spawn_logstash_and_wait_for_exit!(config, timeout) + @logstash.spawn_logstash('-w', '1', '--path.logs', temp_dir, '-e', config) + + time = Time.now + while (Time.now - time) < timeout + sleep(0.1) + break if @logstash.exited? + end + raise 'LS process did not exit!' unless @logstash.exited? + end + +end From 87297c5c7f9c007f47b1218a482d5a62ecafce3d Mon Sep 17 00:00:00 2001 From: Joao Duarte Date: Wed, 13 Jan 2021 08:28:00 -0800 Subject: [PATCH 0655/1126] [forwardport 7.x] Release notes for 7.10.2 (#12553) --- docs/static/releasenotes.asciidoc | 31 ++++++++++++++++++++++++++++++- 1 file changed, 30 insertions(+), 1 deletion(-) diff --git a/docs/static/releasenotes.asciidoc b/docs/static/releasenotes.asciidoc index 0d7052ebf..346fbf4be 100644 --- a/docs/static/releasenotes.asciidoc +++ b/docs/static/releasenotes.asciidoc @@ -3,6 +3,7 @@ This section summarizes the changes in the following releases: +* <> * <> * <> * <> @@ -37,6 +38,34 @@ This section summarizes the changes in the following releases: * <> * <> +[[logstash-7-10-2]] +=== Logstash 7.10.2 Release Notes + +==== Notable issues fixed + +No high impact fixes in this release. + +==== Plugins + +*Beats Input - 6.0.12* + +* Fix: log error when SSL context building fails https://github.com/logstash-plugins/logstash-input-beats/pull/402[#402]. + We've also made sure to log messages on configuration errors as LS 7.8/7.9 only prints details when level set to debug. + +*File Input - 4.2.3* + +* Refactor: improve debug logging (log catched exceptions) https://github.com/logstash-plugins/logstash-input-file/pull/280[#280] + +*Elasticsearch Output - 10.7.3* + +* Added composable index template support for elasticsearch version 8 https://github.com/logstash-plugins/logstash-output-elasticsearch/pull/980[#980] +* [DOC] Fixed links to restructured Logstash-to-cloud docs https://github.com/logstash-plugins/logstash-output-elasticsearch/pull/975[#975] +* [DOC] Document the permissions required in secured clusters https://github.com/logstash-plugins/logstash-output-elasticsearch/pull/969[#969] + +==== Other changes + +* Databind upgraded to 2.9.10.6 + [[logstash-7-10-1]] === Logstash 7.10.1 Release Notes @@ -2031,4 +2060,4 @@ Here are the plugin changes. - Tweaked logging statements to reduce verbosity - Fixed numerous issues relating to builds on Travis https://github.com/logstash-plugins/logstash-output-elasticsearch/pull/799[#799] * logstash-output-s3 - - Fixed issue where on restart, 0 byte files could erroneously be uploaded to s3 https://github.com/logstash-plugins/logstash-output-s3/issues/195[#195] \ No newline at end of file + - Fixed issue where on restart, 0 byte files could erroneously be uploaded to s3 https://github.com/logstash-plugins/logstash-output-s3/issues/195[#195] From b0c81338f3b961511c407c0de940e7d2ed07bb16 Mon Sep 17 00:00:00 2001 From: andsel Date: Mon, 7 Dec 2020 15:44:31 +0100 Subject: [PATCH 0656/1126] Implements scripted log4j filters and appenders to Java, avoid usage of deprecated Javascript Nashorn (#12512) - replaces all scripted filters with custom Java implementation - implemented routing appender per pipeline in Java - adapted log4j configuration shipped with Logstash - print a warn message if it detects an scripted log4j configuration and continue the execution (#12591) --- config/log4j2.properties | 44 ++--- .../resources/log4j2-with-script.properties | 38 ++--- logstash-core/lib/logstash/runner.rb | 16 ++ .../src/main/java/org/logstash/Logstash.java | 10 -- .../logstash/log/PipelineRoutingAppender.java | 155 ++++++++++++++++++ .../logstash/log/PipelineRoutingFilter.java | 50 ++++++ .../log/LogstashConfigurationFactoryTest.java | 2 +- .../log/PipelineRoutingAppenderTest.java | 67 ++++++++ .../log/PipelineRoutingFilterTest.java | 62 +++++++ .../test/resources/log4j-pipeline-routing.xml | 46 ++++++ .../log4j2-log-pipeline-test.properties | 12 +- .../persistent_queues/log4j2.properties | 44 ++--- 12 files changed, 438 insertions(+), 108 deletions(-) create mode 100644 logstash-core/src/main/java/org/logstash/log/PipelineRoutingAppender.java create mode 100644 logstash-core/src/main/java/org/logstash/log/PipelineRoutingFilter.java create mode 100644 logstash-core/src/test/java/org/logstash/log/PipelineRoutingAppenderTest.java create mode 100644 logstash-core/src/test/java/org/logstash/log/PipelineRoutingFilterTest.java create mode 100644 logstash-core/src/test/resources/log4j-pipeline-routing.xml diff --git a/config/log4j2.properties b/config/log4j2.properties index 18e655840..cd6f31593 100644 --- a/config/log4j2.properties +++ b/config/log4j2.properties @@ -26,11 +26,7 @@ appender.rolling.policies.size.type = SizeBasedTriggeringPolicy appender.rolling.policies.size.size = 100MB appender.rolling.strategy.type = DefaultRolloverStrategy appender.rolling.strategy.max = 30 -appender.rolling.avoid_pipelined_filter.type = ScriptFilter -appender.rolling.avoid_pipelined_filter.script.type = Script -appender.rolling.avoid_pipelined_filter.script.name = filter_no_pipelined -appender.rolling.avoid_pipelined_filter.script.language = JavaScript -appender.rolling.avoid_pipelined_filter.script.scriptText = ${sys:ls.pipeline.separate_logs} == false || !(logEvent.getContextData().containsKey("pipeline.id")) +appender.rolling.avoid_pipelined_filter.type = PipelineRoutingFilter appender.json_rolling.type = RollingFile appender.json_rolling.name = json_rolling @@ -47,34 +43,20 @@ appender.json_rolling.policies.size.type = SizeBasedTriggeringPolicy appender.json_rolling.policies.size.size = 100MB appender.json_rolling.strategy.type = DefaultRolloverStrategy appender.json_rolling.strategy.max = 30 -appender.json_rolling.avoid_pipelined_filter.type = ScriptFilter -appender.json_rolling.avoid_pipelined_filter.script.type = Script -appender.json_rolling.avoid_pipelined_filter.script.name = filter_no_pipelined -appender.json_rolling.avoid_pipelined_filter.script.language = JavaScript -appender.json_rolling.avoid_pipelined_filter.script.scriptText = ${sys:ls.pipeline.separate_logs} == false || !(logEvent.getContextData().containsKey("pipeline.id")) +appender.json_rolling.avoid_pipelined_filter.type = PipelineRoutingFilter -appender.routing.type = Routing +appender.routing.type = PipelineRouting appender.routing.name = pipeline_routing_appender -appender.routing.routes.type = Routes -appender.routing.routes.script.type = Script -appender.routing.routes.script.name = routing_script -appender.routing.routes.script.language = JavaScript -appender.routing.routes.script.scriptText = logEvent.getContextData().containsKey("pipeline.id") ? logEvent.getContextData().getValue("pipeline.id") : "sink"; -appender.routing.routes.route_pipelines.type = Route -appender.routing.routes.route_pipelines.rolling.type = RollingFile -appender.routing.routes.route_pipelines.rolling.name = appender-${ctx:pipeline.id} -appender.routing.routes.route_pipelines.rolling.fileName = ${sys:ls.logs}/pipeline_${ctx:pipeline.id}.log -appender.routing.routes.route_pipelines.rolling.filePattern = ${sys:ls.logs}/pipeline_${ctx:pipeline.id}.%i.log.gz -appender.routing.routes.route_pipelines.rolling.layout.type = PatternLayout -appender.routing.routes.route_pipelines.rolling.layout.pattern = [%d{ISO8601}][%-5p][%-25c] %m%n -appender.routing.routes.route_pipelines.rolling.policy.type = SizeBasedTriggeringPolicy -appender.routing.routes.route_pipelines.rolling.policy.size = 100MB -appender.routing.routes.route_pipelines.strategy.type = DefaultRolloverStrategy -appender.routing.routes.route_pipelines.strategy.max = 30 -appender.routing.routes.route_sink.type = Route -appender.routing.routes.route_sink.key = sink -appender.routing.routes.route_sink.null.type = Null -appender.routing.routes.route_sink.null.name = drop-appender +appender.routing.pipeline.type = RollingFile +appender.routing.pipeline.name = appender-${ctx:pipeline.id} +appender.routing.pipeline.fileName = ${sys:ls.logs}/pipeline_${ctx:pipeline.id}.log +appender.routing.pipeline.filePattern = ${sys:ls.logs}/pipeline_${ctx:pipeline.id}.%i.log.gz +appender.routing.pipeline.layout.type = PatternLayout +appender.routing.pipeline.layout.pattern = [%d{ISO8601}][%-5p][%-25c] %m%n +appender.routing.pipeline.policy.type = SizeBasedTriggeringPolicy +appender.routing.pipeline.policy.size = 100MB +appender.routing.pipeline.strategy.type = DefaultRolloverStrategy +appender.routing.pipeline.strategy.max = 30 rootLogger.level = ${sys:ls.log.level} rootLogger.appenderRef.console.ref = ${sys:ls.log.format}_console diff --git a/logstash-core/benchmarks/src/main/resources/log4j2-with-script.properties b/logstash-core/benchmarks/src/main/resources/log4j2-with-script.properties index 7c326d5fb..fe2de91e9 100644 --- a/logstash-core/benchmarks/src/main/resources/log4j2-with-script.properties +++ b/logstash-core/benchmarks/src/main/resources/log4j2-with-script.properties @@ -15,34 +15,20 @@ appender.rolling.policies.size.type = SizeBasedTriggeringPolicy appender.rolling.policies.size.size = 100MB appender.rolling.strategy.type = DefaultRolloverStrategy appender.rolling.strategy.max = 30 -appender.rolling.avoid_pipelined_filter.type = ScriptFilter -appender.rolling.avoid_pipelined_filter.script.type = Script -appender.rolling.avoid_pipelined_filter.script.name = filter_no_pipelined -appender.rolling.avoid_pipelined_filter.script.language = JavaScript -appender.rolling.avoid_pipelined_filter.script.scriptText = ${sys:ls.pipeline.separate_logs} == false || !(logEvent.getContextData().containsKey("pipeline.id")) +appender.rolling.avoid_pipelined_filter.type = PipelineRoutingFilter -appender.routing.type = Routing +appender.routing.type = PipelineRouting appender.routing.name = pipeline_routing_appender -appender.routing.routes.type = Routes -appender.routing.routes.script.type = Script -appender.routing.routes.script.name = routing_script -appender.routing.routes.script.language = JavaScript -appender.routing.routes.script.scriptText = logEvent.getContextData().containsKey("pipeline.id") ? logEvent.getContextData().getValue("pipeline.id") : "sink"; -appender.routing.routes.route_pipelines.type = Route -appender.routing.routes.route_pipelines.rolling.type = RollingFile -appender.routing.routes.route_pipelines.rolling.name = appender-${ctx:pipeline.id} -appender.routing.routes.route_pipelines.rolling.fileName = ${sys:ls.logs}/pipeline_${ctx:pipeline.id}.log -appender.routing.routes.route_pipelines.rolling.filePattern = ${sys:ls.logs}/pipeline_${ctx:pipeline.id}.%i.log.gz -appender.routing.routes.route_pipelines.rolling.layout.type = PatternLayout -appender.routing.routes.route_pipelines.rolling.layout.pattern = [%d{ISO8601}][%-5p][%-25c] %-.10000m%n -appender.routing.routes.route_pipelines.rolling.policy.type = SizeBasedTriggeringPolicy -appender.routing.routes.route_pipelines.rolling.policy.size = 100MB -appender.routing.routes.route_pipelines.strategy.type = DefaultRolloverStrategy -appender.routing.routes.route_pipelines.strategy.max = 30 -appender.routing.routes.route_sink.type = Route -appender.routing.routes.route_sink.key = sink -appender.routing.routes.route_sink.null.type = Null -appender.routing.routes.route_sink.null.name = drop-appender +appender.routing.pipeline.type = RollingFile +appender.routing.pipeline.name = appender-${ctx:pipeline.id} +appender.routing.pipeline.fileName = ${sys:ls.logs}/pipeline_${ctx:pipeline.id}.log +appender.routing.pipeline.filePattern = ${sys:ls.logs}/pipeline_${ctx:pipeline.id}.%i.log.gz +appender.routing.pipeline.layout.type = PatternLayout +appender.routing.pipeline.layout.pattern = [%d{ISO8601}][%-5p][%-25c] %m%n +appender.routing.pipeline.policy.type = SizeBasedTriggeringPolicy +appender.routing.pipeline.policy.size = 100MB +appender.routing.pipeline.strategy.type = DefaultRolloverStrategy +appender.routing.pipeline.strategy.max = 30 rootLogger.level = INFO rootLogger.appenderRef.rolling.ref = ${sys:ls.log.format}_rolling diff --git a/logstash-core/lib/logstash/runner.rb b/logstash-core/lib/logstash/runner.rb index 9a0cf1bcf..7ed06ccad 100644 --- a/logstash-core/lib/logstash/runner.rb +++ b/logstash-core/lib/logstash/runner.rb @@ -296,6 +296,10 @@ class LogStash::Runner < Clamp::StrictCommand # override log level that may have been introduced from a custom log4j config file LogStash::Logging::Logger::configure_logging(setting("log.level")) + if log_configuration_contains_javascript_usage? + logger.warn("Logging configuration uses appender or filter with scripting language JavaScript, which will be removed in a future major release of Logstash.") + end + if setting("config.debug") && !logger.debug? logger.warn("--config.debug was specified, but log.level was not set to \'debug\'! No config info will be logged.") end @@ -437,6 +441,18 @@ class LogStash::Runner < Clamp::StrictCommand @log_fd.close if @log_fd end # def self.main + def log_configuration_contains_javascript_usage? + context = LoggerContext.getContext(false) + config = context.configuration + config_file = config.configuration_source.file + # no config file so nothing to check + return false if config_file.nil? + + logger.info("Log4j configuration path used is: #{config_file.path}") + log_config = File.open(config_file.absolute_path).read + (log_config =~ /^[^#]+script\.language\s*=\s*JavaScript/) != nil + end + def show_version show_version_logstash diff --git a/logstash-core/src/main/java/org/logstash/Logstash.java b/logstash-core/src/main/java/org/logstash/Logstash.java index 7d387bfd5..e2afce899 100644 --- a/logstash-core/src/main/java/org/logstash/Logstash.java +++ b/logstash-core/src/main/java/org/logstash/Logstash.java @@ -62,7 +62,6 @@ public final class Logstash implements Runnable, AutoCloseable { "LS_HOME environment variable must be set. This is likely a bug that should be reported." ); } - configureNashornDeprecationSwitchForJavaAbove11(); installGlobalUncaughtExceptionHandler(); final Path home = Paths.get(lsHome).toAbsolutePath(); @@ -93,15 +92,6 @@ public final class Logstash implements Runnable, AutoCloseable { System.exit(0); } - private static void configureNashornDeprecationSwitchForJavaAbove11() { - final String javaVersion = System.getProperty("java.version"); - // match version 1.x.y, 9.x.y and 10.x.y - if (!javaVersion.matches("^1\\.\\d\\..*") && !javaVersion.matches("^(9|10)\\.\\d\\..*")) { - // Avoid Nashorn deprecation logs in JDK >= 11 - System.setProperty("nashorn.args", "--no-deprecation-warning"); - } - } - private static void installGlobalUncaughtExceptionHandler() { Thread.setDefaultUncaughtExceptionHandler((thread, e) -> { if (e instanceof Error) { diff --git a/logstash-core/src/main/java/org/logstash/log/PipelineRoutingAppender.java b/logstash-core/src/main/java/org/logstash/log/PipelineRoutingAppender.java new file mode 100644 index 000000000..4f8ffccaf --- /dev/null +++ b/logstash-core/src/main/java/org/logstash/log/PipelineRoutingAppender.java @@ -0,0 +1,155 @@ +package org.logstash.log; + +import org.apache.logging.log4j.core.Appender; +import org.apache.logging.log4j.core.Core; +import org.apache.logging.log4j.core.LogEvent; +import org.apache.logging.log4j.core.appender.AbstractAppender; +import org.apache.logging.log4j.core.config.AppenderControl; +import org.apache.logging.log4j.core.config.Configuration; +import org.apache.logging.log4j.core.config.Node; +import org.apache.logging.log4j.core.config.Property; +import org.apache.logging.log4j.core.config.plugins.Plugin; +import org.apache.logging.log4j.core.config.plugins.PluginBuilderFactory; +import org.apache.logging.log4j.core.config.plugins.PluginNode; + +import java.util.Collections; +import java.util.Map; +import java.util.concurrent.ConcurrentHashMap; +import java.util.concurrent.ConcurrentMap; + +/** + * Appender customization to separate logs per pipeline. + * + * It instantiates subappenders, starting from a definition. + * + * Sample of XML configuration: + *
{@code
+ *  
+ *      
+ *          
+ *            [%d{ISO8601}][%-5p][%-25c] %m%n
+ *          
+ *          
+ *          
+ *        
+ *  
+ *  }
+ * 
+ * */ +@Plugin(name = "PipelineRouting", category = Core.CATEGORY_NAME, elementType = Appender.ELEMENT_TYPE, printObject = true, deferChildren = true) +public class PipelineRoutingAppender extends AbstractAppender { + + /** + * Builder for {@link PipelineRoutingAppender} instances + * */ + public static class Builder> extends AbstractAppender.Builder + implements org.apache.logging.log4j.core.util.Builder { + + @PluginNode + private Node appenderNode; + + @Override + public PipelineRoutingAppender build() { + final String name = getName(); + if (name == null) { + LOGGER.error("No name defined for this RoutingAppender"); + return null; + } + return new PipelineRoutingAppender(name, appenderNode, getConfiguration()); + } + } + + /** + * Factory method to instantiate the appender + * */ + @PluginBuilderFactory + public static > B newBuilder() { + return new PipelineRoutingAppender.Builder().asBuilder(); + } + + private final Node appenderNode; + private final Configuration configuration; + private final ConcurrentMap createdAppenders = new ConcurrentHashMap<>(); + private final Map createdAppendersUnmodifiableView = + Collections.unmodifiableMap(createdAppenders); + + protected PipelineRoutingAppender(String name, Node appenderNode, Configuration configuration) { + super(name, null, null, false, new Property[0]); + this.appenderNode = appenderNode; + this.configuration = configuration; + } + + /** + * Returns an unmodifiable view of the appenders created by this {@link PipelineRoutingAppender}. + */ + public Map getAppenders() { + return createdAppendersUnmodifiableView; + } + + /** + * Core method to apply the logic of routing. + * */ + @Override + public void append(LogEvent event) { + AppenderControl appenderControl = getControl(event); + + if (appenderControl != null) { + appenderControl.callAppender(event); + } + } + + /** + * Create or retrieve the sub appender for the pipeline.id provided into the event + * */ + private AppenderControl getControl(LogEvent event) { + String key = event.getContextData().getValue("pipeline.id"); + if (key == null) { + error("Unable to find the pipeline.id in event's context data"); + key = "sink"; + } + + AppenderControl appenderControl = createdAppenders.get(key); + if (appenderControl == null) { + synchronized (this) { + appenderControl = createdAppenders.get(key); + if (appenderControl == null) { + //create new appender and control + final Appender app = createAppender(event); + if (app == null) { + return null; + } + AppenderControl created = new AppenderControl(app, null, null); + appenderControl = created; + createdAppenders.put(key, created); + } + } + } + return appenderControl; + } + + + /** + * Used by @{@link #getControl(LogEvent)} to create new subappenders for not yet encountered pipelines. + * */ + private Appender createAppender(final LogEvent event) { + for (final Node node : appenderNode.getChildren()) { + if (node.getType().getElementName().equals(Appender.ELEMENT_TYPE)) { + final Node appNode = new Node(node); + configuration.createConfiguration(appNode, event); + if (appNode.getObject() instanceof Appender) { + final Appender app = appNode.getObject(); + app.start(); + return app; + } + error("Unable to create Appender of type " + node.getName()); + return null; + } + } + error("No Appender was configured for " + getName()); + return null; + } + +} diff --git a/logstash-core/src/main/java/org/logstash/log/PipelineRoutingFilter.java b/logstash-core/src/main/java/org/logstash/log/PipelineRoutingFilter.java new file mode 100644 index 000000000..544065fe5 --- /dev/null +++ b/logstash-core/src/main/java/org/logstash/log/PipelineRoutingFilter.java @@ -0,0 +1,50 @@ +package org.logstash.log; + +import org.apache.logging.log4j.core.Appender; +import org.apache.logging.log4j.core.Core; +import org.apache.logging.log4j.core.LogEvent; +import org.apache.logging.log4j.core.config.plugins.Plugin; +import org.apache.logging.log4j.core.config.plugins.PluginFactory; +import org.apache.logging.log4j.core.filter.AbstractFilter; + +/** + * Custom filter to avoid that pipeline tagged log events goes in global appender. + * */ +@Plugin(name = "PipelineRoutingFilter", category = Core.CATEGORY_NAME, elementType = Appender.ELEMENT_TYPE, printObject = true) +public final class PipelineRoutingFilter extends AbstractFilter { + + private boolean isSeparateLogs; + + /** + * Factory method to instantiate the filter + * */ + @PluginFactory + public static PipelineRoutingFilter createFilter() { + return new PipelineRoutingFilter(); + } + + /** + * Avoid direct instantiation of the filter + * */ + private PipelineRoutingFilter() { + isSeparateLogs = Boolean.getBoolean("ls.pipeline.separate_logs"); + } + + /** + * Contains the main logic to execute in filtering. + * + * Deny the logging of an event when separate logs feature is enabled and the event is fish tagged with a + * pipeline id. + * + * @param event the log to filter. + * */ + @Override + public Result filter(LogEvent event) { + final boolean directedToPipelineLog = isSeparateLogs && + event.getContextData().containsKey("pipeline.id"); + if (directedToPipelineLog) { + return Result.DENY; + } + return Result.NEUTRAL; + } +} diff --git a/logstash-core/src/test/java/org/logstash/log/LogstashConfigurationFactoryTest.java b/logstash-core/src/test/java/org/logstash/log/LogstashConfigurationFactoryTest.java index 0d1495df9..6bb5dedb9 100644 --- a/logstash-core/src/test/java/org/logstash/log/LogstashConfigurationFactoryTest.java +++ b/logstash-core/src/test/java/org/logstash/log/LogstashConfigurationFactoryTest.java @@ -90,7 +90,7 @@ public class LogstashConfigurationFactoryTest { private void verifyPipelineReceived(String pipelineSubAppenderName, String expectedMessage) { LoggerContext context = LoggerContext.getContext(false); final Configuration config = context.getConfiguration(); - RoutingAppender routingApp = config.getAppender(LogstashConfigurationFactory.PIPELINE_ROUTING_APPENDER_NAME); + PipelineRoutingAppender routingApp = config.getAppender(LogstashConfigurationFactory.PIPELINE_ROUTING_APPENDER_NAME); Map appenders = routingApp.getAppenders(); assertNotNull("Routing appenders MUST be defined", appenders); AppenderControl appenderControl = appenders.get(pipelineSubAppenderName); diff --git a/logstash-core/src/test/java/org/logstash/log/PipelineRoutingAppenderTest.java b/logstash-core/src/test/java/org/logstash/log/PipelineRoutingAppenderTest.java new file mode 100644 index 000000000..5b9309927 --- /dev/null +++ b/logstash-core/src/test/java/org/logstash/log/PipelineRoutingAppenderTest.java @@ -0,0 +1,67 @@ +package org.logstash.log; + +import org.apache.logging.log4j.EventLogger; +import org.apache.logging.log4j.core.LogEvent; +import org.apache.logging.log4j.core.LoggerContext; +import org.apache.logging.log4j.core.config.AppenderControl; +import org.apache.logging.log4j.core.config.Configuration; +import org.apache.logging.log4j.junit.LoggerContextRule; +import org.apache.logging.log4j.message.StructuredDataMessage; +import org.apache.logging.log4j.test.appender.ListAppender; +import org.junit.After; +import org.junit.Rule; +import org.junit.Test; +import org.junit.rules.RuleChain; + +import java.util.List; +import java.util.Map; + +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertNotNull; +import static org.junit.Assert.assertTrue; + +public class PipelineRoutingAppenderTest { + + private static final String CONFIG = "log4j-pipeline-routing.xml"; + + private ListAppender app; + + private final LoggerContextRule loggerContextRule = new LoggerContextRule(CONFIG); + + // this is needed to initialize log context + @Rule + public RuleChain rules = loggerContextRule.withCleanFilesRule(); + + @After + public void tearDown() { + this.app.clear(); + this.loggerContextRule.getLoggerContext().stop(); + } + + @Test + public void routingTest() { + final String pipelineId = "test_pipeline"; + StructuredDataMessage msg = new StructuredDataMessage("Test", "This is a test", "Service"); + org.apache.logging.log4j.ThreadContext.put("pipeline.id", pipelineId); + EventLogger.logEvent(msg); + + this.app = findListAppender(pipelineId); + assertEquals("appender-" + pipelineId, app.getName()); + + final List list = app.getEvents(); + assertNotNull("No events generated", list); + assertEquals("Incorrect number of events. Expected 1, got " + list.size(), 1, list.size()); + } + + private ListAppender findListAppender(String pipelineId) { + LoggerContext context = LoggerContext.getContext(false); + final Configuration config = context.getConfiguration(); + PipelineRoutingAppender routingApp = config.getAppender("pipeline_routing"); + assertNotNull("Can't find pipeline routing appender", routingApp); + Map appenders = routingApp.getAppenders(); + assertTrue("Subappender must exists with id " + pipelineId, appenders.containsKey(pipelineId)); + final AppenderControl appenderControl = appenders.get(pipelineId); + return (ListAppender) appenderControl.getAppender(); + } + +} \ No newline at end of file diff --git a/logstash-core/src/test/java/org/logstash/log/PipelineRoutingFilterTest.java b/logstash-core/src/test/java/org/logstash/log/PipelineRoutingFilterTest.java new file mode 100644 index 000000000..a5ed4cea1 --- /dev/null +++ b/logstash-core/src/test/java/org/logstash/log/PipelineRoutingFilterTest.java @@ -0,0 +1,62 @@ +package org.logstash.log; + +import org.apache.logging.log4j.Level; +import org.apache.logging.log4j.MarkerManager; +import org.apache.logging.log4j.core.Filter; +import org.apache.logging.log4j.core.LogEvent; +import org.apache.logging.log4j.core.config.Property; +import org.apache.logging.log4j.core.impl.Log4jLogEvent; +import org.apache.logging.log4j.message.SimpleMessage; +import org.junit.After; +import org.junit.Test; + +import java.util.Collections; + +import static org.junit.Assert.assertEquals; + +public class PipelineRoutingFilterTest { + + @After + public void tearDown() { + System.clearProperty(LogstashConfigurationFactory.PIPELINE_SEPARATE_LOGS); + } + + @Test + public void testShouldLetEventFlowIfSeparateLogFeatureIsDisabled() { + final PipelineRoutingFilter sut = PipelineRoutingFilter.createFilter(); + + LogEvent log = new Log4jLogEvent(); + final Filter.Result res = sut.filter(log); + + assertEquals("When ls.pipeline.separate_logs is false the filter MUST be neutral", Filter.Result.NEUTRAL, res); + } + + @Test + public void testShouldLetEventFlowIfSeparateLogFeatureIsEnabledAndTheEventIsNotPipelineTagged() { + System.setProperty(LogstashConfigurationFactory.PIPELINE_SEPARATE_LOGS, "true"); + final PipelineRoutingFilter sut = PipelineRoutingFilter.createFilter(); + + LogEvent log = new Log4jLogEvent(); + final Filter.Result res = sut.filter(log); + + assertEquals("When ls.pipeline.separate_logs is enabled and log event is not tagged the filter MUST be neutral", + Filter.Result.NEUTRAL, res); + } + + @Test + public void testDenyEventFlowIfSeparateLogFeatureIsEnabledAndTheEventIsPipelineTagged() { + System.setProperty(LogstashConfigurationFactory.PIPELINE_SEPARATE_LOGS, "true"); + final PipelineRoutingFilter sut = PipelineRoutingFilter.createFilter(); + + final Property prop = Property.createProperty("pipeline.id", "test_pipeline"); + + LogEvent log = new Log4jLogEvent("logstash.test.filer", + new MarkerManager.Log4jMarker("marker"), "a", Level.DEBUG, + new SimpleMessage("test message"), Collections.singletonList(prop), null); + final Filter.Result res = sut.filter(log); + + assertEquals("When ls.pipeline.separate_logs is enabled and log event is tagged the filter MUST deny the flowing", + Filter.Result.DENY, res); + } + +} \ No newline at end of file diff --git a/logstash-core/src/test/resources/log4j-pipeline-routing.xml b/logstash-core/src/test/resources/log4j-pipeline-routing.xml new file mode 100644 index 000000000..7ed55a706 --- /dev/null +++ b/logstash-core/src/test/resources/log4j-pipeline-routing.xml @@ -0,0 +1,46 @@ + + + + + build/routing1/routingtest-$${sd:type}.log + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/logstash-core/src/test/resources/log4j2-log-pipeline-test.properties b/logstash-core/src/test/resources/log4j2-log-pipeline-test.properties index 782af7dc6..49d019840 100644 --- a/logstash-core/src/test/resources/log4j2-log-pipeline-test.properties +++ b/logstash-core/src/test/resources/log4j2-log-pipeline-test.properties @@ -16,16 +16,10 @@ appender.rolling.policies.size.size = 100MB appender.rolling.strategy.type = DefaultRolloverStrategy appender.rolling.strategy.max = 30 -appender.routing.type = Routing +appender.routing.type = PipelineRouting appender.routing.name = pipeline_routing_appender -appender.routing.routes.type = Routes -appender.routing.routes.script.type = Script -appender.routing.routes.script.name = routing_script -appender.routing.routes.script.language = JavaScript -appender.routing.routes.script.scriptText = logEvent.getContextMap().get("pipeline.id") -appender.routing.routes.route1.type = Route -appender.routing.routes.route1.list.type = List -appender.routing.routes.route1.list.name = appender-${mdc:pipeline.id} +appender.routing.pipeline.type = List +appender.routing.pipeline.name = appender-${mdc:pipeline.id} rootLogger.level = DEBUG rootLogger.appenderRef.routing.ref = pipeline_routing_appender diff --git a/qa/integration/fixtures/persistent_queues/log4j2.properties b/qa/integration/fixtures/persistent_queues/log4j2.properties index dffe516fe..1132e88a8 100644 --- a/qa/integration/fixtures/persistent_queues/log4j2.properties +++ b/qa/integration/fixtures/persistent_queues/log4j2.properties @@ -26,11 +26,7 @@ appender.rolling.policies.size.type = SizeBasedTriggeringPolicy appender.rolling.policies.size.size = 100MB appender.rolling.strategy.type = DefaultRolloverStrategy appender.rolling.strategy.max = 30 -appender.rolling.avoid_pipelined_filter.type = ScriptFilter -appender.rolling.avoid_pipelined_filter.script.type = Script -appender.rolling.avoid_pipelined_filter.script.name = filter_no_pipelined -appender.rolling.avoid_pipelined_filter.script.language = JavaScript -appender.rolling.avoid_pipelined_filter.script.scriptText = ${sys:ls.pipeline.separate_logs} == false || !(logEvent.getContextData().containsKey("pipeline.id")) +appender.rolling.avoid_pipelined_filter.type = PipelineRoutingFilter appender.json_rolling.type = RollingFile appender.json_rolling.name = json_rolling @@ -47,34 +43,20 @@ appender.json_rolling.policies.size.type = SizeBasedTriggeringPolicy appender.json_rolling.policies.size.size = 100MB appender.json_rolling.strategy.type = DefaultRolloverStrategy appender.json_rolling.strategy.max = 30 -appender.json_rolling.avoid_pipelined_filter.type = ScriptFilter -appender.json_rolling.avoid_pipelined_filter.script.type = Script -appender.json_rolling.avoid_pipelined_filter.script.name = filter_no_pipelined -appender.json_rolling.avoid_pipelined_filter.script.language = JavaScript -appender.json_rolling.avoid_pipelined_filter.script.scriptText = ${sys:ls.pipeline.separate_logs} == false || !(logEvent.getContextData().containsKey("pipeline.id")) +appender.json_rolling.avoid_pipelined_filter.type = PipelineRoutingFilter -appender.routing.type = Routing +appender.routing.type = PipelineRouting appender.routing.name = pipeline_routing_appender -appender.routing.routes.type = Routes -appender.routing.routes.script.type = Script -appender.routing.routes.script.name = routing_script -appender.routing.routes.script.language = JavaScript -appender.routing.routes.script.scriptText = logEvent.getContextData().containsKey("pipeline.id") ? logEvent.getContextData().getValue("pipeline.id") : "sink"; -appender.routing.routes.route_pipelines.type = Route -appender.routing.routes.route_pipelines.rolling.type = RollingFile -appender.routing.routes.route_pipelines.rolling.name = appender-${ctx:pipeline.id} -appender.routing.routes.route_pipelines.rolling.fileName = ${sys:ls.logs}/pipeline_${ctx:pipeline.id}.log -appender.routing.routes.route_pipelines.rolling.filePattern = ${sys:ls.logs}/pipeline_${ctx:pipeline.id}.%i.log.gz -appender.routing.routes.route_pipelines.rolling.layout.type = PatternLayout -appender.routing.routes.route_pipelines.rolling.layout.pattern = [%d{ISO8601}][%-5p][%-25c] %m%n -appender.routing.routes.route_pipelines.rolling.policy.type = SizeBasedTriggeringPolicy -appender.routing.routes.route_pipelines.rolling.policy.size = 100MB -appender.routing.routes.route_pipelines.strategy.type = DefaultRolloverStrategy -appender.routing.routes.route_pipelines.strategy.max = 30 -appender.routing.routes.route_sink.type = Route -appender.routing.routes.route_sink.key = sink -appender.routing.routes.route_sink.null.type = Null -appender.routing.routes.route_sink.null.name = drop-appender +appender.routing.pipeline.type = RollingFile +appender.routing.pipeline.name = appender-${ctx:pipeline.id} +appender.routing.pipeline.fileName = ${sys:ls.logs}/pipeline_${ctx:pipeline.id}.log +appender.routing.pipeline.filePattern = ${sys:ls.logs}/pipeline_${ctx:pipeline.id}.%i.log.gz +appender.routing.pipeline.layout.type = PatternLayout +appender.routing.pipeline.layout.pattern = [%d{ISO8601}][%-5p][%-25c] %m%n +appender.routing.pipeline.policy.type = SizeBasedTriggeringPolicy +appender.routing.pipeline.policy.size = 100MB +appender.routing.pipeline.strategy.type = DefaultRolloverStrategy +appender.routing.pipeline.strategy.max = 30 rootLogger.level = ${sys:ls.log.level} rootLogger.appenderRef.console.ref = ${sys:ls.log.format}_console From 2e4845df36f93a803945b5a39c6a4e8d04951cd9 Mon Sep 17 00:00:00 2001 From: andsel Date: Fri, 18 Dec 2020 14:39:38 +0100 Subject: [PATCH 0657/1126] Introduction of conditional in jvm.options file (#12530) - moved parsing of jvm.options file into Java code - chnaged the parsing code to consider conditional notation to bind the applicability of certain JVM flags to specific JVM versions - changed the launch scripts (.sh and .bat) to use the options string composition - binded CMS flags to JVM specifications 8-14 --- bin/logstash | 5 +- bin/logstash.bat | 29 +- bin/logstash.lib.sh | 36 +-- config/jvm.options | 6 +- docs/static/config-details.asciidoc | 46 +++ .../logstash/launchers/JvmOptionsParser.java | 303 ++++++++++++++++++ .../launchers/JvmOptionsParserTest.java | 70 ++++ 7 files changed, 449 insertions(+), 46 deletions(-) create mode 100644 logstash-core/src/main/java/org/logstash/launchers/JvmOptionsParser.java create mode 100644 logstash-core/src/test/java/org/logstash/launchers/JvmOptionsParserTest.java diff --git a/bin/logstash b/bin/logstash index 696361964..25998c6ee 100755 --- a/bin/logstash +++ b/bin/logstash @@ -56,9 +56,6 @@ if [ "$1" = "-V" ] || [ "$1" = "--version" ]; then fi echo "logstash $LOGSTASH_VERSION" else - unset CLASSPATH - for J in $(cd "${LOGSTASH_JARS}"; ls *.jar); do - CLASSPATH=${CLASSPATH}${CLASSPATH:+:}${LOGSTASH_JARS}/${J} - done + CLASSPATH="$(setup_classpath $LOGSTASH_JARS)" exec "${JAVACMD}" ${JAVA_OPTS} -cp "${CLASSPATH}" org.logstash.Logstash "$@" fi diff --git a/bin/logstash.bat b/bin/logstash.bat index a04a5de9f..d3fe98562 100644 --- a/bin/logstash.bat +++ b/bin/logstash.bat @@ -15,7 +15,7 @@ if "%1" == "--version" goto version rem iterate over the command line args and look for the argument rem after --path.settings to see if the jvm.options file is in -rem that path and set LS_JVM_OPTIONS_CONFIG accordingly +rem that path and set LS_JVM_OPTS accordingly :loop for /F "usebackq tokens=1-2* delims= " %%A in (!params!) do ( set current=%%A @@ -24,7 +24,7 @@ for /F "usebackq tokens=1-2* delims= " %%A in (!params!) do ( if "!current!" == "--path.settings" ( if exist !next!\jvm.options ( - set "LS_JVM_OPTIONS_CONFIG=!next!\jvm.options" + set "LS_JVM_OPTS=!next!\jvm.options" ) ) @@ -33,25 +33,20 @@ for /F "usebackq tokens=1-2* delims= " %%A in (!params!) do ( ) ) -rem if explicit jvm.options is not found use default location -if "%LS_JVM_OPTIONS_CONFIG%" == "" ( - set LS_JVM_OPTIONS_CONFIG="%LS_HOME%\config\jvm.options" -) - -rem extract the options from the JVM options file %LS_JVM_OPTIONS_CONFIG% -rem such options are the lines beginning with '-', thus "findstr /b" -if exist %LS_JVM_OPTIONS_CONFIG% ( - for /F "usebackq delims=" %%a in (`findstr /b \- %LS_JVM_OPTIONS_CONFIG%`) do set options=!options! %%a - set "LS_JAVA_OPTS=!options! %LS_JAVA_OPTS%" -) else ( - echo "warning: no jvm.options file found" -) -set JAVA_OPTS=%LS_JAVA_OPTS% - for %%i in ("%LS_HOME%\logstash-core\lib\jars\*.jar") do ( call :concat "%%i" ) +@setlocal +for /F "usebackq delims=" %%a in (`CALL %JAVA% -cp "!CLASSPATH!" "org.logstash.launchers.JvmOptionsParser" "!LS_HOME!" "!LS_JVM_OPTS!" ^|^| echo jvm_options_parser_failed`) do set LS_JAVA_OPTS=%%a +@endlocal & set "MAYBE_JVM_OPTIONS_PARSER_FAILED=%LS_JAVA_OPTS%" & set LS_JAVA_OPTS=%LS_JAVA_OPTS% + +if "%MAYBE_JVM_OPTIONS_PARSER_FAILED%" == "jvm_options_parser_failed" ( + echo "error: jvm options parser failed; exiting" + exit /b 1 +) +set JAVA_OPTS=%LS_JAVA_OPTS% + %JAVA% %JAVA_OPTS% -cp "%CLASSPATH%" org.logstash.Logstash %* goto :end diff --git a/bin/logstash.lib.sh b/bin/logstash.lib.sh index 3abe5fcfc..6d1533444 100755 --- a/bin/logstash.lib.sh +++ b/bin/logstash.lib.sh @@ -66,12 +66,6 @@ for i in "$@"; do fi done -parse_jvm_options() { - if [ -f "$1" ]; then - echo "$(grep "^-" "$1" | tr '\n' ' ')" - fi -} - setup_bundled_jdk_part() { OS_NAME="$(uname -s)" if [ $OS_NAME = "Darwin" ]; then @@ -81,6 +75,16 @@ setup_bundled_jdk_part() { fi } +# Accepts 1 parameter which is the path the directory where logstash jar are contained. +setup_classpath() { + local jar_directory="${1?jar directory required}" + local classpath + for J in $(cd "${jar_directory}"; ls *.jar); do + classpath=${classpath}${classpath:+:}${jar_directory}/${J} + done + echo "${classpath}" +} + setup_java() { # set the path to java into JAVACMD which will be picked up by JRuby to launch itself if [ -z "$JAVACMD" ]; then @@ -130,24 +134,12 @@ setup_java() { LS_GC_LOG_FILE="./logstash-gc.log" fi - # Set the initial JVM options from the jvm.options file. Look in - # /etc/logstash first, and break if that file is found readable there. - if [ -z "$LS_JVM_OPTS" ]; then - for jvm_options in /etc/logstash/jvm.options \ - "$LOGSTASH_HOME"/config/jvm.options; - do - if [ -r "$jvm_options" ]; then - LS_JVM_OPTS=$jvm_options - break - fi - done - fi - # then override with anything provided - LS_JAVA_OPTS="$(parse_jvm_options "$LS_JVM_OPTS") $LS_JAVA_OPTS" - JAVA_OPTS=$LS_JAVA_OPTS - # jruby launcher uses JAVACMD as its java executable and JAVA_OPTS as the JVM options export JAVACMD + + CLASSPATH="$(setup_classpath $LOGSTASH_JARS)" + JAVA_OPTS=`exec "${JAVACMD}" -cp "${CLASSPATH}" org.logstash.launchers.JvmOptionsParser "$LOGSTASH_HOME" "$LS_JVM_OPTS"` + unset CLASSPATH export JAVA_OPTS } diff --git a/config/jvm.options b/config/jvm.options index 2d743c8b3..82b08ef14 100644 --- a/config/jvm.options +++ b/config/jvm.options @@ -17,9 +17,9 @@ ################################################################ ## GC configuration --XX:+UseConcMarkSweepGC --XX:CMSInitiatingOccupancyFraction=75 --XX:+UseCMSInitiatingOccupancyOnly +8-14:-XX:+UseConcMarkSweepGC +8-14:-XX:CMSInitiatingOccupancyFraction=75 +8-14:-XX:+UseCMSInitiatingOccupancyOnly ## Locale # Set the locale language diff --git a/docs/static/config-details.asciidoc b/docs/static/config-details.asciidoc index d64196a12..835edcbf3 100644 --- a/docs/static/config-details.asciidoc +++ b/docs/static/config-details.asciidoc @@ -2,6 +2,52 @@ === JVM settings Configure the jvm settings in the `jvm.options` <>. +This file contains a line-delimited list of JVM arguments following a special syntax: + +* lines consisting of whitespace only are ignored +* lines beginning with `#` are treated as comments and are ignored ++ +[source,text] +------------------------------------- +# this is a comment +------------------------------------- + +* lines beginning with a `-` are treated as a JVM option that applies +independent of the version of the JVM ++ +[source,text] +------------------------------------- +-Xmx2g +------------------------------------- + +* lines beginning with a number followed by a `:` followed by a `-` are treated +as a JVM option that applies only if the version of the JVM matches the number ++ +[source,text] +------------------------------------- +8:-Xmx2g +------------------------------------- + +* lines beginning with a number followed by a `-` followed by a `:` are treated +as a JVM option that applies only if the version of the JVM is greater than or +equal to the number ++ +[source,text] +------------------------------------- +8-:-Xmx2g +------------------------------------- + +* lines beginning with a number followed by a `-` followed by a number followed +by a `:` are treated as a JVM option that applies only if the version of the +JVM falls in the inclusive range of the two numbers ++ +[source,text] +------------------------------------- +8-9:-Xmx2g +------------------------------------- + +* all other lines are rejected + [[heap-size]] ==== Setting the JVM heap size diff --git a/logstash-core/src/main/java/org/logstash/launchers/JvmOptionsParser.java b/logstash-core/src/main/java/org/logstash/launchers/JvmOptionsParser.java new file mode 100644 index 000000000..badecfe51 --- /dev/null +++ b/logstash-core/src/main/java/org/logstash/launchers/JvmOptionsParser.java @@ -0,0 +1,303 @@ +package org.logstash.launchers; + +import java.io.BufferedReader; +import java.io.IOException; +import java.io.InputStream; +import java.io.InputStreamReader; +import java.io.Reader; +import java.nio.charset.StandardCharsets; +import java.nio.file.Files; +import java.nio.file.Path; +import java.nio.file.Paths; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.Collections; +import java.util.List; +import java.util.Locale; +import java.util.Map; +import java.util.Optional; +import java.util.SortedMap; +import java.util.TreeMap; +import java.util.regex.Matcher; +import java.util.regex.Pattern; + + +/** + * Parse jvm.options file applying version conditional logic. Heavily inspired by same functionality in Elasticsearch. + * */ +public class JvmOptionsParser { + + static class JvmOptionsFileParserException extends Exception { + + private static final long serialVersionUID = 2446165130736962758L; + + private final Path jvmOptionsFile; + + Path jvmOptionsFile() { + return jvmOptionsFile; + } + + private final SortedMap invalidLines; + + SortedMap invalidLines() { + return invalidLines; + } + + JvmOptionsFileParserException(final Path jvmOptionsFile, final SortedMap invalidLines) { + this.jvmOptionsFile = jvmOptionsFile; + this.invalidLines = invalidLines; + } + + } + + private final String logstashHome; + + JvmOptionsParser(String logstashHome) { + this.logstashHome = logstashHome; + } + + /** + * The main entry point. The exit code is 0 if the JVM options were successfully parsed, otherwise the exit code is 1. If an improperly + * formatted line is discovered, the line is output to standard error. + * + * @param args the args to the program which should consist of a single option, the path to LOGSTASH_HOME + */ + public static void main(final String[] args) throws InterruptedException, IOException { + if (args.length < 1 || args.length > 2) { + throw new IllegalArgumentException( + "Expected two arguments specifying path to LOGSTASH_HOME and an optional LS_JVM_OPTS, but was " + Arrays.toString(args) + ); + } + + final JvmOptionsParser parser = new JvmOptionsParser(args[0]); + final String jvmOpts = args.length == 2 ? args[1] : null; + try { + Optional jvmOptions = parser.lookupJvmOptionsFile(jvmOpts); + if (!jvmOptions.isPresent()) { + System.err.println("warning: no jvm.options file found"); + return; + } + parser.parse(jvmOptions.get()); + } catch (JvmOptionsFileParserException pex) { + System.err.printf(Locale.ROOT, + "encountered [%d] error%s parsing [%s]", + pex.invalidLines().size(), + pex.invalidLines().size() == 1 ? "" : "s", + pex.jvmOptionsFile()); + int errorCounter = 0; + for (final Map.Entry entry : pex.invalidLines().entrySet()) { + errorCounter++; + System.err.printf(Locale.ROOT, + "[%d]: encountered improperly formatted JVM option in [%s] on line number [%d]: [%s]", + errorCounter, + pex.jvmOptionsFile(), + entry.getKey(), + entry.getValue()); + } + } catch (IOException ex) { + System.err.println("Error accessing jvm.options file"); + System.exit(1); + } + } + + private Optional lookupJvmOptionsFile(String jvmOpts) { + if (jvmOpts != null && !jvmOpts.isEmpty()) { + return Optional.of(Paths.get(jvmOpts)); + } + // Set the initial JVM options from the jvm.options file. Look in + // /etc/logstash first, and break if that file is found readable there. + return Arrays.stream(new Path[] { Paths.get("/etc/logstash/jvm.options"), + Paths.get(logstashHome, "config/jvm.options") }) + .filter(p -> p.toFile().canRead()) + .findFirst(); + } + + private void parse(Path jvmOptionsFile) throws IOException, JvmOptionsFileParserException { + final List jvmOptionsContent = parseJvmOptions(jvmOptionsFile); + final String lsJavaOpts = System.getenv("LS_JAVA_OPTS"); + if (lsJavaOpts != null && !lsJavaOpts.isEmpty()) { + jvmOptionsContent.add(lsJavaOpts); + } + System.out.println(String.join(" ", jvmOptionsContent)); + } + + private List parseJvmOptions(Path jvmOptionsFile) throws IOException, JvmOptionsFileParserException { + if (!jvmOptionsFile.toFile().exists()) { + return Collections.emptyList(); + } + final int majorJavaVersion = javaMajorVersion(); + + try (InputStream is = Files.newInputStream(jvmOptionsFile); + Reader reader = new InputStreamReader(is, StandardCharsets.UTF_8); + BufferedReader br = new BufferedReader(reader) + ) { + final ParseResult parseResults = parse(majorJavaVersion, br); + if (parseResults.hasErrors()) { + throw new JvmOptionsFileParserException(jvmOptionsFile, parseResults.getInvalidLines()); + } + return parseResults.getJvmOptions(); + } + } + + /** + * Collector of parsed lines and errors. + * */ + static final class ParseResult { + private final List jvmOptions = new ArrayList<>(); + private final SortedMap invalidLines = new TreeMap<>(); + + void appendOption(String option) { + jvmOptions.add(option); + } + + void appendError(int lineNumber, String malformedLine) { + invalidLines.put(lineNumber, malformedLine); + } + + public boolean hasErrors() { + return !invalidLines.isEmpty(); + } + + public SortedMap getInvalidLines() { + return invalidLines; + } + + public List getJvmOptions() { + return jvmOptions; + } + } + + private static final Pattern OPTION_DEFINITION = Pattern.compile("((?\\d+)(?-)?(?\\d+)?:)?(?

;@HY>f7PkQMigYXS?yAlg{ja92aKY>UThF@123 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