mirror of
https://github.com/spring-projects/spring-boot.git
synced 2024-09-03 04:26:12 +08:00
Add property to control Docker Compose start command execution
If the property 'spring.docker.compose.start.skip' is set to 'never', the start command is always executed. The default value of 'if-running' only executes the start command if there are no services running already, which is the old behavior. Closes gh-39749
This commit is contained in:
parent
2ab0e024c8
commit
6d192e62fd
@ -1,5 +1,5 @@
|
|||||||
/*
|
/*
|
||||||
* Copyright 2012-2023 the original author or authors.
|
* Copyright 2012-2024 the original author or authors.
|
||||||
*
|
*
|
||||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
* you may not use this file except in compliance with the License.
|
* you may not use this file except in compliance with the License.
|
||||||
@ -32,6 +32,7 @@ import org.springframework.boot.docker.compose.core.DockerComposeFile;
|
|||||||
import org.springframework.boot.docker.compose.core.RunningService;
|
import org.springframework.boot.docker.compose.core.RunningService;
|
||||||
import org.springframework.boot.docker.compose.lifecycle.DockerComposeProperties.Readiness.Wait;
|
import org.springframework.boot.docker.compose.lifecycle.DockerComposeProperties.Readiness.Wait;
|
||||||
import org.springframework.boot.docker.compose.lifecycle.DockerComposeProperties.Start;
|
import org.springframework.boot.docker.compose.lifecycle.DockerComposeProperties.Start;
|
||||||
|
import org.springframework.boot.docker.compose.lifecycle.DockerComposeProperties.Start.Skip;
|
||||||
import org.springframework.boot.docker.compose.lifecycle.DockerComposeProperties.Stop;
|
import org.springframework.boot.docker.compose.lifecycle.DockerComposeProperties.Stop;
|
||||||
import org.springframework.context.ApplicationContext;
|
import org.springframework.context.ApplicationContext;
|
||||||
import org.springframework.context.ApplicationListener;
|
import org.springframework.context.ApplicationListener;
|
||||||
@ -119,7 +120,11 @@ class DockerComposeLifecycleManager {
|
|||||||
Wait wait = this.properties.getReadiness().getWait();
|
Wait wait = this.properties.getReadiness().getWait();
|
||||||
List<RunningService> runningServices = dockerCompose.getRunningServices();
|
List<RunningService> runningServices = dockerCompose.getRunningServices();
|
||||||
if (lifecycleManagement.shouldStart()) {
|
if (lifecycleManagement.shouldStart()) {
|
||||||
if (runningServices.isEmpty()) {
|
Skip skip = this.properties.getStart().getSkip();
|
||||||
|
if (skip.shouldSkip(runningServices)) {
|
||||||
|
logger.info(skip.getLogMessage());
|
||||||
|
}
|
||||||
|
else {
|
||||||
start.getCommand().applyTo(dockerCompose, start.getLogLevel());
|
start.getCommand().applyTo(dockerCompose, start.getLogLevel());
|
||||||
runningServices = dockerCompose.getRunningServices();
|
runningServices = dockerCompose.getRunningServices();
|
||||||
if (wait == Wait.ONLY_IF_STARTED) {
|
if (wait == Wait.ONLY_IF_STARTED) {
|
||||||
@ -129,9 +134,6 @@ class DockerComposeLifecycleManager {
|
|||||||
this.shutdownHandlers.add(() -> stop.getCommand().applyTo(dockerCompose, stop.getTimeout()));
|
this.shutdownHandlers.add(() -> stop.getCommand().applyTo(dockerCompose, stop.getTimeout()));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else {
|
|
||||||
logger.info("There are already Docker Compose services running, skipping startup");
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
List<RunningService> relevantServices = new ArrayList<>(runningServices);
|
List<RunningService> relevantServices = new ArrayList<>(runningServices);
|
||||||
relevantServices.removeIf(this::isIgnored);
|
relevantServices.removeIf(this::isIgnored);
|
||||||
|
@ -1,5 +1,5 @@
|
|||||||
/*
|
/*
|
||||||
* Copyright 2012-2023 the original author or authors.
|
* Copyright 2012-2024 the original author or authors.
|
||||||
*
|
*
|
||||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
* you may not use this file except in compliance with the License.
|
* you may not use this file except in compliance with the License.
|
||||||
@ -19,10 +19,12 @@ package org.springframework.boot.docker.compose.lifecycle;
|
|||||||
import java.io.File;
|
import java.io.File;
|
||||||
import java.time.Duration;
|
import java.time.Duration;
|
||||||
import java.util.LinkedHashSet;
|
import java.util.LinkedHashSet;
|
||||||
|
import java.util.List;
|
||||||
import java.util.Set;
|
import java.util.Set;
|
||||||
|
|
||||||
import org.springframework.boot.context.properties.ConfigurationProperties;
|
import org.springframework.boot.context.properties.ConfigurationProperties;
|
||||||
import org.springframework.boot.context.properties.bind.Binder;
|
import org.springframework.boot.context.properties.bind.Binder;
|
||||||
|
import org.springframework.boot.docker.compose.core.RunningService;
|
||||||
import org.springframework.boot.logging.LogLevel;
|
import org.springframework.boot.logging.LogLevel;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -148,6 +150,11 @@ public class DockerComposeProperties {
|
|||||||
*/
|
*/
|
||||||
private LogLevel logLevel = LogLevel.INFO;
|
private LogLevel logLevel = LogLevel.INFO;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Whether to skip executing the start command.
|
||||||
|
*/
|
||||||
|
private Skip skip = Skip.IF_RUNNING;
|
||||||
|
|
||||||
public StartCommand getCommand() {
|
public StartCommand getCommand() {
|
||||||
return this.command;
|
return this.command;
|
||||||
}
|
}
|
||||||
@ -164,6 +171,51 @@ public class DockerComposeProperties {
|
|||||||
this.logLevel = logLevel;
|
this.logLevel = logLevel;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public Skip getSkip() {
|
||||||
|
return this.skip;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setSkip(Skip skip) {
|
||||||
|
this.skip = skip;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Start command skip mode.
|
||||||
|
*/
|
||||||
|
public enum Skip {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Never skip start.
|
||||||
|
*/
|
||||||
|
NEVER {
|
||||||
|
@Override
|
||||||
|
boolean shouldSkip(List<RunningService> runningServices) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
},
|
||||||
|
/**
|
||||||
|
* Skip start if there are already services running.
|
||||||
|
*/
|
||||||
|
IF_RUNNING {
|
||||||
|
@Override
|
||||||
|
boolean shouldSkip(List<RunningService> runningServices) {
|
||||||
|
return !runningServices.isEmpty();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
String getLogMessage() {
|
||||||
|
return "There are already Docker Compose services running, skipping startup";
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
abstract boolean shouldSkip(List<RunningService> runningServices);
|
||||||
|
|
||||||
|
String getLogMessage() {
|
||||||
|
return "";
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -18,6 +18,10 @@
|
|||||||
"name": "spring.docker.compose.start.log-level",
|
"name": "spring.docker.compose.start.log-level",
|
||||||
"defaultValue": "info"
|
"defaultValue": "info"
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
"name": "spring.docker.compose.start.skip",
|
||||||
|
"defaultValue": "if-running"
|
||||||
|
},
|
||||||
{
|
{
|
||||||
"name": "spring.docker.compose.stop.command",
|
"name": "spring.docker.compose.stop.command",
|
||||||
"defaultValue": "stop"
|
"defaultValue": "stop"
|
||||||
|
@ -1,5 +1,5 @@
|
|||||||
/*
|
/*
|
||||||
* Copyright 2012-2023 the original author or authors.
|
* Copyright 2012-2024 the original author or authors.
|
||||||
*
|
*
|
||||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
* you may not use this file except in compliance with the License.
|
* you may not use this file except in compliance with the License.
|
||||||
@ -39,6 +39,7 @@ import org.springframework.boot.docker.compose.core.DockerCompose;
|
|||||||
import org.springframework.boot.docker.compose.core.DockerComposeFile;
|
import org.springframework.boot.docker.compose.core.DockerComposeFile;
|
||||||
import org.springframework.boot.docker.compose.core.RunningService;
|
import org.springframework.boot.docker.compose.core.RunningService;
|
||||||
import org.springframework.boot.docker.compose.lifecycle.DockerComposeProperties.Readiness.Wait;
|
import org.springframework.boot.docker.compose.lifecycle.DockerComposeProperties.Readiness.Wait;
|
||||||
|
import org.springframework.boot.docker.compose.lifecycle.DockerComposeProperties.Start.Skip;
|
||||||
import org.springframework.boot.test.system.CapturedOutput;
|
import org.springframework.boot.test.system.CapturedOutput;
|
||||||
import org.springframework.boot.test.system.OutputCaptureExtension;
|
import org.springframework.boot.test.system.OutputCaptureExtension;
|
||||||
import org.springframework.context.ApplicationContext;
|
import org.springframework.context.ApplicationContext;
|
||||||
@ -384,6 +385,38 @@ class DockerComposeLifecycleManagerTests {
|
|||||||
assertThat(output).doesNotContain("There are already Docker Compose services running, skipping startup");
|
assertThat(output).doesNotContain("There are already Docker Compose services running, skipping startup");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
void shouldStartIfSkipModeIsIfRunningAndNoServicesAreRunning() {
|
||||||
|
given(this.dockerCompose.hasDefinedServices()).willReturn(true);
|
||||||
|
this.properties.getStart().setSkip(Skip.IF_RUNNING);
|
||||||
|
this.lifecycleManager.start();
|
||||||
|
then(this.dockerCompose).should().up(any());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
void shouldNotStartIfSkipModeIsIfRunningAndServicesAreAlreadyRunning() {
|
||||||
|
setUpRunningServices();
|
||||||
|
this.properties.getStart().setSkip(Skip.IF_RUNNING);
|
||||||
|
this.lifecycleManager.start();
|
||||||
|
then(this.dockerCompose).should(never()).up(any());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
void shouldStartIfSkipModeIsNeverAndNoServicesAreRunning() {
|
||||||
|
given(this.dockerCompose.hasDefinedServices()).willReturn(true);
|
||||||
|
this.properties.getStart().setSkip(Skip.NEVER);
|
||||||
|
this.lifecycleManager.start();
|
||||||
|
then(this.dockerCompose).should().up(any());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
void shouldStartIfSkipModeIsNeverAndServicesAreAlreadyRunning() {
|
||||||
|
setUpRunningServices();
|
||||||
|
this.properties.getStart().setSkip(Skip.NEVER);
|
||||||
|
this.lifecycleManager.start();
|
||||||
|
then(this.dockerCompose).should().up(any());
|
||||||
|
}
|
||||||
|
|
||||||
private void setUpRunningServices() {
|
private void setUpRunningServices() {
|
||||||
setUpRunningServices(true);
|
setUpRunningServices(true);
|
||||||
}
|
}
|
||||||
|
@ -1,5 +1,5 @@
|
|||||||
/*
|
/*
|
||||||
* Copyright 2012-2023 the original author or authors.
|
* Copyright 2012-2024 the original author or authors.
|
||||||
*
|
*
|
||||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
* you may not use this file except in compliance with the License.
|
* you may not use this file except in compliance with the License.
|
||||||
@ -18,16 +18,21 @@ package org.springframework.boot.docker.compose.lifecycle;
|
|||||||
|
|
||||||
import java.io.File;
|
import java.io.File;
|
||||||
import java.time.Duration;
|
import java.time.Duration;
|
||||||
|
import java.util.Collections;
|
||||||
import java.util.LinkedHashMap;
|
import java.util.LinkedHashMap;
|
||||||
|
import java.util.List;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
|
|
||||||
import org.junit.jupiter.api.Test;
|
import org.junit.jupiter.api.Test;
|
||||||
|
|
||||||
import org.springframework.boot.context.properties.bind.Binder;
|
import org.springframework.boot.context.properties.bind.Binder;
|
||||||
import org.springframework.boot.context.properties.source.MapConfigurationPropertySource;
|
import org.springframework.boot.context.properties.source.MapConfigurationPropertySource;
|
||||||
|
import org.springframework.boot.docker.compose.core.RunningService;
|
||||||
import org.springframework.boot.docker.compose.lifecycle.DockerComposeProperties.Readiness.Wait;
|
import org.springframework.boot.docker.compose.lifecycle.DockerComposeProperties.Readiness.Wait;
|
||||||
|
import org.springframework.boot.docker.compose.lifecycle.DockerComposeProperties.Start.Skip;
|
||||||
|
|
||||||
import static org.assertj.core.api.Assertions.assertThat;
|
import static org.assertj.core.api.Assertions.assertThat;
|
||||||
|
import static org.mockito.Mockito.mock;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Tests for {@link DockerComposeProperties}.
|
* Tests for {@link DockerComposeProperties}.
|
||||||
@ -84,4 +89,16 @@ class DockerComposePropertiesTests {
|
|||||||
assertThat(properties.getReadiness().getTcp().getReadTimeout()).isEqualTo(Duration.ofMillis(500));
|
assertThat(properties.getReadiness().getTcp().getReadTimeout()).isEqualTo(Duration.ofMillis(500));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
void skipModeNeverShouldNeverSkip() {
|
||||||
|
assertThat(Skip.NEVER.shouldSkip(Collections.emptyList())).isFalse();
|
||||||
|
assertThat(Skip.NEVER.shouldSkip(List.of(mock(RunningService.class)))).isFalse();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
void skipModeIfRunningShouldSkipWhenServicesAreRunning() {
|
||||||
|
assertThat(Skip.IF_RUNNING.shouldSkip(Collections.emptyList())).isFalse();
|
||||||
|
assertThat(Skip.IF_RUNNING.shouldSkip(List.of(mock(RunningService.class)))).isTrue();
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user