Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

support for specifying local bind address #39

Closed
wants to merge 2 commits into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 3 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -1,3 +1,6 @@
.idea/
target/
*.iml
.classpath
.project
.settings
5 changes: 3 additions & 2 deletions src/main/java/org/jolokia/docker/maven/StartMojo.java
Original file line number Diff line number Diff line change
Expand Up @@ -46,6 +46,7 @@ public class StartMojo extends AbstractDockerMojo {
private Map<String, String> imageAliasMap = new HashMap<>();

/** {@inheritDoc} */
@Override
public void executeInternal(DockerAccess docker) throws DockerAccessException, MojoExecutionException {

getPluginContext().put(CONTEXT_KEY_START_CALLED,true);
Expand All @@ -67,8 +68,8 @@ public void executeInternal(DockerAccess docker) throws DockerAccessException, M
runConfig.getEnv());
docker.startContainer(container,
mappedPorts.getPortsMap(),
findContainersForImages(runConfig.getVolumesFrom()),
findLinksWithContainerNames(docker,runConfig.getLinks()));
mappedPorts.getBindToMap(),
findContainersForImages(runConfig.getVolumesFrom()), findLinksWithContainerNames(docker,runConfig.getLinks()));
registerContainer(container, imageConfig);
info("Created and started container " +
getContainerImageDescription(container,imageConfig.getName(),imageConfig.getAlias()));
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -50,10 +50,12 @@ public interface DockerAccess {
* while the values are the host ports to use. If a value is <code>null</code> a port is dynamically selected
* by docker. The value of a dynamically selected port can be obtained via {@link #queryContainerPortMapping(String)}
* This map must not be null (but can be empty)
* @param bindTo bind to addresses. The keys of this map are container ports and the values are the local ip addresses they should be
* bound to.
* @param volumesFrom mount volumes from the given container id. Can be null.
* @throws DockerAccessException if the container could not be started.
*/
void startContainer(String containerId, Map<Integer, Integer> ports, List<String> volumesFrom, List<String> links) throws DockerAccessException;
void startContainer(String containerId, Map<Integer, Integer> ports, Map<Integer, String> bindTo, List<String> volumesFrom, List<String> links) throws DockerAccessException;

/**
* Stop a container.
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -67,6 +67,7 @@ public DockerAccessWithHttpClient(String baseUrl, String certPath, LogHandler lo
}

/** {@inheritDoc} */
@Override
public boolean hasImage(String image) throws DockerAccessException {
Matcher matcher = Pattern.compile("^(.*?):([^:]+)?$").matcher(image);
String base = matcher.matches() ? matcher.group(1) : image;
Expand All @@ -79,6 +80,7 @@ public boolean hasImage(String image) throws DockerAccessException {
}

/** {@inheritDoc} */
@Override
public String createContainer(String image, String command, Set<Integer> ports, Map<String, String> env) throws DockerAccessException {
HttpUriRequest post = newPost(baseUrl + "/containers/create", getContainerConfig(image, ports, command, env));
HttpResponse resp = request(post);
Expand All @@ -98,22 +100,25 @@ public String getContainerName(String id) throws DockerAccessException {
}

/** {@inheritDoc} */
public void startContainer(String containerId, Map<Integer, Integer> ports, List<String> volumesFrom,List<String> links)
@Override
public void startContainer(String containerId, Map<Integer, Integer> ports, Map<Integer, String> bindTo,List<String> volumesFrom, List<String> links)
throws DockerAccessException {
HttpUriRequest req = newPost(baseUrl + "/containers/" + encode(containerId) + "/start",
getStartConfig(ports, volumesFrom, links));
getStartConfig(ports, bindTo, volumesFrom, links));
HttpResponse resp = request(req);
checkReturnCode("Starting container with id " + containerId, resp, 204);
}

/** {@inheritDoc} */
@Override
public void stopContainer(String containerId) throws DockerAccessException {
HttpUriRequest req = newPost(baseUrl + "/containers/" + encode(containerId) + "/stop", null);
HttpResponse resp = request(req);
checkReturnCode("Stopping container with id " + containerId, resp, 204, 304);
}

/** {@inheritDoc} */
@Override
public void buildImage(String image, File dockerArchive) throws DockerAccessException {
String buildUrl = baseUrl + "/build?rm=true" + (image != null ? "&t=" + encode(image) : "");
HttpPost post = new HttpPost(buildUrl);
Expand All @@ -122,6 +127,7 @@ public void buildImage(String image, File dockerArchive) throws DockerAccessExce
}

/** {@inheritDoc} */
@Override
public Map<Integer, Integer> queryContainerPortMapping(String containerId) throws DockerAccessException {
HttpUriRequest req = newGet(baseUrl + "/containers/" + encode(containerId) + "/json");
HttpResponse resp = request(req);
Expand All @@ -130,8 +136,9 @@ public Map<Integer, Integer> queryContainerPortMapping(String containerId) throw
}

/** {@inheritDoc} */
@Override
public List<String> getContainersForImage(String image) throws DockerAccessException {
List<String> ret = new ArrayList<String>();
List<String> ret = new ArrayList<>();
HttpUriRequest req = newGet(baseUrl + "/containers/json?limit=100");
HttpResponse resp = request(req);
checkReturnCode("Fetching container information", resp, 200);
Expand All @@ -157,13 +164,15 @@ public String getLogs(final String containerId) throws DockerAccessException {
}

/** {@inheritDoc} */
@Override
public void removeContainer(String containerId) throws DockerAccessException {
HttpUriRequest req = newDelete(baseUrl + "/containers/" + encode(containerId));
HttpResponse resp = request(req);
checkReturnCode("Stopping container with id " + containerId, resp, 204);
}

/** {@inheritDoc} */
@Override
public void pullImage(String image,AuthConfig authConfig) throws DockerAccessException {
ImageName name = new ImageName(image);
String pullUrl = baseUrl + "/images/create?fromImage=" + encode(name.getRepository());
Expand All @@ -172,6 +181,7 @@ public void pullImage(String image,AuthConfig authConfig) throws DockerAccessExc
}

/** {@inheritDoc} */
@Override
public void pushImage(String image, AuthConfig authConfig) throws DockerAccessException {
ImageName name = new ImageName(image);
String pushUrl = baseUrl + "/images/" + encode(name.getRepository()) + "/push";
Expand All @@ -180,6 +190,7 @@ public void pushImage(String image, AuthConfig authConfig) throws DockerAccessEx
}

/** {@inheritDoc} */
@Override
public boolean removeImage(String image, boolean ... forceOpt) throws DockerAccessException {
boolean force = forceOpt != null && forceOpt.length > 0 && forceOpt[0];
HttpUriRequest req = newDelete(baseUrl + "/images/" + image + (force ? "?force=1" : ""));
Expand All @@ -194,10 +205,12 @@ public boolean removeImage(String image, boolean ... forceOpt) throws DockerAcce
// ---------------
// Lifecycle methods not needed here
/** {@inheritDoc} */
public void start() throws DockerAccessException {}
@Override
public void start() {}


/** {@inheritDoc} */
@Override
public void shutdown() {}

// ====================================================================================================
Expand Down Expand Up @@ -317,7 +330,7 @@ private Map<Integer, Integer> extractPorts(JSONObject info) {
}

private Map<Integer, Integer> createPortMapping(JSONObject ports) {
Map<Integer, Integer> portMapping = new HashMap<Integer, Integer>();
Map<Integer, Integer> portMapping = new HashMap<>();
for (Object portSpecO : ports.keySet()) {
String portSpec = portSpecO.toString();
if (!ports.isNull(portSpec)) {
Expand Down Expand Up @@ -379,17 +392,15 @@ private String getContainerConfig(String image, Set<Integer> ports, String comma
return ret.toString();
}

private String getStartConfig(Map<Integer, Integer> ports, List<String> volumesFrom, List<String> links) {
private String getStartConfig(Map<Integer, Integer> ports, Map<Integer, String> bindTo, List<String> volumesFrom, List<String> links) {
JSONObject ret = new JSONObject();
if (ports != null && ports.size() > 0) {
JSONObject c = new JSONObject();
for (Map.Entry<Integer,Integer> entry : ports.entrySet()) {
Integer port = entry.getValue();
JSONArray a = new JSONArray();
JSONObject o = new JSONObject();
o.put("HostPort",port != null ? port.toString() : "");
a.put(o);
c.put(entry.getKey() + "/tcp",a);
Integer port = entry.getKey();
JSONArray a = addHostIpAndPort(bindTo, port, entry.getValue());

c.put(port + "/tcp",a);
}
ret.put("PortBindings", c);
}
Expand Down Expand Up @@ -447,6 +458,20 @@ private void pullOrPushImage(String image, String uri, String what, AuthConfig a
}
}

private JSONArray addHostIpAndPort(Map<Integer, String> bindTo,
Integer containerPort, Integer hostPort) {
JSONArray a = new JSONArray();
JSONObject o = new JSONObject();
o.put("HostPort",hostPort != null ? hostPort.toString() : "");

if (bindTo.containsKey(containerPort)) {
o.put("HostIp", bindTo.get(containerPort));
}

a.put(o);
return a;
}

private String addTagAndRegistry(String url, ImageName name) {
List<String> params = new ArrayList<>();
if (name.getTag() != null) {
Expand All @@ -465,9 +490,9 @@ private String addTagAndRegistry(String url, ImageName name) {
}
}
return url + (url.contains("?") ? "&" : "?") + addOn.toString();
} else {
return url;
}

return url;
}

private void processPullOrPushResponse(final String image, HttpResponse resp, final String action)
Expand All @@ -476,7 +501,8 @@ private void processPullOrPushResponse(final String image, HttpResponse resp, fi

private boolean downloadInProgress = false;

public void process(JSONObject json) {
@Override
public void process(JSONObject json) {
if (json.has("progressDetail")) {
JSONObject details = json.getJSONObject("progressDetail");
if (details.has("total")) {
Expand All @@ -486,12 +512,12 @@ public void process(JSONObject json) {
log.progressUpdate(details.getInt("current"));
downloadInProgress = true;
return;
} else {
if (downloadInProgress) {
log.progressFinished();
}
downloadInProgress = false;
}

if (downloadInProgress) {
log.progressFinished();
}
downloadInProgress = false;
}
if (json.has("error")) {
String msg = json.getString("error").trim();
Expand All @@ -502,7 +528,8 @@ public void process(JSONObject json) {
}
}

public String getErrorMessage(StatusLine status) {
@Override
public String getErrorMessage(StatusLine status) {
return "Error while " + action + " image '" + image + "' (code: " + status.getStatusCode() + ", " + status.getReasonPhrase() + ")";
}
});
Expand All @@ -511,7 +538,8 @@ public String getErrorMessage(StatusLine status) {
private void processBuildResponse(final String image, org.apache.http.HttpResponse resp) throws DockerAccessException {

processChunkedResponse(resp, new ChunkedCallback() {
public void process(JSONObject json) {
@Override
public void process(JSONObject json) {
if (json.has("error")) {
log.error("Error building image: " + json.get("error"));
if (json.has("errorDetail")) {
Expand All @@ -537,7 +565,8 @@ private String trim(String message) {
return message;
}

public String getErrorMessage(StatusLine status) {
@Override
public String getErrorMessage(StatusLine status) {
return "Error while building image '" + image + "' (code: " + status.getStatusCode()
+ ", " + status.getReasonPhrase() + ")";
}
Expand Down
74 changes: 48 additions & 26 deletions src/main/java/org/jolokia/docker/maven/util/PortMapping.java
Original file line number Diff line number Diff line change
Expand Up @@ -15,14 +15,16 @@
public class PortMapping {

// variables (container port -> variable name)
private final Map<Integer, String> varMap;
private final Map<Integer, String> varMap = new HashMap<>();

// ports map (container port -> host port)
private final Map<Integer, Integer> portsMap;
private final Map<Integer, Integer> portsMap = new HashMap<>();

// Mapping between vars and dynamics ports which gets filled in lately
private final Map<String, Integer> dynamicPorts;
private final Map<String, Integer> dynamicPorts = new HashMap<>();

private final Map<Integer, String> bindToMap = new HashMap<>();

/**
* Create the mapping
* @param config a list of configuration strings where each string hast the format <code>host-port:container-port</code>. If
Expand All @@ -32,38 +34,35 @@ public class PortMapping {
* @throws MojoExecutionException if the format doesn't fit
*/
public PortMapping(List<String> config, Properties variables) throws MojoExecutionException {
portsMap = new HashMap<Integer, Integer>();
varMap = new HashMap<Integer, String>();
dynamicPorts = new HashMap<String, Integer>();
if (config != null) {
for (String port : config) {
try {
String ps[] = port.split(":", 2);
if (ps.length != 2) {
String ps[] = port.split(":", 3);
if (ps.length == 3) {
mapPorts(ps[0], ps[1], ps[2], variables);
} else if (ps.length == 2) {
mapPorts(null, ps[0], ps[1], variables);
} else {
throw new MojoExecutionException("Invalid mapping '" + port + "' (must contain at least one :)");
}
Integer containerPort = Integer.parseInt(ps[1]);
Integer hostPort;
try {
hostPort = Integer.parseInt(ps[0]);
} catch (NumberFormatException exp) {
// Port should be dynamically assigned and set to the variable give in ps[0]
hostPort = getPortFromVariable(variables, ps[0]);
if (hostPort != null) {
dynamicPorts.put(ps[0],hostPort);
} else {
varMap.put(containerPort,ps[0]);
}
}
portsMap.put(containerPort, hostPort);
} catch (NumberFormatException exp) {
throw new MojoExecutionException("Port mappings must be given in the format <hostPort>:<mappedPort> (e.g. 8080:8080). " +
throw new MojoExecutionException("Port mappings must be given in the format <hostPort>:<mappedPort> or " +
"<bindTo>:<hostPort>:<mappedPort> (e.g. 8080:8080 / 127.0.0.1:8080:8080). " +
"The given config '" + port + "' doesn't match this",exp);
}
}
}
}

/**
* Get the local address a container should bind to
*
* @return map of container ports and the local ip addresses they should be bound to
*/
public Map<Integer, String> getBindToMap() {
return bindToMap;
}

/**
* Get the port mapping as map
*
Expand Down Expand Up @@ -156,8 +155,31 @@ private Integer getPortFromVariable(Properties variables, String var) {
} catch (NumberFormatException exp) {
return null;
}
} else {
return null;
}
}

return null;
}

private void mapPorts(String bindTo, String hPort,String cPort, Properties variables) {
Integer containerPort = Integer.parseInt(cPort);
Integer hostPort;
try {
hostPort = Integer.parseInt(hPort);
} catch (NumberFormatException exp) {
// Port should be dynamically assigned and set to the variable give in hPort
hostPort = getPortFromVariable(variables, hPort);
if (hostPort != null) {
dynamicPorts.put(hPort, hostPort);
} else {
varMap.put(containerPort, hPort);
}
}

if (bindTo != null) {
// the container port can never be null, so use that as the key
bindToMap.put(containerPort, bindTo);
}

portsMap.put(containerPort, hostPort);
}
}
Loading