Skip to content

Fix problem if topology isn't applied correctly #70

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

Merged
merged 2 commits into from
May 23, 2023
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
3 changes: 3 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,8 @@
# Changelog

## [Unreleased]
- Fix problem if topology isn't applied correctly

## [0.5.4] - 2023-03-31
- Use tarantool image as base instead of centos in cartridge container

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,8 @@

import com.github.dockerjava.api.command.InspectContainerResponse;
import io.tarantool.driver.exceptions.TarantoolConnectionException;

import org.testcontainers.containers.exceptions.CartridgeTopologyException;
import org.testcontainers.images.builder.ImageFromDockerfile;

import java.net.URL;
Expand Down Expand Up @@ -478,16 +480,21 @@ private boolean setupTopology() {
"--run-dir=" + TARANTOOL_RUN_DIR,
"--file=" + replicasetsFileName, "setup", "--bootstrap-vshard");
if (result.getExitCode() != 0) {
throw new RuntimeException("Failed to change the app topology via cartridge CLI: "
+ result.getStdout());
throw new CartridgeTopologyException("Failed to change the app topology via cartridge CLI: "
+ result.getStdout());
}
} catch (Exception e) {
throw new RuntimeException("Failed to change the app topology: " + e.getMessage());
throw new CartridgeTopologyException(e);
}

} else {
try {
executeScript(topologyConfigurationFile).get();
List<?> res = executeScript(topologyConfigurationFile).get();
if (res.size() >= 2 && res.get(1) != null && res.get(1) instanceof Map) {
HashMap<?, ?> error = ((HashMap<?, ?>) res.get(1));
// that means topology already exists
return error.get("str").toString().contains("collision with another server");
}
// The client connection will be closed after that command
} catch (Exception e) {
if (e instanceof ExecutionException) {
Expand All @@ -500,7 +507,7 @@ private boolean setupTopology() {
return false;
}
} else {
throw new RuntimeException("Failed to change the app topology", e);
throw new CartridgeTopologyException(e);
}
}
}
Expand All @@ -516,7 +523,7 @@ private void retryingSetupTopology() {
throw new RuntimeException(e);
}
if (!setupTopology()) {
throw new RuntimeException("Failed to change the app topology after retry");
throw new CartridgeTopologyException("Failed to change the app topology after retry");
}
}
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -75,7 +75,7 @@ public CompletableFuture<List<?>> executeScript(String scriptResourcePath) {
String scriptName = Paths.get(scriptResourcePath).getFileName().toString();
String containerPath = normalizePath(Paths.get(TMP_DIR, scriptName));
container.copyFileToContainer(MountableFile.forClasspathResource(scriptResourcePath), containerPath);
return executeCommand(String.format("dofile('%s')", containerPath));
return executeCommand(String.format("return dofile('%s')", containerPath));
}

public CompletableFuture<List<?>> executeCommand(String command, Object... arguments) {
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
package org.testcontainers.containers.exceptions;

/**
* Base class for Cartridge runtime exceptions
*
* @author Artyom Dubinin
*/
public abstract class CartridgeContainerException extends TarantoolContainerException {
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
package org.testcontainers.containers.exceptions;

public class CartridgeTopologyException extends TarantoolContainerException {

static final String errorMsg = "Failed to change the app topology";

public CartridgeTopologyException(String message) {
super(message);
}

public CartridgeTopologyException(Throwable cause) {
super(errorMsg, cause);
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
package org.testcontainers.containers.exceptions;

/**
* Base class for Tarantool runtime exceptions
*
* @author Artyom Dubinin
*/
public abstract class TarantoolContainerException extends RuntimeException {
public TarantoolContainerException(String message) {
super(message);
}

public TarantoolContainerException() {
super();
}

public TarantoolContainerException(Throwable cause) {
super(cause);
}

public TarantoolContainerException(String message, Throwable cause) {
super(message, cause);
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
/**
* Exception classes for internal client errors to be translated to user
*/
package org.testcontainers.containers.exceptions;
Original file line number Diff line number Diff line change
@@ -1,14 +1,19 @@
package org.testcontainers.containers;

import org.junit.jupiter.api.Test;
import org.rnorth.ducttape.RetryCountExceededException;
import org.slf4j.LoggerFactory;
import org.testcontainers.containers.exceptions.CartridgeTopologyException;
import org.testcontainers.containers.output.Slf4jLogConsumer;
import org.testcontainers.junit.jupiter.Container;
import org.testcontainers.junit.jupiter.Testcontainers;
import org.testcontainers.utility.MountableFile;

import java.time.Duration;

import static org.junit.Assert.assertThrows;
import static org.junit.jupiter.api.Assertions.assertEquals;

/**
* @author Alexey Kuzin
*/
Expand All @@ -21,8 +26,8 @@ public class TarantoolCartridgeBootstrapFromLuaWithFixedPortsTest {
"Dockerfile",
"cartridge/instances_fixedport.yml",
"cartridge/topology_fixedport.lua")
.withCopyFileToContainer(MountableFile.forClasspathResource("cartridge"), "/app")
.withCopyFileToContainer(MountableFile.forClasspathResource("cartridge/instances_fixedport.yml"),"/app/instances.yml")
.withDirectoryBinding("cartridge")
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

IIRC Vova changed this line because we had some problems with windows (?) or something. Did you look at the history of this change? Is it safe to use binding here? (I know, it's the default preferred variant, but there was some problem)

Copy link
Contributor Author

@ArtDu ArtDu May 23, 2023

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It's hard to see why it had been changed #46. I asked @dkasimovskiy to try to run tests(he has windows + wsl) but he didn't get what I want and merged PR 🤷‍♂️

Copy link
Contributor Author

@ArtDu ArtDu May 23, 2023

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@akudiyar we will test how it's working with windows. You can check other PRs in testcontainers

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

On the latest WSL2 it works fine.

.withEnv("TARANTOOL_INSTANCES_FILE", "instances_fixedport.yml")
.withStartupTimeout(Duration.ofSeconds(300))
.withUseFixedPorts(true)
.withAPIPort(18081)
Expand All @@ -34,4 +39,25 @@ public class TarantoolCartridgeBootstrapFromLuaWithFixedPortsTest {
public void test_StaticClusterContainer_StartsSuccessfully_ifFilesAreCopied() throws Exception {
CartridgeContainerTestUtils.executeProfileReplaceSmokeTest(container);
}

@Test
public void test_retryingSetupTopology_shouldWork() {
try (TarantoolCartridgeContainer testContainer =
new TarantoolCartridgeContainer(
"Dockerfile",
"cartridge/instances.yml",
"cartridge/incorrect_topology.lua")
.withDirectoryBinding("cartridge")
.withLogConsumer(new Slf4jLogConsumer(
LoggerFactory.getLogger(TarantoolCartridgeBootstrapFromLuaWithFixedPortsTest.class)))) {
ContainerLaunchException ex = assertThrows(ContainerLaunchException.class, testContainer::start);
Throwable cause = ex.getCause();
assertEquals(RetryCountExceededException.class, cause.getClass());
cause = cause.getCause();
assertEquals(ContainerLaunchException.class, cause.getClass());
cause = cause.getCause();
assertEquals(CartridgeTopologyException.class, cause.getClass());
assertEquals("Failed to change the app topology after retry", cause.getMessage());
}
}
}
16 changes: 16 additions & 0 deletions src/test/resources/cartridge/incorrect_topology.lua
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
cartridge = require('cartridge')
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

q: what is incorrect in this topology?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

There's no server on 3303 port. I added comment in topology

replicasets = { {
alias = 'app-router',
roles = { 'vshard-router', 'app.roles.custom', 'app.roles.api_router' },
join_servers = { { uri = 'localhost:3301' } }
}, {
alias = 's1-storage',
roles = { 'vshard-storage', 'app.roles.api_storage' },
join_servers = { { uri = 'localhost:3302' } }
},
{
alias = 's2-storage',
roles = { 'vshard-storage', 'app.roles.api_storage' },
join_servers = { { uri = 'localhost:3303' } } -- non-existent server
} }
return cartridge.admin_edit_topology({ replicasets = replicasets })