This is an automated email from the ASF dual-hosted git repository.
ptupitsyn pushed a commit to branch main
in repository https://gitbox.apache.org/repos/asf/ignite-3.git
The following commit(s) were added to refs/heads/main by this push:
new cf96fb5328 IGNITE-17754 Print REST API endpoint address on node start
(#1274)
cf96fb5328 is described below
commit cf96fb5328c4ff6c56f11a63e6103af25702c29b
Author: Aleksandr <[email protected]>
AuthorDate: Fri Nov 25 22:57:47 2022 +0800
IGNITE-17754 Print REST API endpoint address on node start (#1274)
* Write endpoint address to file on startup.
* Read address from file in the start script and print to stdout.
---
.../apache/ignite/internal/rest/RestComponent.java | 8 +-
.../component/ItRestAddressReportTest.java | 100 ++++++++++++++++++++
.../ignite-config-rest-port-not-default.json | 15 +++
.../org/apache/ignite/internal/app/IgniteImpl.java | 10 ++
.../internal/component/RestAddressReporter.java | 60 ++++++++++++
.../component/RestAddressReporterTest.java | 103 +++++++++++++++++++++
packaging/build.gradle | 2 +-
packaging/zip/ignite3db | 16 +++-
8 files changed, 308 insertions(+), 6 deletions(-)
diff --git
a/modules/rest/src/main/java/org/apache/ignite/internal/rest/RestComponent.java
b/modules/rest/src/main/java/org/apache/ignite/internal/rest/RestComponent.java
index 53c2991246..4ae58eeb3d 100644
---
a/modules/rest/src/main/java/org/apache/ignite/internal/rest/RestComponent.java
+++
b/modules/rest/src/main/java/org/apache/ignite/internal/rest/RestComponent.java
@@ -27,6 +27,8 @@ import io.swagger.v3.oas.annotations.info.Contact;
import io.swagger.v3.oas.annotations.info.Info;
import io.swagger.v3.oas.annotations.info.License;
import java.net.BindException;
+import java.net.InetAddress;
+import java.net.UnknownHostException;
import java.util.List;
import java.util.Map;
import org.apache.ignite.internal.logger.IgniteLogger;
@@ -192,6 +194,10 @@ public class RestComponent implements IgniteComponent {
throw new IgniteInternalException("RestComponent has not been
started");
}
- return LOCALHOST;
+ try {
+ return InetAddress.getLocalHost().getHostAddress();
+ } catch (UnknownHostException e) {
+ return LOCALHOST;
+ }
}
}
diff --git
a/modules/runner/src/integrationTest/java/org/apache/ignite/internal/component/ItRestAddressReportTest.java
b/modules/runner/src/integrationTest/java/org/apache/ignite/internal/component/ItRestAddressReportTest.java
new file mode 100644
index 0000000000..6e31bbe4ec
--- /dev/null
+++
b/modules/runner/src/integrationTest/java/org/apache/ignite/internal/component/ItRestAddressReportTest.java
@@ -0,0 +1,100 @@
+/*
+ * 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.ignite.internal.component;
+
+import static
org.apache.ignite.internal.testframework.matchers.CompletableFutureMatcher.willCompleteSuccessfully;
+import static org.hamcrest.MatcherAssert.assertThat;
+import static org.hamcrest.Matchers.equalTo;
+import static org.hamcrest.Matchers.is;
+
+import java.io.File;
+import java.net.InetAddress;
+import java.net.URI;
+import java.net.UnknownHostException;
+import java.nio.file.Files;
+import java.nio.file.Path;
+import java.util.List;
+import java.util.concurrent.CompletableFuture;
+import org.apache.ignite.Ignite;
+import org.apache.ignite.IgnitionManager;
+import org.apache.ignite.app.IgniteRunner;
+import org.apache.ignite.internal.runner.app.IgniteRunnerTest;
+import org.apache.ignite.internal.testframework.WorkDirectory;
+import org.apache.ignite.internal.testframework.WorkDirectoryExtension;
+import org.junit.jupiter.api.DisplayName;
+import org.junit.jupiter.api.Test;
+import org.junit.jupiter.api.extension.ExtendWith;
+
+/**
+ * Test that after Ignite is started there is a file with REST server address
in working directory.
+ */
+@ExtendWith(WorkDirectoryExtension.class)
+public class ItRestAddressReportTest {
+ private static final String NODE_NAME = "node";
+
+ @WorkDirectory
+ private Path workDir;
+
+ private static int cutPort(String retAddress) {
+ return Integer.parseInt(retAddress.split(":")[1]);
+ }
+
+ @Test
+ @DisplayName("Should report rest port to the file after RestComponent
started")
+ void restPortReportedToFile() throws Exception {
+ // Given configuration with rest port configured rest.port=10333,
rest.portRange=10
+ Path configPath =
Path.of(IgniteRunnerTest.class.getResource("/ignite-config-rest-port-not-default.json").toURI());
+
+ // When start node
+ CompletableFuture<Ignite> ign = IgniteRunner.start(
+ "--config-path", configPath.toAbsolutePath().toString(),
+ "--work-dir",
workDir.resolve(NODE_NAME).toAbsolutePath().toString(),
+ "--node-name", NODE_NAME
+ );
+ // And init cluster
+ IgnitionManager.init(NODE_NAME, List.of(NODE_NAME), "cluster");
+
+ // Then node is started
+ assertThat(ign, willCompleteSuccessfully());
+
+ // And there is a file in work dir with the rest address
+ File reportFile =
workDir.resolve(NODE_NAME).resolve("rest-address").toFile();
+ assertThat(reportFile.exists(), is(true));
+
+ // And the file contains valid rest server network address
+ URI restUri =
URI.create(Files.readString(workDir.resolve(NODE_NAME).resolve("rest-address")));
+ assertThat(restUri.getHost(), is(equalTo(getHostAddress())));
+ // And port is in configured range
+ int port = restUri.getPort();
+ assertThat(port >= 10333 && port < 10333 + 10, is(true));
+
+ // When stop node
+ IgnitionManager.stop(NODE_NAME);
+
+ // Then the file is removed
+ assertThat(reportFile.exists(), is(false));
+ }
+
+ private static String getHostAddress() {
+ try {
+ return InetAddress.getLocalHost().getHostAddress();
+ } catch (UnknownHostException e) {
+ return "localhost";
+ }
+ }
+}
diff --git
a/modules/runner/src/integrationTest/resources/ignite-config-rest-port-not-default.json
b/modules/runner/src/integrationTest/resources/ignite-config-rest-port-not-default.json
new file mode 100644
index 0000000000..bd4c4666f7
--- /dev/null
+++
b/modules/runner/src/integrationTest/resources/ignite-config-rest-port-not-default.json
@@ -0,0 +1,15 @@
+{
+ "network": {
+ "port": 3344,
+ "portRange": 10,
+ "nodeFinder": {
+ "netClusterNodes": [
+ "localhost:3344"
+ ]
+ }
+ },
+ "rest": {
+ "port": 10333,
+ "portRange": 10
+ }
+}
diff --git
a/modules/runner/src/main/java/org/apache/ignite/internal/app/IgniteImpl.java
b/modules/runner/src/main/java/org/apache/ignite/internal/app/IgniteImpl.java
index 8f6586f14b..bee5d6a461 100644
---
a/modules/runner/src/main/java/org/apache/ignite/internal/app/IgniteImpl.java
+++
b/modules/runner/src/main/java/org/apache/ignite/internal/app/IgniteImpl.java
@@ -18,6 +18,8 @@
package org.apache.ignite.internal.app;
import java.io.IOException;
+import java.net.InetAddress;
+import java.net.UnknownHostException;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.Paths;
@@ -40,6 +42,7 @@ import
org.apache.ignite.internal.cluster.management.raft.ClusterStateStorage;
import
org.apache.ignite.internal.cluster.management.raft.RocksDbClusterStateStorage;
import
org.apache.ignite.internal.cluster.management.rest.ClusterManagementRestFactory;
import
org.apache.ignite.internal.cluster.management.topology.LogicalTopologyImpl;
+import org.apache.ignite.internal.component.RestAddressReporter;
import org.apache.ignite.internal.components.LongJvmPauseDetector;
import org.apache.ignite.internal.compute.ComputeComponent;
import org.apache.ignite.internal.compute.ComputeComponentImpl;
@@ -235,6 +238,8 @@ public class IgniteImpl implements Ignite {
private final OutgoingSnapshotsManager outgoingSnapshotsManager;
+ private final RestAddressReporter restAddressReporter;
+
/**
* The Constructor.
*
@@ -347,6 +352,8 @@ public class IgniteImpl implements Ignite {
restComponent = createRestComponent(name);
+ restAddressReporter = new RestAddressReporter(workDir);
+
baselineMgr = new BaselineManager(
clusterCfgMgr,
metaStorageMgr,
@@ -522,6 +529,8 @@ public class IgniteImpl implements Ignite {
clusterSvc.updateMetadata(new NodeMetadata(restComponent.host(),
restComponent.port()));
+ restAddressReporter.writeReport(restAddress());
+
LOG.info("Components started, joining the cluster");
return cmgMgr.joinFuture()
@@ -614,6 +623,7 @@ public class IgniteImpl implements Ignite {
*/
public void stop() {
lifecycleManager.stopNode();
+ restAddressReporter.removeReport();
}
/** {@inheritDoc} */
diff --git
a/modules/runner/src/main/java/org/apache/ignite/internal/component/RestAddressReporter.java
b/modules/runner/src/main/java/org/apache/ignite/internal/component/RestAddressReporter.java
new file mode 100644
index 0000000000..9d389a230d
--- /dev/null
+++
b/modules/runner/src/main/java/org/apache/ignite/internal/component/RestAddressReporter.java
@@ -0,0 +1,60 @@
+/*
+ * 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.ignite.internal.component;
+
+import java.io.IOException;
+import java.nio.file.Files;
+import java.nio.file.Path;
+import org.apache.ignite.lang.ErrorGroups.Common;
+import org.apache.ignite.lang.IgniteException;
+import org.apache.ignite.network.NetworkAddress;
+
+/**
+ * Can write network address to file that could be used by other systems to
know on what port Ignite 3 REST server is started.
+ */
+public class RestAddressReporter {
+
+ private static final String REPORT_FILE_NAME = "rest-address";
+
+ private final Path workDir;
+
+ /** Main constructor that accept the root directory where report file will
be written. */
+ public RestAddressReporter(Path workDir) {
+ this.workDir = workDir;
+ }
+
+ /** Write network address to file. */
+ public void writeReport(NetworkAddress networkAddress) {
+ try {
+ Files.writeString(workDir.resolve(REPORT_FILE_NAME), "http://" +
networkAddress.host() + ":" + networkAddress.port());
+ } catch (IOException e) {
+ String message = "Unexpected error when trying to write REST
server network address to file";
+ throw new IgniteException(Common.UNEXPECTED_ERR, message, e);
+ }
+ }
+
+ /** Remove report file. The method is expected to be called on node stop.
*/
+ public void removeReport() {
+ try {
+ Files.delete(workDir.resolve(REPORT_FILE_NAME));
+ } catch (IOException e) {
+ String message = "Unexpected error when trying to remove REST
server network address file";
+ throw new IgniteException(Common.UNEXPECTED_ERR, message, e);
+ }
+ }
+}
diff --git
a/modules/runner/src/test/java/org/apache/ignite/internal/component/RestAddressReporterTest.java
b/modules/runner/src/test/java/org/apache/ignite/internal/component/RestAddressReporterTest.java
new file mode 100644
index 0000000000..654e325863
--- /dev/null
+++
b/modules/runner/src/test/java/org/apache/ignite/internal/component/RestAddressReporterTest.java
@@ -0,0 +1,103 @@
+/*
+ * 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.ignite.internal.component;
+
+import static org.hamcrest.MatcherAssert.assertThat;
+import static org.hamcrest.Matchers.containsString;
+import static org.hamcrest.Matchers.equalTo;
+import static org.hamcrest.Matchers.is;
+import static org.junit.jupiter.api.Assertions.assertThrows;
+
+import java.io.IOException;
+import java.nio.file.Files;
+import java.nio.file.Path;
+import org.apache.ignite.lang.ErrorGroups.Common;
+import org.apache.ignite.lang.IgniteException;
+import org.apache.ignite.network.NetworkAddress;
+import org.junit.jupiter.api.DisplayName;
+import org.junit.jupiter.api.Test;
+import org.junit.jupiter.api.io.TempDir;
+
+/** Test for {@link RestAddressReporter}. */
+class RestAddressReporterTest {
+
+ private static final String REST_ADDRESS_FILENAME = "rest-address";
+
+ @Test
+ @DisplayName("REST server network address is reported to file")
+ void networkAddressReported(@TempDir Path tmpDir) throws IOException {
+ // Given
+ RestAddressReporter reporter = new RestAddressReporter(tmpDir);
+
+ // When
+ reporter.writeReport(new NetworkAddress("localhost", 9999));
+
+ // Then there is a report
+ String restAddress =
Files.readString(tmpDir.resolve(REST_ADDRESS_FILENAME));
+ assertThat(restAddress, equalTo("http://localhost:9999"));
+ }
+
+ @Test
+ @DisplayName("File with network address is removed")
+ void reportDeleted(@TempDir Path tmpDir) throws IOException {
+ // Given reported address
+ RestAddressReporter reporter = new RestAddressReporter(tmpDir);
+ reporter.writeReport(new NetworkAddress("localhost", 9999));
+ // And file exists
+ assertThat(Files.exists(tmpDir.resolve(REST_ADDRESS_FILENAME)),
is(true));
+
+ // When
+ reporter.removeReport();
+
+ // Then file is removed
+ assertThat(Files.exists(tmpDir.resolve(REST_ADDRESS_FILENAME)),
is(false));
+ }
+
+ @Test
+ @DisplayName("If there is no report file for some reason then throw an
exception")
+ void throwsExceptionWhenThereIsNoFile(@TempDir Path tmpDir) {
+ // Given
+ Path path = Path.of(tmpDir.toUri() + "/nosuchpath");
+ RestAddressReporter reporter = new RestAddressReporter(path);
+
+ // When try to removeReport
+ IgniteException thrown = assertThrows(IgniteException.class,
reporter::removeReport);
+
+ // Then exception thrown with proper message
+ assertThat(thrown.getMessage(), containsString("Unexpected error when
trying to remove REST server network address file"));
+ // And it has COMMON error group
+ assertThat(thrown.groupName(),
equalTo(Common.COMMON_ERR_GROUP.name()));
+ }
+
+ @Test
+ @DisplayName("If there is a file with report then it should be rewritten")
+ void rewritesAlreadyExistingFile(@TempDir Path tmpDir) throws IOException {
+ // Given reported address to file
+ Files.writeString(
+ tmpDir.resolve(REST_ADDRESS_FILENAME),
+ new NetworkAddress("localhost", 9999).toString()
+ );
+
+ // When try to write it again but with another port
+ new RestAddressReporter(tmpDir).writeReport(new
NetworkAddress("localhost", 4444));
+
+ // Then file rewritten
+ String restAddress =
Files.readString(tmpDir.resolve(REST_ADDRESS_FILENAME));
+ assertThat(restAddress, equalTo("http://localhost:4444"));
+ }
+}
diff --git a/packaging/build.gradle b/packaging/build.gradle
index 5c013bcf9b..1aa3bfb03e 100644
--- a/packaging/build.gradle
+++ b/packaging/build.gradle
@@ -137,4 +137,4 @@ task buildAndSignAllSrcZip(type: Sign) {
signing {
sign allDistZip
-}
\ No newline at end of file
+}
diff --git a/packaging/zip/ignite3db b/packaging/zip/ignite3db
index 9e90f2fdd2..898af35d36 100755
--- a/packaging/zip/ignite3db
+++ b/packaging/zip/ignite3db
@@ -17,11 +17,10 @@
# limitations under the License.
#
-SCRIPT=$(readlink -f "$0")
-SCRIPT_DIR=$(dirname "$SCRIPT")
+SCRIPT_DIR=$(dirname "$0")
-cd ${SCRIPT_DIR} || exit
-cd .. # SCRIPT_DIR points at bin
+cd ${SCRIPT_DIR} || exit # SCRIPT_DIR points at bin
+cd .. # now SCRIPT_DIR points at parent dir for bin
# if IGNITE_HOME is not set than it will be parent directory for bin
if [ -z ${IGNITE_HOME+x} ]; then IGNITE_HOME=$(pwd); fi
@@ -33,12 +32,21 @@ if [ -z ${IGNITE_HOME+x} ]; then IGNITE_HOME=$(pwd); fi
cd ${IGNITE_HOME} || exit
start() {
+ echo "Starting Ignite 3..."
+
CMD="${JAVA_CMD_WITH_ARGS} ${APPLICATION_ARGS}"
$CMD >>/dev/null 2>&1 </dev/null & echo $! >${IGNITE_HOME}/pid
+
+ rest_address_file=${WORK_DIR}/rest-address
+ while [ ! -f "$rest_address_file" ]; do sleep 0.5; done
+ rest_address=$(cat "$rest_address_file")
+
+ echo "Node named ${NODE_NAME} started successfully. REST address is
$rest_address"
}
stop() {
kill -9 "$(cat ${IGNITE_HOME}/pid)"
+ rm ${WORK_DIR}/rest-address
}
case $1 in