Skip to content

Commit d941757

Browse files
committed
Make elasticsearch optional
1 parent 00d2e9f commit d941757

4 files changed

Lines changed: 145 additions & 42 deletions

File tree

cws-installer/src/main/java/jpl/cws/task/CwsInstaller.java

Lines changed: 66 additions & 33 deletions
Original file line numberDiff line numberDiff line change
@@ -277,12 +277,13 @@ public static void main(String args[]) {
277277
setupAdminUser();
278278
setupNotificationEmails();
279279
setupTokenExpirationHours();
280-
setupPorts();
281-
getKeystorePassword();
282-
setupTaskAssigmentEmails();
283-
setupSMTP();
284-
setupElasticsearch();
285-
setupLogstash();
280+
setupPorts();
281+
getKeystorePassword();
282+
setupTaskAssigmentEmails();
283+
setupSMTP();
284+
// Elasticsearch is now optional - only setup if configured
285+
setupElasticsearch();
286+
setupLogstash();
286287
setupHistoryLevel();
287288
setupAws();
288289
if (installConsole) {
@@ -1279,14 +1280,29 @@ private static void setupElasticsearch() {
12791280
// PROMPT USER FOR ELASTICSEARCH PROTOCOL
12801281
elasticsearch_protocol = getPreset("elasticsearch_protocol");
12811282

1283+
// Elasticsearch is now optional - if no protocol is provided, skip setup
1284+
if (elasticsearch_protocol == null && !cws_installer_mode.equals("interactive")) {
1285+
log.info("Elasticsearch configuration not provided - skipping Elasticsearch setup (optional)");
1286+
return;
1287+
}
1288+
12821289
if (cws_installer_mode.equals("interactive")) {
12831290
if (elasticsearch_protocol == null) {
1291+
String read_elasticsearch_protocol = readLine("Enter the Elasticsearch protocol (HTTP/HTTPS) or press Enter to skip Elasticsearch setup: ", "");
1292+
1293+
// Allow user to skip Elasticsearch setup
1294+
if (read_elasticsearch_protocol == null || read_elasticsearch_protocol.trim().isEmpty()) {
1295+
log.info("Elasticsearch setup skipped by user");
1296+
return;
1297+
}
12841298

1285-
String read_elasticsearch_protocol = "";
12861299
while (!read_elasticsearch_protocol.toLowerCase().startsWith("https") &&
12871300
!read_elasticsearch_protocol.toLowerCase().startsWith("http")) {
1288-
read_elasticsearch_protocol = readRequiredLine("Enter the Elasticsearch protocol (be sure to use HTTP or HTTPS): ",
1289-
"You must enter a protocol");
1301+
read_elasticsearch_protocol = readLine("Invalid protocol. Enter HTTP or HTTPS, or press Enter to skip: ", "");
1302+
if (read_elasticsearch_protocol == null || read_elasticsearch_protocol.trim().isEmpty()) {
1303+
log.info("Elasticsearch setup skipped by user");
1304+
return;
1305+
}
12901306
}
12911307

12921308
elasticsearch_protocol_init = read_elasticsearch_protocol;
@@ -1301,10 +1317,6 @@ private static void setupElasticsearch() {
13011317
elasticsearch_protocol = readLine("Enter the Elasticsearch protocol. " + "Default is " + elasticsearch_protocol + ": ", elasticsearch_protocol);
13021318
}
13031319
} else {
1304-
if (elasticsearch_protocol == null) {
1305-
bailOutMissingOption("elasticsearch_protocol");
1306-
}
1307-
13081320
elasticsearch_protocol_init = elasticsearch_protocol;
13091321
elasticsearch_protocol = elasticsearch_protocol.toLowerCase();
13101322
if (elasticsearch_protocol.startsWith("https")) {
@@ -1319,16 +1331,14 @@ private static void setupElasticsearch() {
13191331

13201332
log.debug("elasticsearch_protocol: " + elasticsearch_protocol);
13211333

1322-
13231334
// PROMPT USER FOR ELASTICSEARCH HOST
13241335
elasticsearch_host = getPreset("elasticsearch_host");
13251336

13261337
if (cws_installer_mode.equals("interactive")) {
13271338
if (elasticsearch_host == null) {
13281339

13291340
String read_elasticsearch_host = "";
1330-
read_elasticsearch_host = readRequiredLine("Enter the Elasticsearch host: ",
1331-
"You must enter a hostname");
1341+
read_elasticsearch_host = readLine("Enter the Elasticsearch host (or press Enter for default 'localhost'): ", "localhost");
13321342

13331343
elasticsearch_host_init = read_elasticsearch_host;
13341344
elasticsearch_host = read_elasticsearch_host.toLowerCase();
@@ -1340,8 +1350,10 @@ private static void setupElasticsearch() {
13401350
elasticsearch_host = readLine("Enter the Elasticsearch host. " + "Default is " + elasticsearch_host + ": ", elasticsearch_host);
13411351
}
13421352
} else {
1353+
// In non-interactive mode, use default if not provided
13431354
if (elasticsearch_host == null) {
1344-
bailOutMissingOption("elasticsearch_host");
1355+
elasticsearch_host = "localhost";
1356+
log.info("Using default Elasticsearch host: localhost");
13451357
}
13461358

13471359
elasticsearch_host_init = elasticsearch_host;
@@ -1391,14 +1403,17 @@ private static void setupElasticsearch() {
13911403
elasticsearch_use_auth = getPreset("default_elasticsearch_use_auth");
13921404
}
13931405

1406+
// Default to 'n' if not provided
1407+
if (elasticsearch_use_auth == null) {
1408+
elasticsearch_use_auth = "n";
1409+
}
1410+
13941411
if (cws_installer_mode.equals("interactive")) {
1395-
String read_elasticsearch_use_auth = "";
1412+
String read_elasticsearch_use_auth = readLine("Does your Elasticsearch cluster require authentication? (Y/N, default N): ", "n");
13961413

13971414
while (!read_elasticsearch_use_auth.equalsIgnoreCase("y") &&
13981415
!read_elasticsearch_use_auth.equalsIgnoreCase("n")) {
1399-
read_elasticsearch_use_auth =
1400-
readRequiredLine("Does you Elasticsearch cluster require authentication? (Y/N): ",
1401-
"ERROR: Must specify either 'Y' or 'N'");
1416+
read_elasticsearch_use_auth = readLine("Invalid input. Enter Y or N (default N): ", "n");
14021417
}
14031418

14041419
elasticsearch_use_auth = read_elasticsearch_use_auth.toLowerCase();
@@ -1414,12 +1429,13 @@ private static void setupElasticsearch() {
14141429
elasticsearch_username = readRequiredLine("Enter the elasticsearch username: ",
14151430
"Must specify an elasticsearch username!");
14161431
} else {
1417-
elasticsearch_username = readLine("Enter the database username. " +
1432+
elasticsearch_username = readLine("Enter the elasticsearch username. " +
14181433
"Default is " + elasticsearch_username + ": ", elasticsearch_username);
14191434
}
14201435
} else {
14211436
if (elasticsearch_username == null) {
1422-
bailOutMissingOption("elasticsearch_username");
1437+
log.warn("elasticsearch_username not provided but authentication is enabled - using empty string");
1438+
elasticsearch_username = "";
14231439
}
14241440
}
14251441

@@ -1439,9 +1455,18 @@ private static void setupElasticsearch() {
14391455
elasticsearch_password = String.valueOf(password);
14401456
} else {
14411457
if (elasticsearch_password == null) {
1442-
bailOutMissingOption("elasticsearch_password");
1458+
log.warn("elasticsearch_password not provided but authentication is enabled - using empty string");
1459+
elasticsearch_password = "";
14431460
}
14441461
}
1462+
} else {
1463+
// Set defaults for username and password when auth is not used
1464+
if (elasticsearch_username == null) {
1465+
elasticsearch_username = "";
1466+
}
1467+
if (elasticsearch_password == null) {
1468+
elasticsearch_password = "";
1469+
}
14451470
}
14461471
}
14471472

@@ -1797,13 +1822,17 @@ private static void showInstallationInfo() {
17971822
print("SMTP host = " + cws_smtp_hostname);
17981823
print("SMTP port = " + cws_smtp_port);
17991824
print("....................................................................................");
1800-
print("Elasticsearch Protocol = " + elasticsearch_protocol);
1801-
print("Elasticsearch Host = " + elasticsearch_host);
1802-
print("Elasticsearch Index Prefix = " + elasticsearch_index_prefix);
1803-
print("Elasticsearch Port = " + elasticsearch_port);
1804-
if (elasticsearch_use_auth.equalsIgnoreCase("Y")) {
1805-
print("Elasticsearch User = " + elasticsearch_username);
1806-
print("Elasticsearch Password = ****** (hidden) ");
1825+
if (elasticsearch_protocol != null && !elasticsearch_protocol.isEmpty()) {
1826+
print("Elasticsearch Protocol = " + elasticsearch_protocol);
1827+
print("Elasticsearch Host = " + elasticsearch_host);
1828+
print("Elasticsearch Index Prefix = " + elasticsearch_index_prefix);
1829+
print("Elasticsearch Port = " + elasticsearch_port);
1830+
if (elasticsearch_use_auth.equalsIgnoreCase("Y")) {
1831+
print("Elasticsearch User = " + elasticsearch_username);
1832+
print("Elasticsearch Password = ****** (hidden) ");
1833+
}
1834+
} else {
1835+
print("Elasticsearch = Not Configured (Optional)");
18071836
}
18081837
print("....................................................................................");
18091838
if (user_provided_logstash.equalsIgnoreCase("Y")) {
@@ -1869,8 +1898,12 @@ private static void validateConfig() {
18691898
warningCount++;
18701899
}
18711900

1872-
// Check that user provided Elasticsearch service is up and healthy
1873-
warningCount += validateElasticsearch();
1901+
// Check that user provided Elasticsearch service is up and healthy (only if configured)
1902+
if (elasticsearch_protocol != null && !elasticsearch_protocol.isEmpty()) {
1903+
warningCount += validateElasticsearch();
1904+
} else {
1905+
log.info("Elasticsearch not configured - skipping validation");
1906+
}
18741907

18751908
// Check that keystore and truststore is valid, not expired
18761909
warningCount += validateKeystoreTruststore();

cws-service/src/main/java/jpl/cws/controller/RestService.java

Lines changed: 63 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -103,14 +103,14 @@ public class RestService extends MvcCore {
103103
@Value("${cws.console.app.root}") private String appRoot;
104104
@Value("${cws.install.hostname}") private String hostName;
105105

106-
@Value("${cws.elasticsearch.protocol}") private String elasticsearchProtocolName;
107-
@Value("${cws.elasticsearch.hostname}") private String elasticsearchHostname;
108-
@Value("${cws.elasticsearch.index.prefix}") private String elasticsearchIndexPrefix;
109-
@Value("${cws.elasticsearch.port}") private String elasticsearchPort;
106+
@Value("${cws.elasticsearch.protocol:#{null}}") private String elasticsearchProtocolName;
107+
@Value("${cws.elasticsearch.hostname:#{null}}") private String elasticsearchHostname;
108+
@Value("${cws.elasticsearch.index.prefix:#{null}}") private String elasticsearchIndexPrefix;
109+
@Value("${cws.elasticsearch.port:#{null}}") private String elasticsearchPort;
110110

111-
@Value("${cws.elasticsearch.use.auth}") private String elasticsearchUseAuth;
112-
@Value("${cws.elasticsearch.username}") private String elasticsearchUsername;
113-
@Value("${cws.elasticsearch.password}") private String elasticsearchPassword;
111+
@Value("${cws.elasticsearch.use.auth:n}") private String elasticsearchUseAuth;
112+
@Value("${cws.elasticsearch.username:#{null}}") private String elasticsearchUsername;
113+
@Value("${cws.elasticsearch.password:#{null}}") private String elasticsearchPassword;
114114

115115
public RestService() {
116116
log.info("RestService controller initialized with @RequestMapping('/api')");
@@ -459,16 +459,31 @@ private String doDeployProcessDefinition(MultipartFile file) {
459459
* @return fully constructed elasticsearch URL string
460460
*/
461461
private String constructElasticsearchUrl(String subPath) {
462+
if (!isElasticsearchConfigured()) {
463+
log.warn("Elasticsearch is not configured. Cannot construct URL.");
464+
return null;
465+
}
462466
String urlString = elasticsearchProtocolName + "://" + elasticsearchHostname + ":" + elasticsearchPort + subPath;
463467
return urlString;
464468
}
465469

470+
/**
471+
* Check if Elasticsearch is properly configured
472+
*
473+
* @return boolean indicating whether elasticsearch is configured
474+
*/
475+
private boolean isElasticsearchConfigured() {
476+
return elasticsearchProtocolName != null && !elasticsearchProtocolName.isEmpty() &&
477+
elasticsearchHostname != null && !elasticsearchHostname.isEmpty() &&
478+
elasticsearchPort != null && !elasticsearchPort.isEmpty();
479+
}
480+
466481
/**
467482
*
468483
* @return boolean indicating whether elasticsearch requires authentication
469484
*/
470485
private Boolean elasticsearchUseAuth() {
471-
return elasticsearchUseAuth.equalsIgnoreCase("Y");
486+
return elasticsearchUseAuth != null && elasticsearchUseAuth.equalsIgnoreCase("Y");
472487
}
473488

474489

@@ -690,6 +705,11 @@ public ModelAndView validateAndSaveSnippets(
690705
@RequestMapping(value = "/logs/get/scroll", method = POST, produces="application/json")
691706
public @ResponseBody String getLogsScroll(
692707
@Parameter(description = "Scroll ID to keep track of already fetched data.", required = true, schema = @Schema(type = "string")) @RequestParam(value = "scrollId") String scrollId) {
708+
if (!isElasticsearchConfigured()) {
709+
log.warn("Elasticsearch is not configured");
710+
return "{\"hits\": {\"hits\": []}, \"error\": \"Elasticsearch is not configured\"}";
711+
}
712+
693713
String urlString = constructElasticsearchUrl("/_search/scroll");
694714
String jsonData = "{ \"scroll\" : \"1m\", \"scroll_id\" : \"" + scrollId + "\" }";
695715

@@ -723,6 +743,11 @@ public ModelAndView validateAndSaveSnippets(
723743
@Operation(summary = "Gets the total number of log rows.", tags = {"Logs"})
724744
@RequestMapping(value="/logs/get/count", method = GET, produces="application/json")
725745
public @ResponseBody String getNumLogs() {
746+
if (!isElasticsearchConfigured()) {
747+
log.warn("Elasticsearch is not configured");
748+
return "{\"count\": 0, \"error\": \"Elasticsearch is not configured\"}";
749+
}
750+
726751
String urlString = constructElasticsearchUrl("/" + elasticsearchIndexPrefix + "-logstash-*/_count");
727752
log.trace("REST getNumLogs query = " + urlString);
728753

@@ -754,6 +779,11 @@ public ModelAndView validateAndSaveSnippets(
754779
@RequestMapping(value = "/logs/get/noScroll", method = GET, produces="application/json")
755780
public @ResponseBody String getLogsNoScroll(
756781
@Parameter(description = "Source of the logs to get.", required = true, schema = @Schema(type = "string")) @RequestParam(value = "source") String source) {
782+
if (!isElasticsearchConfigured()) {
783+
log.warn("Elasticsearch is not configured");
784+
return "{\"hits\": {\"hits\": []}, \"error\": \"Elasticsearch is not configured\"}";
785+
}
786+
757787
String urlString = constructElasticsearchUrl("/" + elasticsearchIndexPrefix + "-logstash-*/_search");
758788
log.debug("REST logs/get/noScroll query = " + urlString);
759789

@@ -789,6 +819,11 @@ public ModelAndView validateAndSaveSnippets(
789819
@RequestMapping(value = "/logs/get", method = GET, produces="application/json")
790820
public @ResponseBody String getLogs(
791821
@Parameter(description = "Source of the logs to get.", required = true, schema = @Schema(type = "string")) @RequestParam(value = "source") String source) {
822+
if (!isElasticsearchConfigured()) {
823+
log.warn("Elasticsearch is not configured");
824+
return "{\"hits\": {\"hits\": []}, \"error\": \"Elasticsearch is not configured\"}";
825+
}
826+
792827
String urlString = constructElasticsearchUrl("/" + elasticsearchIndexPrefix + "-logstash-*/_search?scroll=5m&source=" + source + "&source_content_type=application/json");
793828
log.trace("REST getLogs query = " + urlString);
794829

@@ -823,6 +858,11 @@ public ModelAndView validateAndSaveSnippets(
823858
HttpServletResponse response,
824859
@Parameter(description = "Process definition key to delete logs for.", required = true, schema = @Schema(type = "string")) @PathVariable String procDefKey
825860
) {
861+
if (!isElasticsearchConfigured()) {
862+
log.warn("Elasticsearch is not configured - cannot delete logs");
863+
return "{\"status\": \"SUCCESS\", \"message\": \"Elasticsearch is not configured - no logs to delete\"}";
864+
}
865+
826866
String urlString = constructElasticsearchUrl("/" + elasticsearchIndexPrefix + "-logstash*/_delete_by_query");
827867
log.debug("REST deleteLogsByProcDefKey url = " + urlString);
828868

@@ -907,6 +947,11 @@ public GsonUTCDateAdapter() {
907947
@Operation(summary = "Gets Elasticsearch stats.", tags = {"Elasticsearch"})
908948
@RequestMapping(value = "/stats/es/indices", method = GET, produces="application/json")
909949
public @ResponseBody String getElasticsearchIndices() {
950+
if (!isElasticsearchConfigured()) {
951+
log.warn("Elasticsearch is not configured");
952+
return "{\"error\": \"Elasticsearch is not configured\"}";
953+
}
954+
910955
String urlString = constructElasticsearchUrl("/_cat/indices?v&bytes=b&s=index&format=json");
911956

912957
log.trace("REST query = " + urlString);
@@ -939,6 +984,11 @@ public GsonUTCDateAdapter() {
939984
@Operation(summary = "Gets Elasticsearch cluster health.", tags = {"Elasticsearch"})
940985
@RequestMapping(value = "/stats/es/cluster/health", method = GET, produces="application/json")
941986
public @ResponseBody String getElasticsearchClusterHealth() {
987+
if (!isElasticsearchConfigured()) {
988+
log.warn("Elasticsearch is not configured");
989+
return "{\"error\": \"Elasticsearch is not configured\"}";
990+
}
991+
942992
String urlString = constructElasticsearchUrl("/_cluster/health");
943993

944994
log.trace("REST query = " + urlString);
@@ -971,6 +1021,11 @@ public GsonUTCDateAdapter() {
9711021
@Operation(summary = "Gets Elasticsearch stats.", tags = {"Elasticsearch"})
9721022
@RequestMapping(value = "/stats/es", method = GET, produces="application/json")
9731023
public @ResponseBody String getElasticsearchStats() {
1024+
if (!isElasticsearchConfigured()) {
1025+
log.warn("Elasticsearch is not configured");
1026+
return "{\"error\": \"Elasticsearch is not configured\"}";
1027+
}
1028+
9741029
String urlString = constructElasticsearchUrl("/_nodes/stats/_all");
9751030

9761031
log.trace("REST query = " + urlString);

cws-service/src/main/java/jpl/cws/service/CwsConsoleService.java

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1013,10 +1013,18 @@ public DiskUsage getDiskUsage() throws Exception {
10131013
public void cleanupElasticsearch() {
10141014

10151015
try {
1016+
String cleanupScriptPath = cwsInstallDir + "/clean_es_history.sh";
1017+
File cleanupScript = new File(cleanupScriptPath);
1018+
1019+
// Check if the script exists before attempting to run it
1020+
if (!cleanupScript.exists()) {
1021+
log.info("Elasticsearch cleanup script not found at " + cleanupScriptPath + " - skipping cleanup (Elasticsearch may not be configured)");
1022+
return;
1023+
}
10161024

10171025
log.debug("Cleaning up elasticsearch...");
10181026

1019-
java.lang.Process p = Runtime.getRuntime().exec(cwsInstallDir + "/clean_es_history.sh");
1027+
java.lang.Process p = Runtime.getRuntime().exec(cleanupScriptPath);
10201028

10211029
// Wait for the process to complete
10221030
//

install/example-cws-configuration.properties

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -114,6 +114,8 @@ metrics_publishing_interval=10
114114
cws_notification_emails=[AdminEmailAddresses(comma separated)]
115115

116116
# This allows CWS to use a user provided Elasticsearch service.
117+
# NOTE: Elasticsearch is now OPTIONAL. If you do not wish to use Elasticsearch,
118+
# you can skip these settings or leave elasticsearch_protocol empty.
117119
# If you wish to use an unsecured Elasticsearch host, you may do so
118120
# by specifying elasticsearch_use_auth=n below.
119121
# Also specify if your provided Elasticsearch is encrypted(HTTPS) or non-encrypted(HTTP)
@@ -122,6 +124,11 @@ cws_notification_emails=[AdminEmailAddresses(comma separated)]
122124
# or elasticsearch_protocol=https
123125
# or elasticsearch_protocol=HTTP
124126
# elasticsearch_protocol=HTTPS
127+
#
128+
# To skip Elasticsearch entirely, leave elasticsearch_protocol commented out or empty:
129+
# elasticsearch_protocol=
130+
#
131+
# Or configure with your Elasticsearch instance:
125132
elasticsearch_protocol=[YourElasticsearchProtocol]
126133
elasticsearch_host=[YourElasticsearchHost]
127134
elasticsearch_index_prefix=[YourElasticsearchIndexPrefix]

0 commit comments

Comments
 (0)