Skip to content
Merged
Show file tree
Hide file tree
Changes from 2 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
/*
* Copyright (C) 2024 Volt Active Data Inc.
* Copyright (C) 2024-2025 Volt Active Data Inc.
*
* Use of this source code is governed by an MIT
* license that can be found in the LICENSE file or at
Expand All @@ -18,13 +18,27 @@ public class InetSocketAddressConverter implements CommandLine.ITypeConverter<In
@Override
public InetSocketAddress convert(String value) {
int port = DEFAULT_PORT;
String host;

int pos = value.lastIndexOf(':');
if (pos >= 0) {
// Host and port provided
host = value.substring(0, pos);
port = Integer.parseInt(value.substring(pos + 1));
return new InetSocketAddress(value.substring(0, pos), port);
} else {
// Only hostname provided, use default port
host = value.trim();
}

return new InetSocketAddress(value, port);
if (host.isEmpty()) {
throw new IllegalArgumentException("Hostname is required. Please provide a valid FQDN or IP address.");
}

// Remove IPv6 brackets if present
if (host.startsWith("[") && host.endsWith("]")) {
host = host.substring(1, host.length() - 1);
}

return new InetSocketAddress(host, port);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -71,7 +71,8 @@ public class MeshMonitorCommand implements Callable<Integer> {

@CommandLine.Option(
names = {"-b", "--bind"},
description = "Bind address in format ipv4[:port]",
required = true,
description = "Bind address in format host[:port]",
defaultValue = "127.0.0.1:12222",
converter = InetSocketAddressConverter.class)
private InetSocketAddress bindAddress;
Expand All @@ -85,7 +86,7 @@ public class MeshMonitorCommand implements Callable<Integer> {
names = {"-m", "--metrics-bind"},
description = "Bind address for metrics server in format [host][:port]. Default is 12223 for all interfaces",
defaultValue = "12223",
converter = InetSocketAddressConverter.class)
converter = MetricsInetSocketAddressConverter.class)
private InetSocketAddress metricsBindAddress;

@CommandLine.Option(
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,52 @@
/*
* Copyright (C) 2024-2025 Volt Active Data Inc.
*
* Use of this source code is governed by an MIT
* license that can be found in the LICENSE file or at
* https://opensource.org/licenses/MIT.
*/
package org.voltdb.meshmonitor.cli;

import java.net.InetSocketAddress;
import picocli.CommandLine;

public class MetricsInetSocketAddressConverter implements CommandLine.ITypeConverter<InetSocketAddress> {

public static final int DEFAULT_PORT = 12223;

@Override
public InetSocketAddress convert(String value) {

// Host:port format
int pos = value.lastIndexOf(':');
if (pos >= 0) {
int port = Integer.parseInt(value.substring(pos + 1));
String host = value.substring(0, pos);

// If host is in IPv6 format, remove the brackets
if (host.startsWith("[") && host.endsWith("]")) {
host = host.substring(1, host.length()-1);
}

// No host given, just colon followed by port - bind to all interfaces (wildcard) same as port-only
if (host.equals("")) {
return new InetSocketAddress(port);
}

return new InetSocketAddress(host, port);
}

// port only - bind to all interfaces (wildcard)
if (value.matches("^\\d+$")) { // digits only
return new InetSocketAddress(Integer.parseInt(value));
}

// empty string - use wildcard and default port
if (value.equals("")) {
return new InetSocketAddress(DEFAULT_PORT);
}

// value is hostname only
return new InetSocketAddress(value, DEFAULT_PORT);
}
}
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
/*
* Copyright (C) 2024 Volt Active Data Inc.
* Copyright (C) 2024-2025 Volt Active Data Inc.
*
* Use of this source code is governed by an MIT
* license that can be found in the LICENSE file or at
Expand Down Expand Up @@ -58,16 +58,13 @@ public void shouldThrowExceptionWithInvalidPort() {
}

@Test
public void emptyStringShouldDefaultToLocalhost() {
public void shouldThrowExceptionOnEmptyString() {
// Given
String input = "";

// When
InetSocketAddress result = converter.convert(input);

assertThat(result).isNotNull();
assertThat(result.getHostName()).isEqualTo("localhost");
assertThat(result.getPort()).isEqualTo(InetSocketAddressConverter.DEFAULT_PORT);
// When & Then
assertThatThrownBy(() -> converter.convert(input))
.isInstanceOf(IllegalArgumentException.class);
}

@Test
Expand All @@ -81,16 +78,12 @@ public void shouldThrowExceptionOnInputWithOnlyColon() {
}

@Test
public void shouldDefaultToLocalhostIfONlyColonAndPortIsSpecified() throws UnknownHostException {
public void shouldThrowExceptionIfOnlyColonAndPortIsSpecified() throws UnknownHostException {
// Given
String input = ":8080";

// When
InetSocketAddress result = converter.convert(input);

// Then
assertThat(result).isNotNull();
assertThat(result.getHostName()).isEqualTo("localhost");
assertThat(result.getPort()).isEqualTo(8080);
// When & Then
assertThatThrownBy(() -> converter.convert(input))
.isInstanceOf(IllegalArgumentException.class);
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,96 @@
/*
* Copyright (C) 2024-2025 Volt Active Data Inc.
*
* Use of this source code is governed by an MIT
* license that can be found in the LICENSE file or at
* https://opensource.org/licenses/MIT.
*/
package org.voltdb.meshmonitor.cli;

import org.junit.jupiter.api.Test;

import java.net.InetSocketAddress;
import java.net.UnknownHostException;

import static org.assertj.core.api.Assertions.assertThat;
import static org.assertj.core.api.Assertions.assertThatThrownBy;

public class MetricsInetSocketAddressConverterTest {

private final MetricsInetSocketAddressConverter converter = new MetricsInetSocketAddressConverter();

@Test
public void shouldConvertWithPort() {
// Given
String input = "localhost:8080";

// When
InetSocketAddress result = converter.convert(input);

// Then
assertThat(result).isNotNull();
assertThat(result.getHostName()).isEqualTo("localhost");
assertThat(result.getPort()).isEqualTo(8080);
}

@Test
public void shouldConvertWithoutPort() {
// Given
String input = "localhost";

// When
InetSocketAddress result = converter.convert(input);

// Then
assertThat(result).isNotNull();
assertThat(result.getHostName()).isEqualTo("localhost");
assertThat(result.getPort()).isEqualTo(MetricsInetSocketAddressConverter.DEFAULT_PORT);
}

@Test
public void shouldThrowExceptionWithInvalidPort() {
// Given
String input = "localhost:abc";

// When & Then
assertThatThrownBy(() -> converter.convert(input))
.isInstanceOf(NumberFormatException.class);
}

@Test
public void emptyStringShouldDefaultToWildcard() {
// Given
String input = "";

// When
InetSocketAddress result = converter.convert(input);

assertThat(result).isNotNull();
assertThat(result.getHostName()).isEqualTo("0.0.0.0");
assertThat(result.getPort()).isEqualTo(MetricsInetSocketAddressConverter.DEFAULT_PORT);
}

@Test
public void shouldThrowExceptionOnInputWithOnlyColon() {
// Given
String input = ":";

// When & Then
assertThatThrownBy(() -> converter.convert(input))
.isInstanceOf(IllegalArgumentException.class);
}

@Test
public void shouldDefaultToWildcardIfONlyColonAndPortIsSpecified() throws UnknownHostException {
// Given
String input = ":8080";

// When
InetSocketAddress result = converter.convert(input);

// Then
assertThat(result).isNotNull();
assertThat(result.getHostName()).isEqualTo("0.0.0.0");
assertThat(result.getPort()).isEqualTo(8080);
}
}