Skip to content

Commit

Permalink
Allow to define a custom ImagePullPolicy via configuration (#7520)
Browse files Browse the repository at this point in the history
Use `pull.policy` in configuration file.
  • Loading branch information
eddumelendez authored Sep 27, 2023
1 parent c4d1240 commit 8b6776c
Show file tree
Hide file tree
Showing 6 changed files with 124 additions and 3 deletions.
46 changes: 44 additions & 2 deletions core/src/main/java/org/testcontainers/images/PullPolicy.java
Original file line number Diff line number Diff line change
@@ -1,22 +1,64 @@
package org.testcontainers.images;

import com.google.common.annotations.VisibleForTesting;
import lombok.experimental.UtilityClass;
import lombok.extern.slf4j.Slf4j;
import org.testcontainers.utility.TestcontainersConfiguration;

import java.time.Duration;

/**
* Convenience class with logic for building common {@link ImagePullPolicy} instances.
*
*/
@Slf4j
@UtilityClass
public class PullPolicy {

@VisibleForTesting
static ImagePullPolicy instance;

@VisibleForTesting
static ImagePullPolicy defaultImplementation = new DefaultPullPolicy();

/**
* Convenience method for returning the {@link DefaultPullPolicy} default image pull policy
* @return {@link ImagePullPolicy}
*/
public static ImagePullPolicy defaultPolicy() {
return new DefaultPullPolicy();
public static synchronized ImagePullPolicy defaultPolicy() {
if (instance != null) {
return instance;
}

String imagePullPolicyClassName = TestcontainersConfiguration.getInstance().getImagePullPolicy();
if (imagePullPolicyClassName != null) {
log.debug("Attempting to instantiate an ImagePullPolicy with class: {}", imagePullPolicyClassName);
ImagePullPolicy configuredInstance;
try {
configuredInstance =
(ImagePullPolicy) Thread
.currentThread()
.getContextClassLoader()
.loadClass(imagePullPolicyClassName)
.getConstructor()
.newInstance();
} catch (Exception e) {
throw new IllegalArgumentException(
"Configured ImagePullPolicy could not be loaded: " + imagePullPolicyClassName,
e
);
}

log.info("Found configured Image Pull Policy: {}", configuredInstance.getClass());

instance = configuredInstance;
} else {
instance = defaultImplementation;
}

log.info("Image pull policy will be performed by: {}", instance);

return instance;
}

/**
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -35,7 +35,7 @@ public class RemoteDockerImage extends LazyFuture<String> {
private Future<DockerImageName> imageNameFuture;

@With
private ImagePullPolicy imagePullPolicy = PullPolicy.defaultPolicy();
ImagePullPolicy imagePullPolicy = PullPolicy.defaultPolicy();

@With
private ImageNameSubstitutor imageNameSubstitutor = ImageNameSubstitutor.instance();
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -213,6 +213,10 @@ public String getImageSubstitutorClassName() {
return getEnvVarOrProperty("image.substitutor", null);
}

public String getImagePullPolicy() {
return getEnvVarOrProperty("pull.policy", null);
}

public Integer getClientPingTimeout() {
return Integer.parseInt(getEnvVarOrProperty("client.ping.timeout", "10"));
}
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,54 @@
package org.testcontainers.images;

import org.junit.After;
import org.junit.Before;
import org.junit.Rule;
import org.junit.Test;
import org.mockito.Mockito;
import org.testcontainers.DockerRegistryContainer;
import org.testcontainers.containers.GenericContainer;
import org.testcontainers.utility.FakeImagePullPolicy;
import org.testcontainers.utility.MockTestcontainersConfigurationRule;
import org.testcontainers.utility.TestcontainersConfiguration;

import static org.assertj.core.api.Assertions.assertThat;

public class OverrideImagePullPolicyTest {

@Rule
public MockTestcontainersConfigurationRule config = new MockTestcontainersConfigurationRule();

private ImagePullPolicy originalInstance;

private ImagePullPolicy originalDefaultImplementation;

@Before
public void setUp() {
this.originalInstance = PullPolicy.instance;
this.originalDefaultImplementation = PullPolicy.defaultImplementation;
PullPolicy.instance = null;
PullPolicy.defaultImplementation = Mockito.mock(ImagePullPolicy.class);
}

@After
public void tearDown() {
PullPolicy.instance = originalInstance;
PullPolicy.defaultImplementation = originalDefaultImplementation;
}

@Test
public void simpleConfigurationTest() {
Mockito
.doReturn(FakeImagePullPolicy.class.getCanonicalName())
.when(TestcontainersConfiguration.getInstance())
.getImagePullPolicy();

try (DockerRegistryContainer registry = new DockerRegistryContainer()) {
registry.start();
GenericContainer<?> container = new GenericContainer<>(registry.createImage()).withExposedPorts(8080);
container.start();
assertThat(container.getImage().imagePullPolicy).isInstanceOf(FakeImagePullPolicy.class);
container.stop();
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
package org.testcontainers.utility;

import org.testcontainers.images.AbstractImagePullPolicy;
import org.testcontainers.images.ImageData;

public class FakeImagePullPolicy extends AbstractImagePullPolicy {

@Override
protected boolean shouldPullCached(DockerImageName imageName, ImageData localImageData) {
return false;
}
}
9 changes: 9 additions & 0 deletions docs/features/advanced_options.md
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,15 @@ It is possible to specify an Image Pull Policy to determine at runtime whether a
[Custom image pull policy](../../core/src/test/java/org/testcontainers/images/ImagePullPolicyTest.java) inside_block:custom_image_pull_policy
<!--/codeinclude-->

You can also configure Testcontainers to use your custom implementation by using `pull.policy`

=== "`src/test/resources/testcontainers.properties`"
```text
pull.policy=com.mycompany.testcontainers.ExampleImagePullPolicy
```

Please see [the documentation on configuration mechanisms](./configuration.md) for more information.

## Customizing the container

### Using docker-java
Expand Down

0 comments on commit 8b6776c

Please sign in to comment.