Search in sources :

Example 1 with DevServicesDatasourceProvider

use of io.quarkus.datasource.deployment.spi.DevServicesDatasourceProvider in project quarkus by quarkusio.

the class DerbyDevServicesProcessor method setupDerby.

@BuildStep
DevServicesDatasourceProviderBuildItem setupDerby() {
    return new DevServicesDatasourceProviderBuildItem(DatabaseKind.DERBY, new DevServicesDatasourceProvider() {

        @Override
        public RunningDevServicesDatasource startDatabase(Optional<String> username, Optional<String> password, Optional<String> datasourceName, Optional<String> imageName, Map<String, String> containerProperties, Map<String, String> additionalJdbcUrlProperties, OptionalInt fixedExposedPort, LaunchMode launchMode, Optional<Duration> startupTimeout) {
            try {
                int port = fixedExposedPort.isPresent() ? fixedExposedPort.getAsInt() : 1527 + (launchMode == LaunchMode.TEST ? 0 : 1);
                NetworkServerControl server = new NetworkServerControl(InetAddress.getByName("localhost"), port);
                server.start(new PrintWriter(System.out));
                for (int i = 1; i <= NUMBER_OF_PINGS; i++) {
                    try {
                        LOG.info("Attempt " + i + " to see if Dev Services for Derby started");
                        server.ping();
                        break;
                    } catch (Exception ex) {
                        if (i == NUMBER_OF_PINGS) {
                            LOG.error("Dev Services for Derby failed to start", ex);
                            throw ex;
                        }
                        try {
                            Thread.sleep(SLEEP_BETWEEN_PINGS);
                        } catch (InterruptedException ignore) {
                        }
                    }
                }
                LOG.info("Dev Services for Derby started.");
                StringBuilder additionalArgs = new StringBuilder();
                for (Map.Entry<String, String> i : additionalJdbcUrlProperties.entrySet()) {
                    additionalArgs.append(";");
                    additionalArgs.append(i.getKey());
                    additionalArgs.append("=");
                    additionalArgs.append(i.getValue());
                }
                return new RunningDevServicesDatasource(null, "jdbc:derby://localhost:" + port + "/memory:" + datasourceName.orElse("quarkus") + ";create=true" + additionalArgs.toString(), null, null, new Closeable() {

                    @Override
                    public void close() throws IOException {
                        try {
                            NetworkServerControl server = new NetworkServerControl(InetAddress.getByName("localhost"), port);
                            server.shutdown();
                            LOG.info("Dev Services for Derby shut down");
                        } catch (Exception e) {
                            throw new RuntimeException(e);
                        }
                    }
                });
            } catch (Exception throwable) {
                throw new RuntimeException(throwable);
            }
        }

        @Override
        public boolean isDockerRequired() {
            return false;
        }
    });
}
Also used : Closeable(java.io.Closeable) Duration(java.time.Duration) OptionalInt(java.util.OptionalInt) IOException(java.io.IOException) DevServicesDatasourceProvider(io.quarkus.datasource.deployment.spi.DevServicesDatasourceProvider) NetworkServerControl(org.apache.derby.drda.NetworkServerControl) LaunchMode(io.quarkus.runtime.LaunchMode) DevServicesDatasourceProviderBuildItem(io.quarkus.datasource.deployment.spi.DevServicesDatasourceProviderBuildItem) PrintWriter(java.io.PrintWriter) BuildStep(io.quarkus.deployment.annotations.BuildStep)

Example 2 with DevServicesDatasourceProvider

use of io.quarkus.datasource.deployment.spi.DevServicesDatasourceProvider in project quarkus by quarkusio.

the class DevServicesDatasourceProcessor method launchDatabases.

@BuildStep(onlyIfNot = IsNormal.class, onlyIf = GlobalDevServicesConfig.Enabled.class)
DevServicesDatasourceResultBuildItem launchDatabases(CurateOutcomeBuildItem curateOutcomeBuildItem, DockerStatusBuildItem dockerStatusBuildItem, List<DefaultDataSourceDbKindBuildItem> installedDrivers, List<DevServicesDatasourceProviderBuildItem> devDBProviders, DataSourcesBuildTimeConfig dataSourceBuildTimeConfig, LaunchModeBuildItem launchMode, List<DevServicesDatasourceConfigurationHandlerBuildItem> configurationHandlerBuildItems, BuildProducer<DevServicesResultBuildItem> devServicesResultBuildItemBuildProducer, Optional<ConsoleInstalledBuildItem> consoleInstalledBuildItem, CuratedApplicationShutdownBuildItem closeBuildItem, LoggingSetupBuildItem loggingSetupBuildItem, GlobalDevServicesConfig globalDevServicesConfig) {
    // if not and the DB's have already started we just return
    if (databases != null) {
        boolean restartRequired = false;
        if (!restartRequired) {
            for (Map.Entry<String, String> entry : cachedProperties.entrySet()) {
                if (!Objects.equals(entry.getValue(), trim(ConfigProvider.getConfig().getOptionalValue(entry.getKey(), String.class).orElse(null)))) {
                    restartRequired = true;
                    break;
                }
            }
        }
        if (!restartRequired) {
            // devservices properties may have been added
            for (var name : ConfigProvider.getConfig().getPropertyNames()) {
                if (name.startsWith("quarkus.datasource.") && name.contains(".devservices.") && !cachedProperties.containsKey(name)) {
                    restartRequired = true;
                    break;
                }
            }
        }
        if (!restartRequired) {
            for (RunningDevService database : databases) {
                devServicesResultBuildItemBuildProducer.produce(database.toBuildItem());
            }
            // keep the previous behaviour of producing DevServicesDatasourceResultBuildItem only when the devservice first starts.
            return null;
        }
        for (Closeable i : databases) {
            try {
                i.close();
            } catch (Throwable e) {
                log.error("Failed to stop database", e);
            }
        }
        databases = null;
        cachedProperties = null;
    }
    DevServicesDatasourceResultBuildItem.DbResult defaultResult;
    Map<String, DevServicesDatasourceResultBuildItem.DbResult> namedResults = new HashMap<>();
    // now we need to figure out if we need to launch some databases
    // note that because we run in dev and test mode only we know the runtime
    // config at build time, as they both execute in the same JVM
    // to keep things simpler for now we are only going to support this for the default datasource
    // support for named datasources will come later
    Map<String, String> propertiesMap = new HashMap<>();
    List<RunningDevService> runningDevServices = new ArrayList<>();
    Map<String, List<DevServicesDatasourceConfigurationHandlerBuildItem>> configHandlersByDbType = configurationHandlerBuildItems.stream().collect(Collectors.toMap(DevServicesDatasourceConfigurationHandlerBuildItem::getDbKind, Collections::singletonList, (configurationHandlerBuildItems1, configurationHandlerBuildItems2) -> {
        List<DevServicesDatasourceConfigurationHandlerBuildItem> ret = new ArrayList<>();
        ret.addAll(configurationHandlerBuildItems1);
        ret.addAll(configurationHandlerBuildItems2);
        return ret;
    }));
    Map<String, DevServicesDatasourceProvider> devDBProviderMap = devDBProviders.stream().collect(Collectors.toMap(DevServicesDatasourceProviderBuildItem::getDatabase, DevServicesDatasourceProviderBuildItem::getDevServicesProvider));
    RunningDevService defaultDevService = startDevDb(null, curateOutcomeBuildItem, installedDrivers, !dataSourceBuildTimeConfig.namedDataSources.isEmpty(), devDBProviderMap, dataSourceBuildTimeConfig.defaultDataSource, configHandlersByDbType, propertiesMap, dockerStatusBuildItem, launchMode.getLaunchMode(), consoleInstalledBuildItem, loggingSetupBuildItem, globalDevServicesConfig);
    if (defaultDevService != null) {
        runningDevServices.add(defaultDevService);
    }
    defaultResult = toDbResult(defaultDevService);
    for (Map.Entry<String, DataSourceBuildTimeConfig> entry : dataSourceBuildTimeConfig.namedDataSources.entrySet()) {
        RunningDevService namedDevService = startDevDb(entry.getKey(), curateOutcomeBuildItem, installedDrivers, true, devDBProviderMap, entry.getValue(), configHandlersByDbType, propertiesMap, dockerStatusBuildItem, launchMode.getLaunchMode(), consoleInstalledBuildItem, loggingSetupBuildItem, globalDevServicesConfig);
        if (namedDevService != null) {
            runningDevServices.add(namedDevService);
            namedResults.put(entry.getKey(), toDbResult(namedDevService));
        }
    }
    if (first) {
        first = false;
        Runnable closeTask = new Runnable() {

            @Override
            public void run() {
                if (databases != null) {
                    for (Closeable i : databases) {
                        try {
                            i.close();
                        } catch (Throwable t) {
                            log.error("Failed to stop database", t);
                        }
                    }
                }
                first = true;
                databases = null;
                cachedProperties = null;
            }
        };
        closeBuildItem.addCloseTask(closeTask, true);
    }
    databases = runningDevServices;
    cachedProperties = propertiesMap;
    for (RunningDevService database : databases) {
        devServicesResultBuildItemBuildProducer.produce(database.toBuildItem());
    }
    return new DevServicesDatasourceResultBuildItem(defaultResult, namedResults);
}
Also used : IsNormal(io.quarkus.deployment.IsNormal) DataSourcesBuildTimeConfig(io.quarkus.datasource.runtime.DataSourcesBuildTimeConfig) DevServicesDatasourceProvider(io.quarkus.datasource.deployment.spi.DevServicesDatasourceProvider) Logger(org.jboss.logging.Logger) LaunchMode(io.quarkus.runtime.LaunchMode) HashMap(java.util.HashMap) DevServicesDatasourceConfigurationHandlerBuildItem(io.quarkus.datasource.deployment.spi.DevServicesDatasourceConfigurationHandlerBuildItem) RunningDevService(io.quarkus.deployment.builditem.DevServicesResultBuildItem.RunningDevService) ConsoleInstalledBuildItem(io.quarkus.deployment.console.ConsoleInstalledBuildItem) CurateOutcomeBuildItem(io.quarkus.deployment.pkg.builditem.CurateOutcomeBuildItem) DevServicesDatasourceResultBuildItem(io.quarkus.datasource.deployment.spi.DevServicesDatasourceResultBuildItem) BuildProducer(io.quarkus.deployment.annotations.BuildProducer) ArrayList(java.util.ArrayList) BuildStep(io.quarkus.deployment.annotations.BuildStep) CuratedApplicationShutdownBuildItem(io.quarkus.deployment.builditem.CuratedApplicationShutdownBuildItem) Map(java.util.Map) LoggingSetupBuildItem(io.quarkus.deployment.logging.LoggingSetupBuildItem) DevServicesResultBuildItem(io.quarkus.deployment.builditem.DevServicesResultBuildItem) StartupLogCompressor(io.quarkus.deployment.console.StartupLogCompressor) GlobalDevServicesConfig(io.quarkus.deployment.dev.devservices.GlobalDevServicesConfig) DataSourceBuildTimeConfig(io.quarkus.datasource.runtime.DataSourceBuildTimeConfig) Collectors(java.util.stream.Collectors) DevServicesDatasourceProviderBuildItem(io.quarkus.datasource.deployment.spi.DevServicesDatasourceProviderBuildItem) Objects(java.util.Objects) List(java.util.List) ConfigProvider(org.eclipse.microprofile.config.ConfigProvider) LaunchModeBuildItem(io.quarkus.deployment.builditem.LaunchModeBuildItem) Closeable(java.io.Closeable) DefaultDataSourceDbKindBuildItem(io.quarkus.datasource.deployment.spi.DefaultDataSourceDbKindBuildItem) Optional(java.util.Optional) DockerStatusBuildItem(io.quarkus.deployment.builditem.DockerStatusBuildItem) Collections(java.util.Collections) HashMap(java.util.HashMap) Closeable(java.io.Closeable) ArrayList(java.util.ArrayList) DevServicesDatasourceProvider(io.quarkus.datasource.deployment.spi.DevServicesDatasourceProvider) RunningDevService(io.quarkus.deployment.builditem.DevServicesResultBuildItem.RunningDevService) ArrayList(java.util.ArrayList) List(java.util.List) DevServicesDatasourceResultBuildItem(io.quarkus.datasource.deployment.spi.DevServicesDatasourceResultBuildItem) DataSourceBuildTimeConfig(io.quarkus.datasource.runtime.DataSourceBuildTimeConfig) HashMap(java.util.HashMap) Map(java.util.Map) BuildStep(io.quarkus.deployment.annotations.BuildStep)

Example 3 with DevServicesDatasourceProvider

use of io.quarkus.datasource.deployment.spi.DevServicesDatasourceProvider in project quarkus by quarkusio.

the class DevServicesDatasourceProcessor method startDevDb.

private RunningDevService startDevDb(String dbName, CurateOutcomeBuildItem curateOutcomeBuildItem, List<DefaultDataSourceDbKindBuildItem> installedDrivers, boolean hasNamedDatasources, Map<String, DevServicesDatasourceProvider> devDBProviders, DataSourceBuildTimeConfig dataSourceBuildTimeConfig, Map<String, List<DevServicesDatasourceConfigurationHandlerBuildItem>> configurationHandlerBuildItems, Map<String, String> propertiesMap, DockerStatusBuildItem dockerStatusBuildItem, LaunchMode launchMode, Optional<ConsoleInstalledBuildItem> consoleInstalledBuildItem, LoggingSetupBuildItem loggingSetupBuildItem, GlobalDevServicesConfig globalDevServicesConfig) {
    boolean explicitlyDisabled = !(dataSourceBuildTimeConfig.devservices.enabled.orElse(true));
    if (explicitlyDisabled) {
        // explicitly disabled
        log.debug("Not starting devservices for " + (dbName == null ? "default datasource" : dbName) + " as it has been disabled in the config");
        return null;
    }
    Boolean enabled = dataSourceBuildTimeConfig.devservices.enabled.orElse(!hasNamedDatasources);
    Optional<String> defaultDbKind = DefaultDataSourceDbKindBuildItem.resolve(dataSourceBuildTimeConfig.dbKind, installedDrivers, dbName != null || enabled, curateOutcomeBuildItem);
    if (!defaultDbKind.isPresent()) {
        // nothing we can do
        log.warn("Unable to determine a database type for " + (dbName == null ? "default datasource" : dbName));
        return null;
    }
    DevServicesDatasourceProvider devDbProvider = devDBProviders.get(defaultDbKind.get());
    List<DevServicesDatasourceConfigurationHandlerBuildItem> configHandlers = configurationHandlerBuildItems.get(defaultDbKind.get());
    if (devDbProvider == null || configHandlers == null) {
        log.warn("Unable to start devservices for " + (dbName == null ? "default datasource" : dbName) + " as this datasource type (" + defaultDbKind.get() + ") does not support devservices");
        return null;
    }
    if (dataSourceBuildTimeConfig.devservices.enabled.isEmpty()) {
        for (DevServicesDatasourceConfigurationHandlerBuildItem i : configHandlers) {
            if (i.getCheckConfiguredFunction().test(dbName)) {
                // this database has explicit configuration
                // we don't start the devservices
                log.debug("Not starting devservices for " + (dbName == null ? "default datasource" : dbName) + " as it has explicit configuration");
                return null;
            }
        }
    }
    String prettyName = dbName == null ? "the default datasource" : " datasource '" + dbName + "'";
    if (devDbProvider.isDockerRequired() && !dockerStatusBuildItem.isDockerAvailable()) {
        String message = "Please configure the datasource URL for " + prettyName + " or ensure the Docker daemon is up and running.";
        if (launchMode == LaunchMode.TEST) {
            throw new IllegalStateException(message);
        } else {
            // in dev-mode we just want to warn users and allow them to recover
            log.warn(message);
            return null;
        }
    }
    // ok, so we know we need to start one
    StartupLogCompressor compressor = new StartupLogCompressor((launchMode == LaunchMode.TEST ? "(test) " : "") + "Database for " + prettyName + " (" + defaultDbKind.get() + ") starting:", consoleInstalledBuildItem, loggingSetupBuildItem);
    try {
        String prefix = "quarkus.datasource.";
        if (dbName != null) {
            prefix = prefix + dbName + ".";
        }
        DevServicesDatasourceProvider.RunningDevServicesDatasource datasource = devDbProvider.startDatabase(ConfigProvider.getConfig().getOptionalValue(prefix + "username", String.class), ConfigProvider.getConfig().getOptionalValue(prefix + "password", String.class), Optional.ofNullable(dbName), dataSourceBuildTimeConfig.devservices.imageName, dataSourceBuildTimeConfig.devservices.containerProperties, dataSourceBuildTimeConfig.devservices.properties, dataSourceBuildTimeConfig.devservices.port, launchMode, globalDevServicesConfig.timeout);
        propertiesMap.put(prefix + "db-kind", dataSourceBuildTimeConfig.dbKind.orElse(null));
        String devServicesPrefix = prefix + "devservices.";
        if (dataSourceBuildTimeConfig.devservices.imageName.isPresent()) {
            propertiesMap.put(devServicesPrefix + "image-name", dataSourceBuildTimeConfig.devservices.imageName.get());
        }
        if (dataSourceBuildTimeConfig.devservices.port.isPresent()) {
            propertiesMap.put(devServicesPrefix + "port", Integer.toString(dataSourceBuildTimeConfig.devservices.port.getAsInt()));
        }
        if (!dataSourceBuildTimeConfig.devservices.properties.isEmpty()) {
            for (var e : dataSourceBuildTimeConfig.devservices.properties.entrySet()) {
                propertiesMap.put(devServicesPrefix + "properties." + e.getKey(), e.getValue());
            }
        }
        Map<String, String> devDebProperties = new HashMap<>();
        for (DevServicesDatasourceConfigurationHandlerBuildItem devDbConfigurationHandlerBuildItem : configHandlers) {
            devDebProperties.putAll(devDbConfigurationHandlerBuildItem.getConfigProviderFunction().apply(dbName, datasource));
        }
        devDebProperties.put(prefix + "db-kind", defaultDbKind.get());
        if (datasource.getUsername() != null) {
            devDebProperties.put(prefix + "username", datasource.getUsername());
        }
        if (datasource.getPassword() != null) {
            devDebProperties.put(prefix + "password", datasource.getPassword());
        }
        compressor.close();
        log.info("Dev Services for " + prettyName + " (" + defaultDbKind.get() + ") started.");
        String devservices = prefix + "devservices.";
        for (var name : ConfigProvider.getConfig().getPropertyNames()) {
            if (name.startsWith(devservices)) {
                devDebProperties.put(name, ConfigProvider.getConfig().getValue(name, String.class));
            }
        }
        return new RunningDevService(defaultDbKind.get(), datasource.getId(), datasource.getCloseTask(), devDebProperties);
    } catch (Throwable t) {
        compressor.closeAndDumpCaptured();
        throw new RuntimeException(t);
    }
}
Also used : HashMap(java.util.HashMap) DevServicesDatasourceConfigurationHandlerBuildItem(io.quarkus.datasource.deployment.spi.DevServicesDatasourceConfigurationHandlerBuildItem) StartupLogCompressor(io.quarkus.deployment.console.StartupLogCompressor) DevServicesDatasourceProvider(io.quarkus.datasource.deployment.spi.DevServicesDatasourceProvider) RunningDevService(io.quarkus.deployment.builditem.DevServicesResultBuildItem.RunningDevService)

Example 4 with DevServicesDatasourceProvider

use of io.quarkus.datasource.deployment.spi.DevServicesDatasourceProvider in project quarkus by quarkusio.

the class H2DevServicesProcessor method setupH2.

@BuildStep
DevServicesDatasourceProviderBuildItem setupH2() {
    return new DevServicesDatasourceProviderBuildItem(DatabaseKind.H2, new DevServicesDatasourceProvider() {

        @Override
        public RunningDevServicesDatasource startDatabase(Optional<String> username, Optional<String> password, Optional<String> datasourceName, Optional<String> imageName, Map<String, String> containerProperties, Map<String, String> additionalJdbcUrlProperties, OptionalInt port, LaunchMode launchMode, Optional<Duration> startupTimeout) {
            try {
                final Server tcpServer = Server.createTcpServer("-tcpPort", port.isPresent() ? String.valueOf(port.getAsInt()) : "0", "-ifNotExists");
                tcpServer.start();
                StringBuilder additionalArgs = new StringBuilder();
                for (Map.Entry<String, String> i : additionalJdbcUrlProperties.entrySet()) {
                    additionalArgs.append(";");
                    additionalArgs.append(i.getKey());
                    additionalArgs.append("=");
                    additionalArgs.append(i.getValue());
                }
                LOG.info("Dev Services for H2 started.");
                String connectionUrl = "jdbc:h2:tcp://localhost:" + tcpServer.getPort() + "/mem:" + datasourceName.orElse("default") + ";DB_CLOSE_DELAY=-1" + additionalArgs.toString();
                return new RunningDevServicesDatasource(null, connectionUrl, "sa", "sa", new Closeable() {

                    @Override
                    public void close() throws IOException {
                        // (perhaps we failed to start?)
                        if (tcpServer.isRunning(false)) {
                            // make sure the DB is removed on close
                            try (Connection connection = DriverManager.getConnection(connectionUrl, "sa", "sa")) {
                                try (Statement statement = connection.createStatement()) {
                                    statement.execute("SET DB_CLOSE_DELAY 0");
                                }
                            } catch (SQLException t) {
                                t.printStackTrace();
                            }
                            tcpServer.stop();
                            LOG.info("Dev Services for H2 shut down; server status: " + tcpServer.getStatus());
                        } else {
                            LOG.info("Dev Services for H2 was NOT shut down as it appears it was down already; server status: " + tcpServer.getStatus());
                        }
                    }
                });
            } catch (SQLException throwables) {
                throw new RuntimeException(throwables);
            }
        }

        @Override
        public boolean isDockerRequired() {
            return false;
        }
    });
}
Also used : Server(org.h2.tools.Server) SQLException(java.sql.SQLException) Statement(java.sql.Statement) Closeable(java.io.Closeable) Connection(java.sql.Connection) Duration(java.time.Duration) OptionalInt(java.util.OptionalInt) DevServicesDatasourceProvider(io.quarkus.datasource.deployment.spi.DevServicesDatasourceProvider) LaunchMode(io.quarkus.runtime.LaunchMode) DevServicesDatasourceProviderBuildItem(io.quarkus.datasource.deployment.spi.DevServicesDatasourceProviderBuildItem) BuildStep(io.quarkus.deployment.annotations.BuildStep)

Aggregations

DevServicesDatasourceProvider (io.quarkus.datasource.deployment.spi.DevServicesDatasourceProvider)4 DevServicesDatasourceProviderBuildItem (io.quarkus.datasource.deployment.spi.DevServicesDatasourceProviderBuildItem)3 BuildStep (io.quarkus.deployment.annotations.BuildStep)3 LaunchMode (io.quarkus.runtime.LaunchMode)3 Closeable (java.io.Closeable)3 DevServicesDatasourceConfigurationHandlerBuildItem (io.quarkus.datasource.deployment.spi.DevServicesDatasourceConfigurationHandlerBuildItem)2 RunningDevService (io.quarkus.deployment.builditem.DevServicesResultBuildItem.RunningDevService)2 StartupLogCompressor (io.quarkus.deployment.console.StartupLogCompressor)2 Duration (java.time.Duration)2 HashMap (java.util.HashMap)2 OptionalInt (java.util.OptionalInt)2 DefaultDataSourceDbKindBuildItem (io.quarkus.datasource.deployment.spi.DefaultDataSourceDbKindBuildItem)1 DevServicesDatasourceResultBuildItem (io.quarkus.datasource.deployment.spi.DevServicesDatasourceResultBuildItem)1 DataSourceBuildTimeConfig (io.quarkus.datasource.runtime.DataSourceBuildTimeConfig)1 DataSourcesBuildTimeConfig (io.quarkus.datasource.runtime.DataSourcesBuildTimeConfig)1 IsNormal (io.quarkus.deployment.IsNormal)1 BuildProducer (io.quarkus.deployment.annotations.BuildProducer)1 CuratedApplicationShutdownBuildItem (io.quarkus.deployment.builditem.CuratedApplicationShutdownBuildItem)1 DevServicesResultBuildItem (io.quarkus.deployment.builditem.DevServicesResultBuildItem)1 DockerStatusBuildItem (io.quarkus.deployment.builditem.DockerStatusBuildItem)1