You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@ignite.apache.org by ap...@apache.org on 2023/09/22 13:32:31 UTC

[ignite-3] branch main updated: IGNITE 20434 Provide jdbc port in Node Info REST API (#2607)

This is an automated email from the ASF dual-hosted git repository.

apkhmv 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 d30ca93c56 IGNITE 20434 Provide jdbc port in Node Info REST API (#2607)
d30ca93c56 is described below

commit d30ca93c569c8bcc6f88153924634467349a1d89
Author: Dmitry Baranov <ne...@gmail.com>
AuthorDate: Fri Sep 22 16:32:26 2023 +0300

    IGNITE 20434 Provide jdbc port in Node Info REST API (#2607)
---
 .../cli/call/connect/ConnectionChecker.java        |  9 +++--
 .../ignite/internal/cli/core/JdbcUrlFactory.java   |  9 ++---
 .../repl/registry/impl/JdbcUrlRegistryImpl.java    | 10 +++---
 .../internal/cli/core/JdbcUrlFactoryTest.java      | 10 +++---
 modules/rest-api/openapi/openapi.yaml              | 33 +++++++++++++++++++
 .../api/node/{NodeState.java => NodeInfo.java}     | 25 +++++++-------
 .../internal/rest/api/node/NodeManagementApi.java  | 10 ++++++
 .../ignite/internal/rest/api/node/NodeState.java   |  3 ++
 .../internal/rest/node/JdbcPortProvider.java       | 26 +++++++++++++++
 .../rest/node/NodeManagementController.java        | 14 +++++++-
 .../rest/node/NodeManagementRestFactory.java       | 15 ++++++++-
 .../ignite/internal/deployment/DeployFiles.java    |  2 +-
 .../deployment/ItDeploymentUnitFailoverTest.java   |  2 +-
 .../org/apache/ignite/internal/app/IgniteImpl.java |  4 ++-
 .../configuration/JdbcPortProviderImpl.java        | 38 ++++++++++++++++++++++
 15 files changed, 172 insertions(+), 38 deletions(-)

diff --git a/modules/cli/src/main/java/org/apache/ignite/internal/cli/call/connect/ConnectionChecker.java b/modules/cli/src/main/java/org/apache/ignite/internal/cli/call/connect/ConnectionChecker.java
index 5b7e07b6a6..00275ff8ba 100644
--- a/modules/cli/src/main/java/org/apache/ignite/internal/cli/call/connect/ConnectionChecker.java
+++ b/modules/cli/src/main/java/org/apache/ignite/internal/cli/call/connect/ConnectionChecker.java
@@ -33,10 +33,10 @@ import org.apache.ignite.internal.cli.core.repl.SessionInfo;
 import org.apache.ignite.internal.cli.core.rest.ApiClientFactory;
 import org.apache.ignite.internal.cli.core.rest.ApiClientSettings;
 import org.apache.ignite.internal.cli.core.rest.ApiClientSettingsBuilder;
-import org.apache.ignite.rest.client.api.NodeConfigurationApi;
 import org.apache.ignite.rest.client.api.NodeManagementApi;
 import org.apache.ignite.rest.client.invoker.ApiClient;
 import org.apache.ignite.rest.client.invoker.ApiException;
+import org.apache.ignite.rest.client.model.NodeInfo;
 
 /**
  * Checks connection to the Ignite3 node. Creates {@link SessionInfo} on success.
@@ -94,11 +94,10 @@ public class ConnectionChecker {
     private SessionInfo checkConnection(ApiClientSettings apiClientSettings) throws ApiException {
         ApiClient apiClient = ApiClientFactory.buildClient(apiClientSettings);
 
-        String configuration = new NodeConfigurationApi(apiClient).getNodeConfiguration();
-        String nodeName = new NodeManagementApi(apiClient).nodeState().getName();
-        String jdbcUrl = jdbcUrlFactory.constructJdbcUrl(configuration, apiClientSettings.basePath());
+        NodeInfo nodeInfo = new NodeManagementApi(apiClient).nodeInfo();
+        String jdbcUrl = jdbcUrlFactory.constructJdbcUrl(apiClientSettings.basePath(), nodeInfo.getJdbcPort());
         return SessionInfo.builder().nodeUrl(apiClientSettings.basePath())
-                .nodeName(nodeName).jdbcUrl(jdbcUrl).username(apiClientSettings.basicAuthenticationUsername()).build();
+                .nodeName(nodeInfo.getName()).jdbcUrl(jdbcUrl).username(apiClientSettings.basicAuthenticationUsername()).build();
     }
 
     /**
diff --git a/modules/cli/src/main/java/org/apache/ignite/internal/cli/core/JdbcUrlFactory.java b/modules/cli/src/main/java/org/apache/ignite/internal/cli/core/JdbcUrlFactory.java
index 6fe03f514e..8693119317 100644
--- a/modules/cli/src/main/java/org/apache/ignite/internal/cli/core/JdbcUrlFactory.java
+++ b/modules/cli/src/main/java/org/apache/ignite/internal/cli/core/JdbcUrlFactory.java
@@ -26,7 +26,6 @@ import static org.apache.ignite.internal.cli.config.CliConfigKeys.JDBC_SSL_ENABL
 import static org.apache.ignite.internal.cli.config.CliConfigKeys.JDBC_TRUST_STORE_PASSWORD;
 import static org.apache.ignite.internal.cli.config.CliConfigKeys.JDBC_TRUST_STORE_PATH;
 
-import com.google.gson.Gson;
 import jakarta.inject.Singleton;
 import java.net.MalformedURLException;
 import java.net.URL;
@@ -36,7 +35,6 @@ import java.util.stream.Collectors;
 import org.apache.ignite.internal.cli.config.CliConfigKeys;
 import org.apache.ignite.internal.cli.config.ConfigManager;
 import org.apache.ignite.internal.cli.config.ConfigManagerProvider;
-import org.apache.ignite.internal.cli.core.repl.config.RootConfig;
 import org.apache.ignite.lang.util.StringUtils;
 import org.jetbrains.annotations.Nullable;
 
@@ -51,16 +49,15 @@ public class JdbcUrlFactory {
     }
 
     /**
-     * Constructs JDBC URL from node URL, port taken from the node configuration, SSL and basic authentication properties from the config.
+     * Constructs JDBC URL from node URL and port, SSL and basic authentication properties from the config.
      *
-     * @param configuration Node configuration in HOCON format.
      * @param nodeUrl Node URL.
+     * @param port client port.
      * @return JDBC URL.
      */
     @Nullable
-    public String constructJdbcUrl(String configuration, String nodeUrl) {
+    public String constructJdbcUrl(String nodeUrl, int port) {
         try {
-            int port = new Gson().fromJson(configuration, RootConfig.class).clientConnector.port;
             String host = new URL(nodeUrl).getHost();
             return applyConfig("jdbc:ignite:thin://" + host + ":" + port);
         } catch (MalformedURLException ignored) {
diff --git a/modules/cli/src/main/java/org/apache/ignite/internal/cli/core/repl/registry/impl/JdbcUrlRegistryImpl.java b/modules/cli/src/main/java/org/apache/ignite/internal/cli/core/repl/registry/impl/JdbcUrlRegistryImpl.java
index 8dc499df19..2d3df416c7 100644
--- a/modules/cli/src/main/java/org/apache/ignite/internal/cli/core/repl/registry/impl/JdbcUrlRegistryImpl.java
+++ b/modules/cli/src/main/java/org/apache/ignite/internal/cli/core/repl/registry/impl/JdbcUrlRegistryImpl.java
@@ -29,8 +29,9 @@ import org.apache.ignite.internal.cli.core.repl.registry.NodeNameRegistry;
 import org.apache.ignite.internal.cli.core.rest.ApiClientFactory;
 import org.apache.ignite.internal.cli.logger.CliLoggers;
 import org.apache.ignite.internal.logger.IgniteLogger;
-import org.apache.ignite.rest.client.api.NodeConfigurationApi;
+import org.apache.ignite.rest.client.api.NodeManagementApi;
 import org.apache.ignite.rest.client.invoker.ApiException;
+import org.apache.ignite.rest.client.model.NodeInfo;
 import org.jetbrains.annotations.Nullable;
 
 /** Implementation of {@link JdbcUrlRegistry}. */
@@ -77,14 +78,11 @@ public class JdbcUrlRegistryImpl implements JdbcUrlRegistry, PeriodicSessionTask
     @Nullable
     private String fetchJdbcUrl(String nodeUrl) {
         try {
-            return jdbcUrlFactory.constructJdbcUrl(fetchNodeConfiguration(nodeUrl), nodeUrl);
+            NodeInfo nodeInfo = new NodeManagementApi(clientFactory.getClient(nodeUrl)).nodeInfo();
+            return jdbcUrlFactory.constructJdbcUrl(nodeUrl, nodeInfo.getJdbcPort());
         } catch (ApiException e) {
             LOG.warn("Couldn't fetch jdbc url of " + nodeUrl + " node: ", e);
             return null;
         }
     }
-
-    private String fetchNodeConfiguration(String nodeUrl) throws ApiException {
-        return new NodeConfigurationApi(clientFactory.getClient(nodeUrl)).getNodeConfiguration();
-    }
 }
diff --git a/modules/cli/src/test/java/org/apache/ignite/internal/cli/core/JdbcUrlFactoryTest.java b/modules/cli/src/test/java/org/apache/ignite/internal/cli/core/JdbcUrlFactoryTest.java
index 5fed2f0c62..b626afa008 100644
--- a/modules/cli/src/test/java/org/apache/ignite/internal/cli/core/JdbcUrlFactoryTest.java
+++ b/modules/cli/src/test/java/org/apache/ignite/internal/cli/core/JdbcUrlFactoryTest.java
@@ -37,7 +37,7 @@ class JdbcUrlFactoryTest {
         // Given default config
 
         // Then JDBC URL is constructed without SSL settings
-        String jdbcUrl = factory.constructJdbcUrl("{clientConnector:{port:10800}}", "http://localhost:10300");
+        String jdbcUrl = factory.constructJdbcUrl("http://localhost:10300", 10800);
         assertEquals("jdbc:ignite:thin://localhost:10800", jdbcUrl);
     }
 
@@ -47,7 +47,7 @@ class JdbcUrlFactoryTest {
         configManagerProvider.setConfigFile(createIntegrationTestsConfig(), createJdbcTestsSslSecretConfig());
 
         // Then JDBC URL is constructed with SSL settings
-        String jdbcUrl = factory.constructJdbcUrl("{clientConnector:{port:10800}}", "http://localhost:10300");
+        String jdbcUrl = factory.constructJdbcUrl("http://localhost:10300", 10800);
         String expectedJdbcUrl = "jdbc:ignite:thin://localhost:10800"
                 + "?sslEnabled=true"
                 + "&trustStorePath=ssl/truststore.jks"
@@ -64,7 +64,7 @@ class JdbcUrlFactoryTest {
         configManagerProvider.configManager.setProperty(CliConfigKeys.JDBC_SSL_ENABLED.value(), "true");
 
         // Then JDBC URL is constructed with SSL settings
-        String jdbcUrl = factory.constructJdbcUrl("{clientConnector:{port:10800}}", "http://localhost:10300");
+        String jdbcUrl = factory.constructJdbcUrl("http://localhost:10300", 10800);
         String expectedJdbcUrl = "jdbc:ignite:thin://localhost:10800"
                 + "?sslEnabled=true"
                 + "&trustStorePath=ssl/truststore.jks"
@@ -80,7 +80,7 @@ class JdbcUrlFactoryTest {
         configManagerProvider.setConfigFile(createIntegrationTestsConfig(), createJdbcTestsBasicSecretConfig());
 
         // Then JDBC URL is constructed with basic authentication settings
-        String jdbcUrl = factory.constructJdbcUrl("{clientConnector:{port:10800}}", "http://localhost:10300");
+        String jdbcUrl = factory.constructJdbcUrl("http://localhost:10300", 10800);
         String expectedJdbcUrl = "jdbc:ignite:thin://localhost:10800"
                 + "?basicAuthenticationUsername=admin"
                 + "&basicAuthenticationPassword=password";
@@ -93,7 +93,7 @@ class JdbcUrlFactoryTest {
         configManagerProvider.setConfigFile(createIntegrationTestsConfig(), createJdbcTestsSslBasicSecretConfig());
 
         // Then JDBC URL is constructed with SSL and basic authentication settings
-        String jdbcUrl = factory.constructJdbcUrl("{clientConnector:{port:10800}}", "http://localhost:10300");
+        String jdbcUrl = factory.constructJdbcUrl("http://localhost:10300", 10800);
         String expectedJdbcUrl = "jdbc:ignite:thin://localhost:10800"
                 + "?sslEnabled=true"
                 + "&trustStorePath=ssl/truststore.jks"
diff --git a/modules/rest-api/openapi/openapi.yaml b/modules/rest-api/openapi/openapi.yaml
index 24727400aa..1b2f39f785 100644
--- a/modules/rest-api/openapi/openapi.yaml
+++ b/modules/rest-api/openapi/openapi.yaml
@@ -677,6 +677,25 @@ paths:
             application/problem+json:
               schema:
                 $ref: '#/components/schemas/Problem'
+  /management/v1/node/info:
+    get:
+      tags:
+      - nodeManagement
+      description: Gets node info.
+      operationId: nodeInfo
+      responses:
+        "200":
+          description: Node info.
+          content:
+            application/json:
+              schema:
+                $ref: '#/components/schemas/NodeInfo'
+        "500":
+          description: Internal error.
+          content:
+            application/problem+json:
+              schema:
+                $ref: '#/components/schemas/Problem'
   /management/v1/node/state:
     get:
       tags:
@@ -862,6 +881,20 @@ components:
           description: Port the node runs on.
           format: int32
       description: Node network address information.
+    NodeInfo:
+      required:
+      - jdbcPort
+      - name
+      type: object
+      properties:
+        name:
+          type: string
+          description: Unique node name.
+        jdbcPort:
+          type: integer
+          description: Node JDBC port.
+          format: int32
+      description: Node info.
     NodeMetadata:
       type: object
       properties:
diff --git a/modules/rest-api/src/main/java/org/apache/ignite/internal/rest/api/node/NodeState.java b/modules/rest-api/src/main/java/org/apache/ignite/internal/rest/api/node/NodeInfo.java
similarity index 74%
copy from modules/rest-api/src/main/java/org/apache/ignite/internal/rest/api/node/NodeState.java
copy to modules/rest-api/src/main/java/org/apache/ignite/internal/rest/api/node/NodeInfo.java
index ee5c2dc957..a952263536 100644
--- a/modules/rest-api/src/main/java/org/apache/ignite/internal/rest/api/node/NodeState.java
+++ b/modules/rest-api/src/main/java/org/apache/ignite/internal/rest/api/node/NodeInfo.java
@@ -24,21 +24,24 @@ import io.swagger.v3.oas.annotations.media.Schema;
 import io.swagger.v3.oas.annotations.media.Schema.RequiredMode;
 
 /**
- * Node state that is returned by REST.
+ * Node info that is returned by REST.
  */
-@Schema(description = "Node state.")
-public class NodeState {
+@Schema(description = "Node info.")
+public class NodeInfo {
     @Schema(description = "Unique node name.", requiredMode = RequiredMode.REQUIRED)
     private final String name;
 
-    @Schema(description = "Node status.", requiredMode = RequiredMode.REQUIRED)
-    private final State state;
+    @Schema(description = "Node JDBC port.", requiredMode = RequiredMode.REQUIRED)
+    private final int jdbcPort;
 
+    /**
+     * Construct NodeInfo DTO.
+     */
     @JsonCreator
-    public NodeState(@JsonProperty("name") String name,
-            @JsonProperty("state") State state) {
+    public NodeInfo(@JsonProperty("name") String name,
+            @JsonProperty("jdbcPort") int jdbcPort) {
         this.name = name;
-        this.state = state;
+        this.jdbcPort = jdbcPort;
     }
 
     @JsonGetter("name")
@@ -46,8 +49,8 @@ public class NodeState {
         return name;
     }
 
-    @JsonGetter("state")
-    public State state() {
-        return state;
+    @JsonGetter("jdbcPort")
+    public int jdbcPort() {
+        return jdbcPort;
     }
 }
diff --git a/modules/rest-api/src/main/java/org/apache/ignite/internal/rest/api/node/NodeManagementApi.java b/modules/rest-api/src/main/java/org/apache/ignite/internal/rest/api/node/NodeManagementApi.java
index 0fea70e9e6..551e7c3cd2 100644
--- a/modules/rest-api/src/main/java/org/apache/ignite/internal/rest/api/node/NodeManagementApi.java
+++ b/modules/rest-api/src/main/java/org/apache/ignite/internal/rest/api/node/NodeManagementApi.java
@@ -49,6 +49,16 @@ public interface NodeManagementApi {
     })
     NodeState state();
 
+    @Get("info")
+    @Operation(operationId = "nodeInfo", description = "Gets node info.")
+    @ApiResponses({
+            @ApiResponse(responseCode = "200", description = "Node info.",
+                    content = @Content(mediaType = MediaType.APPLICATION_JSON, schema = @Schema(implementation = NodeInfo.class))),
+            @ApiResponse(responseCode = "500", description = "Internal error.",
+                    content = @Content(mediaType = MediaType.PROBLEM_JSON, schema = @Schema(implementation = Problem.class)))
+    })
+    NodeInfo info();
+
     @Get("version")
     @Operation(operationId = "nodeVersion", description = "Gets the version of Apache Ignite the node uses.")
     @ApiResponse(responseCode = "200", description = "Node version.",
diff --git a/modules/rest-api/src/main/java/org/apache/ignite/internal/rest/api/node/NodeState.java b/modules/rest-api/src/main/java/org/apache/ignite/internal/rest/api/node/NodeState.java
index ee5c2dc957..d55c78cce0 100644
--- a/modules/rest-api/src/main/java/org/apache/ignite/internal/rest/api/node/NodeState.java
+++ b/modules/rest-api/src/main/java/org/apache/ignite/internal/rest/api/node/NodeState.java
@@ -34,6 +34,9 @@ public class NodeState {
     @Schema(description = "Node status.", requiredMode = RequiredMode.REQUIRED)
     private final State state;
 
+    /**
+     * Construct NodeState DTO.
+     */
     @JsonCreator
     public NodeState(@JsonProperty("name") String name,
             @JsonProperty("state") State state) {
diff --git a/modules/rest/src/main/java/org/apache/ignite/internal/rest/node/JdbcPortProvider.java b/modules/rest/src/main/java/org/apache/ignite/internal/rest/node/JdbcPortProvider.java
new file mode 100644
index 0000000000..6d59df9615
--- /dev/null
+++ b/modules/rest/src/main/java/org/apache/ignite/internal/rest/node/JdbcPortProvider.java
@@ -0,0 +1,26 @@
+/*
+ * 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.rest.node;
+
+/**
+ * Provides JDBC port.
+ */
+@FunctionalInterface
+public interface JdbcPortProvider {
+    int jdbcPort();
+}
diff --git a/modules/rest/src/main/java/org/apache/ignite/internal/rest/node/NodeManagementController.java b/modules/rest/src/main/java/org/apache/ignite/internal/rest/node/NodeManagementController.java
index dbb5ade3f7..fb0b6dfb60 100644
--- a/modules/rest/src/main/java/org/apache/ignite/internal/rest/node/NodeManagementController.java
+++ b/modules/rest/src/main/java/org/apache/ignite/internal/rest/node/NodeManagementController.java
@@ -19,6 +19,7 @@ package org.apache.ignite.internal.rest.node;
 
 import io.micronaut.http.annotation.Controller;
 import org.apache.ignite.internal.properties.IgniteProductVersion;
+import org.apache.ignite.internal.rest.api.node.NodeInfo;
 import org.apache.ignite.internal.rest.api.node.NodeManagementApi;
 import org.apache.ignite.internal.rest.api.node.NodeState;
 
@@ -31,9 +32,15 @@ public class NodeManagementController implements NodeManagementApi {
 
     private final NameProvider nameProvider;
 
-    public NodeManagementController(NameProvider nameProvider, StateProvider stateProvider) {
+    private final JdbcPortProvider jdbcPortProvider;
+
+    /**
+     * Constructs node management controller.
+     */
+    public NodeManagementController(NameProvider nameProvider, StateProvider stateProvider, JdbcPortProvider jdbcPortProvider) {
         this.nameProvider = nameProvider;
         this.stateProvider = stateProvider;
+        this.jdbcPortProvider = jdbcPortProvider;
     }
 
     @Override
@@ -41,6 +48,11 @@ public class NodeManagementController implements NodeManagementApi {
         return new NodeState(nameProvider.getName(), stateProvider.getState());
     }
 
+    @Override
+    public NodeInfo info() {
+        return new NodeInfo(nameProvider.getName(), jdbcPortProvider.jdbcPort());
+    }
+
     @Override
     public String version() {
         return IgniteProductVersion.CURRENT_VERSION.toString();
diff --git a/modules/rest/src/main/java/org/apache/ignite/internal/rest/node/NodeManagementRestFactory.java b/modules/rest/src/main/java/org/apache/ignite/internal/rest/node/NodeManagementRestFactory.java
index 344103a7a5..636a5deb7a 100644
--- a/modules/rest/src/main/java/org/apache/ignite/internal/rest/node/NodeManagementRestFactory.java
+++ b/modules/rest/src/main/java/org/apache/ignite/internal/rest/node/NodeManagementRestFactory.java
@@ -31,9 +31,15 @@ public class NodeManagementRestFactory implements RestFactory {
 
     private NameProvider nameProvider;
 
-    public NodeManagementRestFactory(StateProvider stateProvider, NameProvider nameProvider) {
+    private JdbcPortProvider jdbcPortProvider;
+
+    /**
+     * Constructs node management rest factory.
+     */
+    public NodeManagementRestFactory(StateProvider stateProvider, NameProvider nameProvider, JdbcPortProvider jdbcPortProvider) {
         this.stateProvider = stateProvider;
         this.nameProvider = nameProvider;
+        this.jdbcPortProvider = jdbcPortProvider;
     }
 
     @Singleton
@@ -48,9 +54,16 @@ public class NodeManagementRestFactory implements RestFactory {
         return nameProvider;
     }
 
+    @Singleton
+    @Bean
+    public JdbcPortProvider jdbcPortProvider() {
+        return jdbcPortProvider;
+    }
+
     @Override
     public void cleanResources() {
         stateProvider = null;
         nameProvider = null;
+        jdbcPortProvider = null;
     }
 }
diff --git a/modules/runner/src/integrationTest/java/org/apache/ignite/internal/deployment/DeployFiles.java b/modules/runner/src/integrationTest/java/org/apache/ignite/internal/deployment/DeployFiles.java
index 235be55ae3..7baa4c8789 100644
--- a/modules/runner/src/integrationTest/java/org/apache/ignite/internal/deployment/DeployFiles.java
+++ b/modules/runner/src/integrationTest/java/org/apache/ignite/internal/deployment/DeployFiles.java
@@ -56,7 +56,7 @@ class DeployFiles {
 
     private DeployFile bigFile;
 
-    // TODO https://issues.apache.org/jira/browse/IGNITE-19009
+    // TODO https://issues.apache.org/jira/browse/IGNITE-20204
     DeployFiles(Path workDir) {
         this.workDir = workDir;
     }
diff --git a/modules/runner/src/integrationTest/java/org/apache/ignite/internal/deployment/ItDeploymentUnitFailoverTest.java b/modules/runner/src/integrationTest/java/org/apache/ignite/internal/deployment/ItDeploymentUnitFailoverTest.java
index ae16d20b20..a6567fbaa1 100644
--- a/modules/runner/src/integrationTest/java/org/apache/ignite/internal/deployment/ItDeploymentUnitFailoverTest.java
+++ b/modules/runner/src/integrationTest/java/org/apache/ignite/internal/deployment/ItDeploymentUnitFailoverTest.java
@@ -45,7 +45,7 @@ public class ItDeploymentUnitFailoverTest extends ClusterPerTestIntegrationTest
     }
 
     @Test
-    @Disabled("IGNITE-19009")
+    @Disabled("IGNITE-20204")
     public void testDeployWithNodeStop() {
         int nodeIndex = 1;
         IgniteImpl node = node(nodeIndex);
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 740830510b..b4dbda2b96 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
@@ -68,6 +68,7 @@ import org.apache.ignite.internal.configuration.ConfigurationModules;
 import org.apache.ignite.internal.configuration.ConfigurationRegistry;
 import org.apache.ignite.internal.configuration.ConfigurationTreeGenerator;
 import org.apache.ignite.internal.configuration.DistributedConfigurationUpdater;
+import org.apache.ignite.internal.configuration.JdbcPortProviderImpl;
 import org.apache.ignite.internal.configuration.SecurityConfiguration;
 import org.apache.ignite.internal.configuration.ServiceLoaderModulesProvider;
 import org.apache.ignite.internal.configuration.presentation.HoconPresentation;
@@ -640,7 +641,8 @@ public class IgniteImpl implements Ignite {
     private RestComponent createRestComponent(String name) {
         Supplier<RestFactory> presentationsFactory = () -> new PresentationsFactory(nodeCfgMgr, clusterCfgMgr);
         Supplier<RestFactory> clusterManagementRestFactory = () -> new ClusterManagementRestFactory(clusterSvc, cmgMgr);
-        Supplier<RestFactory> nodeManagementRestFactory = () -> new NodeManagementRestFactory(lifecycleManager, () -> name);
+        Supplier<RestFactory> nodeManagementRestFactory = () -> new NodeManagementRestFactory(lifecycleManager, () -> name,
+                new JdbcPortProviderImpl(nodeCfgMgr.configurationRegistry()));
         Supplier<RestFactory> nodeMetricRestFactory = () -> new MetricRestFactory(metricManager);
         Supplier<RestFactory> authProviderFactory = () -> new AuthenticationProviderFactory(authenticationManager);
         Supplier<RestFactory> deploymentCodeRestFactory = () -> new CodeDeploymentRestFactory(deploymentManager);
diff --git a/modules/runner/src/main/java/org/apache/ignite/internal/configuration/JdbcPortProviderImpl.java b/modules/runner/src/main/java/org/apache/ignite/internal/configuration/JdbcPortProviderImpl.java
new file mode 100644
index 0000000000..9f800d1f9e
--- /dev/null
+++ b/modules/runner/src/main/java/org/apache/ignite/internal/configuration/JdbcPortProviderImpl.java
@@ -0,0 +1,38 @@
+/*
+ * 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.configuration;
+
+import org.apache.ignite.client.handler.configuration.ClientConnectorConfiguration;
+import org.apache.ignite.internal.rest.node.JdbcPortProvider;
+
+/**
+ * Provider of client port from node configuration.
+ */
+public class JdbcPortProviderImpl implements JdbcPortProvider {
+
+    private final ConfigurationRegistry configurationRegistry;
+
+    public JdbcPortProviderImpl(ConfigurationRegistry configurationRegistry) {
+        this.configurationRegistry = configurationRegistry;
+    }
+
+    @Override
+    public int jdbcPort() {
+        return configurationRegistry.getConfiguration(ClientConnectorConfiguration.KEY).port().value();
+    }
+}