|
27 | 27 | import io.milvus.orm.iterator.QueryIterator; |
28 | 28 | import io.milvus.orm.iterator.SearchIterator; |
29 | 29 | import io.milvus.orm.iterator.SearchIteratorV2; |
| 30 | +import io.milvus.v2.exception.ErrorCode; |
| 31 | +import io.milvus.v2.exception.MilvusClientException; |
30 | 32 | import io.milvus.v2.service.cdc.CDCService; |
31 | 33 | import io.milvus.v2.service.cdc.request.UpdateReplicateConfigurationReq; |
32 | 34 | import io.milvus.v2.service.cdc.response.UpdateReplicateConfigurationResp; |
|
69 | 71 |
|
70 | 72 | import java.util.List; |
71 | 73 | import java.util.concurrent.TimeUnit; |
| 74 | +import java.net.InetAddress; |
| 75 | +import java.net.UnknownHostException; |
| 76 | +import java.net.Socket; |
| 77 | +import java.io.IOException; |
| 78 | +import java.net.InetSocketAddress; |
| 79 | +import javax.net.ssl.*; |
72 | 80 |
|
73 | 81 | public class MilvusClientV2 { |
74 | 82 | private static final Logger logger = LoggerFactory.getLogger(MilvusClientV2.class); |
@@ -124,6 +132,9 @@ private void initServices(String dbName) { |
124 | 132 | */ |
125 | 133 | private void connect(ConnectConfig connectConfig) { |
126 | 134 | this.connectConfig = connectConfig; |
| 135 | + validateHostname(connectConfig); |
| 136 | + validatePort(connectConfig); |
| 137 | + validateCert(connectConfig); |
127 | 138 | try { |
128 | 139 | if (this.channel != null) { |
129 | 140 | // close channel first |
@@ -215,6 +226,94 @@ public String currentUsedDatabase() { |
215 | 226 | return dbName; |
216 | 227 | } |
217 | 228 |
|
| 229 | + /** |
| 230 | + * Validates that the hostname can be resolved before attempting connection. |
| 231 | + * This provides early failure with clear error messages for DNS issues. |
| 232 | + * |
| 233 | + * @param connectConfig Connection configuration containing the host to validate |
| 234 | + * @throws MilvusClientException if hostname cannot be resolved |
| 235 | + */ |
| 236 | + public void validateHostname(ConnectConfig connectConfig) { |
| 237 | + String host = connectConfig.getHost(); |
| 238 | + |
| 239 | + if (StringUtils.isEmpty(host)) { |
| 240 | + throw new MilvusClientException(ErrorCode.CLIENT_ERROR, |
| 241 | + "Hostname cannot be null or empty"); |
| 242 | + } |
| 243 | + |
| 244 | + try { |
| 245 | + // Attempt DNS resolution |
| 246 | + InetAddress.getByName(host); |
| 247 | + logger.debug("Successfully resolved hostname: {}", host); |
| 248 | + } catch (UnknownHostException e) { |
| 249 | + String message = String.format( |
| 250 | + "Failed to resolve hostname '%s'. Please verify the hostname is correct and DNS is configured properly.", |
| 251 | + host |
| 252 | + ); |
| 253 | + logger.error(message, e); |
| 254 | + throw new MilvusClientException(ErrorCode.RPC_ERROR, message); |
| 255 | + } |
| 256 | + } |
| 257 | + |
| 258 | + /** |
| 259 | + * Validates port number and tests connectivity. |
| 260 | + * |
| 261 | + * @param connectConfig Connection configuration containing the port to validate |
| 262 | + * @throws MilvusClientException if port is invalid or unreachable |
| 263 | + */ |
| 264 | + public void validatePort(ConnectConfig connectConfig) { |
| 265 | + int port = connectConfig.getPort(); |
| 266 | + String host = connectConfig.getHost(); |
| 267 | + |
| 268 | + // Check valid range |
| 269 | + if (port < 1 || port > 65535) { |
| 270 | + String message = String.format( |
| 271 | + "Invalid port number '%d'. Port must be between 1 and 65535.", |
| 272 | + port |
| 273 | + ); |
| 274 | + logger.error(message); |
| 275 | + throw new MilvusClientException(ErrorCode.CLIENT_ERROR, message); |
| 276 | + } |
| 277 | + |
| 278 | + // Test if port is reachable |
| 279 | + try (Socket socket = new Socket()) { |
| 280 | + socket.connect(new InetSocketAddress(host, port), 3000); // 3 second timeout |
| 281 | + logger.debug("Successfully validated port: {}", port); |
| 282 | + } catch (IOException e) { |
| 283 | + String message = String.format( |
| 284 | + "Cannot connect to '%s:%d'. Please verify the port number is correct and server is running.", |
| 285 | + host, port |
| 286 | + ); |
| 287 | + logger.error(message, e); |
| 288 | + throw new MilvusClientException(ErrorCode.RPC_ERROR, message); |
| 289 | + } |
| 290 | + } |
| 291 | + |
| 292 | + /** |
| 293 | + * Validates SSL connection with certificates. |
| 294 | + * |
| 295 | + * @param connectConfig Connection configuration |
| 296 | + * @throws MilvusClientException if SSL connection fails |
| 297 | + */ |
| 298 | + public void validateCert(ConnectConfig connectConfig) { |
| 299 | + if (!connectConfig.isSecure()) { |
| 300 | + return; |
| 301 | + } |
| 302 | + |
| 303 | + try (SSLSocket socket = (SSLSocket) SSLSocketFactory.getDefault().createSocket()) { |
| 304 | + socket.connect(new InetSocketAddress(connectConfig.getHost(), connectConfig.getPort()), 5000); |
| 305 | + socket.startHandshake(); |
| 306 | + logger.debug("SSL certificate validation passed"); |
| 307 | + } catch (SSLException e) { |
| 308 | + throw new MilvusClientException(ErrorCode.RPC_ERROR, |
| 309 | + "SSL certificate validation failed: " + e.getMessage() + |
| 310 | + ". Please verify your certificates are correct."); |
| 311 | + } catch (IOException e) { |
| 312 | + throw new MilvusClientException(ErrorCode.RPC_ERROR, |
| 313 | + "Failed to connect with SSL: " + e.getMessage()); |
| 314 | + } |
| 315 | + } |
| 316 | + |
218 | 317 | ///////////////////////////////////////////////////////////////////////////////////////////// |
219 | 318 | // Database Operations |
220 | 319 | ///////////////////////////////////////////////////////////////////////////////////////////// |
|
0 commit comments