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

Fix broken links section in docker-compose recipe #2850

Merged
merged 12 commits into from
Oct 31, 2016
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@

/** @author andrew00x */
public class NetworkSettings {
private String ipAddress;
private String iPAddress;
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I would keep ipAddress as it was as method name is getIpAddress() not getIPAddress()

Copy link
Contributor Author

@mmorhun mmorhun Oct 21, 2016

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yes, ipAddress is conventional name , but iPAddress is needed for parsing value from json. Exactly like iPPrefixLen, iPv6Gateway in the same class.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I agree with @benoitf that iPAddress is weird. Wouldn't it possible to use @SerializedName annotation instead?

private int iPPrefixLen;
private String gateway;
private String bridge;
Expand All @@ -32,11 +32,11 @@ public class NetworkSettings {
private Map<String, List<PortBinding>> ports = new HashMap<>();

public String getIpAddress() {
return ipAddress;
return iPAddress;
}

public void setIpAddress(String ipAddress) {
this.ipAddress = ipAddress;
this.iPAddress = ipAddress;
}

public int getIpPrefixLen() {
Expand Down Expand Up @@ -130,7 +130,7 @@ public void setLinkLocalIPv6Address(String linkLocalIPv6Address) {
@Override
public String toString() {
return "NetworkSettings{" +
"ipAddress='" + ipAddress + '\'' +
"ipAddress='" + iPAddress + '\'' +
", iPPrefixLen=" + iPPrefixLen +
", gateway='" + gateway + '\'' +
", bridge='" + bridge + '\'' +
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -41,7 +41,6 @@
import org.eclipse.che.plugin.docker.client.ProgressMonitor;
import org.eclipse.che.plugin.docker.client.UserSpecificDockerRegistryCredentialsProvider;
import org.eclipse.che.plugin.docker.client.exception.ContainerNotFoundException;
import org.eclipse.che.plugin.docker.client.exception.DockerException;
import org.eclipse.che.plugin.docker.client.exception.ImageNotFoundException;
import org.eclipse.che.plugin.docker.client.exception.NetworkNotFoundException;
import org.eclipse.che.plugin.docker.client.json.ContainerConfig;
Expand Down Expand Up @@ -484,7 +483,8 @@ private String createContainer(String workspaceId,
isDev,
service);

EndpointConfig endpointConfig = new EndpointConfig().withAliases(machineName);
EndpointConfig endpointConfig = new EndpointConfig().withAliases(machineName)
.withLinks(toArrayIfNotNull(service.getLinks()));
NetworkingConfig networkingConfig = new NetworkingConfig().withEndpointsConfig(singletonMap(networkName,
endpointConfig));

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -352,24 +352,24 @@ public Instance startMachine(String workspaceId,
machine.setId(service.getId());

machineStarter = (machineLogger, machineSource) -> {
CheServiceImpl serviceWithCorrectSource = getServiceWithCorrectSource(service, machineSource);
CheServiceImpl serviceWithNormalizedSource = normalizeServiceSource(service, machineSource);

normalize(namespace,
workspaceId,
machineConfig.getName(),
serviceWithCorrectSource);
serviceWithNormalizedSource);

ExtendedMachineImpl extendedMachine = new ExtendedMachineImpl();
extendedMachine.setAgents(agents);
applyAgents(extendedMachine, serviceWithCorrectSource);
applyAgents(extendedMachine, serviceWithNormalizedSource);

return machineProvider.startService(namespace,
workspaceId,
environmentHolder.name,
machineConfig.getName(),
machineConfig.isDev(),
environmentHolder.networkId,
serviceWithCorrectSource,
serviceWithNormalizedSource,
machineLogger);
};
} else {
Expand Down Expand Up @@ -667,6 +667,7 @@ private void startEnvironmentQueue(String namespace,
try {
machineProvider.createNetwork(networkId);

final List<CheServiceImpl> launchedServices = new ArrayList<>();
String machineName = queuePeekOrFail(workspaceId);
while (machineName != null) {
boolean isDev = devMachineName.equals(machineName);
Expand All @@ -691,18 +692,19 @@ private void startEnvironmentQueue(String namespace,
format("Environment of workspace with ID '%s' failed due to internal error", workspaceId));
}

final String finalMachineName = machineName;
service.setName(machineName);
// needed to reuse startInstance method and
// create machine instances by different implementation-specific providers
MachineStarter machineStarter = (machineLogger, machineSource) -> {
CheServiceImpl serviceWithCorrectSource = getServiceWithCorrectSource(service, machineSource);
CheServiceImpl serviceWithNormalizedSource = normalizeServiceSource(service, machineSource);
replaceServiceToContainerNameInLinks(serviceWithNormalizedSource, launchedServices);
return machineProvider.startService(namespace,
workspaceId,
envName,
finalMachineName,
serviceWithNormalizedSource.getName(),
isDev,
networkId,
serviceWithCorrectSource,
serviceWithNormalizedSource,
machineLogger);
};

Expand Down Expand Up @@ -775,6 +777,7 @@ private void startEnvironmentQueue(String namespace,
"' start interrupted. Workspace stopped before all its machines started");
}

launchedServices.add(service);
machineName = queuePeekOrFail(workspaceId);
}
} catch (RuntimeException | ServerException e) {
Expand Down Expand Up @@ -887,32 +890,32 @@ Instance startMachine(LineConsumer machineLogger,
NotFoundException;
}

private CheServiceImpl getServiceWithCorrectSource(CheServiceImpl service,
MachineSource machineSource)
private CheServiceImpl normalizeServiceSource(CheServiceImpl service,
MachineSource machineSource)
throws ServerException {
CheServiceImpl serviceWithCorrectSource = service;
CheServiceImpl serviceWithNormalizedSource = service;
if (machineSource != null) {
serviceWithCorrectSource = new CheServiceImpl(service);
serviceWithNormalizedSource = new CheServiceImpl(service);
if ("image".equals(machineSource.getType())) {
serviceWithCorrectSource.setBuild(null);
serviceWithCorrectSource.setImage(machineSource.getLocation());
serviceWithNormalizedSource.setBuild(null);
serviceWithNormalizedSource.setImage(machineSource.getLocation());
} else {
// dockerfile
serviceWithCorrectSource.setImage(null);
serviceWithNormalizedSource.setImage(null);
if (machineSource.getContent() != null) {
serviceWithCorrectSource.setBuild(new CheServiceBuildContextImpl(null,
null,
machineSource.getContent(),
null));
serviceWithNormalizedSource.setBuild(new CheServiceBuildContextImpl(null,
null,
machineSource.getContent(),
null));
} else {
serviceWithCorrectSource.setBuild(new CheServiceBuildContextImpl(machineSource.getLocation(),
null,
null,
null));
serviceWithNormalizedSource.setBuild(new CheServiceBuildContextImpl(machineSource.getLocation(),
null,
null,
null));
}
}
}
return serviceWithCorrectSource;
return serviceWithNormalizedSource;
}

private Machine getMachineWithCorrectSource(MachineImpl machine, MachineSource machineSource) {
Expand All @@ -930,6 +933,45 @@ private Machine getMachineWithCorrectSource(MachineImpl machine, MachineSource m
return machineWithCorrectSource;
}

/**
* Replaces linked to this service's name with container name which represents the service in links section.
* The problem is that a user writes names of other services in links section in compose file.
* But actually links are constraints and they values should be names of containers (not services) to be linked.
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

and they values => and their values

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

thx

* <br/>
* For example: serviceDB:serviceDbAlias -> container_1234:serviceDbAlias <br/>
* If alias is omitted then service name will be used.
*
* @param serviceToStart
* service which is starting now
* @param launchedServices
* already running services
*/
@VisibleForTesting
void replaceServiceToContainerNameInLinks(CheServiceImpl serviceToStart, List<CheServiceImpl> launchedServices) {
final List<String> containerLinks = serviceToStart.getLinks();
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

we couldn't use Java8 stream/filter/collect for the whole method ?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yes, we can, but I think that it is redundant here.
If we used stream here it would made code more complicated and we would had additional expenses for stream creation/collection here (note, that in many cases list with links contains 0 or 1 element, i.e. how often and how many links you use in docker compose?)

for (int i = 0; i < containerLinks.size(); i++) {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

You could probably use for each here (for (String link: containersLinks) {)

Copy link
Contributor Author

@mmorhun mmorhun Oct 26, 2016

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

No, I cannot. I need to change the list. I can use Iterator here, but I think that current version is more readable.

String link = containerLinks.get(i);
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Extracting the body of the for loop in a new method would make it more readable

Copy link
Contributor Author

@mmorhun mmorhun Oct 26, 2016

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Taking into account, that we have only one loop in the method and this loop actually is method's body and body of this loop cannot be reused somewhere and if so, we should pass iterator and links list into new method as parameters, IMO, there is no point to extract loop body into another method. @garagatyi WDYT?

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Since you are going to refactor this code lets figure out what can be cleaned up after that refactoring

String serviceName;
String serviceAlias;
int colonIndex = link.indexOf(':');
if (colonIndex != -1) {
serviceName = link.substring(0, colonIndex);
serviceAlias = link.substring(colonIndex + 1);
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

What happen if user provide a (bad) link with an empty alias like: serviceDb:

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

split() method is probably more appropriate here instead of manually parsing the links string.

Copy link
Contributor Author

@mmorhun mmorhun Oct 26, 2016

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

If user provide link with empty alias, like serviceDb:, than CheEnvironmentValidator will throw an exception and a user will be notified about syntax error.

} else {
serviceName = link;
serviceAlias = null;
}
for (CheServiceImpl launchedService : launchedServices) {
if (serviceName.equals(launchedService.getName())) {
containerLinks.set(i, (serviceAlias == null) ?
launchedService.getContainerName() + ':' + serviceName :
launchedService.getContainerName() + ':' + serviceAlias);
break;
}
}
}
}

private void addMachine(MachineImpl machine) throws ServerException {
Instance instance = new NoOpMachineInstance(machine);
try (StripedLocks.WriteLock lock = stripedLocks.acquireWriteLock(machine.getWorkspaceId())) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@
*/
public class CheServiceImpl {
private String id;
private String name;
private String containerName;
private List<String> command;
private List<String> entrypoint;
Expand All @@ -43,6 +44,7 @@ public CheServiceImpl() {}

public CheServiceImpl(CheServiceImpl service) {
id = service.getId();
name = service.getName();
image = service.getImage();
if (service.getBuild() != null) {
build = new CheServiceBuildContextImpl(service.getBuild());
Expand Down Expand Up @@ -100,6 +102,22 @@ public CheServiceImpl withId(String id) {
return this;
}

/**
* Name of service
*/
public String getName() {
return name;
}

public void setName(String name) {
this.name = name;
}

public CheServiceImpl withName(String name) {
this.name = name;
return this;
}

/**
* Image for container creation.
*/
Expand Down