Skip to content

Commit

Permalink
v0.5.10 update
Browse files Browse the repository at this point in the history
added email, uptime, decrypt, set ram, and about commands
fixed bug that commands are skipped when a reboot is skipped due to early termination
use the current server's ID when none is provided for creating new commands and trend mappings
added %NAME% variable expansion to duplicate commands
bumped dependency versions
small styling changes to front-end
improved buffer size estimate for config file
added optional secondary SFTP port for some servers
improved front-end status message logic
updated sort-order of server list for front-end
implemented hidden HTTP request parameter that allows authenticated users to reset the server's ID to a specified value
update README
  • Loading branch information
cvogt729 committed Jan 24, 2025
1 parent 51c0915 commit a52844e
Show file tree
Hide file tree
Showing 14 changed files with 546 additions and 52 deletions.
35 changes: 28 additions & 7 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,9 @@ WebCTRL is a trademark of Automated Logic Corporation. Any other trademarks men
- [Examples](#examples)
- [Find Trends](#find-trends)
- [Trend Mappings](#trend-mappings)
- [Technical Information](#technical-information)
- [Packaged Dependencies](#packaged-dependencies)
- [Server ID Reset](#server-id-reset)

## Feature Summary

Expand Down Expand Up @@ -168,14 +171,16 @@ In addition to the SFTP connection settings shown in the previous section, there
| `debug` | `false` | When enabled, log messages will be more verbose. |
| `log_expiration` | `60` | Specifies how many days to retain log messages in the database. |
| `auto_update` | `true` | Specifies whether to attempt automatic updates for this add-on. |
| `version` | `0.5.9.1` | When `auto_update` is enabled, any connected client whose add-on version is less than this value will be updated. |
| `version` | `0.5.10` | When `auto_update` is enabled, any connected client whose add-on version is less than this value will be updated. |
| `download_path` | `/webctrl/addons/PostgreSQL_Connect.addon` | When `auto_update` is enabled, this is the SFTP server path where the latest version add-on file will be retrieved. |
| `license_directory` | `/webctrl/licenses` | Specifies an SFTP server directory path for where to store WebCTRL license files. |
| `ftp_host` | `postgresql.domain.com` | SFTP server hostname or IP address. |
| `ftp_port` | `22` | SFTP server port. |
| `ftp_username` | `webctrl` | SFTP server username to use for connections. |
| `ftp_known_hosts` | `postgresql.domain.com ecdsa-sha2-nistp256 ...` | Public key of the SFTP server to verify the server's identity. [Documentation](https://help.salesforce.com/s/articleView?id=001120703&type=1) |
| `ftp_key` | `-----BEGIN OPENSSH PRIVATE KEY----- ...` | Private key which authenticates the client to the SFTP server. |
| `ftp_port_secondary` | `443` | Secondary SFTP port which may be utilized by some servers. This may be useful to bypass certain firewalls. |
| `ftp_port_secondary_ids` | `46;51;60;61;62` | Semi-colon delimited list of server IDs which should use the secondary SFTP port. |

When trying to push out an update for the add-on, you should do things in the following order:

Expand All @@ -199,7 +204,7 @@ This page lists all connected servers. If a server is decomissioned or permanent
| ID | `1` | Internal ID which uniquely identifies the server within the PostgreSQL database. (Read-only) |
| Name | `ACES Main Building` | User-friendly display name for the server. This defaults to the display name of the root of the Geo tree. |
| WebCTRL Version | `8.5.002.20230323-123687` | Full version of the WebCTRL server. (Read-only) |
| Add-On Version | `0.5.9.1` | Installed version of the PostgreSQL_Connect add-on. (Read-only) |
| Add-On Version | `0.5.10` | Installed version of the PostgreSQL_Connect add-on. (Read-only) |
| IP Address | `123.45.67.89` | External IP address of the server as viewed by the PostgreSQL database. (Read-only) |
| Last Sync | `2024-12-02 14:05:32` | Timestamp of the last successful synchronization. If synced within the last 24 hours, the background color is green; otherwise, the background is red. (Read-only) |
| License | `WebCTRL Premium` | Click this field to download WebCTRL's license. (Read-only) |
Expand Down Expand Up @@ -285,16 +290,20 @@ Commands entered into this table are executed on servers during their next sync
| Ordering | `3` | When there are multiple command entries for a single server, this column specifies the ascending order in which commands are executed. |
| Command | `notify "Hello!"` | The command(s) to execute. Multiple commands can be separated by newlines for fail-fast semantics. |

Commands chained together using new-lines in a single entry are fail-fast, which means that execution is terminated immediately when an error is encountered. However, errors in one command entry do not affect other entries. Generally, commands are case-insensitive. Commands are tokenized using whitespace as delimiters. Double quotes can be used if a token must include whitespace. The caret character `^` can be used as an escape character. The local file path are specified, paths starting with `/` or `\` are treated as relative to WebCTRL's installation directory, and paths starting with `./` or `.\` are treated as relative to WebCTRL's active system directory. The two dots in `a/../b` go to the parent folder of `a`, so that `b` would be a sibling folder of `a`. Single-line comments are supported when a line is starts with `//`. The following commands are supported.
Commands chained together using new-lines in a single entry are fail-fast, which means that execution is terminated immediately when an error is encountered. However, errors in one command entry do not affect other entries. Generally, commands are case-insensitive. Commands are tokenized using whitespace as delimiters. Double quotes can be used if a token must include whitespace. The caret character `^` can be used as an escape character. The local file path are specified, paths starting with `/` or `\` are treated as relative to WebCTRL's installation directory, and paths starting with `./` or `.\` are treated as relative to WebCTRL's active system directory. The two dots in `a/../b` go to the parent folder of `a`, so that `b` would be a sibling folder of `a`. Environment variables enclosed in percent signs (e.g, `%USERNAME%`) are expanded when present in local paths. Single-line comments are supported when a line is starts with `//`. The following commands are supported.

| Command | Description |
| - | - |
| `duplicate [id1,id2,...]` | When a new pending command is created, and `duplicate` is on the first line, the command is copied to all servers with the specified IDs. If no server IDs are specified, then the command is copied to all servers. You can use `%ID%` anywhere in the command after the `duplicate` statement, and it will be replaced with the server ID of each server the command is copied to. |
| `duplicate [id1,id2,...]` | When a new pending command is created, and `duplicate` is on the first line, the command is copied to all servers with the specified IDs. If no server IDs are specified, then the command is copied to all servers. You can use `%ID%` or `%NAME%` anywhere in the command after the `duplicate` statement, and it will be replaced with the server ID or name of each server the command is copied to. |
| `about` | Logs a bunch of information relevant to the WebCTRL server. This functions similarly to the `about` manual command. |
| `log <message>` | Writes a message to the add-on's log file. |
| `notify <message>` | Functions identically to the `notify` manual command. Logged in operators get a popup message in their web browsers. |
| `email <recipients> <subject> <message>` | Sends a email using WebCTRL's primary email server configuration. Recipient addresses should be semi-colon delimited. |
| `sleep <milliseconds>` | Sleeps for the specified number of milliseconds. |
| `reboot` | Functions identically to the `rebootserver` manual command. The WebCTRL server reboots. |
| `set <key> <value>` | Sets an add-on connection parameter to the specified value. These parameters can all be changed on the add-on's main page on each server, but this command allows remotely editing connection parameters in bulk. The following keys are supported: `connectionURL`, `username`, `password`, `keystorePassword`, `maxRandomOffset`, `cronSync`. |
| `uptime` | Logs a message saying how long the WebCTRL server has been online. |
| `set <key> <value>` | Sets a parameter to the specified value. Most of the parameters can be changed on the add-on's main page on each server, but this command allows remote editing in bulk. The following keys are supported: `connectionURL`, `username`, `password`, `keystorePassword`, `maxRandomOffset`, `cronSync`, `RAM`. The `RAM` key changes the amount of memory allocated to WebCTRL in MB and goes into affect at the next reboot. |
| `decrypt <value>` | Logs a message containing the decrypted value. This function is only meant to work on encrypted WebCTRL database passwords found in *db.properties* in the system folder. |
| `mkdir <folder_path>` | Creates a new directory on the local file system of the WebCTRL server. |
| `rmdir <folder_path>` | Deletes a directory and contents on the local file system of the WebCTRL server. |
| `rm <file_path>` | Deletes a file on the local file system of the WebCTRL server. |
Expand All @@ -303,7 +312,7 @@ Commands chained together using new-lines in a single entry are fail-fast, which
| `cat <file_path>` | Logs the contents of the specified file. |
| `exists <path>` | Asserts that the specified file or directory exists. If non-existent, then command execution is terminated. |
| `!exists <path>` | Asserts that the specified file or directory does not exists. If it exists, then command execution is terminated. |
| `regex <file_path> <find> [replace]` | If a replacement string is not given, then this commands logs all matches of the regular expression in the specified file. If a replacement string is given, then this command edits the specified file by replacing all matches of the regular expression. The file's contents are assumed to be UTF-8 encoded text. The [MULTILINE](https://docs.oracle.com/en/java/javase/17/docs/api/java.base/java/util/regex/Pattern.html#MULTILINE) and [DOTALL](https://docs.oracle.com/en/java/javase/17/docs/api/java.base/java/util/regex/Pattern.html#DOTALL) flags are used by default. |
| `regex <file_path> <find> [replace]` | If a replacement string is not given, then this commands logs all matches of the regular expression in the specified file. If a replacement string is given, then this command edits the specified file by replacing all matches of the regular expression. The file's contents are assumed to be UTF-8 encoded text. The [MULTILINE](https://docs.oracle.com/en/java/javase/21/docs/api/java.base/java/util/regex/Pattern.html#MULTILINE) and [DOTALL](https://docs.oracle.com/en/java/javase/21/docs/api/java.base/java/util/regex/Pattern.html#DOTALL) flags are used by default. |
| `download <sftp_file_path> <local_file_path>` | Downloads a file from the SFTP server into the local file system of the WebCTRL server. |
| `upload <local_file_path> <sftp_file_path>` | Uploads a file from the local file system of the WebCTRL server into the SFTP server. |
| `canApplyUpdate <file_path>` | Asserts that WebCTRL is able to apply the specified *.update* patch file. If the update cannot be applied, then command execution is terminated. |
Expand Down Expand Up @@ -402,4 +411,16 @@ CREATE TABLE webctrl.trend_data (
);
CREATE INDEX webctrl_trend_data_id ON webctrl.trend_data ("id" ASC);
CREATE INDEX webctrl_trend_data_time ON webctrl.trend_data ("time" DESC);
```
```

## Technical Information

### Packaged Dependencies

- [PostgreSQL JDBC 42.7.5](https://jdbc.postgresql.org/) - Used to connect to PostgreSQL databases.
- [JSch 0.2.22](https://github.com/mwiede/jsch) - Used to connect to SFTP servers.
- [JSON-java 20250107](https://github.com/stleary/JSON-java) - Used to encode and decode JSON data.

### Server ID Reset

There is a *Reset ID* button on the add-on's main page. This will make the add-on forget its current server ID and re-register with the database at the start of the next sync. This server ID is the primary mechanism for how the database separates out data corresponding to different WebCTRL servers. If you ever need to force the add-on to choose a particular ID, you can craft and submit a particular HTTP request to the WebCTRL server. For example, *https://localhost/PostgreSQL_Connect/index?type=resetNow&newID=3* will force the ID of the WebCTRL server accessible at *localhost* to 3.
15 changes: 9 additions & 6 deletions config/BUILD_DETAILS
Original file line number Diff line number Diff line change
Expand Up @@ -19,20 +19,23 @@ common-9.0.002
commonbaseutils-2.0.5
commonexceptions-9.0.002
core-9.0.002
core-api-9.0.002
databasebridge-9.0.002
datatable-9.0.002
directaccess-9.0.002
directaccess-api-9.0.002
extensionsupport-api-9.0.002
launcher-3.0.10
serviceframework-9.0.002
spring-context-5.3.33
update-api-9.0.002
webserver-api-9.0.002
webui-9.0.002

Packaged Dependencies:
jsch-0.2.21-sources
jsch-0.2.21
json-20240303-sources
json-20240303
postgresql-42.7.4-sources
postgresql-42.7.4
jsch-0.2.22-sources
jsch-0.2.22
json-20250107-sources
json-20250107
postgresql-42.7.5-sources
postgresql-42.7.5
12 changes: 6 additions & 6 deletions config/EXTERNAL_DEPS
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
url:postgresql-42.7.4.jar:https://repo1.maven.org/maven2/org/postgresql/postgresql/42.7.4/postgresql-42.7.4.jar
url:postgresql-42.7.4-sources.jar:https://repo1.maven.org/maven2/org/postgresql/postgresql/42.7.4/postgresql-42.7.4-sources.jar
url:jsch-0.2.21.jar:https://repo1.maven.org/maven2/com/github/mwiede/jsch/0.2.21/jsch-0.2.21.jar
url:jsch-0.2.21-sources.jar:https://repo1.maven.org/maven2/com/github/mwiede/jsch/0.2.21/jsch-0.2.21-sources.jar
url:json-20240303.jar:https://repo1.maven.org/maven2/org/json/json/20240303/json-20240303.jar
url:json-20240303-sources.jar:https://repo1.maven.org/maven2/org/json/json/20240303/json-20240303-sources.jar
url:postgresql-42.7.5.jar:https://repo1.maven.org/maven2/org/postgresql/postgresql/42.7.5/postgresql-42.7.5.jar
url:postgresql-42.7.5-sources.jar:https://repo1.maven.org/maven2/org/postgresql/postgresql/42.7.5/postgresql-42.7.5-sources.jar
url:jsch-0.2.22.jar:https://repo1.maven.org/maven2/com/github/mwiede/jsch/0.2.22/jsch-0.2.22.jar
url:jsch-0.2.22-sources.jar:https://repo1.maven.org/maven2/com/github/mwiede/jsch/0.2.22/jsch-0.2.22-sources.jar
url:json-20250107.jar:https://repo1.maven.org/maven2/org/json/json/20250107/json-20250107.jar
url:json-20250107-sources.jar:https://repo1.maven.org/maven2/org/json/json/20250107/json-20250107-sources.jar
5 changes: 4 additions & 1 deletion config/RUNTIME_DEPS
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ file:datatable:modules\datatable
file:webserver-api:modules\webserver
file:extensionsupport-api:modules\extensionsupport
file:core:modules\core
file:core-api:modules\core
file:common:modules\common
file:commonexceptions:modules\commonexceptions
file:commonbaseutils:bin\lib
Expand All @@ -11,4 +12,6 @@ file:directaccess-api:modules\directaccess
file:cjupdate:bin\lib
file:update-api:modules\update
file:webui:webroot\WEB-INF\lib
file:serviceframework:modules\serviceframework
file:serviceframework:modules\serviceframework
file:databasebridge:modules\databasebridge
file:launcher:bin\lib
2 changes: 1 addition & 1 deletion root/info.xml
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
<extension version="1">
<name>PostgreSQL_Connect</name>
<description>Periodically synchronizes operators, add-ons, and specified trends with an external PostgreSQL database.</description>
<version>0.5.9.1</version>
<version>0.5.10</version>
<vendor>Automatic Controls Equipment Systems, Inc.</vendor>
<system-menu-provider>aces.webctrl.postgresql.web.SystemMenuEditor</system-menu-provider>
</extension>
98 changes: 97 additions & 1 deletion src/aces/webctrl/postgresql/core/Command.java
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,10 @@
import java.nio.*;
import java.nio.file.*;
import java.nio.channels.*;
import com.controlj.green.common.launcher.MonitoredLauncher;
import com.controlj.green.common.policy.PolicyUtils;
import com.controlj.green.common.policy.PolicyUtils.KeyType;
import com.controlj.launcher.ConfigurationDecorator;
public class Command {
private final static HashMap<String,Cmd> commandMap = new HashMap<>();
static {
Expand All @@ -19,6 +23,62 @@ public class Command {
}
}
});
commandMap.put("uptime", new Cmd(){
@Override public boolean exec(Command c, String[] tokens) throws Throwable {
if (tokens.length==1){
long uptime = com.controlj.green.core.main.Core.getSystemUptime();
int days = (int)(uptime/86400000L);
uptime-=(long)days*86400000L;
int hours = (int)(uptime/3600000L);
uptime-=(long)hours*3600000L;
int minutes = (int)(uptime/60000L);
//uptime-=(long)minutes*60000L;
c.sb.append("\nWebCTRL has been online for "+days+" days, "+hours+" hours, and "+minutes+" minutes.");
return true;
}else{
c.sb.append("\n'uptime' does not accept any arguments.");
return false;
}
}
});
commandMap.put("about", new Cmd(){
@Override public boolean exec(Command c, String[] tokens) throws Throwable {
if (tokens.length==1){
HelperAPI.about(c.sb);
return true;
}else{
c.sb.append("\n'about' does not accept any arguments.");
return false;
}
}
});
commandMap.put("decrypt", new Cmd(){
@Override public boolean exec(Command c, String[] tokens) throws Throwable {
if (tokens.length==2){
String p;
try{
try {
p = PolicyUtils.AESdecrypt(tokens[1], KeyType.DBPROPERTIES);
} catch (Throwable t) {
p = PolicyUtils.decode(tokens[1]);
if (Initializer.debug()){
Initializer.log(t);
}
}
} catch (Throwable t) {
p = "";
if (Initializer.debug()){
Initializer.log(t);
}
}
c.sb.append('\n').append(p);
return true;
}else{
c.sb.append("\n'decrypt' accepts exactly one argument.");
return false;
}
}
});
commandMap.put("updatedst", new Cmd(){
@Override public boolean exec(Command c, String[] tokens) throws Throwable {
if (tokens.length==1){
Expand All @@ -45,6 +105,20 @@ public class Command {
}
}
});
commandMap.put("email", new Cmd(){
@Override public boolean exec(Command c, String[] tokens) throws Throwable {
if (tokens.length==4){
if (HelperAPI.sendEmail(tokens[1], tokens[2], tokens[3])){
return true;
}else{
c.sb.append("\n'email' failed to send message.");
}
}else{
c.sb.append("\n'email' accepts exactly three arguments.");
}
return false;
}
});
commandMap.put("log", new Cmd(){
@Override public boolean exec(Command c, String[] tokens) throws Throwable {
if (tokens.length==2){
Expand Down Expand Up @@ -287,6 +361,28 @@ public class Command {
}
break;
}
case "ram":{
try{
final int ram = Integer.parseInt(value);
if (ram<512 || ram>131072){
c.sb.append("\n'set' ram value is out-of-range.");
return false;
}
final ConfigurationDecorator config = new ConfigurationDecorator(MonitoredLauncher.loadConfiguration());
if (config.getMaxMemory()!=ram){
config.setMaxMemory(ram);
MonitoredLauncher.saveConfiguration(config.getConfiguration());
}
}catch(NumberFormatException e){
c.sb.append("\n'set' failed to parse number from expected value.");
return false;
}catch(Throwable t){
c.sb.append("\n'set' encountered error while configuring RAM.");
Initializer.log(t);
return false;
}
break;
}
default:{
c.sb.append("\n'set' does not recognize key: "+key);
return false;
Expand Down Expand Up @@ -480,7 +576,7 @@ public boolean execute(){
try{
for (String[] tokens: lines){
if (!execute(tokens)){
break;
return false;
}
}
return true;
Expand Down
Loading

0 comments on commit a52844e

Please sign in to comment.