Installation FAQs
I Have Just Enabled RBAC and Set the rbac-force-user Option, Why Can't I Start the System? (Enterprise Edition Only)
A typical rbac-force-user option setting in the options file could be as follows:
qorus.rbac-force-user: localhost=admin
Which could result in an error as follows if the admin
user doesn't exist in the system:
RBAC-OVERRIDE-ERROR: User exception: RBAC.qc:996: RBAC-OVERRIDE-ERROR: cannot override source "localhost" to user "admin"; user does not exist
call stack:
RBAC::addOverrideIntern() called at RBAC.qc:979 (user function)
RBAC::init() called at qorus.q:367 (user function)
In this case, you need to create the admin
user before the system can be started.
To do this offline, use the user-tool script to create the user offline as follows:
user-tool -Aadmin:password:superuser:Administrator
Note:
- The Community Edition of Qorus does not support users or permissions; this question only applies to the Enterprise Edition of Qorus
- To create a user when the system is running, use qrest with the POST /api/latest/users API as in the following example:
qrest post users username=admin,pass=password,roles=superuser,name=Administrator
Operational FAQs
How Can I See Which Objects Are in the Database from the Command Line?
Use oload to list objects with the -L
object option as follows:
List Workflows
oload -Lw
List Services
oload -Ls
List Jobs
oload -Lj
List Mappers
oload -Lm
List Classes
oload -Lc
Notes:
- These commands can be executed even when the server is down because they use direct database access.
- Execute
oload -h
for a complete list of objects that can be listed
How Can I Set Config Item Values from the Command Line?
Use qrest to set config item values as in the following examples:
Set Config Item Values on a Workflow Step
qrest put workflows/WORKFLOW-NAME/stepinfo/StepName/config/config-item-name "value={opt1=value,opt2=value}"
Set Config Item Values on a Service
qrest put services/service-name/config/config-item-name "value={opt1=value,opt2=value}"
Set Config Item Values on a Job
qrest put jobs/job-name/config/config-item-name "value={opt1=value,opt2=value}"
Notes:
- The APIs called by qrest in the above examples use parse_to_qore_value() to parse command-line arguments used as the message body.
How Can I Set Workflow / Service / Job Options from the Command Line?
Use qrest to set interface options as in the following examples:
Set Workflow Options
qrest put workflows/WORKFLOW-NAME.setOptions "options={opt1=value,opt2=value}"
Set Service Options
qrest put services/service-name/setOptions "options={opt1=value,opt2=value}"
Set Job Options
qrest put jobs/job-name/setOptions "options={opt1=value,opt2=value}"
Notes:
- The APIs called by qrest in the above examples use parse_to_qore_value() to parse command-line arguments used as the message body.
How Can I Update a Connection From the Command Line?
See the following example for updating a connection option:
qrest put connections/connection-name options='{keyfile=path_to_key}'
How Can I See a Call Stack of Interface Execution in Realtime?
Use qctl to display a list of all thread call stacks with the threads
option as in the following example:
qctl threads <process-name>
Note: Each line in each Qorus log file shows the thread ID in the field immediately following the date and time; in the following example
T793
gives TID 7932016.08.31 11:01:39.580030 T793: ID 142: WI 167261: mip96_it_finalize(1078/0): step completed with status "C" (COMPLETE)
Why Can't I Stop My Interface?
If you are stopping your workflow, service, or job manually, the system will start it again automatically if all its dependencies are available and the manage-interfaces option is enabled and the interface is eligible for autostarting.
To be eligible for autostarting, a workflow must have a positive autostart value; a service must have its autostart values enabled, and a job must be active.
Instead of stopping a workflow or unloading a job, workflows, services, and jobs should be disabled. See the next question for more information on how to disable interfaces.
How Do I Disable an Interface from the Command Line?
Use qrest as follows:
Disable a Workflow
qrest put workflows/WORKFLOW-NAME/disable
Disable a Service
qrest put services/service-name/disable
Disable a Job
qrest put jobs/job-name/disable
How Do I Enable a Disabled Interface?
Use qrest to enable a disabled interface as follows:
Enable a Workflow
qrest put workflows/WORKFLOW-NAME/enable
Enable a Service
qrest put services/service-name/enable
Enable a Job
qrest put jobs/job-name/enable
How Are Arguments Specified on the Command Line?
Command-line arguments (with qrest, oprop, and ocmd, for example) are parsed on the client side before sending to the server with QorusClientApi::parseToQoreValue().
To send a list of values, write the values separated by commas as follows:
1, "2", three, 4
To include a hash, write it in key=value format surrounded by curly brackets and separated by commas:
1, "2", three, 4, {key1 = value1, key2 = value2}
To send a raw string without any format parsing, prepend %STR=
to the string as follows:
%STR=1, "2", three, 4, {key1 = value1, key2 = value2}
It's also possible to send an expression to be evaluated on the server side by prepending %EVAL=
as follows:
%EVAL={"key": get_qore_library_info()}
How Can I Restart the System Remotely?
For Qorus in a Docker Container or in Kubernetes
The recommended way to restart Qorus in Docker is to execute docker restart <qorus-container-name>
, in Kubernetes is to recreate the qorus-core
deployment, otherwise a brute-force way to restart Qorus in Docker or Kubernetes it to kill the qorus-core
process.
This can be performed with the UI by killing the process in the cluster page (System -> Cluster); click on the red x
icon next to the qorus-core
process to kill it.
qorus-master
will restart qorus-core
automatically in this case.
For Non-Container-Based Installations
Use qrest to call the PUT /api/latestsystem/restart API as in the following example:
qrest put system/restart
Notes:
- The calling user must have the SHUTDOWN permission to execute this API.
- The PUT /api/system/restart API uses a default two-minute timeout for restarting the system; if the system does not shut down within the timeout period, then the Qorus process is killed and immediately restarted; see the documentation in the previous links for information about how to send a different
timeout
option if necessary (for example your Qorus system needs more time to perform an orderly shutdown due to the nature of the interfaces running on it).- Do not use this API in Docker or Kubernetes instances, as it can cause problems
How Can I Rotate Log Files Manually?
Use qrest to call the PUT /api/system/rotateLogFiles API as in the following example:
qrest put system/rotateLogFiles
Note that log file rotation can be enabled automatically using the qorus-log-rotator
job; this as well as system schema archiving can be enabled by running schema-tool -m
in Qorus 6.0 or later.
See also:
How Can I Update an External Connection With the Command Line?
You can update it in the system using qrest and the PUT /api/latest/connections/name/update REST API as follows:
qrest put connections/connection-name/update url=ftp://example.com
How Are Arguments Specified in the UI?
Arguments when sent from the UI are specified as strings and parsed server-side with parse_to_qore_value().
To send a list of values, write the values separated by commas as follows:
1, "2", three, 4
To include a hash, write it in key=value
format surrounded by curly brackets and separated by commas:
1, "2", three, 4, {key1 = value1, key2 = value2}
To send a raw string without any format parsing, prepend %STR=
to the string as follows:
%STR=1, "2", three, 4, {key1 = value1, key2 = value2}
It's also possible to send an expression to be evaluated on the server side by prepending %EVAL=
as follows:
%EVAL={"key": get_qore_library_info()}
Docker and Kubernetes FAQs
How Can I Execute Qorus Command-Line Commands in a Container?
From Docker:
docker exec qorus bash -l -c "qrest system/pid"
From Kubernetes:
kubectl exec deploy/qorus-core -- bash -l -c "qrest system/pid"
How Can I Install Python Modules For Use With Qorus in Docker?
Use pip
in the container to install the modules in /opt/qorus/user/python
, the standard location and persistent directory for Python modules in Qorus:
docker exec qorus bash -l -c "pip install --prefix=/opt/qorus/user/python <python-module-name>"
How Can I Install Python Modules For Use With Qorus in Kubernetes?
Use pip
in any Qorus pod to install the modules in /opt/qorus/user/python
, the standard location and persistent directory shared in all pods for Python modules in Qorus:
kubectl exec deploy/qorus-core -- bash -l -c "pip install --prefix=/opt/qorus/user/python <python-module-name>"
Where Can I Find More Information About Qorus in Docker?
See the qorus-docker project on GitHub.
Qorus images are available here: https://gallery.ecr.aws/qorus. qorus-ee
images are for the Enterprise Edition, qorus-ce
images are for the Community Edition.
Where Can I Find More Information About Qorus in Kubernetes?
See the qorus-kubernetes project on GitHub.
Developer FAQs
How can I see the source of objects from the command-line?
If the Qorus server is running, then you can use oview to dump the source code to objects from REST APIs as in the following examples:
Dump a Function's Source Code
oview func:function_name:1.0
Dump a Class's Source Code
oview class:ClassName:1.0
Dump a Service's Source Code
oview svc:service-name:1.0
Dump a Job's Source Code
oview job:job-name:1.0
More objects can be dumped; type oview -h
for runtime help or check the oview documentation for more information.
Note: ojview can also dump job source code with
ojview -f
How to add or update Qorus objects
Use oload utility with flags to refresh cache
# Qorus 3.1+
oload -Rlv <files>
# Qorus 3.0+
oload -lvra <files>
Can I delete objects from the system?
Use the IDE
The Qorus IDE can be used to delete interfaces in a connected instance. Navigate to the Delete Interaces
page and select the objects to be deleted.
Use oload
oload can be used to delete interfaces as well as code and configuration objects in the database.
When deleting workflows, services, and jobs, ensure that the interface is not active by disabling the interface with qrest, then use the appropriate oload -X option delete the interface as in the following examples:
Delete a Workflow
oload -vR -Xworkflow:WORKFLOW-NAME:1.0
Delete a Service
oload -vR -Xservice:service-name:1.0
Delete a Job
oload -vR -Xjob:job-name:1.0
More objects can be deleted; type oload -h
for runtime help or check the oload documentation for more information.
Notes:
- The examples above use the -vR options to show more output and to also notify any running server that the given objects have been deleted
Why can't my workflow / service / job / mapper see the changes I just made to a DB table?
SqlUtil-based interfaces and system mappers use the Qorus SQL Object Cache in order to share SQL resource and provide high-performance access to static SQL configuration.
When interfaces and SqlUtil-based system mappers (i.e. any mapper using a DB table as an input or output data provider, for example) will retrieve the table definition from the cache to eliminate the acquisition and creation cost of the underlying AbstractTable objects.
When the tables change in the DB, the cached definitions need to be cleared so the new definition can be used in Qorus.
Clear SQL Cache Entries With the UI
Navigate to System -> Cache and clear the cached entries by clicking on the Clear
button next to the entries you want to clear.
Clear SQL Cache With the Command Line
To clear the entire SQL cache with the command line, see the following example:
qrest put system/sqlcache/clear
Note: The above example clears the entire system SQL cache; see PUT /api/system/sqlcache/clear for more information about how objects for specific datasources and/or tables can be cleared.
I just deleted an interface with oload, but it's still visible in the UI, what's wrong?
You have to use the oload -R
option to refresh the server after creating or deleting interfaces; to refresh the server by hand after deleting from the database, try one of the following commands:
After Deleting a Workflow
qrest put system/metadata/reload workflows=id
qrest put system/rbac/reload
After Deleting a Service
qrest put system/metadata/reload services=id
qrest put system/rbac/reload
After Deleting a Job
qrest put system/metadata/reload jobs=id
qrest put system/rbac/reload
Notes: Make sure and substitute id with the actual interface ID that was deleted.
Type oload -h
for runtime help or check the oload documentation for more information on oload and also refer to the REST API documentation.
What is the easiest way to get the current workflow_instanceid
from workflow code?
The easiest way is to call WorkflowApi::getWfiid() as in the following example:
int wfiid = WorkflowApi::getWfiid();
Another way is to call WorkflowApi::getWorkflowInstanceData() as in the following example:
softint wfiid = WorkflowApi::getWorkflowInstanceData().workflow_instanceid;
See Also: WorkflowApi::parentWfiid()
How can I insert the same sequence values in multiple columns using a system mapper?
When using a Qorus mapper with a DB table as an output data provider, you can use the sequence_currval
field option to specify that a sequence value should be inserted with the same value as in another field (i.e. another column must insert this sequence with the sequence
option).
How can I cancel a workflow order from within the same workflow?
Sometimes you may have the requirement to cancel a workflow order if a certain error occurs or if a certain condition is detected.
Workflow orders cannot be canceled from within their own code, so this must be done outside the workflow. The best way to do this is with a service.
The following is some example code that will cancel the workflow order and leave a note why the order was canceled.
cancel-service-1.0.qsd.yaml
:
# This is a generated file, don't edit!
type: service
name: cancel-order
desc: |-
## Order cancelation service
Cancels workflow orders in a background thread
lang: qore
author:
- Qore Technologies, s.r.o.
base-class-name: QorusService
class-name: CancelOrder
version: "1.0"
groups:
- EXAMPLES
servicetype: USER
code: cancel-order-1.0.qsd
methods:
- name: cancel
desc: cancels a workflow order in a background thread
- name: stop
desc: Stops the service
- name: ping
desc: returns the string OK
cancel-service-1.0.qsd
:
%new-style
%strict-args
%require-types
%enable-all-warnings
class CancelOrder inherits QorusService {
private {
# statuses where it's OK to cancel; we use a hash with boolean True values to simulate a set
const CancelStatuses = {
OMQ::StatError: True,
OMQ::StatRetry: True,
OMQ::StatAsyncWaiting: True,
OMQ::StatEventWaiting: True,
};
# check every 200 ms
const PollInterval = 200ms;
}
int cancel(softint wfiid, timeout to = 1m) {
return startThread(doCancel(), wfiid, to);
}
stop() {
# this method is necessary due to the startThread() call in the cancel method
# noop; cancel actions will time out
}
string ping() {
return "OK";
}
private waitForStatus(int wfiid, timeout to) {
date now = now_us();
hash<auto> h;
while (True) {
# info.getWorkflowStatus2() retrieves the status from the cache if possible,
# so if the order is being processed, then there is no SQL I/O
h = omqservice.system.info.getWorkflowStatus2(wfiid);
if (CancelStatuses{h.workflowstatus}) {
break;
}
if (h.workflowstatus == OMQ::StatComplete) {
throw "STATUS-ERROR", sprintf("workflow instance ID %d has status %y; cannot cancel", wfiid,
h.workflowstatus);
}
# wait for status to change
# NOTE: this function call can throw an exception if the system is being shut down;
# it's not legal to sleep when a shutdown is in progress
usleep(PollInterval);
if ((now_us() - now) >= to) {
throw "CANCEL-TIMEOUT", sprintf("cannot cancel workflow_instanceid %d (%s v%s workflowid %d) because "
"the timeout period of %y has been exceeded, and the order still has status %y", wfiid, h.name,
h.version, h.workflowid, to, h.workflowstatus);
}
}
logInfo("wfiid %d has status %y", wfiid, h.workflowstatus);
}
private hash doCancel(softint wfiid, timeout to = 1m) {
waitForStatus(wfiid, to);
# add a note to the order instance giving the reason why the order was canceled
callRestApi("POST", "orders/" + wfiid + "?action=Notes", {
"note": "this order was canceled by the 'cancel-order' service",
});
return cancelOrder(wfiid);
}
}
How can I see the raw HTTP headers and body for outgoing SOAP messages?
SOAP messages are sent with the SoapClient class and in Qorus should normally be acquired through a user connection object returned from the UserApi::getUserConnection() API function.
The recommended way to make the SOAP call and to allow for verbose debugging is to use the info output parameter in the SoapClient::call() or SoapClient::callOperation() method and log it with UserApi::logDebug() or higher as in the following example:
SoapClient sc = UserApi::getUserConnection(conn_name);
hash<auto> response;
{
hash<auto> info;
on_exit UserApi::logDebug("info: %N", info);
response = sc.call(info, operation_name, msg);
}
Note: Raw HTTP headers and message information is included when logging using the above technique; in case of HTTP basic authentication or user authentication information in the SOAP message, this information will also appear in the logs. Keep this in mind when dealing with sensitive information.
How can I see the raw HTTP headers and body for incoming HTTP messages?
Logging for raw HTTP information can be enabled by turning on the option on the HTTP listener using qrest to issue the appropriate REST API commands.
To list listeners:
qrest system/listeners?short
To turn on HTTP header and body logging for a particular listener (in this example, qorus-0
):
qrest put system/listeners/qorus-0/setLogOptions option=-1
To turn off HTTP header and body logging for a particular listener (in this example, qorus-0
):
qrest put system/listeners/qorus-0/setLogOptions option=0
The log information will appear in the system HTTP log unless listener is created in service. In this case it goes to service log!
Note: Raw HTTP headers and message information is included when logging using the above technique; in case of HTTP basic authentication or user authentication information in HTTP messages, this information will also appear in the logs. Keep this in mind when dealing with sensitive information.
How can I create a new workflow order from the command line?
qrest post workflows/WORKFLOW-NAME/createOrder
staticdata='{transaction_id="ABC12345"}'
How can I set a system property with a list or hash value from the command-line?
Qorus supports complex command-line parsing as in the following examples:
oprop set domain property '("item1","item2","item3)'
oprop set domain property key='{sub1=a,sub2=b,sub3=(1,2,three)}'
How do I clear Qorus's SQL cache when a database table has been changed?
qrest put system/sqlcache/clearCache
How do I reset a workflow from the command line?
qrest put workflows/WORKFLOW-NAME/reset
How do I set a system option from the command line?
qrest put system/options/verbose/set value=11
How do I get a list of interfaces Qorus is listening on at runtime?
# for a brief listing
qrest system/listeners?short
# for a verbose listing
qrest system/listeners
The values returned are all listeners; for Qorus and also for any services that have dedicated HTTP listeners.
Cloud VM FAQs
How do I update the VM with the newest software?
To update the software, log in to the VM with ssh
with a user with sudo
access (ex: ec2-user
on AWS) and first shut down qorus with the following command:
sudo systemctl stop qorus-6.0-ee
Update the qorus software with the following command:
sudo dnf update -y
After a successful update, restart Qorus with the following command:
sudo systemctl start qorus-6.0-ee