Skip to content

Commit e993112

Browse files
committed
fix: gcp health check fix
1 parent 4383369 commit e993112

10 files changed

Lines changed: 50 additions & 16 deletions

File tree

CHANGELOG.md

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,12 @@ This project uses [Semantic Versioning](https://semver.org/).
77

88
## [Unreleased]
99

10+
## [0.1.4] — 2026-06-02
11+
12+
### Fixed
13+
14+
- `floci gcp wait` / `status` / `version` / `services` / `doctor` timed out or reported the server unreachable even when the floci-gcp container was healthy — the CLI probed the AWS/Azure control path `/_floci/health`, which the GCP server routes into its GCS service (`object not found bucket=_floci name=health`). The GCP control plane lives under `/_floci-gcp`; `FlociHttpClient` now takes a configurable control-plane prefix and the `floci gcp` commands use `/_floci-gcp`
15+
1016
## [0.1.3] — 2026-06-02
1117

1218
### Added

pom.xml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@
66

77
<groupId>io.floci</groupId>
88
<artifactId>floci-cli</artifactId>
9-
<version>0.1.3</version>
9+
<version>0.1.4</version>
1010
<packaging>jar</packaging>
1111

1212
<name>Floci CLI</name>

src/main/java/io/floci/cli/GcpGlobalOptions.java

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,9 @@
1010

1111
public class GcpGlobalOptions {
1212

13+
/** Control-plane path prefix exposed by the floci-gcp server (differs from AWS/Azure's {@code /_floci}). */
14+
public static final String CONTROL_PREFIX = "/_floci-gcp";
15+
1316
@Option(names = {"--endpoint"},
1417
description = "Floci GCP server endpoint URL",
1518
defaultValue = "${FLOCI_GCP_ENDPOINT:-http://localhost:4588}",

src/main/java/io/floci/cli/commands/gcp/GcpDoctorCommand.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -54,7 +54,7 @@ public class GcpDoctorCommand implements Callable<Integer> {
5454
checks.add(new ImagePresentCheck("floci/floci-gcp"));
5555
checks.add(new ImageVersionCheck("floci/floci-gcp"));
5656
checks.add(new ContainerRunningCheck());
57-
checks.add(new EndpointReachableCheck());
57+
checks.add(new EndpointReachableCheck(io.floci.cli.GcpGlobalOptions.CONTROL_PREFIX));
5858
ALL_CHECKS = List.copyOf(checks);
5959
}
6060

src/main/java/io/floci/cli/commands/gcp/GcpServicesCommand.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -25,7 +25,7 @@ public class GcpServicesCommand implements Callable<Integer> {
2525
@Override
2626
public Integer call() {
2727
Printer printer = global.printer();
28-
FlociHttpClient client = new FlociHttpClient(global.endpoint);
28+
FlociHttpClient client = new FlociHttpClient(global.endpoint, GcpGlobalOptions.CONTROL_PREFIX);
2929

3030
List<String> services;
3131
try {

src/main/java/io/floci/cli/commands/gcp/GcpStatusCommand.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -48,7 +48,7 @@ public Integer call() {
4848
String serverVersion = "unavailable";
4949
String serverEdition = "";
5050
boolean reachable = false;
51-
FlociHttpClient client = new FlociHttpClient(effectiveEndpoint);
51+
FlociHttpClient client = new FlociHttpClient(effectiveEndpoint, GcpGlobalOptions.CONTROL_PREFIX);
5252
try {
5353
var health = client.health();
5454
serverVersion = health.version();

src/main/java/io/floci/cli/commands/gcp/GcpVersionCommand.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -35,7 +35,7 @@ public Integer call() {
3535
DockerClient docker = new DockerClient();
3636
String effectiveEndpoint = global.resolvedEndpoint(docker);
3737

38-
FlociHttpClient client = new FlociHttpClient(effectiveEndpoint);
38+
FlociHttpClient client = new FlociHttpClient(effectiveEndpoint, GcpGlobalOptions.CONTROL_PREFIX);
3939
try {
4040
var info = client.info();
4141
serverVersion = info.version();

src/main/java/io/floci/cli/commands/gcp/GcpWaitCommand.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -34,7 +34,7 @@ public Integer call() {
3434
Printer printer = global.printer();
3535
long timeoutMillis = WaitCommand.parseDuration(timeout);
3636
String effectiveEndpoint = global.resolvedEndpoint(new io.floci.cli.docker.DockerClient());
37-
FlociHttpClient client = new FlociHttpClient(effectiveEndpoint);
37+
FlociHttpClient client = new FlociHttpClient(effectiveEndpoint, GcpGlobalOptions.CONTROL_PREFIX);
3838
Instant deadline = Instant.now().plusMillis(timeoutMillis);
3939

4040
while (Instant.now().isBefore(deadline)) {

src/main/java/io/floci/cli/doctor/checks/EndpointReachableCheck.java

Lines changed: 12 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -6,9 +6,19 @@
66

77
public class EndpointReachableCheck implements Check {
88

9+
private final String controlPrefix;
10+
11+
public EndpointReachableCheck() {
12+
this(FlociHttpClient.DEFAULT_CONTROL_PREFIX);
13+
}
14+
15+
public EndpointReachableCheck(String controlPrefix) {
16+
this.controlPrefix = controlPrefix;
17+
}
18+
919
@Override
1020
public CheckResult run(String endpoint, String container) {
11-
FlociHttpClient client = new FlociHttpClient(endpoint);
21+
FlociHttpClient client = new FlociHttpClient(endpoint, controlPrefix);
1222
if (client.isReachable()) {
1323
try {
1424
var health = client.health();
@@ -19,7 +29,7 @@ public CheckResult run(String endpoint, String container) {
1929
}
2030
}
2131
return CheckResult.fail("endpoint.reachable",
22-
"GET /_floci/health at " + endpoint + " did not return 200",
32+
"GET " + controlPrefix + "/health at " + endpoint + " did not return 200",
2333
"Is Floci running? Try 'floci start'.");
2434
}
2535
}

src/main/java/io/floci/cli/http/FlociHttpClient.java

Lines changed: 23 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -15,18 +15,33 @@ public class FlociHttpClient {
1515

1616
private static final ObjectMapper MAPPER = new ObjectMapper();
1717

18+
/** Default control-plane path prefix used by the AWS and Azure emulators. */
19+
public static final String DEFAULT_CONTROL_PREFIX = "/_floci";
20+
1821
private final String endpoint;
22+
private final String controlPrefix;
1923
private final HttpClient http;
2024

2125
public FlociHttpClient(String endpoint) {
26+
this(endpoint, DEFAULT_CONTROL_PREFIX);
27+
}
28+
29+
/**
30+
* @param controlPrefix the control-plane path prefix exposed by the target server
31+
* (e.g. {@code /_floci} for AWS/Azure, {@code /_floci-gcp} for GCP).
32+
*/
33+
public FlociHttpClient(String endpoint, String controlPrefix) {
2234
this.endpoint = endpoint.endsWith("/") ? endpoint.substring(0, endpoint.length() - 1) : endpoint;
35+
this.controlPrefix = controlPrefix.endsWith("/")
36+
? controlPrefix.substring(0, controlPrefix.length() - 1)
37+
: controlPrefix;
2338
this.http = HttpClient.newBuilder()
2439
.connectTimeout(Duration.ofSeconds(5))
2540
.build();
2641
}
2742

2843
public HealthInfo health() throws FlociException {
29-
JsonNode node = getJson("/_floci/health");
44+
JsonNode node = getJson(controlPrefix + "/health");
3045
return new HealthInfo(
3146
node.path("version").asText("unknown"),
3247
node.path("original_edition").asText(node.path("edition").asText("community")),
@@ -44,14 +59,14 @@ public Optional<HealthInfo> healthOptional() {
4459
}
4560

4661
public ServerInfo info() throws FlociException {
47-
JsonNode node = getJson("/_floci/info");
62+
JsonNode node = getJson(controlPrefix + "/info");
4863
return new ServerInfo(
4964
node.path("version").asText("unknown"),
5065
node.path("original_edition").asText(node.path("edition").asText("community")));
5166
}
5267

5368
public InitState initState() throws FlociException {
54-
JsonNode node = getJson("/_floci/init");
69+
JsonNode node = getJson(controlPrefix + "/init");
5570
JsonNode completed = node.path("completed");
5671
return new InitState(
5772
completed.path("boot").asBoolean(),
@@ -63,7 +78,7 @@ public InitState initState() throws FlociException {
6378
public boolean isReachable() {
6479
try {
6580
HttpRequest req = HttpRequest.newBuilder()
66-
.uri(URI.create(endpoint + "/_floci/health"))
81+
.uri(URI.create(endpoint + controlPrefix + "/health"))
6782
.timeout(Duration.ofSeconds(3))
6883
.GET()
6984
.build();
@@ -75,19 +90,19 @@ public boolean isReachable() {
7590
}
7691

7792
public Map<String, Object> postSnapshot(String name) throws FlociException {
78-
return postJson("/_floci/snapshots/" + name, "{}");
93+
return postJson(controlPrefix + "/snapshots/" + name, "{}");
7994
}
8095

8196
public Map<String, Object> loadSnapshot(String name) throws FlociException {
82-
return postJson("/_floci/snapshots/" + name + "/load", "{}");
97+
return postJson(controlPrefix + "/snapshots/" + name + "/load", "{}");
8398
}
8499

85100
public JsonNode listSnapshots() throws FlociException {
86-
return getJson("/_floci/snapshots");
101+
return getJson(controlPrefix + "/snapshots");
87102
}
88103

89104
public void deleteSnapshot(String name) throws FlociException {
90-
deleteRequest("/_floci/snapshots/" + name);
105+
deleteRequest(controlPrefix + "/snapshots/" + name);
91106
}
92107

93108
private JsonNode getJson(String path) throws FlociException {

0 commit comments

Comments
 (0)