Project

General

Profile

Feature #6377

provide tooling (and UI in the admin interface) to manage appserver agents (start/stop/bounce)

Added by Greg Shah about 4 years ago. Updated over 1 year ago.

Status:
WIP
Priority:
Normal
Assignee:
-
Target version:
-
Start date:
Due date:
% Done:

80%

billable:
No
vendor_id:
GCD
case_num:
version_reported:
version_resolved:
reviewer:
production:
No
env_name:
topics:

6377-admin-screen-for-appservers.xlsx (9.15 KB) Galya B, 09/24/2024 09:54 AM

two-appservers-screen.png (250 KB) Galya B, 10/03/2024 01:30 PM


Related issues

Related to Runtime Infrastructure - Feature #7080: expose all admin APIs via REST Test
Related to Runtime Infrastructure - Feature #6871: add JMX instrumentation to monitor the appserver agents Closed

History

#1 Updated by Greg Shah about 4 years ago

A customer that is heavily invested in classic appserver has to use the "trim" processing to stop appserver agents when they are consuming too many resources. They would prefer a "bounce" capability (stop and then restart) but OE doesn't provide it. This task is meant to expose some back capabilities in this regard. We must expose the rest of the appserver configuration as well as a view of the currently running agents.

#3 Updated by Greg Shah over 3 years ago

See #6878 for an example of the kind of status reporting that is available in OE. We must provide this level or better.

#5 Updated by Greg Shah over 3 years ago

I would prefer to implement this using a REST API. We will provide a CLI (command line interface) and would probably also implement a UI in the admin console. Having a REST API as the backing implementation gives customers the ultimate flexibility. They can create their own tooling if the built-in FWD tools don't meet their needs.

A first pass has been implemented for #7074 using the ServerDriver "status" approach. We will need to shift this to REST when possible.

#6 Updated by Greg Shah almost 2 years ago

  • Assignee set to Galya B

#7 Updated by Galya B almost 2 years ago

#8 Updated by Galya B almost 2 years ago

The attached spreadsheet is a sort of a wireframe for the admin console screen that will display some basic info for the appservers. The initial implementation may lack some of the functionality or info. Also more data can be added to the tables later. The buttons got deformed by saving the file in the format, but should do for the purpose.

PASOE appservers don't need info on agents, because of the clientless approach that will be implemented in #8661.

#9 Updated by Galya B almost 2 years ago

There is a lot more work to get all the data in one place. The tables seem to need fixed height, which is not ideal, but I'm trying to reuse the same widgets as on the other pages for consistency:

#10 Updated by Galya B almost 2 years ago

A question: can there be several processes configured for one appserver? Is this a way to simply have different FWD configurations for the same definition?

#11 Updated by Constantin Asofiei almost 2 years ago

Galya B wrote:

A question: can there be several processes configured for one appserver? Is this a way to simply have different FWD configurations for the same definition?

No, a single process account must be defined, this is enforced in AppServerLauncher.launch.

#12 Updated by Galya B almost 2 years ago

SecurityCache.getAccountsForAppserver returns an array, but I guess I should just ignore it and consider the first result.

#13 Updated by Constantin Asofiei almost 2 years ago

Galya B wrote:

SecurityCache.getAccountsForAppserver returns an array, but I guess I should just ignore it and consider the first result.

You should handle both cases, when there are none setup and 2 or more, and show errors/warnings. I don't know how appserver configuration is enforced at the batch process config via AdminConsole.

#14 Updated by Galya B almost 2 years ago

For now I'm implementing only displaying the info read-only. If we add edit functionality later on, an error can be shown. When no process is defined, FWD process name will simply be empty. The trickier part is that the configs will reflect only the 'first' of the processes if multiple.

#15 Updated by Constantin Asofiei almost 2 years ago

Galya B wrote:

For now I'm implementing only displaying the info read-only. If we add edit functionality later on, an error can be shown. When no process is defined, FWD process name will simply be empty. The trickier part is that the configs will reflect only the 'first' of the processes if multiple.

Understood, that's fine - just show a warning that there are multiple processes defined.

#16 Updated by Galya B almost 2 years ago

Constantin, I had to remove security:certificate:validate as you asked me in #7808-115, because it took me quite a while now to find out that the : symbols in the node id messes up directory reads. Is it that the prop is not valid anywhere in the code? All connections need to have a valid certificate?

#17 Updated by Constantin Asofiei almost 2 years ago

Galya B wrote:

Constantin, I had to remove security:certificate:validate as you asked me in #7808-115, because it took me quite a while now to find out that the : symbols in the node id messes up directory reads.

OK.

Is it that the prop is not valid anywhere in the code? All connections need to have a valid certificate?

This prop is (was) used only when launching appserver agents or batch processes via the scheduler (i.e. they are 'spawned' and not launched explicitly). Until now, the default was 'false'; I still think we need to force it to 'true', but we need some tests of some apps to see if the appserver agents (or batch processes) still start, with that app configuration. Just make the change for now and lets not forget to do this test.

#18 Updated by Galya B almost 2 years ago

  • % Done changed from 0 to 80

#19 Updated by Greg Shah almost 2 years ago

When the work is ready, Sergey and Constantin will review it.

#20 Updated by Galya B almost 2 years ago

  • % Done changed from 80 to 100
  • Status changed from WIP to Review
8661a r15503 ready for review. Notes:
  • A new Admin Console screen added under Console -> Appservers to list appserver configs and agents, and allow execution of the actions added in #7074.
  • New report added, used to print the contents of the Appservers admin page. It doesn't use filter-select, but simply prints all active agents, which is what it's meant for: giving a complete picture on the state of the agents.
  • After #8661 is implemented a new PASOE widget will be implemented and displayed, now present as a stub in the code.
  • Different new fields are added or exposed from Agent, AgentPool, etc. Agent.runningProc will most definitely need refinement, because I wasn't able to test all routes of invoking execution on the agent. The two main routes of executing an external or persistent procedures on the appserver from batch client that connects, are both showing the correct values.
  • The UI can be polished, but I think this is functional (sufficient for now).
  • The 'Client' column is empty now. I have the intention to find the HTTP request path (when such available) and add it there, probably with #8661.

#21 Updated by Galya B almost 2 years ago

Also, security:certificate:validate has been either removed or set to true in critical places and now I get an error, when testing with customer project:

24/10/10 11:58:43.513+0300 | WARNING | com.goldencode.p2j.net.RouterSessionManager | ThreadName:Incoming SSL Connector#15 | Incoming SSL Connector#15:Handshake timed out.
24/10/10 11:58:43.515+0300 | WARNING | com.goldencode.p2j.net.SSL | ThreadName:Incoming SSL Connector#15:nioSslTaskWorker#29 | InterruptedException
java.lang.InterruptedException
    at java.util.concurrent.locks.AbstractQueuedSynchronizer.tryAcquireNanos(AbstractQueuedSynchronizer.java:1245)
    at java.util.concurrent.locks.ReentrantLock.tryLock(ReentrantLock.java:442)
    at com.goldencode.p2j.net.SSL.tryLock(SSL.java:393)
    at com.goldencode.p2j.net.SSL.wrap(SSL.java:537)
    at com.goldencode.p2j.net.SSL.handshake(SSL.java:503)
    at com.goldencode.p2j.net.SSL.run(SSL.java:316)
    at com.goldencode.p2j.net.SSL.notify(SSL.java:307)
    at com.goldencode.p2j.net.BlockingSSL.processInput(BlockingSSL.java:236)
    at com.goldencode.p2j.net.BlockingSSL.checkInput(BlockingSSL.java:115)
    at com.goldencode.p2j.net.NIOSslSocket.lambda$new$1(NIOSslSocket.java:175)
    at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1149)
    at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:624)
    at java.lang.Thread.run(Thread.java:750)
24/10/10 11:58:43.515+0300 | WARNING | com.goldencode.p2j.net.NIOSslSocket | ThreadName:Incoming SSL Connector#15:nioSslTaskWorker#29 | Exception on SSL handshake 
java.lang.RuntimeException: Faild to acquire lock
    at com.goldencode.p2j.net.SSL.tryLock(SSL.java:402)
    at com.goldencode.p2j.net.SSL.wrap(SSL.java:537)
    at com.goldencode.p2j.net.SSL.handshake(SSL.java:503)
    at com.goldencode.p2j.net.SSL.run(SSL.java:316)
    at com.goldencode.p2j.net.SSL.notify(SSL.java:307)
    at com.goldencode.p2j.net.BlockingSSL.processInput(BlockingSSL.java:236)
    at com.goldencode.p2j.net.BlockingSSL.checkInput(BlockingSSL.java:115)
    at com.goldencode.p2j.net.NIOSslSocket.lambda$new$1(NIOSslSocket.java:175)
    at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1149)
    at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:624)
    at java.lang.Thread.run(Thread.java:750)

#22 Updated by Galya B almost 2 years ago

The above exception doesn't seem to prevent the scheduled processes from starting. I've encountered another error in web login - the customer login in the session shows an error with code 2512 not found, but I don't see an error in the logs, so maybe the login credentials have changed.

#23 Updated by Sergey Ivanovskiy almost 2 years ago

Is this task branch 8661a?

#24 Updated by Greg Shah almost 2 years ago

Is this task branch 8661a?

Yes

#25 Updated by Galya B almost 2 years ago

r15504 fixes persistent procedures not showing in the table. I broke it with the cleanup.

Here are the procs I'm testing the 'Session Procedure' column with:

appserver.p:

def var h as handle.

create server h.
h:connect("-S 21200 -H localhost -sessionModel Session-Free -DirectConnect").

run longrun.p on server h.

h:disconnect().
delete object h.

appserver-persistent.p:

def var h as handle.

create server h.
h:connect("-S 21200 -H localhost -sessionModel Session-Free -DirectConnect").

run longrun.p persistent on h asynchronous.

h:disconnect().
delete object h.

longrun.p:

message "started" view-as alert-box.
pause 30 no-message.
message "ended" view-as alert-box.

#26 Updated by Sergey Ivanovskiy almost 2 years ago

The second program appserver-persistent.p that runs longrun.p asynchronously has h:disconnect(). The 4GL docs said that pending asynchronous requests are cancelled and the corresponding event procedure is called for each request. Correct?

#27 Updated by Galya B almost 2 years ago

Sergey Ivanovskiy wrote:

The second program appserver-persistent.p that runs longrun.p asynchronously has h:disconnect(). The 4GL docs said that pending asynchronous requests are cancelled and the corresponding event procedure is called for each request. Correct?

Someone else can say how it's supposed to work. I'll tell you what it does for my test - it doesn't get cancelled and runs for a long time, so the proc doesn't seem to be executed async, probably because it's persistent (I may have created an incompatible mix).

#28 Updated by Constantin Asofiei almost 2 years ago

Galya B wrote:

Constantin, I had to remove security:certificate:validate as you asked me in #7808-115, because it took me quite a while now to find out that the : symbols in the node id messes up directory reads. Is it that the prop is not valid anywhere in the code? All connections need to have a valid certificate?

Galya, this was not meant to remove the entire security:certificate:validate support from bootstrap config - just that directory-specific setting. Did you remove this security:certificate:validate=false completely, no longer supported via bootstrap option?

#29 Updated by Galya B almost 2 years ago

Constantin Asofiei wrote:

Galya B wrote:

Constantin, I had to remove security:certificate:validate as you asked me in #7808-115, because it took me quite a while now to find out that the : symbols in the node id messes up directory reads. Is it that the prop is not valid anywhere in the code? All connections need to have a valid certificate?

Galya, this was not meant to remove the entire security:certificate:validate support from bootstrap config - just that directory-specific setting. Did you remove this security:certificate:validate=false completely, no longer supported via bootstrap option?

Good time to know the answer. I haven't removed it from all places, where it's used, but let me revise. It should be deleted from the directory reads and process builder / spawn, and the ClientConfig wasn't used in another place, but I'll confirm if I've changed the bootstrap reads.

#30 Updated by Constantin Asofiei almost 2 years ago

Galya B wrote:

Constantin Asofiei wrote:

Galya B wrote:

Constantin, I had to remove security:certificate:validate as you asked me in #7808-115, because it took me quite a while now to find out that the : symbols in the node id messes up directory reads. Is it that the prop is not valid anywhere in the code? All connections need to have a valid certificate?

Galya, this was not meant to remove the entire security:certificate:validate support from bootstrap config - just that directory-specific setting. Did you remove this security:certificate:validate=false completely, no longer supported via bootstrap option?

Good time to know the answer. I haven't removed it from all places, where it's used, but let me revise. It should be deleted from the directory reads and process builder / spawn, and the ClientConfig wasn't used in another place, but I'll confirm if I've changed the bootstrap reads.

Thanks, please double-check; what I'm interested in: a manually-started batch process should be able to specify security:certificate:validate=false at its bootstrap config, and work properly. For whatever is spawned via the FWD server, that security:certificate:validate=true should be enforced.

#31 Updated by Galya B almost 2 years ago

I've reverted the relevant changes in ClientCore and SecurityManager in r15506. Otherwise it's ok to remove the config, since it hasn't been used for the bootstrap value.

#32 Updated by Sergey Ivanovskiy almost 2 years ago

The changes rev 15506 (8661a) related to my view are good except a minor issue found in ClassicAppserverView, where the constants for columns widths are defined. Does it make sense to define these named constants for each column? There is column names array AGENT_COL_NAMES but their widths are defined in the code.

+      GridHelper.ColumnInfo<AppserverInfo.AgentInfo> col8 =
+         new GridHelper.ColumnInfo<>(AGENT_COL_NAMES[7],
+                                     agentInfo -> agentInfo.clientType == null ? "" : agentInfo.clientType);
+
+      col1.setWidthInPercents(10);
+      col2.setWidthInPercents(10);
+      col3.setWidthInPercents(16);
+      col4.setWidthInPercents(12);
+      col5.setWidthInPercents(12);
+      col6.setWidthInPercents(16);
+      col7.setWidthInPercents(12);
+      col8.setWidthInPercents(12);

#33 Updated by Galya B almost 2 years ago

Sergey Ivanovskiy wrote:

The changes rev 15506 (8661a) related to my view are good except a minor issue found in ClassicAppserverView, where the constants for columns widths are defined. Does it make sense to define these named constants for each column? There is column names array AGENT_COL_NAMES but their widths are defined in the code.
[...]

Up in r15507.

#34 Updated by Galya B almost 2 years ago

Constantin, how is the review going?

#35 Updated by Constantin Asofiei almost 2 years ago

Review for 8661a rev 15508:
  • please remove the src/com/goldencode/p2j/util/appserver/ empty package. Even if we want to move all appserver-related classes there, we can't move them all, as there are dependencies on customer code for these classes to be where they are now, and some of this code we can't refactor (don't have source access). For now, we need to leave p2j.util as is.
  • ClientCore - no functional change, please revert the file.
  • OERequestInfo
    • buildFromArray(Object[] arr) needs javadoc
    • using new OerequestInfo(); I don't think is OK. This will bypass reference counting. The OERequestInfo is a context-local singleton which is read via SessionUtils.currentRequestInfo(). Also, the single usage is from Agent$AgentCommand.oeRequestInfo, which is never read. So, can we remove this field and back out the buildFromArray changes?
  • Agent.java
    • setExternalProcedure is being called with the target's name, which can be either an external procedure or an internal procedure/function. So, what do you want to track? If is the actual program being executed, then this needs to resolve the program name for the cases where it can invoke an internal procedure/function in a handle.
      • for the case of JavaInvokeConfig on line 1485, resolve the class name, too. cfg can never be null here.
      • on line 1405, resolve the resId external program (if specified)
      • on line 1215, for the InvokeConfig case, resolve the external program, if specified via InvokeConfig.inHandle, and not just the target. cfg can never be null here.
      • on line 936, resolve the class name from resId
  • AgentPool.getAll() - we shouldn't expose the reference to the set, please return a copy.

#36 Updated by Galya B almost 2 years ago

Constantin Asofiei wrote:

  • please remove the src/com/goldencode/p2j/util/appserver/ empty package. Even if we want to move all appserver-related classes there, we can't move them all, as there are dependencies on customer code for these classes to be where they are now, and some of this code we can't refactor (don't have source access). For now, we need to leave p2j.util as is.

I want to move the PASOE classes I'm adding in 8661b to the new package. Maybe for that purpose a separate merge is not needed, but maybe other classes like AppServerDefinition are also going there. I won't move other core appserver classes if this can break customer dependencies (hopefully soon we'll have proper java 9+ support to define the exposed interfaces).

  • ClientCore - no functional change, please revert the file.

OK.

  • OERequestInfo
    • buildFromArray(Object[] arr) needs javadoc

Added.

  • using new OerequestInfo(); I don't think is OK. This will bypass reference counting. The OERequestInfo is a context-local singleton which is read via SessionUtils.currentRequestInfo(). Also, the single usage is from Agent$AgentCommand.oeRequestInfo, which is never read. So, can we remove this field and back out the buildFromArray changes?

Yes, I removed the code using the OerequestInfo object, because the array seemed to be empty in my tests. I wonder if this is always the case? I struggle to follow the lifecycle of OerequestInfo. My reasoning of leaving the transformation is that OerequestInfo at one point is supposed to be the central piece containing all the important data for the request (which it still is not) and it should be accessed from other parts of the code, not only the 4GL code. The reference you're referring to, is probably related to how it's used in 4GL. Am I correct? I actually didn't remove the original SessionUtils.currentRequestInfo().ref().fromArray(requestInfo); that should be tracking the reference (whatever that is), just added additional transformation to be able to use the data before the 4GL execution. I usually remove unused code, but this I got attached to, imagining I'll use it some day.

  • Agent.java
    • setExternalProcedure is being called with the target's name, which can be either an external procedure or an internal procedure/function. So, what do you want to track? If is the actual program being executed, then this needs to resolve the program name for the cases where it can invoke an internal procedure/function in a handle.
      • for the case of JavaInvokeConfig on line 1485, resolve the class name, too. cfg can never be null here.
      • on line 1405, resolve the resId external program (if specified)
      • on line 1215, for the InvokeConfig case, resolve the external program, if specified via InvokeConfig.inHandle, and not just the target. cfg can never be null here.
      • on line 936, resolve the class name from resId

If by 'external procedure or an internal procedure/function' you mean nested calls, then it should be changed to the 'actual program'. All the invoke methods are super confusing, because I don't know how to test all the calls, but let me try and fix it.
For line 936 isn't character name The legacy 4GL name for the class method.? Please see what I've pushed, it doesn't look like the solution.

  • AgentPool.getAll() - we shouldn't expose the reference to the set, please return a copy.

Roger that.

Changes up in r15509.

#37 Updated by Constantin Asofiei almost 2 years ago

Review for 8661a rev 15509:
  • AgentPool - Set.copyOf is not available in Java 8 - please replace this code.
  • in Agent.java
    • invokeMethod around line 936 - use both the class name and the method name
    • invoke line 1411 - resId is null when invoking an external program, and not-null otherwise; in this case, when is not null, use both ext prog name and the target name.

Yes, I removed the code using the OerequestInfo object, because the array seemed to be empty in my tests. I wonder if this is always the case? I struggle to follow the lifecycle of OerequestInfo. My reasoning of leaving the transformation is that OerequestInfo at one point is supposed to be the central piece containing all the important data for the request (which it still is not) and it should be accessed from other parts of the code, not only the 4GL code.

The right way to access it is from SessionUtils.currentRequestInfo. Please remove AgentCommand.oeRequestInfo. If you mean you need OerequestInfo state read outside of the agent's context, lets discuss that, but current approach is not OK.

#38 Updated by Galya B almost 2 years ago

Constantin Asofiei wrote:

  • invokeMethod around line 936 - use both the class name and the method name

How to get the class name from resId / handle (handle proc = handle.fromString(resId);) ?

  • invoke line 1411 - resId is null when invoking an external program, and not-null otherwise; in this case, when is not null, use both ext prog name and the target name.

What target? Name?

   public AppServerInvocationResult invoke(final String    id,
                                           final int       requestId,
                                           final long      timeout,
                                           final character name,
                                           final String    resId,
                                           final boolean   function,
                                           final boolean   dynamicFunction,
                                           final boolean   superCall,
                                           final boolean   transactionDistinct,
                                           final String    modes,
                                           final Object... args)

#39 Updated by Constantin Asofiei almost 2 years ago

Galya B wrote:

Constantin Asofiei wrote:

  • invokeMethod around line 936 - use both the class name and the method name

How to get the class name from resId / handle (handle proc = handle.fromString(resId);) ?

Yes, extract the name from the handle - proc.get().getClass().getName().

  • invoke line 1411 - resId is null when invoking an external program, and not-null otherwise; in this case, when is not null, use both ext prog name and the target name.

What target? Name?

Yes, name is the target - which can be external program when resId is null and internal procedure/function, otherwise.

#40 Updated by Galya B almost 2 years ago

Please check r15510.

#41 Updated by Constantin Asofiei almost 2 years ago

Only one issue, please; in this code at line 1412:

         {
            String runningProgram = null;
            ExternalProgramWrapper proc = getProcedure(resId);
            if (proc != null)
            {
               runningProgram = proc.name().toStringMessage() + " # " + name.toStringMessage();
            }
            setRunningProgram(runningProgram);
         }

should be like this:
            String runningProgram = null;
            if (resId == null)
            {
               // external program call
               runningProgram = name.toStringMessage();
            }
            else
            {
...
}

#42 Updated by Galya B almost 2 years ago

Constantin Asofiei wrote:

Only one issue, please; in this code at line 1412:
[...]
should be like this:
[...]

In the else having runningProgram = proc.name().toStringMessage() + " # " + name.toStringMessage(); or only proc.name()?

#43 Updated by Constantin Asofiei almost 2 years ago

Galya B wrote:

Constantin Asofiei wrote:

Only one issue, please; in this code at line 1412:
[...]
should be like this:
[...]

In the else having runningProgram = proc.name().toStringMessage() + " # " + name.toStringMessage(); ..

Both external program and target 'name'.

#44 Updated by Galya B almost 2 years ago

r15511.

#45 Updated by Constantin Asofiei almost 2 years ago

  • Status changed from Review to Internal Test

Thanks, we can move this to internal test. Please check for some apps (GUI and appserver and batch processes) that everything starts properly, and also how the Admin Console looks.

#46 Updated by Galya B almost 2 years ago

The branch has been tested with a customer project and testcases.

#47 Updated by Galya B almost 2 years ago

How about I merge now?

#48 Updated by Constantin Asofiei almost 2 years ago

  • Status changed from Internal Test to Merge Pending

Galya B wrote:

How about I merge now?

You are next in queue for merge, go ahead when available.

#49 Updated by Galya B almost 2 years ago

After which branch?

#50 Updated by Constantin Asofiei almost 2 years ago

Galya B wrote:

After which branch?

Sorry, I meant first, you can merge.

#51 Updated by Galya B almost 2 years ago

  • Status changed from Merge Pending to Test

8661a was merged to trunk as rev. 15504 and archived.

Is this needed in #7156?

#52 Updated by Constantin Asofiei almost 2 years ago

Galya B wrote:

8661a was merged to trunk as rev. 15504 and archived.

Is this needed in #7156?

Not at this time. We'll rebase that branch when all support is in trunk.

#53 Updated by Galya B over 1 year ago

6377a r15513 fixes an issue with resolving the running procedure in Agent.invoke as originally reported by #7143-1268. Tested by Radu in #7143-1285. Waiting for merge approval.

#54 Updated by Greg Shah over 1 year ago

  • Status changed from Test to Review

Code Review Task branch 6377a Revision 15513

Please add a history entry.

Constantin: Please review.

#55 Updated by Galya B over 1 year ago

File header in r15514.

#56 Updated by Constantin Asofiei over 1 year ago

Galya B wrote:

File header in r15514.

Thanks, you can merge to trunk now.

#57 Updated by Greg Shah over 1 year ago

  • Status changed from Review to Merge Pending

#58 Updated by Galya B over 1 year ago

  • Status changed from Merge Pending to Test

6377a was merged to trunk as rev. 15515 and archived.

#59 Updated by Greg Shah over 1 year ago

  • Related to Feature #6871: add JMX instrumentation to monitor the appserver agents added

#60 Updated by Greg Shah over 1 year ago

I think we need to reopen this task to get the REST API implemented. The admin console UI is useful but it will not be the way most customers need to use this feature.

#62 Updated by Galya B over 1 year ago

Greg Shah wrote:

I think we need to reopen this task to get the REST API implemented. The admin console UI is useful but it will not be the way most customers need to use this feature.

Constantin had the actions exposed via java commands, so they are not available only via the console UI. I can't find the original task where he did it though.

#63 Updated by Galya B over 1 year ago

#7074-6.

#64 Updated by Greg Shah over 1 year ago

  • Assignee deleted (Galya B)
  • Status changed from Test to WIP
  • % Done changed from 100 to 80

It is a fair point that we have something rudimentary. It is not a proper replacement for a REST API.

Also available in: Atom PDF