-
Notifications
You must be signed in to change notification settings - Fork 130
Conversation
homeDirectory.resolve("plugins").toFile().mkdirs(); | ||
copyResource( | ||
pluginName + ".jar", homeDirectory.resolve("plugins/" + pluginName + ".jar")); | ||
PantheonNode.this.plugins.add(pluginName); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
nice trick - haven't seen this syntax before 😄
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
It's essential for inner classes where names are shadowed.
@@ -390,7 +403,7 @@ public Address getAddress() { | |||
return Util.publicKeyToAddress(keyPair.getPublicKey()); | |||
} | |||
|
|||
Path homeDirectory() { | |||
public Path homeDirectory() { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
(nit) getHomeDirectory
?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
+1 for consistency of getters.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Fixed at the interface, along with other inconsistent names.
} | ||
|
||
@Override | ||
public void setPlugins(final List<String> plugins) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
this looks like dead code
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
When we are acceptance testing specific plugins it will be needed, so I'll bring it back then.
|
||
for (final PantheonPlugin plugin : serviceLoader) { | ||
try { | ||
plugin.register(this); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Is it a little dangerous to give plugins access to the object that can start / stop / register plugins? Why not just have a separate object that holds your services?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This is written with Java modules in mind. The class they would need to cast it to (PantheonPluginContextImpl) will not be visible in the modules and the JVM will enforce that barrier at compile time and runtime. The interface only exposes a PantheonContext to them.
If we used a proxy class they will still be able to (pre Java modules) use reflection to navigate to the containing context and get access.
Plugins right now are not meant to run byzantine plugins.
If I am missing something ping me on slack.
|
||
public interface PantheonContext { | ||
|
||
<T> Optional<T> getService(Class<T> serviceType); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Curious - why go with this generic pattern rather than just explicitly exposing some services like registerCLIOptions
, getPantheonEvents
, etc? Is the idea that this makes it easier for us to remove services in the future?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Also wondering if we shouldn't just return the service class directly rather than wrapping in it in an Optional
? And in the case where a plugin asks for a service that isn't registered, we could just throw an exception and disable that plugin. Seems safer to disable plugins that might be missing required services.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This is so we can expose more services later and not have to mutate the API. In a future revision the plugins themselves could expose services.
The Optional is there in case plugins want to do graceful degraded service. A plugin may want a service but not require it. For example a plugin that interacts with consensus engines would only expect one to be operating but would go down the list of possible engines that expose services to the plugin architecture.
plugins/src/main/java/tech/pegasys/pantheon/plugins/internal/PantheonPluginContextImpl.java
Outdated
Show resolved
Hide resolved
public void register(final PantheonContext context) { | ||
this.context = context; | ||
|
||
if (System.getProperty("testPlugin.failAtRegister") != null) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Any plans to add tests that hit these failure cases or check that the registered CLI flags are used?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yes, with this commit. Validating the flag is a bit tricky and needs to be done as part of the acceptance tests.
package tech.pegasys.pantheon.plugins.services; | ||
|
||
/** This service will be available during the registration callbacks. */ | ||
public interface PicoCLIOptions { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Just checking my understanding here. Seems like the idea in tying this class to PicoCLI rather than making it something more generic like CLIOptions
is that in the future we might use a different CLI system, that will be supported by a completely different service / api?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
+1, strongly coupled to Pico cli library.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yes, graceful migration.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Few comments left.
General mechanism looks good to me.
@@ -390,7 +403,7 @@ public Address getAddress() { | |||
return Util.publicKeyToAddress(keyPair.getPublicKey()); | |||
} | |||
|
|||
Path homeDirectory() { | |||
public Path homeDirectory() { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
+1 for consistency of getters.
@@ -184,6 +184,13 @@ public void startNode(final PantheonNode node) { | |||
.directory(new File(System.getProperty("user.dir")).getParentFile()) | |||
.redirectErrorStream(true) | |||
.redirectInput(Redirect.INHERIT); | |||
if (!node.getPlugins().isEmpty()) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I'm quite sceptical to put environment variables directly in the code.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
It's a test harness and environmental variables is the documented way we add Java options (such as memory) to the invocation. This reflects real world usage.
@@ -43,6 +43,7 @@ | |||
long DEFAULT_MIN_REFRESH_DELAY = 1; | |||
String DOCKER_GENESIS_LOCATION = "/etc/pantheon/genesis.json"; | |||
String DOCKER_DATADIR_LOCATION = "/var/lib/pantheon"; | |||
String DOCKER_PLUGINSDIR_LOCATION = "/etc/pantheon/plugins"; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This will disappear with Kubernetes work as all others docker paths.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Until k8s lands we need it.
@@ -1205,6 +1217,21 @@ private Path dataDir() { | |||
} | |||
} | |||
|
|||
private Path pluginsDir() { | |||
if (isFullInstantiation()) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Same as previous comment. App should not behave differently when run inside docker.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This is a concern outside the scope of this PR. I am being consistent with the current architecture.
state = Lifecycle.STARTING; | ||
final Iterator<PantheonPlugin> pluginsIterator = plugins.iterator(); | ||
|
||
while (pluginsIterator.hasNext()) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Do we really want to start plugins sequentially ?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The other option being parallel? I don't see parallel startup ending well.
package tech.pegasys.pantheon.plugins.services; | ||
|
||
/** This service will be available during the registration callbacks. */ | ||
public interface PicoCLIOptions { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
+1, strongly coupled to Pico cli library.
…antheonPluginContextImpl.java Co-Authored-By: mbaxter <mbaxter@users.noreply.github.com>
...ests/src/test/java/tech/pegasys/pantheon/tests/acceptance/plugins/PluginsAcceptanceTest.java
Outdated
Show resolved
Hide resolved
* @param optionObject The instance of the object to be inspected. PicoCLI will reflect the fields | ||
* of this object to extract the CLI options. | ||
*/ | ||
void addPicoCLIOptions(String namespace, Object optionObject); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
void addPicoCLIOptions(String namespace, Object optionObject); | |
void addCLIOptions(String namespace, Object optionObject); |
(optional) We could still probably make the method name more generic
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Because it is very tied to PicoCLI's style I feel we should communicate that wherever possible.
public class PluginsAcceptanceTest extends AcceptanceTestBase { | ||
private PantheonNode node; | ||
|
||
// context: https://en.wikipedia.org/wiki/The_Magic_Words_are_Squeamish_Ossifrage |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
nice 😄
…eptance/plugins/PluginsAcceptanceTest.java Co-Authored-By: mbaxter <mbaxter@users.noreply.github.com>
PR description
Provide a mechanism for Pantheon to integrate plugin code at runtime.
Fixed Issue(s)