Skip to content
This repository was archived by the owner on Aug 20, 2025. It is now read-only.

Conversation

@ottobackwards
Copy link
Contributor

@ottobackwards ottobackwards commented Apr 13, 2017

Contributor Comments

The pr. introduces an extension system for metron, along with refactoring the metron parsers on top of it. This is the base work for METRON-258 - Sideloading parsers, which is to follow, as it enables the creation and management of extensions outside of the metron codebase. The work for enabling side loading is the ability to install and deploy 3rd party extensions/parsers.

There is a lot that can be done with this, but I could nibble at it forever, and I'd like to get feedback and improvements going. There is still more documentation work that can be done for example.

The areas of change:

Travis

  • Building requires a VM instead of a container - requires : sudo

Metron Maven Bundle Plugin

  • adaptation of the nifi plugin
  • more configurable wrt file extension/dependency and metadata naming
  • new pre-build step on clean systems to install plugin

bundle-lib

My goal here was not to make any radical changes. If you want the diff, I would suggest cloning nifi latest and diffing this module with nifi-nar_utils

  • adaptation of nifi-nar-utils to be used outside of the nifi project
  • rudimentary extensibility to allow configuration and injection of service types and other things that were hard coded to nifi
  • refactored from File based to VFS based
  • introduced class cluster for FileUtils to allow for specialized HDFS file functionality ( HDFS with VFS is read only )
  • rebranding to Bundle from Nar ( although the lib and the plugin allow that to be configured now )
  • added capability to the properties class to write to stream, adapted to uri from paths
  • added integration tests for hdfs
  • changed to be ClassIndex based instead of ServiceLoader. Service loader is slower, and Casey's ClassIndex work is great. This also removes the NAR's required manual maintenance of the service file.
  • refactored to use VFS to load the bundle/nar into the classloader AND to use VFS to load the dependency jars -> VFS as a composite filesystem. Thus going from NAR's 'working directory', exploded NARS to just loading the bundle/nar.

Metron Maven Parser Extension Archetype

  • locally installable archetype for creating Metron Parsers
  • dependencies instead of shading
  • builds Bundle
  • creates an assembly with bundle and configuration
  • configuration for parsers now includes all parser related configurations ( except ES and Logrotate )
  • Includes sample data for testing, global config etc. ( such that you don't need metron code to build and test ).
  • Can be used with configuration only parsers, so that you can still unit and integration test them, common deployment
  • Creates documentation readme.

Metron-Platform/Metron-Extensions / Metron-Parser-Extensions/**

  • Module area for extensions, first extension type is parsers
  • All parsers re-based on archetype generated projects
  • All parser test data/ configuration located with parser ( see above )
  • Each parser had a readme that should be filled out, but I didn't do that
    [note - during integration tests, the parsers are found in the system classloader not the bundles, because the way the tests are tied together]

Bundle Extension Test

  • added a separate test to test loading parsers without any dependency

Metron-Parsers

  • Removed all parsers and their tests etc except CSV, JSON, GROK
  • Still shaded, still the storm loaded jar
  • extended or fix tests so that they work when derived outside of code tree
  • Parser bolt no longer takes MessageParser<> instance, loads it as from extension/bundle system
  • MessageParser<> annotated for ClassIndex

Metron-configuration

  • changes to support new parser locations
  • added functionality to load and store bundle.properties to zk

Metron Tests

  • Extended to work with relative path / formatted paths

RPM-Build

  • Copy all the parser extensions
  • Include in the spec

/usr/metron/V/ now has a new directories for extensions:

/extension_etc/PARSER_NAME/ -> that parser's configuration
/extension_alt_etc/ -> location for 3rd Party extension configuration
/extension_lib -> location on disk for rpm to place bundles
/extension_alt_lib -> location on disk for staging 3rd party bundles

METRON-SERVICE ambari

  • Load zk configurations for parsers from their location
  • filles out the properties template and deploys to hdfs
  • create HDFS directories
  • deploy/copy bundles to HDFS

the metron workflow that this enables

We need a new parser:
*create with archetype under metron-extensions/metron-parser-extensions
*implement including tests and test data, all configurations
*add to the copy-resources of RPM-Docker pom
*add to the spec file
*add to the all_parsers variable in params

  • this will get it installed but not started, no ES no log rotate
  • add to parsers variable in the env.xml to get it to start as well ( still no ES or Log rotate )
  • other steps to get the ES template integrated with indexing scripts and log rotate with ansible

I have been working in Full Dev to get this going, and I believe it is working enough to get this started.
At the end of vagrant up with full dev, you should have data in kibana, as if nothing had changed ;)

There are issues however:
I have not integrated this with the Metron Docker project, I'm not sure how yet.
I have fixed Metron-Interface to get the test to run, but I think that work needs to be done there.

The next steps here are follow ons for installing parsers from the ui.

Testing:

  • Build with tests works
  • Start full_dev_platform and confirm parsers are installed and working as expected
  • Management UI confirm that all 14 parsers are installed and available
  • Ensure the UI can spin up the squid parser
  • Follow the metron-platform/metron-extensions/metron-parser-extensions/ADDING_SYSTEM_PARSERS.md guide

I am sure I missed many things, and that there are things that could be better. Thank you in advance for your review.

Pull Request Checklist

Thank you for submitting a contribution to Apache Metron (Incubating).
Please refer to our Development Guidelines for the complete guide to follow for contributions.
Please refer also to our Build Verification Guidelines for complete smoke testing guides.

In order to streamline the review of the contribution we ask you follow these guidelines and ask you to double check the following:

For all changes:

  • [x ] Is there a JIRA ticket associated with this PR? If not one needs to be created at Metron Jira.
  • [x ] Does your PR title start with METRON-XXXX where XXXX is the JIRA number you are trying to resolve? Pay particular attention to the hyphen "-" character.
  • [ x] Has your PR been rebased against the latest commit within the target branch (typically master)?

For code changes:

  • [x ] Have you included steps to reproduce the behavior or problem that is being changed or addressed?

  • [x ] Have you included steps or a guide to how the change may be verified and tested manually?

  • [x ] Have you ensured that the full suite of tests and checks have been executed in the root incubating-metron folder via:

    mvn -q clean integration-test install && build_utils/verify_licenses.sh 
    
  • [x ] Have you written or updated unit tests and or integration tests to verify your changes?

  • [x ] If adding new dependencies to the code, are these dependencies licensed in a way that is compatible for inclusion under ASF 2.0?

  • [x ] Have you verified the basic functionality of the build by building and running locally with Vagrant full-dev environment or the equivalent?

For documentation related changes:

  • [ x] Have you ensured that format looks appropriate for the output in which it is rendered by building and verifying the site-book? If not then run the following commands and the verify changes via site-book/target/site/index.html:

    cd site-book
    bin/generate-md.sh
    mvn site:site
    

Note:

Please ensure that once the PR is submitted, you check travis-ci for build issues and submit an update to your PR as soon as possible.
It is also recommened that travis-ci is set up for your personal repository such that your branches are built there before submitting a pull request.

Based on Apache Nifi Nars

NAR changes
* new lib , rebrand to bundles from NAR
* port to VFS/FileObject from File based
* ability to set property values
* Rework FileUtils so that you can derive and override
* added initializers to set 'classes' that we care about instead of hard coding them, still needs defaults
* added components nec. for integration tests ( do not want dep. on metron-* )
* VFSClassloader for NarClassLoader
* Hdfs based integration test version of unpacknars tests
* HDFS ( filesystem ) based fileutilities to cover for writes to hdfs, since VFS is currently R/O HDFS
* modified plugin to support configuration of outputs
* use class index not service loader ( both subclass and annotated supported )

Archetype
* Parser Extension archetyp
* incudes all configuration
* creates tar.gz with bundle and configuration
* class index support ( automatic generation )

Extensions
* new extensions modules
* parser
* archetype built module for each parser type
* support for configuration only parsers with tests

Parsers
* moved all but json, csv, grok to extensions
* Bolt now loads from bundle properties

Deployment
* rpms for parsers
* create extension directories
* ambari initializes zookeeper per parser
* amabri creates hdfs directories
* ISSUE: Writing to hdfs

Rest-API
* only test against parsers in metron-parsers
* still needs integration
@cestella
Copy link
Member

Woah, big contribution here; thanks @ottobackwards ! So this one is hard to review because a lot of it is:

  • Copied from NiFi's nar
  • Moving files around.

Would you mind giving us a list of files where changes are made that don't fit those two categories? I think that'd help us isolate the bits to review easier.

In the meantime, I have a couple of questions:

  • Could you go over again why we needed the VM in travis?
  • What is the parser file size impact? In other words, when we create a new bundle for a parser, are we shading and including all of metron-parser or is that isolated from the parser?

@ottobackwards
Copy link
Contributor Author

RE: Travis
I was getting these and going to vm was the only way I could get rid of them:

The system is out of resources.
Consult the following stack trace for details.
java.lang.OutOfMemoryError: Java heap space
at java.util.Arrays.copyOf(Arrays.java:3181)
at java.util.ArrayList.grow(ArrayList.java:261)
at java.util.ArrayList.ensureExplicitCapacity(ArrayList.java:235)
at java.util.ArrayList.ensureCapacityInternal(ArrayList.java:227)
at java.util.ArrayList.add(ArrayList.java:458)
at com.sun.tools.javac.file.ZipFileIndex$ZipDirectory.readEntry(ZipFileIndex.java:674)
at com.sun.tools.javac.file.ZipFileIndex$ZipDirectory.buildIndex(ZipFileIndex.java:578)
at com.sun.tools.javac.file.ZipFileIndex$ZipDirectory.access$000(ZipFileIndex.java:485)
at com.sun.tools.javac.file.ZipFileIndex.checkIndex(ZipFileIndex.java:193)
at com.sun.tools.javac.file.ZipFileIndex.(ZipFileIndex.java:137)
at com.sun.tools.javac.file.ZipFileIndexCache.getZipFileIndex(ZipFileIndexCache.java:100)
at com.sun.tools.javac.file.JavacFileManager.openArchive(JavacFileManager.java:598)
at com.sun.tools.javac.file.JavacFileManager.openArchive(JavacFileManager.java:545)
at com.sun.tools.javac.file.JavacFileManager.listContainer(JavacFileManager.java:429)
at com.sun.tools.javac.file.JavacFileManager.list(JavacFileManager.java:676)
at com.sun.tools.javac.code.ClassFinder.scanUserPaths(ClassFinder.java:564)
at com.sun.tools.javac.code.ClassFinder.fillIn(ClassFinder.java:504)
at com.sun.tools.javac.code.ClassFinder.complete(ClassFinder.java:287)
at com.sun.tools.javac.code.ClassFinder.access$000(ClassFinder.java:72)
at com.sun.tools.javac.code.ClassFinder$1.complete(ClassFinder.java:159)
at com.sun.tools.javac.code.Symbol.complete(Symbol.java:579)
at com.sun.tools.javac.comp.Enter.visitTopLevel(Enter.java:299)
at com.sun.tools.javac.tree.JCTree$JCCompilationUnit.accept(JCTree.java:509)
at com.sun.tools.javac.comp.Enter.classEnter(Enter.java:255)
at com.sun.tools.javac.comp.Enter.classEnter(Enter.java:270)
at com.sun.tools.javac.comp.Enter.complete(Enter.java:483)
at com.sun.tools.javac.comp.Enter.main(Enter.java:467)
at com.sun.tools.javac.main.JavaCompiler.enterTrees(JavaCompiler.java:952)
at com.sun.tools.javac.main.JavaCompiler.compile(JavaCompiler.java:833)
at com.sun.tools.javac.main.Main.compile(Main.java:253)
at com.google.errorprone.BaseErrorProneCompiler.run(BaseErrorProneCompiler.java:214)
at com.google.errorprone.BaseErrorProneCompiler.run(BaseErrorProneCompiler.java:106)
[ERROR] Failed to execute goal org.apache.maven.plugins:maven-compiler-plugin:3.5.1:compile (default-compile) on project metron-parser-lancope: Compilation failure -> [Help 1]
[ERROR]

@ottobackwards
Copy link
Contributor Author

RE: parser size
The metron-parser jar is still shaded. it is 97M JAR, 87M archive
The parsers, individually like the ASA are 44k JAR, 44k Bundle, 49K tar.gz each

@ottobackwards
Copy link
Contributor Author

ottobackwards commented Apr 14, 2017

So do you like want a listing of files?
All the areas of functionality that are not bundle or parser extensions would be the areas to look at.
Although I would say that the bundle-lib should still be reviewed in general.

Here is a high level by the file guide, but I may be missing something

changes to OOM issues in travis container

.travis.yml
README.md

packaging and deployment

metron-deployment/packaging/ambari/metron-mpack/src/main/resources/common-services/METRON/CURRENT/configuration/metron-env.xml
metron-deployment/packaging/ambari/metron-mpack/src/main/resources/common-services/METRON/CURRENT/metainfo.xml
metron-deployment/packaging/ambari/metron-mpack/src/main/resources/common-services/METRON/CURRENT/package/scripts/metron_service.py
metron-deployment/packaging/ambari/metron-mpack/src/main/resources/common-services/METRON/CURRENT/package/scripts/params/params_linux.py
metron-deployment/packaging/ambari/metron-mpack/src/main/resources/common-services/METRON/CURRENT/package/scripts/params/status_params.py
metron-deployment/packaging/ambari/metron-mpack/src/main/resources/common-services/METRON/CURRENT/package/scripts/parser_commands.py
metron-deployment/packaging/ambari/metron-mpack/src/main/resources/common-services/METRON/CURRENT/package/templates/bundle.properties.j2
metron-deployment/packaging/docker/rpm-docker/SPECS/metron.spec
metron-deployment/packaging/docker/rpm-docker/pom.xml

metron-extensions/README.md
metron-extensions/metron-parser-extensions/README.md

asa integration test, but from bundle, not dep on asa

metron-extensions/metron-parser-extensions/metron-parser-bundle-tests/pom.xml
metron-extensions/metron-parser-extensions/metron-parser-bundle-tests/src/test/java/org/apache/metron/parsers/ASABundleHDFSIntegrationTest.java
metron-extensions/metron-parser-extensions/metron-parser-bundle-tests/src/test/resources/metron/extension_contrib_lib/metron-parser-test-bundle-1.0-SNAPSHOT.bundle
metron-extensions/metron-parser-extensions/metron-parser-bundle-tests/src/test/resources/metron/extension_lib/metron-parser-asa-bundle-0.3.1.bundle
metron-extensions/metron-parser-extensions/metron-parser-bundle-tests/src/test/resources/zookeeper/bundle.properties
metron-extensions/metron-parser-extensions/metron-parser-bundle-tests/src/test/resources/zookeeper/enrichments/test.json
metron-extensions/metron-parser-extensions/metron-parser-bundle-tests/src/test/resources/zookeeper/global.json
metron-extensions/metron-parser-extensions/metron-parser-bundle-tests/src/test/resources/zookeeper/indexing/test.json

fixes for tests

metron-interface/metron-rest/src/main/java/org/apache/metron/rest/MetronRestConstants.java
metron-interface/metron-rest/src/test/java/org/apache/metron/rest/controller/GrokControllerIntegrationTest.java
metron-interface/metron-rest/src/test/java/org/apache/metron/rest/controller/KafkaControllerIntegrationTest.java
metron-interface/metron-rest/src/test/java/org/apache/metron/rest/controller/SensorParserConfigControllerIntegrationTest.java
metron-interface/metron-rest/src/test/java/org/apache/metron/rest/service/impl/GrokServiceImplTest.java
metron-interface/metron-rest/src/test/java/org/apache/metron/rest/service/impl/SensorParserConfigServiceImplTest.java

new functions for bundle.properties and tests - dealing with paths etc

metron-platform/metron-common/src/main/java/org/apache/metron/common/configuration/ConfigurationsUtils.java
metron-platform/metron-common/src/test/java/org/apache/metron/common/cli/ConfigurationsUtilsTest.java
metron-platform/metron-common/src/test/java/org/apache/metron/common/configuration/SensorEnrichmentConfigTest.java

support new directories

metron-platform/metron-enrichment/src/test/java/org/apache/metron/enrichment/integration/components/ConfigUploadComponent.java

load parsers from bundles

metron-platform/metron-parsers/src/main/java/org/apache/metron/parsers/bolt/ParserBolt.java
metron-platform/metron-parsers/src/main/java/org/apache/metron/parsers/bolt/ParserLoader.java
metron-platform/metron-parsers/src/main/java/org/apache/metron/parsers/topology/ParserTopologyBuilder.java

the system bundle properties to tests

metron-platform/metron-integration-test/src/main/config/zookeeper/bundle.properties

test function fixes for new paths

metron-platform/metron-management/src/test/java/org/apache/metron/management/ConfigurationFunctionsTest.java
metron-platform/metron-management/src/test/java/org/apache/metron/management/ParserConfigFunctionsTest.java

fix to work with new paths

metron-platform/metron-test-utilities/src/main/java/org/apache/metron/test/utils/SampleDataUtils.java

@ottobackwards
Copy link
Contributor Author

if you don't review the parsers, because the code didn't change, you still need to review or think about the concept that each parser, as an extension should have all of the things ( configuration etc ) that it needs within it's package. So the parsers have their grok statements, their configuration ( index, enrichment , and parsers and in the future ES + log rotate )

… it is when running from archetype, causing the extension versio to be used for this dependency
@ottobackwards
Copy link
Contributor Author

@mattf-horton I really like how this is evolving. One thing I have been thinking of since adding the BundleSystem interface ( which should be the main external interface ) is that I would like to refactor the packages, and introduce a .core, with the current roots and subfolders, exposing only the BundleSystem at the root. Do you have any thoughts on this? I know it assumes you have caught up with and are OK with the BundleSystem.... sorry

@mattf-apache
Copy link
Member

@ottobackwards , many good improvements here. A few comments on the singleton idiom, and a couple other details.

public final class BundleClassLoaders {

private static volatile BundleClassLoaders bundleClassLoaders;
private volatile InitContext initContext;
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Since BundleClassLoaders is a singleton, this (initContext) should be static too.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

done

}
}
return result;
}
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

But this can return an uninitialized singleton. It is better to have getInstance() just test for null and throw UnitializedException or return an initialized instance. The creation of the singleton should be in init() -- which must be static so you can invoke before the instance exists.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

done

* @throws IllegalStateException when already initialized with a given set of extension directories
* and extensionDirs does not match
*/
public void init(final FileSystemManager fileSystemManager, final List<FileObject> extensionsDirs,
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

As noted above, this method should be static, and create the singleton instance at the same time as initializing it. Creation and init of both BundleClassLoaders and InitContext instances should be in the same synchronized block, and of course be conditional on either not already existing.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

done

synchronized (this) {
if(initContext != null) {
initContext = null;
}
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Recommend combining reset and unInit methods. This avoids the issues of

  • having reset static while unInit is per-instance (doesn't matter which since is singleton, but confusing to use both)
  • using double synchronize calls (ok even with both static or both per-instance, because Java locks are reentrant, but unnecessary and raises concerns in paranoid reviewers like me)

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

done

static final Logger LOG = LoggerFactory.getLogger(BundleThreadContextClassLoader.class);
static final ContextSecurityManager contextSecurityManager = new ContextSecurityManager();
private final ClassLoader forward = ClassLoader.getSystemClassLoader();

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I very much like that you made BundleThreadContextClassLoader statically self-initializing, by using ExtensionManager.getInstance().getExtensionClasses() instead of keeping a copy here that had to be initialized. Good job.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

If we can't get rid of all the static init, at least we can get rid of as much as possible.

}

private InitContext discoverExtensions(final List<Class> classes, final Bundle systemBundle, final Set<Bundle> bundles)
throws NotInitializedException {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Can NotInitializedException still occur? If so, something below is calling getInstance() instead of static methods, which it will need to change anyway in order to change init() to static.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

gone

*
* {@see com.google.common.collect}
*/
public class ImmutableCollectionUtils {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I guess you're trying to assure thread-safeness. Is it worth the extra effort and object spawning? Are the underlying objects likely to be attempted to be modified by other threads, given first-level ("shallow") immutability?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think it is more const correct

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

accepted.

*/
public BundleSystem build() throws NotInitializedException {
if (this.properties == null) {
throw new IllegalArgumentException("BundleProperties are required");
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

But you also said the only use of properties file is for the extension classes. This suggests an either/or with the "extensionClasses" field. But if you feel making properties mandatory is future-proofing, that's okay.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We need the properties for other things

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Ah, then please correct the above comment on withExtensionClasses() that says "If [ExtensionClasses] provided, the properties file will not be used.".

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I will make it more clear they will not be used for the classes, but will be used for other things

* The ExtensionMapping represents a mapping of the extensions available to the system.
* It is the product of the BundleMapper.
*
* It is NOT used at runtime for loading extensions, rather it may be used by a system to
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Please note which method does load extensions at startup.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

done

* extension type.
* @param extensionTypeName the extension type name, such as parser, stellar, indexing
* @return Map of extension class name to a Set of BundleCoordinates
*/
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

good. Thanks for adding all the javadocs.

@ottobackwards
Copy link
Contributor Author

@mattf-horton all feedback addressed, as noted above

@mmiklavc
Copy link
Contributor

I'm seeing this error spinning up topologies in full-dev.

1:50.278 o.a.s.util [ERROR] Async loop died!
java.lang.RuntimeException: Grok parser Error: Grok parser unable to initialize grok parser: Unable to load /patterns/yaf from either classpath or HDFS
	at org.apache.metron.parsers.grok.GrokParser.init(GrokParser.java:123) ~[stormjar.jar:?]
	at org.apache.metron.parsers.bolt.ParserBolt.prepare(ParserBolt.java:127) ~[stormjar.jar:?]
	at org.apache.storm.daemon.executor$fn__6573$fn__6586.invoke(executor.clj:798) ~[storm-core-1.0.1.2.5.6.0-40.jar:1.0.1.2.5.6.0-40]
	at org.apache.storm.util$async_loop$fn__554.invoke(util.clj:482) [storm-core-1.0.1.2.5.6.0-40.jar:1.0.1.2.5.6.0-40]
	at clojure.lang.AFn.run(AFn.java:22) [clojure-1.7.0.jar:?]
	at java.lang.Thread.run(Thread.java:745) [?:1.8.0_77]
Caused by: java.lang.RuntimeException: Grok parser unable to initialize grok parser: Unable to load /patterns/yaf from either classpath or HDFS
	at org.apache.metron.parsers.grok.GrokParser.init(GrokParser.java:107) ~[stormjar.jar:?]
	... 5 more

I get this for both an existing parser, yaf in this case, as well as a newly-created parser. Would any of this have changed in this PR?

@ottobackwards
Copy link
Contributor Author

I don't think so. Are you running the latest? I'll run up full dev and check.

return bundleClassLoaders;
}
return result;
}
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

There's no longer a need for getInstance() to synchronize, if we deal with bundleClassLoader atomically. (See also init() method comment below):

  public static BundleClassLoaders getInstance() throws NotInitializedException {
    BundleClassLoaders result = bundleClassLoaders;
    if (result == null) {
      throw new NotInitializedException("BundleClassLoaders not initialized");
    }
    return result;
  }

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

ok

throw new IllegalStateException("BundleClassloader already exists");
}
bundleClassLoaders = new BundleClassLoaders();
initContext = bundleClassLoaders.load(fileSystemManager, extensionsDirs, props);
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

So that getInstance() can safely not synchronize, do this:

      BundleClassLoaders b = new BundleClassLoaders();
      InitContext ic = b.load(fileSystemManager, extensionsDirs, props);
      initContext = ic;
      bundleClassLoaders = b;

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

ok

return extensionManager;
}
return result;
}
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

As with BundleClassLoader, to deal with extensionManager atomically:

  public static ExtensionManager getInstance() throws NotInitializedException {
    ExtensionManager result = extensionManager;
    if (result == null) {
      throw new NotInitializedException("ExtensionManager not initialized");
    }
    return result;
  }

throw new IllegalStateException("ExtensionManager already exists");
}
extensionManager = new ExtensionManager();
initContext = extensionManager.discoverExtensions(classes, systemBundle, bundles);
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

And to protect unsynchronized getInstance():

      ExtensionManager em = new ExtensionManager();
      InitContext ic = em.discoverExtensions(classes, systemBundle, bundles);
      initContext = ic;
      extensionManager = em;

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

ok

* before the rest of the methods are called afterwards.
* This is for TESTING ONLY at this time. Reset does not unload or clear any loaded classloaders.
*/
public static void reset() {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Please add @ VisibleForTesting annotation.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

ok

@AfterClass
public static void after() {
BundleClassLoaders.reset();
}
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Did you intend to do ExtensionManager.reset(); here also?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I hate this static stuff.

@mattf-apache
Copy link
Member

@ottobackwards , looking very good. Couple more comments above (unfortunately the system decided they are on "outdated" code, so you'll have to press the "Show outdated" buttons), then you have my +1.

@mattf-apache
Copy link
Member

Looks good, you've responded to all my comments satisfactorily, and Travis is still happy.
You have my +1, contingent on @mmiklavc 's approval, since he's doing the practical testing.

@mattf-apache
Copy link
Member

And @ottobackwards , I want to say thank you for all your patience plowing thru this stuff, with unavoidably slow rates of review. It's been a monumental contribution, and I look forward to seeing it in.

@ottobackwards
Copy link
Contributor Author

Thank you @mattf-horton.

@ottobackwards
Copy link
Contributor Author

Here is the current status

  • bundles-lib and maven plugin review is almost done.
  • testing has shown both a bug in grok rules from hdfs in my implementation and in the system as well
    I am working on a refactoring to get this working as it was intended, but on a different branch
  • sample parser not reviewed
  • parser loading not reviewed
  • ambari installation not reviewed

I think I have the hdfs grok stuff fixed, accept in the rest services which are super tightly coupled to metron-parsers and count on the common rules being in the classloader.

@ottobackwards
Copy link
Contributor Author

OK @merrimanr , @mmiklavc
I have resolved the issues for working with grok from the rest/ui.

PR INTO 777 for fixing GROK

Please review so we can get this into 777.

@ottobackwards
Copy link
Contributor Author

NOTE On current configure UI limitations

Because I was already tasked with making this PR smaller ( don't laugh ), I left the Configuration UI and REST not integrated with Bundles. That means that they only have access to metron-parsers homed parser types ( JSON, CSV, GROK ) when creating parsers.

All of the ZK based stuff works, and all parsers are listed. But there are areas where the REST API is tightly coupled to metron-parsers and is using the service loader pattern that have technically regressed.

If we need this to be addressed as part of this PR, I can do that.
By that I mean integrate the parser extensions + bundles system into rest.
But given the history of feedback on this pr, I will put it out for comment.

@merrimanr ?

@ottobackwards
Copy link
Contributor Author

And also, the PR for fixing grok needs to go in to do the next step there as well.

@merrimanr
Copy link
Contributor

There are some consequences of not having the bundle classes available in rest. The list of available classes will only contain metron-parsers homed parser types so those are the only type of parsers you would be able to create in the UI. Editing parsers outside of these will also not work correctly because the classes won't be available to parse sample messages. These are fairly significant regressions in my opinion. I'm fine with this work being split up into 2 PRs but I believe they should go in at the same time. Otherwise we'll be in a state where the UI does not work.

@ottobackwards
Copy link
Contributor Author

closing this in preparation for feature branch

@ottobackwards
Copy link
Contributor Author

Note to all reviewers:

#720
and the new feature branch have been created.

I believe I have addressed everything brought up here at this point ( including grok not working, and the config-ui creating instances of the non-base parsers )

Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.