selenium icon indicating copy to clipboard operation
selenium copied to clipboard

GridLauncher missing

Open ccarmannt opened this issue 4 years ago • 26 comments

🐛 Bug Report

The class org.openqa.grid.selenium.GridLauncherV4 does not exist. This makes us unable to use the parameters "-proxy" and "-servlets".

To Reproduce

Detailed steps to reproduce the behavior:

java -cp selenium-server-4.0.0-beta-2.jar org.openqa.grid.selenium.GridLauncherV4 -role node Error: Could not find or load main class org.openqa.grid.selenium.GridLauncherV4

Expected behavior

The class should exist.

Environment

OS: Windows 10 Selenium Grid version (if applicable): 4.0.0-beta2

ccarmannt avatar Aug 02 '21 18:08 ccarmannt

Grid 4 is not compatible with Grid 3.

What is your use case?

diemol avatar Aug 04 '21 10:08 diemol

Our implementation needs to be able to launch our customized proxy on the hub and servlets on the nodes.

ccarmannt avatar Aug 04 '21 13:08 ccarmannt

Same here, in v3 there was a section in the proxy, before session and after session that was maintained throughout the iterations and could be used to prep the node before the test starts like starting/stopping a video recording.

Where in the v4 code can we do this?

csgbn avatar Dec 11 '21 14:12 csgbn

No movement on this in 6 months? This is a serious loss of functionality. @diemol @titusfortner

ccarmannt avatar Feb 15 '22 17:02 ccarmannt

What does your customized proxy do? That reply was very ambiguous.

diemol avatar Feb 15 '22 17:02 diemol

The customized proxy does various work inside the proxy class methods (eg. beforeSession, afterSession, etc.). This includes things to prepare the node for use before the test starts, like killing rogue processes.

The custom servlet is similar, allowing us to run commands on the nodes from inside tests.

ccarmannt avatar Feb 15 '22 17:02 ccarmannt

To alter the behaviour of a session, you need to provide a Node implementation. The default one is the LocalNode, which serves as a good template to build from there. An example of that is the OneShotNode.

You can provide the implementation through the --node-implementation flag.

diemol avatar Feb 22 '22 11:02 diemol

Thanks for this pointer, @diemol .

However, it doesn't work. If I include the --node-implementation flag in the command, the node doesn't launch. It just prints the help:

>java -jar selenium-server-4.1.2.jar --node-implementation SuperNode node

Selenium Server commands

A list of all the commands available. To use one, run `java -jar selenium.jar
commandName`.
[...]

ccarmannt avatar Feb 22 '22 16:02 ccarmannt

https://www.selenium.dev/documentation/grid/getting_started/

The arguments are in the wrong order, also you would need to share the class path.

diemol avatar Feb 22 '22 21:02 diemol

I don't see anything in that link that defines an order for arguments. And what do you mean by share the class path ?

ccarmannt avatar Feb 23 '22 14:02 ccarmannt

This is an example that shows how a Node is started https://www.selenium.dev/documentation/grid/getting_started/#nodes and you add the parameters after that:

java -jar selenium-server-4.1.2.jar node --node-implementation SuperNode

The class path the same way you were doing it java -cp

diemol avatar Feb 23 '22 14:02 diemol

Ok, using this modified command:

java -cp . -jar selenium-server-4.1.2.jar node --node-implementation SuperNode

Generates this ClassNotFoundException:

09:42:16.126 INFO [LogManager$RootLogger.log] - Using the system default encoding
09:42:16.129 INFO [OpenTelemetryTracer.createTracer] - Using OpenTelemetry for tracing
09:42:16.683 INFO [UnboundZmqEventBus.<init>] - Connecting to tcp://0.0.0.0:4442 and tcp://0.0.0.0:4443
09:42:16.738 INFO [UnboundZmqEventBus.<init>] - Sockets created
09:42:17.751 INFO [UnboundZmqEventBus.<init>] - Event bus ready
09:42:18.548 INFO [NodeServer.createHandlers] - Reporting self as: http://10.12.73.121:5555
java.lang.reflect.InvocationTargetException
        at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
        at sun.reflect.NativeMethodAccessorImpl.invoke(Unknown Source)
        at sun.reflect.DelegatingMethodAccessorImpl.invoke(Unknown Source)
        at java.lang.reflect.Method.invoke(Unknown Source)
        at org.openqa.selenium.grid.Bootstrap.runMain(Bootstrap.java:77)
        at org.openqa.selenium.grid.Bootstrap.main(Bootstrap.java:70)
Caused by: org.openqa.selenium.grid.config.ConfigException: java.lang.ClassNotFoundException: SuperNode
        at org.openqa.selenium.grid.config.MemoizedConfig.getClass(MemoizedConfig.java:115)
        at org.openqa.selenium.grid.node.config.NodeOptions.getNode(NodeOptions.java:148)
        at org.openqa.selenium.grid.node.httpd.NodeServer.createHandlers(NodeServer.java:127)
        at org.openqa.selenium.grid.node.httpd.NodeServer.asServer(NodeServer.java:183)
        at org.openqa.selenium.grid.node.httpd.NodeServer.execute(NodeServer.java:230)
        at org.openqa.selenium.grid.TemplateGridCommand.lambda$configure$4(TemplateGridCommand.java:129)
        at org.openqa.selenium.grid.Main.launch(Main.java:83)
        at org.openqa.selenium.grid.Main.go(Main.java:57)
        at org.openqa.selenium.grid.Main.main(Main.java:42)
        ... 6 more
Caused by: java.lang.ClassNotFoundException: SuperNode
        at java.net.URLClassLoader.findClass(Unknown Source)
        at java.lang.ClassLoader.loadClass(Unknown Source)
        at sun.misc.Launcher$AppClassLoader.loadClass(Unknown Source)
        at java.lang.ClassLoader.loadClass(Unknown Source)
        at java.lang.Class.forName0(Native Method)
        at java.lang.Class.forName(Unknown Source)
        at org.openqa.selenium.grid.config.ClassCreation.callCreateMethod(ClassCreation.java:35)
        at org.openqa.selenium.grid.config.MemoizedConfig.lambda$getClass$4(MemoizedConfig.java:100)
        at java.util.concurrent.ConcurrentHashMap.computeIfAbsent(Unknown Source)
        at org.openqa.selenium.grid.config.MemoizedConfig.getClass(MemoizedConfig.java:95)
        ... 14 more
Exception in thread "Thread-1" java.lang.NullPointerException
        at org.openqa.selenium.grid.node.httpd.NodeServer.lambda$new$0(NodeServer.java:79)
        at java.lang.Thread.run(Unknown Source)

ccarmannt avatar Feb 23 '22 14:02 ccarmannt

But where did you package the overloaded class? In a jar? Why are you not putting the whole class name?

diemol avatar Feb 23 '22 14:02 diemol

That is the whole class name. The file SuperNode.class is in the current directory when running the command to start the node.

ccarmannt avatar Feb 23 '22 14:02 ccarmannt

Ok, so a more concrete example. We have the OneShotNode, and to use that, we generate a jar that contains the class and the jar is called libk8s.jar.

We added a flag that lets you add that jar in a more simple way, no class path commands needed. The command will look like this:

java -jar selenium-server-4.1.2.jar --ext libk8s.jar node --node-implementation org.openqa.selenium.grid.node.k8s.OneShotNode

Even if the class is called OneShotNode, I need to put the whole class name: org.openqa.selenium.grid.node.k8s.OneShotNode

diemol avatar Feb 23 '22 15:02 diemol

I was able to build a jar that allows the node to attempt to start, but it throws an exception when trying to read the configuration information:

Caused by: org.openqa.selenium.grid.config.ConfigException: Unable to find node stereotype
        at nthrive.SuperNode.lambda$create$0(SuperNode.java:112)

This code block appears to be at fault:

Map<String, Object> raw = new Json().toType(
          config.get("k8s", "stereotype")
            .orElseThrow(() -> new ConfigException("Unable to find node stereotype")),
          MAP_TYPE);

How do I have to modify this to read a standard toml config file?

ccarmannt avatar Feb 23 '22 19:02 ccarmannt

Seems you are copying the exact same code from OneShotNode, where that configuration field is needed.

Feel free to strip down things that you do not need for your purpose. Also, you can use LocalNodeFactory and LocalNode as guides too.

diemol avatar Feb 23 '22 19:02 diemol

Is LocalNode the class that is used for nodes when a grid is started without options? (java -jar server.jar) ?

I was able to hack the code to get around the previous error, but it appears the custom class is not being used, as my added logging statements don't show up in the node log file.

Everything we've discussed so far only relates to the -proxy parameter that was lost. Where's the replacement for the -servlet parameter?

ccarmannt avatar Feb 24 '22 16:02 ccarmannt

We did not implement ways for servlets, and in most cases it could be also done in a proxy. What servlet cases do you have in mind?

diemol avatar Mar 02 '22 16:03 diemol

We were using the servlets to create callable endpoints on the hub, e.g.:

http://hub:4444/grid/admin/tasklist?sessionId=12345

So that when these endpoints were hit, we could execute some custom code in response inside of the servlet's process method:

	protected void process(HttpServletRequest request, HttpServletResponse response) throws IOException

ccarmannt avatar Mar 02 '22 19:03 ccarmannt

@diemol will there be support for servlets in Se 4?

quldude avatar Mar 21 '22 19:03 quldude

We can have a look at that based on community feedback. So far, the need for it seems to be very low, and therefore is low priority. Obviously, if someone wants to give us a hand implementing that, we are open to collaborate.

diemol avatar Mar 23 '22 18:03 diemol

We have been discussing this (Proxy and Servlet) for Grid 4 in the team, and so far we see:

  • Proxy: can be done by providing a Node implementation.
  • Servlets: Use cases point to admin tasks done in the server. That type of work can be done outside the Grid server, implemented in any language/framework.

Are there any other use cases that would require to have Servlets supported again? Looking forward to your feedback.

diemol avatar Aug 17 '22 21:08 diemol

Very glad to hear this is still under consideration.

I have not been able to find a way to create a custom "Node implementation" that works. If you have a working example, I'd love to see it.

As to servlets, our use was to be able to send a command to the hub to be executed or to be forwarded to a node for execution. e.g. to find out whether a specific process is running on the node, etc.

ccarmannt avatar Aug 18 '22 13:08 ccarmannt

Very glad to hear this is still under consideration.

Not exactly being considered for development at the moment. We are open to hear use cases for Servlets that need to be inside the Grid for them to work properly.

Regarding the Node implementation, I will add something to the docs to make it clear.

diemol avatar Aug 22 '22 09:08 diemol

Hello

from what I've seen, it's not possible do add routes to node / hub, so I ended up using a node-implementation that creates a servlet server, but it's not ideal as from my grid client, I need to adress servers, depending on the action performed

An example on a detailed node inplementation would be great

bhecquet avatar Sep 05 '22 07:09 bhecquet

@bhecquet : Any chance you could share some of your implementation? What are you using to run servlets, and what command are you using to launch your custom node?

ccarmannt avatar Oct 28 '22 13:10 ccarmannt

@ccarmannt : you can look at my custom grid: https://github.com/bhecquet/seleniumRobot-grid/tree/selenium4 Especially

  • for servlets on node: https://github.com/bhecquet/seleniumRobot-grid/blob/selenium4/src/main/java/com/infotel/seleniumrobot/grid/node/SeleniumRobotNodeFactory.java
  • for servlets on hub/router: https://github.com/bhecquet/seleniumRobot-grid/blob/selenium4/src/main/java/com/infotel/seleniumrobot/grid/GridStarter.java#L443

Servlet server is started on router / node port + 10 so it's not pretty, but it works :)

If you have any question, I will be happy to reply

bhecquet avatar Oct 29 '22 18:10 bhecquet

@bhecquet : thanks for this. Much appreciated.

ccarmannt avatar Oct 31 '22 13:10 ccarmannt

Closing since, thanks to @krmahadevan, we have now documentation that shows how to create your own Node.

diemol avatar Nov 09 '22 15:11 diemol