Skip to content

Commit

Permalink
#513 : Removed listContainers() and list containers only for API <1.23
Browse files Browse the repository at this point in the history
For an API >= 1.23 /containers/ listing with an `ancestor` filter can be used to the the image for a container (which is required mostly only for stopping containers in an external call).
For API < 1.23 there is still a call to /containers/ with a limit.
  • Loading branch information
rhuss committed Jul 13, 2016
1 parent 1438879 commit cec36fe
Show file tree
Hide file tree
Showing 8 changed files with 132 additions and 40 deletions.
4 changes: 2 additions & 2 deletions src/main/java/io/fabric8/maven/docker/AbstractDockerMojo.java
Original file line number Diff line number Diff line change
Expand Up @@ -281,9 +281,9 @@ private DockerAccess createDockerAccess(String minimalVersion) throws MojoExecut
access.start();
setDockerHostAddressProperty(dockerUrl);
serverVersion = access.getServerApiVersion();
if (EnvUtil.extractLargerVersion(version,serverVersion).equals(version)) {
if (!EnvUtil.greaterOrEqualsVersion(serverVersion,version)) {
throw new MojoExecutionException(
String.format("Server API version %s is smaller than request API version %s",serverVersion,version));
String.format("Server API version %s is smaller than request API version %s", serverVersion, version));
}
}
catch (IOException e) {
Expand Down
12 changes: 7 additions & 5 deletions src/main/java/io/fabric8/maven/docker/access/DockerAccess.java
Original file line number Diff line number Diff line change
Expand Up @@ -54,12 +54,14 @@ public interface DockerAccess {
String getImageId(String name) throws DockerAccessException;

/**
* List containers
*
* @return list of <code>Container<code> objects
* @throws DockerAccessException if the containers could not be listed
* Get all containers which are build from an image. By default only the last containers are considered but this
* can be tuned with a global parameters.
*
* @param image for which its container are looked up
* @return list of <code>Container</code> objects
* @throws DockerAccessException if the request fails
*/
List<Container> listContainers() throws DockerAccessException;
List<Container> getContainersForImage(String image) throws DockerAccessException;

/**
* Starts a previously set up exec instance id.
Expand Down
19 changes: 15 additions & 4 deletions src/main/java/io/fabric8/maven/docker/access/UrlBuilder.java
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@
import java.util.*;

import io.fabric8.maven.docker.util.ImageName;
import org.json.JSONArray;
import org.json.JSONObject;

public final class UrlBuilder {
Expand Down Expand Up @@ -75,13 +76,23 @@ public String inspectContainer(String containerId) {
.build();
}

public String listContainers(int limit) {
public String listContainers(int limit, String ... filter) {
Builder builder = u("containers/json");
if (limit == 0) {
builder.p("all", 1);
} else {
if (limit != 0) {
builder.p("limit", limit);
}
if (filter.length > 0) {
if (filter.length % 2 != 0) {
throw new IllegalArgumentException("Filters must be given as key value pairs and not " +Arrays.asList(filter));
}
JSONObject filters = new JSONObject();
for (int i = 0; i < filter.length; i +=2) {
JSONArray value = new JSONArray();
value.put(filter[i+1]);
filters.put(filter[i],value);
}
builder.p("filters",filters.toString());
}
return builder.build();
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -21,9 +21,7 @@
import io.fabric8.maven.docker.model.ContainersListElement;
import io.fabric8.maven.docker.model.Network;
import io.fabric8.maven.docker.model.NetworksListElement;
import io.fabric8.maven.docker.util.ImageName;
import io.fabric8.maven.docker.util.Logger;
import io.fabric8.maven.docker.util.Timestamp;
import io.fabric8.maven.docker.util.*;
import io.fabric8.maven.docker.access.hc.unix.UnixSocketClientBuilder;
import org.apache.http.HttpResponse;
import org.apache.http.client.ResponseHandler;
Expand Down Expand Up @@ -258,18 +256,28 @@ public Container inspectContainer(String containerIdOrName) throws DockerAccessE
}

@Override
public List<Container> listContainers() throws DockerAccessException {
String url = urlBuilder.listContainers(fetchLimit);
public List<Container> getContainersForImage(String image) throws DockerAccessException {
String url;
String serverApiVersion = getServerApiVersion();
if (EnvUtil.greaterOrEqualsVersion(serverApiVersion, "1.23")) {
// For Docker >= 1.11 we can use a new filter when listing containers
url = urlBuilder.listContainers(0,"ancestor",image);
} else {
// For older versions (< Docker 1.11) we need to iterate over the containers.
url = urlBuilder.listContainers(fetchLimit);
}

try {
String response = delegate.get(url, HTTP_OK);
JSONArray array = new JSONArray(response);
List<Container> containers = new ArrayList<>(array.length());
List<Container> containers = new ArrayList<>();

for (int i = 0; i < array.length(); i++) {
containers.add(new ContainersListElement(array.getJSONObject(i)));
JSONObject element = array.getJSONObject(i);
if (image.equals(element.getString("Image"))) {
containers.add(new ContainersListElement(element));
}
}

return containers;
} catch (IOException e) {
throw new DockerAccessException(e.getMessage());
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -98,14 +98,7 @@ public String getContainerName(String containerId) throws DockerAccessException
* @throws DockerAccessException if the request fails
*/
public List<Container> getContainersForImage(final String image) throws DockerAccessException {
List<Container> list = docker.listContainers();
List<Container> ret = new ArrayList<>();
for (Container el : list) {
if (image.equals(el.getImage())) {
ret.add(el);
}
}
return ret;
return docker.getContainersForImage(image);
}

/**
Expand Down
30 changes: 26 additions & 4 deletions src/main/java/io/fabric8/maven/docker/util/EnvUtil.java
Original file line number Diff line number Diff line change
Expand Up @@ -59,7 +59,7 @@ public static String getCertPath(String certPath) {
/**
* Compare to version strings and return the larger version strings. This is used in calculating
* the minimal required API version for this plugin. Version strings must be comparable as floating numbers.
* (and parse via {@link Float#parseFloat(String)}.
* The versions must be given in the format in a semantic version foramt (e.g. "1.23"
*
* If either version is <code>null</code>, the other version is returned (which can be null as well)
*
Expand All @@ -71,12 +71,32 @@ public static String extractLargerVersion(String versionA, String versionB) {
if (versionB == null || versionA == null) {
return versionA == null ? versionB : versionA;
} else {
return
Float.parseFloat(versionA) > Float.parseFloat(versionB) ?
versionA : versionB;
String partsA[] = versionA.split("\\.");
String partsB[] = versionB.split("\\.");
for (int i = 0; i < (partsA.length < partsB.length ? partsA.length : partsB.length); i++) {
int pA = Integer.parseInt(partsA[i]);
int pB = Integer.parseInt(partsB[i]);
if (pA > pB) {
return versionA;
} else if (pB > pA) {
return versionB;
}
}
return partsA.length > partsB.length ? versionA : versionB;
}
}

/**
* Check whether the first given API version is larger or equals the second given version
*
* @param versionA first version to check against
* @param versionB the second version
* @return true if versionA is greater or equals versionB, false otherwise
*/
public static boolean greaterOrEqualsVersion(String versionA, String versionB) {
String largerVersion = extractLargerVersion(versionA, versionB);
return largerVersion != null && largerVersion.equals(versionA);
}

/**
* Splits every element in the given list on the last colon in the name and returns a list with
Expand Down Expand Up @@ -331,4 +351,6 @@ public static Date loadTimestamp(File tsFile) throws MojoExecutionException {
public static boolean isWindows() {
return System.getProperty("os.name").toLowerCase().contains("windows");
}


}
51 changes: 51 additions & 0 deletions src/test/java/io/fabric8/maven/docker/UrlBuilderTest.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,51 @@
package io.fabric8.maven.docker;
/*
*
* Copyright 2016 Roland Huss
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/

import java.io.UnsupportedEncodingException;
import java.net.*;

import io.fabric8.maven.docker.access.UrlBuilder;
import org.junit.Test;

import static org.junit.Assert.*;

/**
* @author roland
* @since 13/07/16
*/
public class UrlBuilderTest {

@Test
public void listContainers() throws MalformedURLException, UnsupportedEncodingException {
UrlBuilder builder = new UrlBuilder("","1.0");

assertEquals("/1.0/containers/json?limit=100",builder.listContainers(100));
assertEquals("/1.0/containers/json",builder.listContainers(0));
assertEquals("/1.0/containers/json?filters=" + URLEncoder.encode("{\"ancestor\":[\"nginx\"]}","UTF8"),
builder.listContainers(0, "ancestor", "nginx"));
assertEquals("/1.0/containers/json?limit=10&filters=" + URLEncoder.encode("{\"ancestor\":[\"nginx\"]}","UTF8"),
builder.listContainers(10, "ancestor", "nginx"));

try {
builder.listContainers(10,"ancestor");
fail();
} catch (IllegalArgumentException exp) {
assertTrue(exp.getMessage().contains("pair"));
}
}
}
23 changes: 14 additions & 9 deletions src/test/java/io/fabric8/maven/docker/util/EnvUtilTest.java
Original file line number Diff line number Diff line change
Expand Up @@ -87,16 +87,21 @@ public void mavenPropertyExtract() {
}

@Test
public void minimalVersion() {
String[] data = {
null, null, null,
"1.10", null, "1.10",
null, "1.10", "1.10",
"1.22", "1.10", "1.22",
"1.10", "1.25", "1.25"
public void versionChecks() {
Object[] data = {
null, null, null, false,
"1.10", null, "1.10", true,
null, "1.10", "1.10", false,
"1.22", "1.10", "1.22", true,
"1.10", "1.25", "1.25", false,
"1.23", "1.23", "1.23", true,
"1.23.1", "1.23", "1.23.1", true,
"1.25", "1.25.1", "1.25.1", false,
"1.23.1", "2.0", "2.0", false
};
for (int i = 0; i < data.length; i+=3) {
assertEquals(data[i+2],EnvUtil.extractLargerVersion(data[i],data[i+1]));
for (int i = 0; i < data.length; i+=4) {
assertEquals(data[i+2],EnvUtil.extractLargerVersion((String) data[i],(String) data[i+1]));
assertEquals(data[i+3],EnvUtil.greaterOrEqualsVersion((String) data[i],(String) data[i+1]));
}
}

Expand Down

0 comments on commit cec36fe

Please sign in to comment.