22
33import static io .quarkus .devservices .common .ContainerLocator .locateContainerWithLabels ;
44
5+ import java .io .IOException ;
6+ import java .io .InputStream ;
7+ import java .io .UncheckedIOException ;
58import java .time .Duration ;
69import java .util .Collections ;
710import java .util .HashMap ;
1013import java .util .Locale ;
1114import java .util .Map ;
1215import java .util .Optional ;
16+ import java .util .Properties ;
1317import java .util .Set ;
1418import java .util .function .Supplier ;
1519
@@ -59,19 +63,21 @@ public class DevServicesElasticsearchProcessor {
5963 static final String DEV_SERVICE_LABEL = "quarkus-dev-service-elasticsearch" ;
6064 static final String NEW_DEV_SERVICE_LABEL = "io.quarkus.devservice.elasticsearch" ;
6165 static final int ELASTICSEARCH_PORT = 9200 ;
62- static final int KIBANA_PORT = 5601 ;
66+ static final int DASHBOARD_PORT = 5601 ;
6367
6468 private static final ContainerLocator elasticsearchContainerLocator = locateContainerWithLabels (ELASTICSEARCH_PORT ,
6569 DEV_SERVICE_LABEL , NEW_DEV_SERVICE_LABEL );
66- private static final ContainerLocator dashboardContainerLocator = locateContainerWithLabels (KIBANA_PORT ,
70+ private static final ContainerLocator dashboardContainerLocator = locateContainerWithLabels (DASHBOARD_PORT ,
6771 DEV_SERVICE_LABEL , NEW_DEV_SERVICE_LABEL );
6872
6973 private static final Distribution DEFAULT_DISTRIBUTION = Distribution .ELASTIC ;
7074 private static final String DEV_SERVICE_ELASTICSEARCH = "elasticsearch" ;
71- private static final String DEV_SERVICE_KIBANA = "kibana" ;
7275 private static final String DEV_SERVICE_OPENSEARCH = "opensearch" ;
76+ private static final String DEV_SERVICE_DASHBOARDS = "opensearch-dashboards" ;
77+ private static final String DEV_SERVICE_KIBANA = "kibana" ;
7378
7479 static volatile RunningDevService devService ;
80+ static volatile RunningDevService devDashboardService ;
7581 static volatile ElasticsearchCommonBuildTimeConfig cfg ;
7682 static volatile boolean first = true ;
7783
@@ -113,11 +119,11 @@ public DevServicesResultBuildItem startElasticsearchDevService(
113119 devServicesSharedNetworkBuildItem );
114120 devService = startElasticsearchDevServices (dockerStatusBuildItem , composeProjectBuildItem ,
115121 configuration .devservices (), buildItemsConfig , launchMode , useSharedNetwork , devServicesConfig .timeout ());
116- //BS
117122
118- startDashboardDevServices (dockerStatusBuildItem , composeProjectBuildItem , configuration .devservices (),
123+ devDashboardService = startDashboardDevServices (dockerStatusBuildItem , composeProjectBuildItem ,
124+ configuration .devservices (),
119125 buildItemsConfig , launchMode , useSharedNetwork , devServicesConfig .timeout ());
120- //End BS
126+
121127 if (devService == null ) {
122128 compressor .closeAndDumpCaptured ();
123129 } else {
@@ -139,6 +145,9 @@ public DevServicesResultBuildItem startElasticsearchDevService(
139145 if (devService != null ) {
140146 shutdownElasticsearch ();
141147 }
148+ if (devDashboardService != null ) {
149+ shutdownDashboard ();
150+ }
142151 first = true ;
143152 devService = null ;
144153 cfg = null ;
@@ -174,6 +183,18 @@ private void shutdownElasticsearch() {
174183 }
175184 }
176185
186+ private void shutdownDashboard () {
187+ if (devService != null ) {
188+ try {
189+ devDashboardService .close ();
190+ } catch (Throwable e ) {
191+ log .error ("Failed to stop the Dashboard" , e );
192+ } finally {
193+ devService = null ;
194+ }
195+ }
196+ }
197+
177198 private RunningDevService startElasticsearchDevServices (
178199 DockerStatusBuildItem dockerStatusBuildItem ,
179200 DevServicesComposeProjectBuildItem composeProjectBuildItem ,
@@ -262,7 +283,7 @@ private RunningDevService startDashboardDevServices(
262283 return null ;
263284 }
264285
265- if (!config .kibana ().enabled ()) {
286+ if (!config .dashboard ().enabled ()) {
266287 // Kibana explicitly disabled
267288 log .debug ("Not starting Kibana Dev Service, as it has been disabled in the config." );
268289 return null ;
@@ -284,15 +305,15 @@ private RunningDevService startDashboardDevServices(
284305 }
285306
286307 Distribution resolvedDistribution = resolveDistribution (config , buildItemConfig );
287- DockerImageName resolvedImageName = resolveKibanaImageName (config , resolvedDistribution );
308+ DockerImageName resolvedImageName = resolveDashboardImageName (config , resolvedDistribution );
288309
289310 final Optional <ContainerAddress > maybeContainerAddress = dashboardContainerLocator .locateContainer (
290311 config .serviceName (),
291312 config .shared (),
292313 launchMode .getLaunchMode ())
293314 .or (() -> ComposeLocator .locateContainer (composeProjectBuildItem ,
294315 List .of (resolvedImageName .getUnversionedPart (), "elasticsearch" , "opensearch" ),
295- KIBANA_PORT ,
316+ DASHBOARD_PORT ,
296317 launchMode .getLaunchMode (), useSharedNetwork ));
297318
298319 // Starting the server
@@ -302,25 +323,24 @@ private RunningDevService startDashboardDevServices(
302323 CreatedContainer createdContainer = resolvedDistribution .equals (Distribution .ELASTIC )
303324 ? createKibanaContainer (config , resolvedImageName , defaultNetworkId , useSharedNetwork , launchMode ,
304325 composeProjectBuildItem )
305- : createKibanaContainer (config , resolvedImageName , defaultNetworkId , useSharedNetwork , launchMode ,
326+ : createDashboardsContainer (config , resolvedImageName , defaultNetworkId , useSharedNetwork , launchMode ,
306327 composeProjectBuildItem );
307328 GenericContainer <?> container = createdContainer .genericContainer ();
308329
309330 if (config .serviceName () != null ) {
310331 container .withLabel (DEV_SERVICE_LABEL , config .serviceName ());
311332 container .withLabel (Labels .QUARKUS_DEV_SERVICE , config .serviceName ());
312333 }
313- if (config .port ().isPresent ()) {
314- //TODO port mapping configuration
315- container .setPortBindings (List .of (KIBANA_PORT + ":" + KIBANA_PORT ));
334+ if (config .dashboard ().port ().isPresent ()) {
335+ container .setPortBindings (List .of (config .dashboard ().port ().get () + ":" + DASHBOARD_PORT ));
316336 }
317337 timeout .ifPresent (container ::withStartupTimeout );
318- container .withEnv (config .containerEnv ());
338+ container .withEnv (config .dashboard (). containerEnv ());
319339 container .withReuse (config .reuse ());
320340 container .start ();
321341
322342 var httpHost = createdContainer .hostName + ":"
323- + (useSharedNetwork ? KIBANA_PORT : container .getMappedPort (KIBANA_PORT ));
343+ + (useSharedNetwork ? DASHBOARD_PORT : container .getMappedPort (DASHBOARD_PORT ));
324344 return new RunningDevService (Feature .ELASTICSEARCH_REST_CLIENT_COMMON .getName (),
325345 container .getContainerId (),
326346 new ContainerShutdownCloseable (container , "Kibana" ),
@@ -389,9 +409,7 @@ private CreatedContainer createKibanaContainer(ElasticsearchDevServicesBuildTime
389409
390410 String kibanaHostName = ConfigureUtil .configureNetwork (container , defaultNetworkId , useSharedNetwork ,
391411 DEV_SERVICE_KIBANA );
392- String elasticsearchHostName = ConfigureUtil .configureNetwork (container , defaultNetworkId , useSharedNetwork ,
393- DEV_SERVICE_ELASTICSEARCH );
394- container .setExposedPorts (List .of (KIBANA_PORT ));
412+ container .setExposedPorts (List .of (DASHBOARD_PORT ));
395413
396414 final Optional <ContainerAddress > maybeContainerAddress = elasticsearchContainerLocator .locateContainer (
397415 config .serviceName (),
@@ -407,9 +425,37 @@ private CreatedContainer createKibanaContainer(ElasticsearchDevServicesBuildTime
407425 .replace ("localhost" , "host.docker.internal" ))
408426 .ifPresent (addressStr -> container .addEnv ("ELASTICSEARCH_HOSTS" ,
409427 addressStr ));
410- container .addEnv ("ELASTICSEARCH_USERNAME" , "kibana_system" );
411- container .addEnv ("ELASTICSEARCH_PASSWORD" , "test" );
428+ container .addEnv ("NODE_OPTIONS" , config .dashboard ().nodeOpts ());
429+ return new CreatedContainer (container , kibanaHostName );
430+ }
431+
432+ private CreatedContainer createDashboardsContainer (ElasticsearchDevServicesBuildTimeConfig config ,
433+ DockerImageName resolvedImageName , String defaultNetworkId , boolean useSharedNetwork ,
434+ LaunchModeBuildItem launchMode , DevServicesComposeProjectBuildItem composeProjectBuildItem ) {
435+ //Create Generic Kibana container
436+ GenericContainer <?> container = new GenericContainer <>(
437+ resolvedImageName .asCompatibleSubstituteFor ("opensearchproject/opensearch-dashboards" ));
438+
439+ String kibanaHostName = ConfigureUtil .configureNetwork (container , defaultNetworkId , useSharedNetwork ,
440+ DEV_SERVICE_DASHBOARDS );
441+ container .setExposedPorts (List .of (DASHBOARD_PORT ));
442+
443+ final Optional <ContainerAddress > maybeContainerAddress = elasticsearchContainerLocator .locateContainer (
444+ config .serviceName (),
445+ config .shared (),
446+ launchMode .getLaunchMode ())
447+ .or (() -> ComposeLocator .locateContainer (composeProjectBuildItem ,
448+ List .of (resolvedImageName .getUnversionedPart (), "elasticsearch" , "opensearch" ),
449+ ELASTICSEARCH_PORT ,
450+ launchMode .getLaunchMode (), useSharedNetwork ));
412451
452+ maybeContainerAddress
453+ .map (containerAddress -> ("http://" + containerAddress .getHost () + ":" + containerAddress .getPort ())
454+ .replace ("localhost" , "host.docker.internal" ))
455+ .ifPresent (addressStr -> container .addEnv ("OPENSEARCH_HOSTS" ,
456+ addressStr ));
457+ container .addEnv ("NODE_OPTIONS" , config .dashboard ().nodeOpts ());
458+ container .addEnv ("DISABLE_SECURITY_DASHBOARDS_PLUGIN" , "true" );
413459 return new CreatedContainer (container , kibanaHostName );
414460 }
415461
@@ -424,11 +470,27 @@ private DockerImageName resolveImageName(ElasticsearchDevServicesBuildTimeConfig
424470 : DEV_SERVICE_OPENSEARCH )));
425471 }
426472
427- private DockerImageName resolveKibanaImageName (ElasticsearchDevServicesBuildTimeConfig config ,
473+ private DockerImageName resolveDashboardImageName (ElasticsearchDevServicesBuildTimeConfig config ,
428474 Distribution resolvedDistribution ) {
429- return DockerImageName .parse ("docker.io/elastic/kibana:9.1.5" );
430- //return DockerImageName.parse(
431- // config.imageKibanaName().orElseThrow(() -> new RuntimeException("Image name for Kibana is not configured")));
475+ return DockerImageName .parse (config .dashboard ().imageName ().orElseGet (() -> loadProperties (
476+ Distribution .ELASTIC .equals (resolvedDistribution )
477+ ? DEV_SERVICE_ELASTICSEARCH
478+ : DEV_SERVICE_OPENSEARCH )
479+ .getProperty ("default.dashboard.image" )));
480+ }
481+
482+ private static Properties loadProperties (String devserviceName ) {
483+ var fileName = devserviceName + "-devservice.properties" ;
484+ try (InputStream in = Thread .currentThread ().getContextClassLoader ().getResourceAsStream (fileName )) {
485+ if (in == null ) {
486+ throw new IllegalArgumentException (fileName + " not found on classpath" );
487+ }
488+ var properties = new Properties ();
489+ properties .load (in );
490+ return properties ;
491+ } catch (IOException e ) {
492+ throw new UncheckedIOException (e );
493+ }
432494 }
433495
434496 private Distribution resolveDistribution (ElasticsearchDevServicesBuildTimeConfig config ,
0 commit comments