Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

couchbase: wait until all services are part of the config #3003

Merged
merged 2 commits into from
Feb 6, 2021
Merged
Show file tree
Hide file tree
Changes from all 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
Expand Up @@ -36,10 +36,12 @@
import java.util.ArrayList;
import java.util.Arrays;
import java.util.EnumSet;
import java.util.Iterator;
import java.util.List;
import java.util.Optional;
import java.util.Set;
import java.util.concurrent.TimeUnit;
import java.util.function.Predicate;
import java.util.stream.Collectors;

/**
Expand Down Expand Up @@ -181,7 +183,7 @@ protected void configure() {
.map("healthy"::equals)
.orElse(false);
} catch (IOException e) {
logger().error("Unable to parse response {}", response, e);
logger().error("Unable to parse response: {}", response, e);
return false;
}
})
Expand Down Expand Up @@ -254,15 +256,10 @@ private void renameNode() {
private void initializeServices() {
logger().debug("Initializing couchbase services on host: {}", enabledServices);

final String services = enabledServices.stream().map(s -> {
switch (s) {
case KV: return "kv";
case QUERY: return "n1ql";
case INDEX: return "index";
case SEARCH: return "fts";
default: throw new IllegalStateException("Unknown service!");
}
}).collect(Collectors.joining(","));
final String services = enabledServices
.stream()
.map(CouchbaseService::getIdentifier)
.collect(Collectors.joining(","));

@Cleanup Response response = doHttpRequest(MGMT_PORT, "/node/controller/setupServices", "POST", new FormBody.Builder()
.add("services", services)
Expand Down Expand Up @@ -363,10 +360,11 @@ private void createBuckets() {
checkSuccessfulResponse(response, "Could not create bucket " + bucket.getName());

new HttpWaitStrategy()
.forPath("/pools/default/buckets/" + bucket.getName())
.forPath("/pools/default/b/" + bucket.getName())
.forPort(MGMT_PORT)
.withBasicCredentials(username, password)
.forStatusCode(200)
.forResponsePredicate(new AllServicesEnabledPredicate())
.waitUntilReady(this);

if (enabledServices.contains(CouchbaseService.QUERY)) {
Expand Down Expand Up @@ -472,4 +470,38 @@ private Response doHttpRequest(final int port, final String path, final String m
throw new RuntimeException("Could not perform request against couchbase HTTP endpoint ", ex);
}
}

/**
* In addition to getting a 200, we need to make sure that all services we need are enabled and available on
* the bucket.
* <p>
* Fixes the issue observed in https://github.com/testcontainers/testcontainers-java/issues/2993
*/
private class AllServicesEnabledPredicate implements Predicate<String> {

@Override
public boolean test(final String rawConfig) {
try {
for (JsonNode node : MAPPER.readTree(rawConfig).at("/nodesExt")) {
for (CouchbaseService enabledService : enabledServices) {
boolean found = false;
Iterator<String> fieldNames = node.get("services").fieldNames();
while (fieldNames.hasNext()) {
if (fieldNames.next().startsWith(enabledService.getIdentifier())) {
found = true;
}
}
if (!found) {
logger().trace("Service {} not yet part of config, retrying.", enabledService);
return false;
}
}
}
return true;
} catch (IOException ex) {
logger().error("Unable to parse response: {}", rawConfig, ex);
return false;
}
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -24,21 +24,30 @@ public enum CouchbaseService {
/**
* Key-Value service.
*/
KV,
KV("kv"),

/**
* Query (N1QL) service.
*/
QUERY,
QUERY("n1ql"),

/**
* Search (FTS) service.
*/
SEARCH,
SEARCH("fts"),

/**
* Indexing service (needed if QUERY is also used!).
*/
INDEX
INDEX("index");

private final String identifier;

CouchbaseService(String identifier) {
this.identifier = identifier;
}

String getIdentifier() {
return identifier;
}
}