Skip to content

Commit

Permalink
Add Ollama module (#8369)
Browse files Browse the repository at this point in the history
Co-authored-by: Kevin Wittek <kiview@users.noreply.github.com>
  • Loading branch information
eddumelendez and kiview authored Mar 2, 2024
1 parent 33c904e commit 93ca7cd
Show file tree
Hide file tree
Showing 12 changed files with 206 additions and 0 deletions.
1 change: 1 addition & 0 deletions .github/ISSUE_TEMPLATE/bug_report.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -43,6 +43,7 @@ body:
- Neo4j
- NGINX
- OceanBase
- Ollama
- OpenFGA
- Oracle Free
- Oracle XE
Expand Down
1 change: 1 addition & 0 deletions .github/ISSUE_TEMPLATE/enhancement.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -43,6 +43,7 @@ body:
- Neo4j
- NGINX
- OceanBase
- Ollama
- OpenFGA
- Oracle Free
- Oracle XE
Expand Down
1 change: 1 addition & 0 deletions .github/ISSUE_TEMPLATE/feature.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -43,6 +43,7 @@ body:
- Neo4j
- NGINX
- OceanBase
- Ollama
- OpenFGA
- Oracle Free
- Oracle XE
Expand Down
5 changes: 5 additions & 0 deletions .github/dependabot.yml
Original file line number Diff line number Diff line change
Expand Up @@ -224,6 +224,11 @@ updates:
schedule:
interval: "weekly"
open-pull-requests-limit: 10
- package-ecosystem: "gradle"
directory: "/modules/ollama"
schedule:
interval: "weekly"
open-pull-requests-limit: 10
- package-ecosystem: "gradle"
directory: "/modules/openfga"
schedule:
Expand Down
4 changes: 4 additions & 0 deletions .github/labeler.yml
Original file line number Diff line number Diff line change
Expand Up @@ -139,6 +139,10 @@
- changed-files:
- any-glob-to-any-file:
- modules/oceanbase/**/*
"modules/ollama":
- changed-files:
- any-glob-to-any-file:
- modules/ollama/**/*
"modules/openfga":
- changed-files:
- any-glob-to-any-file:
Expand Down
3 changes: 3 additions & 0 deletions .github/settings.yml
Original file line number Diff line number Diff line change
Expand Up @@ -196,6 +196,9 @@ labels:
- name: modules/oceanbase
color: '#006b75'

- name: modules/ollama
color: '#006b75'

- name: modules/openfga
color: '#006b75'

Expand Down
30 changes: 30 additions & 0 deletions docs/modules/ollama.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
# Ollama

Testcontainers module for [Ollama](https://hub.docker.com/r/ollama/ollama) .

## Ollama's usage examples

You can start an Ollama container instance from any Java application by using:

<!--codeinclude-->
[Ollama container](../../modules/ollama/src/test/java/org/testcontainers/ollama/OllamaContainerTest.java) inside_block:container
<!--/codeinclude-->

## Adding this module to your project dependencies

Add the following dependency to your `pom.xml`/`build.gradle` file:

=== "Gradle"
```groovy
testImplementation "org.testcontainers:ollama:{{latest_version}}"
```

=== "Maven"
```xml
<dependency>
<groupId>org.testcontainers</groupId>
<artifactId>ollama</artifactId>
<version>{{latest_version}}</version>
<scope>test</scope>
</dependency>
```
1 change: 1 addition & 0 deletions mkdocs.yml
Original file line number Diff line number Diff line change
Expand Up @@ -90,6 +90,7 @@ nav:
- modules/minio.md
- modules/mockserver.md
- modules/nginx.md
- modules/ollama.md
- modules/openfga.md
- modules/pulsar.md
- modules/qdrant.md
Expand Down
8 changes: 8 additions & 0 deletions modules/ollama/build.gradle
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
description = "Testcontainers :: Ollama"

dependencies {
api project(':testcontainers')

testImplementation 'org.assertj:assertj-core:3.25.1'
testImplementation 'io.rest-assured:rest-assured:5.4.0'
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,80 @@
package org.testcontainers.ollama;

import com.github.dockerjava.api.DockerClient;
import com.github.dockerjava.api.model.DeviceRequest;
import com.github.dockerjava.api.model.Image;
import com.github.dockerjava.api.model.Info;
import com.github.dockerjava.api.model.RuntimeInfo;
import org.testcontainers.DockerClientFactory;
import org.testcontainers.containers.GenericContainer;
import org.testcontainers.utility.DockerImageName;

import java.util.Collections;
import java.util.List;
import java.util.Map;

/**
* Testcontainers implementation for Ollama.
* <p>
* Supported image: {@code ollama/ollama}
* <p>
* Exposed ports: 11434
*/
public class OllamaContainer extends GenericContainer<OllamaContainer> {

private static final DockerImageName DOCKER_IMAGE_NAME = DockerImageName.parse("ollama/ollama");

public OllamaContainer(String image) {
this(DockerImageName.parse(image));
}

public OllamaContainer(DockerImageName dockerImageName) {
super(dockerImageName);
dockerImageName.assertCompatibleWith(DOCKER_IMAGE_NAME);

Info info = this.dockerClient.infoCmd().exec();
Map<String, RuntimeInfo> runtimes = info.getRuntimes();
if (runtimes != null) {
if (runtimes.containsKey("nvidia")) {
withCreateContainerCmdModifier(cmd -> {
cmd
.getHostConfig()
.withDeviceRequests(
Collections.singletonList(
new DeviceRequest()
.withCapabilities(Collections.singletonList(Collections.singletonList("gpu")))
.withCount(-1)
)
);
});
}
}
withExposedPorts(11434);
}

/**
* Commits the current file system changes in the container into a new image.
* Should be used for creating an image that contains a loaded model.
* @param imageName the name of the new image
*/
public void commitToImage(String imageName) {
DockerImageName dockerImageName = DockerImageName.parse(getDockerImageName());
if (!dockerImageName.equals(DockerImageName.parse(imageName))) {
DockerClient dockerClient = DockerClientFactory.instance().client();
List<Image> images = dockerClient.listImagesCmd().withReferenceFilter(imageName).exec();
if (images.isEmpty()) {
DockerImageName imageModel = DockerImageName.parse(imageName);
dockerClient
.commitCmd(getContainerId())
.withRepository(imageModel.getUnversionedPart())
.withLabels(Collections.singletonMap("org.testcontainers.sessionId", ""))
.withTag(imageModel.getVersionPart())
.exec();
}
}
}

public String getEndpoint() {
return "http://" + getHost() + ":" + getMappedPort(11434);
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,56 @@
package org.testcontainers.ollama;

import org.junit.Test;
import org.testcontainers.utility.Base58;
import org.testcontainers.utility.DockerImageName;

import java.io.IOException;

import static io.restassured.RestAssured.given;
import static org.assertj.core.api.Assertions.assertThat;

public class OllamaContainerTest {

@Test
public void withDefaultConfig() {
try ( // container {
OllamaContainer ollama = new OllamaContainer("ollama/ollama:0.1.26")
// }
) {
ollama.start();

String version = given().baseUri(ollama.getEndpoint()).get("/api/version").jsonPath().get("version");
assertThat(version).isEqualTo("0.1.26");
}
}

@Test
public void downloadModelAndCommitToImage() throws IOException, InterruptedException {
String newImageName = "tc-ollama-allminilm-" + Base58.randomString(4).toLowerCase();
try (OllamaContainer ollama = new OllamaContainer("ollama/ollama:0.1.26")) {
ollama.start();
ollama.execInContainer("ollama", "pull", "all-minilm");

String modelName = given()
.baseUri(ollama.getEndpoint())
.get("/api/tags")
.jsonPath()
.getString("models[0].name");
assertThat(modelName).contains("all-minilm");
ollama.commitToImage(newImageName);
}
try (
OllamaContainer ollama = new OllamaContainer(
DockerImageName.parse(newImageName).asCompatibleSubstituteFor("ollama/ollama")
)
) {
ollama.start();
String modelName = given()
.baseUri(ollama.getEndpoint())
.get("/api/tags")
.jsonPath()
.getString("models[0].name");
assertThat(modelName).contains("all-minilm");
}
}
}
16 changes: 16 additions & 0 deletions modules/ollama/src/test/resources/logback-test.xml
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
<configuration>

<appender name="STDOUT" class="ch.qos.logback.core.ConsoleAppender">
<!-- encoders are assigned the type
ch.qos.logback.classic.encoder.PatternLayoutEncoder by default -->
<encoder>
<pattern>%d{HH:mm:ss.SSS} %-5level %logger - %msg%n</pattern>
</encoder>
</appender>

<root level="INFO">
<appender-ref ref="STDOUT"/>
</root>

<logger name="org.testcontainers" level="INFO"/>
</configuration>

0 comments on commit 93ca7cd

Please sign in to comment.