This is an automated email from the ASF dual-hosted git repository.
frankgh pushed a commit to branch trunk
in repository https://gitbox.apache.org/repos/asf/cassandra-sidecar.git
The following commit(s) were added to refs/heads/trunk by this push:
new 995d1683 CASSSIDECAR-122: yaml configuration defaults to a file that
doesn't e… (#153)
995d1683 is described below
commit 995d1683eb688a75d53cbaef4b1507905dcf24e0
Author: Francisco Guerrero <[email protected]>
AuthorDate: Fri Dec 6 13:02:34 2024 -0800
CASSSIDECAR-122: yaml configuration defaults to a file that doesn't e…
(#153)
* CASSSIDECAR-122: yaml configuration defaults to a file that doesn't exist
Patch by Francisco Guerrero; Reviewed by Jon Haddad, Yifan Cai for
CASSSIDECAR-122
---
CHANGES.txt | 1 +
build.gradle | 32 ++--
{server/src/main/dist/conf => conf}/logback.xml | 0
{server/src/main/dist/conf => conf}/sidecar.yaml | 0
.../cassandra/sidecar/CassandraSidecarDaemon.java | 53 +++++--
.../sidecar/CassandraSidecarDaemonTest.java | 173 +++++++++++++++++++++
.../cassandra/sidecar/server/ServerTest.java | 2 +-
... => sidecar_single_instance_non_zero_port.yaml} | 2 +-
8 files changed, 233 insertions(+), 30 deletions(-)
diff --git a/CHANGES.txt b/CHANGES.txt
index d790c1b5..9ae24873 100644
--- a/CHANGES.txt
+++ b/CHANGES.txt
@@ -1,5 +1,6 @@
1.0.0
-----
+ * yaml configuration defaults to a file that doesn't exist (CASSSIDECAR-122)
* Add advanced driver settings to allow taking in password or certificates
for Cassandra connection (CASSSIDECAR-159)
* Add metric to report consistency check duration (CASSSIDECAR-165)
* Add mTLS Authentication in Sidecar (CASSANDRASC-156)
diff --git a/build.gradle b/build.gradle
index 52e53116..12ac1b8c 100644
--- a/build.gradle
+++ b/build.gradle
@@ -131,7 +131,14 @@ distributions {
main {
contents {
from 'LICENSE.txt'
- from 'server/src/main/dist'
+ // Include the "agents" directory in the distribution
+ from('agents') {
+ into('agents')
+ }
+ // Include the "conf" directory in the distribution
+ from('conf') {
+ into('conf')
+ }
}
}
}
@@ -171,26 +178,22 @@ tasks.named('idea').configure {
dependsOn copyIdeaSettings
}
-// Lets copy the distributions from build/install directory to /bin and /lib
-// directories to be aligned with C* distribution format
-tasks.register('copyDist', Copy) {
- from "$buildDir/install/$applicationName"
+tasks.register('copyJolokia', Copy) {
into "$projectDir"
-}
-tasks.register('copyJolokia', Copy) {
- from configurations.jolokia
- into "$projectDir/src/main/dist/agents"
+ into("agents") {
+ from configurations.jolokia
+ }
}
// Lets clean distribution directories along with default build directories.
clean.doLast {
- ["agents", "bin", "conf", "lib"].each {
+ ["agents"].each {
println "Deleting directory $projectDir/$it"
delete "$projectDir/$it"
}
- println "Deleting generated docs $projectDir/src/main/resources/docs"
- delete "$projectDir/src/main/resources/docs"
+ println "Deleting generated docs
$projectDir/server/src/main/resources/docs"
+ delete "$projectDir/server/src/main/resources/docs"
}
subprojects {
@@ -287,10 +290,9 @@ rat {
reportDir.set(file("build/reports/rat"))
}
-// copyDist gets called on every build
-copyDist.dependsOn installDist, copyJolokia
+installDist.dependsOn copyJolokia
check.dependsOn codeCheckTasks
-build.dependsOn copyDist, copyJolokia, copyDocs
+build.dependsOn copyJolokia, copyDocs
run.dependsOn build
tasks.named('rat').configure {
diff --git a/server/src/main/dist/conf/logback.xml b/conf/logback.xml
similarity index 100%
rename from server/src/main/dist/conf/logback.xml
rename to conf/logback.xml
diff --git a/server/src/main/dist/conf/sidecar.yaml b/conf/sidecar.yaml
similarity index 100%
rename from server/src/main/dist/conf/sidecar.yaml
rename to conf/sidecar.yaml
diff --git
a/server/src/main/java/org/apache/cassandra/sidecar/CassandraSidecarDaemon.java
b/server/src/main/java/org/apache/cassandra/sidecar/CassandraSidecarDaemon.java
index fd020a22..276282f3 100644
---
a/server/src/main/java/org/apache/cassandra/sidecar/CassandraSidecarDaemon.java
+++
b/server/src/main/java/org/apache/cassandra/sidecar/CassandraSidecarDaemon.java
@@ -19,6 +19,7 @@
package org.apache.cassandra.sidecar;
import java.net.URI;
+import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.util.concurrent.TimeUnit;
@@ -29,6 +30,7 @@ import org.slf4j.LoggerFactory;
import com.google.inject.Guice;
import org.apache.cassandra.sidecar.server.MainModule;
import org.apache.cassandra.sidecar.server.Server;
+import org.jetbrains.annotations.VisibleForTesting;
/**
* Main class for initiating the Cassandra sidecar
@@ -37,23 +39,15 @@ import org.apache.cassandra.sidecar.server.Server;
public class CassandraSidecarDaemon
{
private static final Logger LOGGER =
LoggerFactory.getLogger(CassandraSidecarDaemon.class);
+ @VisibleForTesting
+ static Server runningApplication;
public static void main(String[] args)
{
- String yamlConfigurationPath = System.getProperty("sidecar.config",
"file://./conf/config.yaml");
-
- Path confPath;
- try
- {
- confPath = Paths.get(new URI(yamlConfigurationPath));
- }
- catch (Throwable e)
- {
- throw new RuntimeException("Invalid URI: " +
yamlConfigurationPath, e);
- }
+ Path confPath = determineConfigPath();
Server app = Guice.createInjector(new
MainModule(confPath)).getInstance(Server.class);
-
+ runningApplication = app;
app.start().onSuccess(deploymentId ->
Runtime.getRuntime().addShutdownHook(new Thread(() -> {
if (close(app))
{
@@ -72,7 +66,8 @@ public class CassandraSidecarDaemon
* @param app the server
* @return {@code true} if the server shutdown successfully, {@code false}
otherwise
*/
- private static boolean close(Server app)
+ @VisibleForTesting
+ static boolean close(Server app)
{
try
{
@@ -88,5 +83,37 @@ public class CassandraSidecarDaemon
}
return false;
}
+
+ private static Path determineConfigPath()
+ {
+ Path confPath;
+ String yamlConfigurationPath = System.getProperty("sidecar.config");
+ if (yamlConfigurationPath != null)
+ {
+ try
+ {
+ confPath = Paths.get(new URI(yamlConfigurationPath));
+ }
+ catch (Throwable e)
+ {
+ throw new IllegalArgumentException("Invalid URI: " +
yamlConfigurationPath, e);
+ }
+ }
+ else
+ {
+ confPath = Paths.get("conf/sidecar.yaml");
+ }
+ return ensurePathExists(confPath);
+ }
+
+ private static Path ensurePathExists(Path confPath)
+ {
+ if (!Files.exists(confPath))
+ {
+ throw new IllegalArgumentException(String.format("Sidecar
configuration file '%s' does not exist",
+
confPath.toAbsolutePath()));
+ }
+ return confPath;
+ }
}
diff --git
a/server/src/test/java/org/apache/cassandra/sidecar/CassandraSidecarDaemonTest.java
b/server/src/test/java/org/apache/cassandra/sidecar/CassandraSidecarDaemonTest.java
new file mode 100644
index 00000000..bad370ae
--- /dev/null
+++
b/server/src/test/java/org/apache/cassandra/sidecar/CassandraSidecarDaemonTest.java
@@ -0,0 +1,173 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.apache.cassandra.sidecar;
+
+import java.io.IOException;
+import java.nio.file.Files;
+import java.nio.file.Path;
+import java.nio.file.Paths;
+import java.util.ArrayList;
+import java.util.List;
+import java.util.concurrent.TimeUnit;
+
+import org.junit.jupiter.api.BeforeEach;
+import org.junit.jupiter.api.Test;
+
+import io.vertx.core.Vertx;
+import io.vertx.ext.web.client.HttpResponse;
+import io.vertx.ext.web.client.WebClient;
+import io.vertx.ext.web.codec.BodyCodec;
+import org.apache.cassandra.sidecar.server.Server;
+
+import static io.netty.handler.codec.http.HttpResponseStatus.OK;
+import static org.assertj.core.api.Assertions.assertThat;
+import static
org.assertj.core.api.Assertions.assertThatIllegalArgumentException;
+
+/**
+ * Unit tests for the {@link CassandraSidecarDaemon}
+ */
+class CassandraSidecarDaemonTest
+{
+ static final String[] NO_ARGS = {};
+
+ @BeforeEach
+ void setup()
+ {
+ System.clearProperty("sidecar.config");
+ }
+
+ @Test
+ void testStartFailsWithInvalidURI()
+ {
+ System.setProperty("sidecar.config", "file://./invalid/URI");
+
+ assertThatIllegalArgumentException().isThrownBy(() ->
CassandraSidecarDaemon.main(NO_ARGS))
+ .withMessage("Invalid URI:
file://./invalid/URI");
+ }
+
+ @Test
+ void testStartFailsWithNonExistentFile()
+ {
+ System.setProperty("sidecar.config",
"file:///tmp/file/does/not/exist.yaml");
+
+ assertThatIllegalArgumentException().isThrownBy(() ->
CassandraSidecarDaemon.main(NO_ARGS))
+ .withMessage("Sidecar
configuration file '/tmp/file/does/not/exist.yaml' does not exist");
+ }
+
+ @Test
+ void testSuccessfulStartup() throws Exception
+ {
+ Path path = Paths.get("../conf/sidecar.yaml");
+ assertThat(path).exists();
+
+ System.setProperty("sidecar.config", path.toUri().toString());
+ try
+ {
+ CassandraSidecarDaemon.main(NO_ARGS);
+
+ WebClient client = WebClient.create(Vertx.vertx());
+ HttpResponse<String> response = client.get(9043, "localhost",
"/api/v1/__health")
+ .as(BodyCodec.string())
+ .send()
+ .toCompletionStage()
+ .toCompletableFuture()
+ .get(10, TimeUnit.SECONDS);
+ assertThat(response.statusCode()).isEqualTo(OK.code());
+ assertThat(response.body()).isEqualTo("{\"status\":\"OK\"}");
+ }
+ finally
+ {
+ maybeStopCassandraSidecar();
+ }
+ }
+
+ @Test
+ void testSuccessfulStartupWithDefaultPath() throws Exception
+ {
+ Path path = Paths.get("../conf/sidecar.yaml");
+ assertThat(path).exists();
+
+ // First ensure startup fails because the conf file does not exist
+ assertThatIllegalArgumentException().isThrownBy(() ->
CassandraSidecarDaemon.main(NO_ARGS))
+ .withMessageMatching("Sidecar
configuration file '.*/conf/sidecar.yaml' does not exist");
+
+ // Now let's copy the file to the expected location
+ Path targetFile = Paths.get("conf/sidecar.yaml");
+ List<Path> createdParents = null;
+
+ try
+ {
+ createdParents = createParents(targetFile.toAbsolutePath());
+ Files.copy(path.toAbsolutePath(), targetFile.toAbsolutePath());
+
+ CassandraSidecarDaemon.main(NO_ARGS);
+
+ WebClient client = WebClient.create(Vertx.vertx());
+ HttpResponse<String> response = client.get(9043, "localhost",
"/api/v1/__health")
+ .as(BodyCodec.string())
+ .send()
+ .toCompletionStage()
+ .toCompletableFuture()
+ .get(10, TimeUnit.SECONDS);
+ assertThat(response.statusCode()).isEqualTo(OK.code());
+ assertThat(response.body()).isEqualTo("{\"status\":\"OK\"}");
+ }
+ finally
+ {
+ maybeStopCassandraSidecar();
+ Files.deleteIfExists(targetFile);
+
+ if (createdParents != null)
+ {
+ for (Path createdParent : createdParents)
+ {
+ Files.deleteIfExists(createdParent);
+ }
+ }
+ }
+ }
+
+ static void maybeStopCassandraSidecar()
+ {
+ Server runningApplication = CassandraSidecarDaemon.runningApplication;
+ if (runningApplication != null)
+ {
+ CassandraSidecarDaemon.close(runningApplication);
+ }
+ }
+
+ static List<Path> createParents(Path file) throws IOException
+ {
+ List<Path> createdParents = new ArrayList<>();
+ Path parentDirectory = file.getParent();
+ if (parentDirectory == null)
+ {
+ return createdParents;
+ }
+ Path directory = parentDirectory;
+
+ while (directory != null && !Files.exists(directory))
+ {
+ createdParents.add(directory);
+ directory = directory.getParent();
+ }
+ Files.createDirectories(parentDirectory);
+ return createdParents;
+ }
+}
diff --git
a/server/src/test/java/org/apache/cassandra/sidecar/server/ServerTest.java
b/server/src/test/java/org/apache/cassandra/sidecar/server/ServerTest.java
index 53dfd2e3..e294cd50 100644
--- a/server/src/test/java/org/apache/cassandra/sidecar/server/ServerTest.java
+++ b/server/src/test/java/org/apache/cassandra/sidecar/server/ServerTest.java
@@ -200,7 +200,7 @@ class ServerTest
@DisplayName("Updating traffic shaping options with non-zero listen port
should succeed")
void updateTrafficShapingOptionsWithNonZeroListenPort()
{
- configureServer("config/sidecar_single_instance_default_port.yaml");
+ configureServer("config/sidecar_single_instance_non_zero_port.yaml");
assertThatNoException().isThrownBy(() -> {
server.start().toCompletionStage().toCompletableFuture().get(30,
TimeUnit.SECONDS);
diff --git
a/server/src/test/resources/config/sidecar_single_instance_default_port.yaml
b/server/src/test/resources/config/sidecar_single_instance_non_zero_port.yaml
similarity index 99%
rename from
server/src/test/resources/config/sidecar_single_instance_default_port.yaml
rename to
server/src/test/resources/config/sidecar_single_instance_non_zero_port.yaml
index 5e3d5b2d..de40d57c 100644
--- a/server/src/test/resources/config/sidecar_single_instance_default_port.yaml
+++
b/server/src/test/resources/config/sidecar_single_instance_non_zero_port.yaml
@@ -16,7 +16,7 @@ cassandra:
sidecar:
host: 0.0.0.0
- port: 9043
+ port: 9046
request_idle_timeout_millis: 300000 # this field expects integer value
request_timeout_millis: 300000
tcp_keep_alive: false
---------------------------------------------------------------------
To unsubscribe, e-mail: [email protected]
For additional commands, e-mail: [email protected]