NOAA-OWP / wres

Code and scripts for the Water Resources Evaluation Service
Other
2 stars 1 forks source link

As a user, I want to be able to use the GUI without having to connect to a broker/tasker version of the WRES #202

Open epag opened 3 months ago

epag commented 3 months ago

Author Name: Chris (Chris) Original Redmine Issue: 61633, https://vlab.noaa.gov/redmine/issues/61633 Original Date: 2019-03-22


Currently, the WRES GUI interacts with the WRES by calling it directly through the HTTP service deployed via our docker containers on the dev02, dev03, ti02, and ti03 systems. That's a fairly complex deployment process and does not lend itself to local instances. As a result, there should be a new mode of operation for the GUI to call the WRES directly.

There are a couple possible routes that jump to mind when implementing this. The easiest process would be to call the WRES directly through @subprocess.Popen@ through another thread. Another is by using a framework to interact with a JVM directly through something like Jpype or javabridge. Yet another option is by creating another driver for Control, which will provide a very basic http entrance that will serve as a sort of replacement for the @Main@ class that is used for the CLI. That last one is probably one of the better solutions.

One of the difficulties would be the interaction between the @Job@ view and


Redmine related issue(s): 59938


epag commented 3 months ago

Original Redmine Comment Author Name: James (James) Original Date: 2019-03-22T15:28:19Z


Would another way to look at this be as follows - make it easy to install/instantiate the WRES as a service (e.g. operating on localhost where a remote instance was not accessible)?

I think we want it to be easy to host/instantiate a service instance in general.

It might be possible to not rely on the WRES operating as a service and, instead, to rely on the WRES operating as an application (create a request string, spin-up the application in a separate VM, wait for it to finish, look for results, obtain the results, do something with them), but I could imagine this would be a massive headache to maintain (i.e. a separate track). First thought is that I would probably prioritize two things:

  1. Invest our effort in making the UI work against the service (HTTP API), making use of all of the front doors the service has available to it, and incorporating new ones as they become available; and
  2. Make it easy to spin up a local instance of the service (e.g. using Tomcat or whatever).

In other words, this might not be a GUI ticket.

epag commented 3 months ago

Original Redmine Comment Author Name: Hank (Hank) Original Date: 2019-03-22T15:41:38Z


James,

Agreed on your priority item 1. But... I don't think a user who wants to do a quick one-off run of WRES for a massive, local data set is going to want to deal with setting up a service. They'll just want a stand-alone application with a front-end GUI to guide configuration. Assuming that GUI is the Django stuff run via browser, then it would need to talk to command-line WRES.

Having said that, if by making it easy you mean no effort at all, I'm fine with that.

Hank

epag commented 3 months ago

Original Redmine Comment Author Name: Chris (Chris) Original Date: 2019-03-22T15:49:20Z


I agree with just about everything said here.

bq. In other words, this might not be a GUI ticket.

This started out as a WRES ticket, then a GUI ticket, then a WRES ticket, then a GUI ticket. It crosses into both realms pretty thoroughly. Luckily, it looks like I can change through project via a drop down. Want me to pull the trigger on that?

epag commented 3 months ago

Original Redmine Comment Author Name: James (James) Original Date: 2019-03-22T16:03:33Z


Hank wrote:

But... I don't think a user who wants to do a quick one-off run of WRES for a massive, local data set is going to want to deal with setting up a service.

Hank, at some level, I really don't think a user cares whether they're starting a service or an application, providing it's easy and it works consistently. If you're saying that a user should not be a system administrator in order to use the WRES, I agree, of course. Spinning up a service instance can be incredibly easy. By way of example, postgres is a service, and that service is going to need to be available/started either way (H2 work notwithstanding). There are many services operating on your computer right now without you knowing much of anything about them.

Hank wrote:

They'll just want a stand-alone application with a front-end GUI to guide configuration. Assuming that GUI is the Django stuff run via browser, then it would need to talk to command-line WRES.

I think that is a PITA waiting to happen, for us and ultimately for them. Sure, it's easy to create a request string and to start a process that lives for the duration of the execution. But then what? How do we use any of the existing and future (super duper) services offered by the HTTP API to monitor what is going on, what has been going, to ask for specific outputs etc. etc. Are you going to hide all the stuff in the UI that doesn't work because there isn't a service available?

Hank wrote:

Having said that, if by making it easy you mean no effort at all, I'm fine with that.

No, that is not the benchmark for me. It needs to be easy, but if the benchmark is no effort at all, then we've lost already. Installing postgres is not "no effort", for example. We can invest time in making an installation easier, even easy, which includes spinning up a service instance IMO.

epag commented 3 months ago

Original Redmine Comment Author Name: James (James) Original Date: 2019-03-22T16:04:52Z


Chris wrote:

I agree with just about everything said here.

bq. In other words, this might not be a GUI ticket.

This started out as a WRES ticket, then a GUI ticket, then a WRES ticket, then a GUI ticket. It crosses into both realms pretty thoroughly. Luckily, it looks like I can change through project via a drop down. Want me to pull the trigger on that?

Yeah, I would. I think it's more far-reaching than the UI.

epag commented 3 months ago

Original Redmine Comment Author Name: Hank (Hank) Original Date: 2019-03-22T16:38:40Z


James,

Once we need to look toward supporting WRES "the locally installed application" (eventually, it will have to happen, but it may be a year or more in the future), we may have to revisit the decision to have this depend on Postgres. Maybe H2 will avoid that potential headache. Maybe architecting the code such that we can plug-in a fully, in-memory version of WRES (no database at all; all that code being merely an implementation of an API) is an option. I haven't thought this through and really don't want to at the moment, but I can't help but believe a dependency on Postgres is going to be a problem for some of our users.

I agree in general with what you said, so long as a user does not need to be a sys admin and the process to get WRES going as as easy as possible.

Hank

epag commented 3 months ago

Original Redmine Comment Author Name: Chris (Chris) Original Date: 2019-03-22T16:51:55Z


bq. Yeah, I would. I think it's more far-reaching than the UI.

And...done.

I don't know how much this matters, but the way I had a lot of this in mind for eventually working is that you'd have a couple different modes with your install. By default, you'd get your standalone version using an H2, in-memory instance. I can get it, unpack it, run it, bam. Done. Django does this. You can just slap it together and it's neat. If you need to push it in terms of dataset size a little, however, you can configure it to consume a more powerful database, such as postgresql. If that is still rough and you need to crank it into high gear for 800lb Gorilla mode, you deploy the service AND link it to postgresql.

epag commented 3 months ago

Original Redmine Comment Author Name: James (James) Original Date: 2019-03-22T16:54:37Z


Hank wrote:

James,

Once we need to look toward supporting WRES "the locally installed application" (eventually, it will have to happen, but it may be a year or more in the future), we may have to revisit the decision to have this depend on Postgres. Maybe H2 will avoid that potential headache. Maybe architecting the code such that we can plug-in a fully, in-memory version of WRES (no database at all; all that code being merely an implementation of an API) is an option. I haven't thought this through and really don't want to at the moment, but I can't help but believe a dependency on Postgres is going to be a problem for some of our users.

I agree in general with what you said, so long as a user does not need to be a sys admin and the process to get WRES going as as easy as possible.

Hank

Right, it needs to be easy, even for a sysadmin who wants to configure a service. For example, if an RFC really needs a local instance for whatever reason, that could imply a locally hosted service for all users in that RFC accessible on their LAN (or, indeed, one user).

I can't usefully speak to H2 vs. postgres, but the people that know about this stuff (i.e. Chris and Jesse) seem to be saying that postgres is the big dog, the database you use for anything approaching big data. Since you mentioned "massive local dataset", I have my doubts (and if it weren't massive, would a local installation be necessary, i.e. what is the reason for the local installation - rhetorical question), but "massive" is subjective and H2 does cover a spectrum (embedded and in-memory through client-server and on disk).

epag commented 3 months ago

Original Redmine Comment Author Name: James (James) Original Date: 2019-03-22T17:25:12Z


Chris wrote:

bq. Yeah, I would. I think it's more far-reaching than the UI.

And...done.

I don't know how much this matters, but the way I had a lot of this in mind for eventually working is that you'd have a couple different modes with your install. By default, you'd get your standalone version using an H2, in-memory instance. I can get it, unpack it, run it, bam. Done. Django does this. You can just slap it together and it's neat. If you need to push it in terms of dataset size a little, however, you can configure it to consume a more powerful database, such as postgresql. If that is still rough and you need to crank it into high gear for 800lb Gorilla mode, you deploy the service AND link it to postgresql.

I think I still see the two categories of WRES instances we started with, i.e. an "unconnected" laptop and a centralized service.

I would break the centralized service into:

  1. The centralized instance that we maintain, which is currently NWCAL but may not be hosted on OWP infrastructure always (but is the instance to which we direct people, by default);
  2. Any number of instances that we do not maintain, but are nevertheless running in server mode and intended to serve a group of users, possibly large (and for which we want to make it easy/repeatable for others to stand up, as far as possible/practical).

What's common about these is that the WRES is operating continuously, as a service in a long running server process or processes.

Then we also have "laptop users". What do they look like? I think I see the following:

  1. User operates the software with files, as an application running in a JVM for the duration of one evaluation, with no UI and no service running. They provide a file with a declaration string as input and they get some output, also in files. This is the most basic use case. Obviously, using a UI is orthogonal to using an application vs. service. They could use the UI to write the declaration string. In principle, the UI could call the application with that string, but that seems very brittle to me, and none of the extra services would be available, because the UI isn't running against a service. This is the option I am most wary about, not the command line operation, but spending much effort on connecting the UI to this.
  2. User points their UI to a local instance of the service, which is running on their machine (as a service, but not a centralized one), just like any other service instance.

Three of these options involve running against a service instance, which is accessible continuously, and one does not. I think all of our UI efforts should be directed towards the HTTP API, which includes the possibility of a laptop user running against a service on localhost, I think.

All that being said, I may have missed a piece of the jigsaw puzzle w/r to connecting the UI to an application instance (rather than a service instance) and the work involved in having that as a separate pathway. Even if that work is small, I think I would deprecate that pathway as a priority, but I do see the command line operation of a local instance or a UI pointed to a service instance running on localhost as being reasonable options for laptop users (again, even though the use of the UI is strictly orthogonal to how the WRES is deployed).

epag commented 3 months ago

Original Redmine Comment Author Name: Chris (Chris) Original Date: 2019-03-22T17:41:40Z


bq. User operates the software with files, as an application running in a JVM for the duration of one evaluation, with no UI and no service running. They provide a file with a declaration string as input and they get some output, also in files. This is the most basic use case. Obviously, using a UI is orthogonal to using an application vs. service. They could use the UI to write the declaration string. In principle, the UI could call the application with that string, but that seems very brittle to me, and none of the extra services would be available, because the UI isn't running against a service. This is the option I am most wary about, not the command line operation, but spending much effort on connecting the UI to this.

I'm assuming this is the one you don't like. In this use case, I was more imagining launching a toned down implementation of the service when launching the gui (i.e. essentially a one worker service with less moving parts), then having the gui point at that. Same idea as to what's going on everywhere else.

What is the declaration string here? The project? If it's the project that the UI is sending to the application that you think is brittle, wouldn't that mean that any instance of a UI sending a project developed within itself would be brittle, local or otherwise?

epag commented 3 months ago

Original Redmine Comment Author Name: James (James) Original Date: 2019-03-22T17:53:08Z


Chris wrote:

bq. User operates the software with files, as an application running in a JVM for the duration of one evaluation, with no UI and no service running. They provide a file with a declaration string as input and they get some output, also in files. This is the most basic use case. Obviously, using a UI is orthogonal to using an application vs. service. They could use the UI to write the declaration string. In principle, the UI could call the application with that string, but that seems very brittle to me, and none of the extra services would be available, because the UI isn't running against a service. This is the option I am most wary about, not the command line operation, but spending much effort on connecting the UI to this.

I'm assuming this is the one you don't like. In this use case, I was more imagining launching a toned down implementation of the service when launching the gui (i.e. essentially a one worker service with less moving parts), then having the gui point at that. Same idea as to what's going on everywhere else.

What is the declaration string here? The project? If it's the project that the UI is sending to the application that you think is brittle, wouldn't that mean that any instance of a UI sending a project developed within itself would be brittle, local or otherwise?

I think I'd want to see what "a toned down implementation of the service when launching the gui" meant in practice. Otherwise, I think we're on the same page. If we can make "a toned down implementation of the service when launching the gui" look the same as (minimally different from) running the UI against a long-running service that is not spawned by the UI, I think that could work.

I guess my underlying skepticism is as follows. I want to prioritize the use of the centralized service, including for the UI. At the same time, I understand the possibility that a local deployment of the WRES may be necessary. The biggest use case I've heard for that, so far, has been to handle a "massive local dataset", probably hosted by an RFC. I am assuming this "massive local dataset" probably wants to be verified by more than one person. Well, OK, but that use case doesn't sound very much like a short-lived application instance running against H2, for example. Based on what we know now, I would invest in the centralized service, firstly, and perhaps in making it easy-ish to spin-up a local instance of a long-running service against which the UI can operate, secondly (but that still means dealing with postgres etc.).

Does that make sense?

epag commented 3 months ago

Original Redmine Comment Author Name: James (James) Original Date: 2019-03-22T17:55:53Z


Would also like to hear Jesse's thoughts.

epag commented 3 months ago

Original Redmine Comment Author Name: Hank (Hank) Original Date: 2019-03-22T18:01:09Z


Another use case...

The evaluator does not have permission to access a WRES centrally deployed service for whatever reason.

And of course the dreaded...

Upper management says they won't support a WRES centrally deployed service.

That last one is probably not worth thinking about until it happens, however, since it would require many changes beyond just the UI. The first one is perhaps not a concern soon, since I view that as most likely if WRES goes beyond OWP and the RFCs.

Thanks,

Hank

epag commented 3 months ago

Original Redmine Comment Author Name: James (James) Original Date: 2019-03-22T18:05:09Z


Hank wrote:

Another use case...

The evaluator does not have permission to access a WRES centrally deployed service for whatever reason.

Sounds painful, regardless of what we do. What is their evaluation use case? If it looks like the sort of use case we handle with the centralized service (i.e. all manner of), then I think they're going to need a bigger boat, and I would want to make it easier for them to launch that boat (but not as a top priority). As a top priority, I'd want to understand how permission could be granted somehow, i.e. why did we decide to deploy to somewhere inaccessible?

Hank wrote:

And of course the dreaded...

Yeah, I'd ignore that one. That changes everything and, even if it happens, I don't think that necessarily equates to prioritizing a short-lived instance of WRES (e.g. like running EVS).

epag commented 3 months ago

Original Redmine Comment Author Name: Hank (Hank) Original Date: 2019-03-22T19:00:01Z


Agreed on both counts.

What was passing through my mind with the first was someone in academia, outside the government, wants to perform an evaluation and use WRES. Obviously, that user has lower priority than the others and it would still get back to what you said: "I'd want to understand how permission could be granted somehow, i.e. why did we decide to deploy to somewhere inaccessible?"

Hank

epag commented 3 months ago

Original Redmine Comment Author Name: Jesse (Jesse) Original Date: 2019-03-22T19:09:28Z


See #54143, #54170-21, #54170-119. Another thing to try is this:

  1. replace the word "wres.Main" in the build.gradle with "wres.server.WebServer",
  2. run ./gradlew, and
  3. run build/install/wres/bin/wres (with your favorite JAVA_OPTS in front, of course).

This will show you my desired way that WRES would run in standalone mode.

epag commented 3 months ago

Original Redmine Comment Author Name: Jesse (Jesse) Original Date: 2019-03-22T19:10:13Z


Actually this is the way it should run in any mode. The central instance would wrap this with similar wrappers to how it's wrapped now.

epag commented 3 months ago

Original Redmine Comment Author Name: James (James) Original Date: 2019-03-22T19:56:33Z


The way I interpret the above is "start the service" with the host as localhost and the port as the prescribed port (with some default, I assume). Startup could be manual or automatic, probably manual. Then, for example, we point the UI at that. Before starting the service, we have things like "install postgres" and "create a database".

epag commented 3 months ago

Original Redmine Comment Author Name: Jesse (Jesse) Original Date: 2019-03-22T21:02:00Z


Sure.

"your favorite JAVA_OPTS" and/or wresconfig.xml has the parameters to decide whether to use an existing database server or to generate one or whatever.

All of this depends on #40271.

epag commented 3 months ago

Original Redmine Comment Author Name: Jesse (Jesse) Original Date: 2019-03-22T21:02:52Z


I shouldn't say it technically depends on #40271, but a lot of things become much more congruent when we solve #40271.

epag commented 3 months ago

Original Redmine Comment Author Name: James (James) Original Date: 2019-03-22T21:29:24Z


Right, I see it the same way.

epag commented 3 months ago

Original Redmine Comment Author Name: Chris (Chris) Original Date: 2019-06-19T13:38:04Z


I think this got unintentionally switched back to the GUI project in comment #61633-8. I realized this morning that something adjacent to this needs to be done to perform selenium tests. The GUI needs to be able to test flinging projects at a service and getting results back. In a containerized setup, that's relatively easy as long as there can be a container-local version of the WRES that accepts http calls. It shouldn't try to reach out to one of our deployed services because we want to test the GUI, not the WRES.

In a single hidden, individual environment for the WRES to run (i.e. within a container with no port mapping), an H2 database isn't needed (there's already a postgres server running within the container) and there's no need to worry about other instances hitting the database since it is for an internal testing environment local to a test version of the GUI (prod containers won't ship with the WRES embedded).

I want to bump this up to urgent, but that's a little extreme. Something like this needs to be done prior the implementation of selenium testing and that needs to be done real soon.

I would use the preexisting WRES/Tasker/Broker/Worker, however they are too specific for a COWRES environment, not for simply launching the WRES and revealing a super simple API.

epag commented 3 months ago

Original Redmine Comment Author Name: Hank (Hank) Original Date: 2019-06-19T13:51:05Z


Chris,

Looking up Selenium, its a tool for testing web applications. I believe that means it tests the clicks within a web interface which means its an automated (web) GUI testing tool, more or less. Is this correct?

If so, my experience with automated GUI testing (admittedly, with tools of questionable quality) is that its a pain to keep up to date with changes to an interface and should only be put in place once a tool is mature. The WRES GUI is months away from being mature. However, from this statement, I assume I am misunderstanding something about Selenium:

Something like this needs to be done prior the implementation of selenium testing and that needs to be done real soon.

How much effort would it be to setup Selenium to perform some tests? How much overhead will it create when trying to update those tests when, for example, a label on the screen changes, a button name changes, a text field moves a few pixels, a font changes, etc?

Thanks,

Hank

epag commented 3 months ago

Original Redmine Comment Author Name: Chris (Chris) Original Date: 2019-06-19T14:05:44Z


Element selection can be done via CSS selector, so actual location on the screen doesn't really matter. If elements are added/changed, they will need to be modified just like a unit test would and the difficulty is just about the same. Even then, elements can and should be identified in a unique enough fashion that relative selectors aren't needed. Instead of checking to see if a click action on "#content table.some_class tbody tr[2] td button" goes to a specific page, it should perform a click action on "#navigation_button_2" to see if it navigates to the correct page. With that setup, it doesn't matter at all where an element on a screen is.

Maturity matters for these tests just as much as it matters with unit tests on any application. Once the application is very mature, there needs to be a large amount of coverage. Until then, though, there still need to be tests that evaluate "Yes, I can indeed click a button to go to this other screen". Coverage will come in time, but it needs to start somewhere.

The difficulty of implementation is about as hard as switching to any testing framework for the first time. Luckily, there's already an example of a testing setup that worked attached to the selenium ticket. Getting that up and running won't be a herculean task.

Luckily, selenium testing is 400 Quintilian times easier than desktop form testing.