Skip to content
Snippets Groups Projects
Commit a1ecd296 authored by Martin Weise's avatar Martin Weise
Browse files

db + container endpoints now sufficiently working

parent 30b5df5d
No related branches found
No related tags found
3 merge requests!23Sprint results,!18Merge Conflicts,!15Sprint ended, merge into master
Showing
with 87 additions and 27 deletions
......@@ -22,6 +22,10 @@ public class ContainerBriefDto {
private String hash;
@NotBlank
@ApiModelProperty(name = "container name", example = "nyse")
@ApiModelProperty(name = "container name", example = "New York Stock Exchange")
private String name;
@NotBlank
@ApiModelProperty(name = "container internal name", example = "new_york_stock_exchange")
private String internalName;
}
......@@ -15,7 +15,7 @@ import javax.validation.constraints.Size;
public class ContainerCreateRequestDto {
@NotBlank
@ApiModelProperty(name = "name", example = "nyse")
@ApiModelProperty(name = "name", example = "New York Stock Exchange")
private String name;
@NotBlank
......
......@@ -46,6 +46,10 @@ public class Container {
@Column(nullable = false)
private String name;
@ToString.Exclude
@Column(nullable = false)
private String internalName;
@ToString.Include
@Column(nullable = false)
private String hash;
......
......@@ -10,7 +10,10 @@ import at.tuwien.entity.ContainerImage;
import com.github.dockerjava.api.command.InspectContainerResponse;
import org.mapstruct.*;
import java.text.Normalizer;
import java.util.Locale;
import java.util.Objects;
import java.util.regex.Pattern;
@Mapper(componentModel = "spring")
public interface ContainerMapper {
......@@ -39,4 +42,14 @@ public interface ContainerMapper {
default ContainerStateDto containerStateToContainerStateDto(InspectContainerResponse.ContainerState data) {
return ContainerStateDto.valueOf(Objects.requireNonNull(data.getStatus()).toUpperCase());
}
// https://stackoverflow.com/questions/1657193/java-code-library-for-generating-slugs-for-use-in-pretty-urls#answer-1657250
default String containerToInternalContainerName(Container data) {
final Pattern NONLATIN = Pattern.compile("[^\\w-]");
final Pattern WHITESPACE = Pattern.compile("[\\s]");
String nowhitespace = WHITESPACE.matcher(data.getName()).replaceAll("-");
String normalized = Normalizer.normalize(nowhitespace, Normalizer.Form.NFD);
String slug = NONLATIN.matcher(normalized).replaceAll("");
return "fda-userdb-" + slug.toLowerCase(Locale.ENGLISH);
}
}
......@@ -64,12 +64,19 @@ public class ContainerService {
.withNetworkMode("fda-userdb")
.withLinks(List.of(new Link("fda-database-managing-service", "fda-database-managing-service")))
.withPortBindings(PortBinding.parse(availableTcpPort + ":" + containerImage.getDefaultPort()));
/* save to metadata database */
Container container = new Container();
container.setContainerCreated(Instant.now());
container.setImage(containerImage);
container.setPort(availableTcpPort);
container.setName(createDto.getName());
container.setInternalName(containerMapper.containerToInternalContainerName(container));
/* create the container */
final CreateContainerResponse response;
createDto.setName("fda-userdb-" + createDto.getName());
try {
response = dockerClient.createContainerCmd(containerMapper.containerCreateRequestDtoToDockerImage(createDto))
.withName(createDto.getName())
.withHostName(createDto.getName())
.withName(container.getInternalName())
.withHostName(container.getInternalName())
.withEnv(imageMapper.environmentItemsToStringList(containerImage.getEnvironment()))
.withHostConfig(hostConfig)
.exec();
......@@ -77,13 +84,7 @@ public class ContainerService {
log.error("conflicting names for container {}, reason: {}", createDto, e.getMessage());
throw new DockerClientException("Unexpected behavior", e);
}
/* save to metadata database */
Container container = new Container();
container.setContainerCreated(Instant.now());
container.setImage(containerImage);
container.setName(createDto.getName());
container.setHash(response.getId());
container.setPort(availableTcpPort);
container = containerRepository.save(container);
log.info("Created container with hash {}", container.getHash());
log.debug("container created {}", container);
......
......@@ -22,6 +22,10 @@ public class ContainerBriefDto {
private String hash;
@NotBlank
@ApiModelProperty(name = "container name", example = "nyse")
@ApiModelProperty(name = "container name", example = "New York Stock Exchange")
private String name;
@NotBlank
@ApiModelProperty(name = "container internal name", example = "new_york_stock_exchange")
private String internalName;
}
......@@ -21,7 +21,11 @@ public class DatabaseBriefDto {
private Long id;
@NotBlank
@Parameter(name = "database name", example = "CTFs")
@Parameter(name = "database name", example = "Exchange Traded Funds")
private String name;
@NotBlank
@Parameter(name = "database internal name", example = "exchange_traded_funds")
private String internalName;
}
......@@ -19,7 +19,7 @@ public class DatabaseCreateDto {
private Long containerId;
@NotBlank
@ApiModelProperty(name = "database name", example = "ctfs")
@ApiModelProperty(name = "database name", example = "Exchange Traded Fund")
private String name;
}
......@@ -33,7 +33,7 @@ public class SwaggerConfig {
"Service that can manage a database container",
"1.0",
null,
new Contact("Martin Weise", "https://informatics.tuwien.ac.at/people/martin-weise", "martin.weise@tuwien.ac.at"),
new Contact("Ao.Univ.Prof. Andreas Rauber", "http://www.ifs.tuwien.ac.at/~andi/", "rauber@ifs.tuwien.ac.at"),
"API license",
null,
Collections.emptyList());
......
......@@ -35,6 +35,10 @@ public class Container extends Auditable {
@Column
private Integer port;
@ToString.Exclude
@Column(nullable = false)
private String internalName;
@ToString.Include
@ManyToOne(fetch = FetchType.EAGER, cascade = CascadeType.ALL)
private ContainerImage image;
......
......@@ -47,6 +47,10 @@ public class Database {
@Column(nullable = false)
private String name;
@ToString.Exclude
@Column(nullable = false)
private String internalName;
@ToString.Include
@Column(nullable = false)
private Boolean isPublic;
......
......@@ -6,6 +6,10 @@ import org.mapstruct.Mapper;
import org.mapstruct.Mapping;
import org.mapstruct.Mappings;
import java.text.Normalizer;
import java.util.Locale;
import java.util.regex.Pattern;
@Mapper(componentModel = "spring")
public interface DatabaseMapper {
......@@ -14,4 +18,14 @@ public interface DatabaseMapper {
})
DatabaseBriefDto databaseToDatabaseBriefDto(Database data);
// https://stackoverflow.com/questions/1657193/java-code-library-for-generating-slugs-for-use-in-pretty-urls#answer-1657250
default String databaseToInternalDatabaseName(Database data) {
final Pattern NONLATIN = Pattern.compile("[^\\w-]");
final Pattern WHITESPACE = Pattern.compile("[\\s]");
String nowhitespace = WHITESPACE.matcher(data.getName()).replaceAll("_");
String normalized = Normalizer.normalize(nowhitespace, Normalizer.Form.NFD);
String slug = NONLATIN.matcher(normalized).replaceAll("");
return slug.toLowerCase(Locale.ENGLISH);
}
}
......@@ -4,6 +4,7 @@ import at.tuwien.dto.database.DatabaseCreateDto;
import at.tuwien.entity.Container;
import at.tuwien.entity.Database;
import at.tuwien.exception.*;
import at.tuwien.mapper.DatabaseMapper;
import at.tuwien.repository.ContainerRepository;
import at.tuwien.repository.DatabaseRepository;
import lombok.extern.log4j.Log4j2;
......@@ -20,13 +21,15 @@ public class DatabaseService {
private final ContainerRepository containerRepository;
private final DatabaseRepository databaseRepository;
private final PostgresService postgresService;
private final DatabaseMapper databaseMapper;
@Autowired
public DatabaseService(ContainerRepository containerRepository, DatabaseRepository databaseRepository,
PostgresService postgresService) {
PostgresService postgresService, DatabaseMapper databaseMapper) {
this.containerRepository = containerRepository;
this.databaseRepository = databaseRepository;
this.postgresService = postgresService;
this.databaseMapper = databaseMapper;
}
/**
......@@ -95,6 +98,7 @@ public class DatabaseService {
database.setName(createDto.getName());
database.setContainer(container);
database.setIsPublic(false);
database.setInternalName(databaseMapper.databaseToInternalDatabaseName(database));
postgresService.create(database);
// save in metadata database
final Database out = databaseRepository.save(database);
......
......@@ -42,7 +42,7 @@ public abstract class JdbcConnector {
* @return A prepared statement
* @throws SQLException In case the compiled query is invalid
*/
abstract PreparedStatement getCreateDatabaseStatement(Connection connection, String databaseName)
abstract PreparedStatement getCreateDatabaseStatement(Connection connection, Database database)
throws SQLException;
/**
......@@ -53,7 +53,7 @@ public abstract class JdbcConnector {
* @return A prepared statement
* @throws SQLException In case the compiled query is invalid
*/
abstract PreparedStatement getDeleteDatabaseStatement(Connection connection, String databaseName)
abstract PreparedStatement getDeleteDatabaseStatement(Connection connection, Database database)
throws SQLException;
}
......@@ -3,6 +3,7 @@ package at.tuwien.service;
import at.tuwien.entity.Database;
import at.tuwien.exception.DatabaseConnectionException;
import at.tuwien.exception.DatabaseMalformedException;
import at.tuwien.mapper.DatabaseMapper;
import at.tuwien.repository.DatabaseRepository;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
......@@ -18,18 +19,21 @@ import java.util.Properties;
public class PostgresService extends JdbcConnector {
private final Properties postgresProperties;
private final DatabaseMapper databaseMapper;
private final DatabaseRepository databaseRepository;
@Autowired
public PostgresService(Properties postgresProperties, DatabaseRepository databaseRepository) {
public PostgresService(Properties postgresProperties, DatabaseMapper databaseMapper,
DatabaseRepository databaseRepository) {
this.postgresProperties = postgresProperties;
this.databaseMapper = databaseMapper;
this.databaseRepository = databaseRepository;
}
@Override
void create(Database database) throws DatabaseConnectionException, DatabaseMalformedException {
final Connection connection;
final String URL = "jdbc:postgresql://" + database.getContainer().getName() + ":"
final String URL = "jdbc:postgresql://" + database.getContainer().getInternalName() + ":"
+ database.getContainer().getImage().getDefaultPort() + "/postgres";
try {
connection = open(URL, postgresProperties);
......@@ -38,7 +42,7 @@ public class PostgresService extends JdbcConnector {
throw new DatabaseConnectionException("Could not connect to the database container, is it running?", e);
}
try {
final PreparedStatement statement = getCreateDatabaseStatement(connection, database.getName());
final PreparedStatement statement = getCreateDatabaseStatement(connection, database);
statement.execute();
} catch (SQLException e) {
log.error("The SQL statement seems to contain invalid syntax");
......@@ -49,7 +53,7 @@ public class PostgresService extends JdbcConnector {
@Override
void delete(Database database) throws DatabaseConnectionException, DatabaseMalformedException {
final Connection connection;
final String URL = "jdbc:postgresql://" + database.getContainer().getName() + ":"
final String URL = "jdbc:postgresql://" + database.getContainer().getInternalName() + ":"
+ database.getContainer().getImage().getDefaultPort() + "/postgres";
try {
connection = open(URL, postgresProperties);
......@@ -58,7 +62,7 @@ public class PostgresService extends JdbcConnector {
throw new DatabaseConnectionException("Could not connect to the database container, is it running?", e);
}
try {
final PreparedStatement statement = getDeleteDatabaseStatement(connection, database.getName());
final PreparedStatement statement = getDeleteDatabaseStatement(connection, database);
statement.execute();
} catch (SQLException e) {
log.error("The SQL statement seems to contain invalid syntax or already exists");
......@@ -68,11 +72,11 @@ public class PostgresService extends JdbcConnector {
@Override
PreparedStatement getCreateDatabaseStatement(Connection connection, String databaseName)
PreparedStatement getCreateDatabaseStatement(Connection connection, Database database)
throws SQLException {
final StringBuilder queryBuilder = new StringBuilder()
.append("CREATE DATABASE ")
.append(databaseName);
.append(database.getInternalName());
queryBuilder.append(";");
final String createQuery = queryBuilder.toString();
log.debug("compiled create db query as \"{}\"", createQuery);
......@@ -80,10 +84,10 @@ public class PostgresService extends JdbcConnector {
}
@Override
PreparedStatement getDeleteDatabaseStatement(Connection connection, String databaseName) throws SQLException {
PreparedStatement getDeleteDatabaseStatement(Connection connection, Database database) throws SQLException {
final StringBuilder queryBuilder = new StringBuilder()
.append("DROP DATABASE ")
.append(databaseName);
.append(database.getInternalName());
queryBuilder.append(";");
final String deleteQuery = queryBuilder.toString();
log.debug("compiled delete db query as \"{}\"", deleteQuery);
......
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Please register or to comment