Skip to content

Commit

Permalink
Factorize code of ServerEvaluationStrategy classes, to use the Cust…
Browse files Browse the repository at this point in the history
…om strategy as the basis of other strategies (#5366)

* Pull-up the local docker port management (use exposed ports)

Signed-off-by: David Festal <dfestal@redhat.com>

* Make all the strategies extend `CustomEvaluationStrategy`

Signed-off-by: David Festal <dfestal@redhat.com>

* Add a `workspaceIdWithoutPrefix` macro and use it for `single-port`

This macro is based on the `workspaceId` macro, but without the
`workspace` prefix.

Signed-off-by: David Festal <dfestal@redhat.com>

* Add the `isDevMachine` to allow conditions in the ST template.

This is required to allow the `single-port` strategy to have a different
url according to the type of machine. (see the work done for CHE-175 :
Support multi-container workspaces on OpenShift)

Signed-off-by: David Festal <dfestal@redhat.com>

* Small fixes after comments from @fbenoit

Signed-off-by: David Festal <dfestal@redhat.com>

* Fix unnecessary space pointed out by @sunix

Signed-off-by: David Festal <dfestal@redhat.com>

* Remove unnecessary `else` as suggested by @sunix

Signed-off-by: David Festal <dfestal@redhat.com>

* Keep the method signatures compatible with the `condenvy` strategy

Signed-off-by: David Festal <dfestal@redhat.com>

* Align names of parameters of constructors (requested by @garagatyi)

Signed-off-by: David Festal <dfestal@redhat.com>

* Add a default implementation to avoid breaking the Codenvy build

Signed-off-by: David Festal <dfestal@redhat.com>

* Also rename the attributes

Signed-off-by: David Festal <dfestal@redhat.com>

* Use a constant for the `workspace` prefix string

Signed-off-by: David Festal <dfestal@redhat.com>

* Fix formatting as requested by @sunix

Signed-off-by: David Festal <dfestal@redhat.com>

* Use a constant for the `isDevMachine` macro name

Signed-off-by: David Festal <dfestal@redhat.com>

* Add unit tests for `workspaceIdWithoutPrefixè and `isDevMachine` macros

Signed-off-by: David Festal <dfestal@redhat.com>

* Another requested formatting fix

Signed-off-by: David Festal <dfestal@redhat.com>

* Make new tests clearer

Signed-off-by: David Festal <dfestal@redhat.com>

* yet another formatting request

Signed-off-by: David Festal <dfestal@redhat.com>

* Respect the original order of imports

Signed-off-by: David Festal <dfestal@redhat.com>

* remove unnecessary `toString()`

Signed-off-by: David Festal <dfestal@redhat.com>

* use a lowercase `S` in the `server-` prefix

Signed-off-by: David Festal <dfestal@redhat.com>
  • Loading branch information
davidfestal authored and sunix committed Jun 29, 2017
1 parent 46b2f8c commit a822958
Show file tree
Hide file tree
Showing 10 changed files with 251 additions and 196 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -40,7 +40,7 @@
* @author Florent Benoit
* @see ServerEvaluationStrategy
*/
public class CustomServerEvaluationStrategy extends DefaultServerEvaluationStrategy {
public class CustomServerEvaluationStrategy extends ServerEvaluationStrategy {

/**
* Regexp to extract port (under the form 22/tcp or 4401/tcp, etc.) from label references
Expand All @@ -57,6 +57,32 @@ public class CustomServerEvaluationStrategy extends DefaultServerEvaluationStrat
*/
public static final String CHE_MACHINE_NAME_PROPERTY = "CHE_MACHINE_NAME=";

/**
* Name of the property to get the property that indicates if the machine is the dev machine
*/
public static final String CHE_IS_DEV_MACHINE_PROPERTY = "CHE_IS_DEV_MACHINE=";

/**
* Prefix added in front of the generated name to build the workspaceId
*/
public static final String CHE_WORKSPACE_ID_PREFIX = "workspace";


/**
* name of the macro that indicates if the machine is the dev machine
*/
public static final String IS_DEV_MACHINE_MACRO = "isDevMachine";

/**
* Used to store the address set by property {@code che.docker.ip}, if applicable.
*/
protected String cheDockerIp;

/**
* Used to store the address set by property {@code che.docker.ip.external}. if applicable.
*/
protected String cheDockerIpExternal;

/**
* The current port of che.
*/
Expand All @@ -72,6 +98,17 @@ public class CustomServerEvaluationStrategy extends DefaultServerEvaluationStrat
*/
private String cheDockerCustomExternalTemplate;

/**
* Option to enable the use of the container address, when searching for addresses.
*/
private boolean useContainerAddress;


/**
* Option to tell if an exception should be thrown when the host defined in the `externalAddress` isn't known
* and cannot be converted into a valid IP.
*/
private boolean throwOnUnknownHost = true;

/**
* Default constructor
Expand All @@ -82,12 +119,49 @@ public CustomServerEvaluationStrategy(@Nullable @Named("che.docker.ip") String c
@Nullable @Named("che.docker.server_evaluation_strategy.custom.template") String cheDockerCustomExternalTemplate,
@Nullable @Named("che.docker.server_evaluation_strategy.custom.external.protocol") String cheDockerCustomExternalProtocol,
@Named("che.port") String chePort) {
super(cheDockerIp, cheDockerIpExternal);
this(cheDockerIp, cheDockerIpExternal, cheDockerCustomExternalTemplate, cheDockerCustomExternalProtocol, chePort, false);
}

/**
* Constructor to be called by derived strategies
*/
public CustomServerEvaluationStrategy(@Nullable @Named("che.docker.ip") String cheDockerIp,
@Nullable @Named("che.docker.ip.external") String cheDockerIpExternal,
@Nullable @Named("che.docker.server_evaluation_strategy.custom.template") String cheDockerCustomExternalTemplate,
@Nullable @Named("che.docker.server_evaluation_strategy.custom.external.protocol") String cheDockerCustomExternalProtocol,
@Named("che.port") String chePort,
boolean useContainerAddress) {
this.cheDockerIp = cheDockerIp;
this.cheDockerIpExternal = cheDockerIpExternal;
this.chePort = chePort;
this.cheDockerCustomExternalTemplate = cheDockerCustomExternalTemplate;
this.cheDockerCustomExternalProtocol = cheDockerCustomExternalProtocol;
this.useContainerAddress = useContainerAddress;
}

@Override
protected Map<String, String> getInternalAddressesAndPorts(ContainerInfo containerInfo, String internalHost) {
final String internalAddressContainer = containerInfo.getNetworkSettings().getIpAddress();

final String internalAddress;

if (useContainerAddress) {
internalAddress = !isNullOrEmpty(internalAddressContainer) ?
internalAddressContainer :
internalHost;
} else {
internalAddress =
cheDockerIp != null ?
cheDockerIp :
internalHost;
}

boolean useExposedPorts = useContainerAddress && internalAddress != internalHost;

return getExposedPortsToAddressPorts(internalAddress, containerInfo.getNetworkSettings().getPorts(), useExposedPorts);
}


/**
* Override the host for all ports by using the external template.
*/
Expand All @@ -100,6 +174,10 @@ protected Map<String, String> getExternalAddressesAndPorts(ContainerInfo contain
// get current ports
Map<String, List<PortBinding>> ports = containerInfo.getNetworkSettings().getPorts();

if (isNullOrEmpty(cheDockerCustomExternalTemplate)) {
return getExposedPortsToAddressPorts(renderingEvaluation.getExternalAddress(), ports, false);
}

return ports.keySet().stream()
.collect(Collectors.toMap(portKey -> portKey,
portKey -> renderingEvaluation.render(cheDockerCustomExternalTemplate, portKey)));
Expand Down Expand Up @@ -180,6 +258,11 @@ public interface RenderingEvaluation {
* @return the rendering of the template
*/
String render(String template, String port);

/**
* Gets default external address.
*/
String getExternalAddress();
}

/**
Expand All @@ -202,14 +285,22 @@ protected OnlineRenderingEvaluation withInternalHost(String internalHost) {
}

@Override
protected String getExternalAddress() {
return externalAddressProperty != null ?
externalAddressProperty :
internalAddressProperty != null ?
internalAddressProperty :
!isNullOrEmpty(gatewayAddressContainer) ?
gatewayAddressContainer :
this.internalHost;
public String getExternalAddress() {
if (useContainerAddress) {
return cheDockerIpExternal != null ?
cheDockerIpExternal :
cheDockerIp != null ?
cheDockerIp :
!isNullOrEmpty(gatewayAddressContainer) ?
gatewayAddressContainer :
this.internalHost;
}

return cheDockerIpExternal != null ?
cheDockerIpExternal :
cheDockerIp != null ?
cheDockerIp :
this.internalHost;
}
}

Expand Down Expand Up @@ -294,7 +385,7 @@ protected void initPortMapping() {
// add to this map only port without a known ref name
Map<String, String> portsToUnkownRefName =
exposedPorts.stream().filter((port) -> !portsToKnownRefName.containsKey(port))
.collect(Collectors.toMap(p -> p, p -> "Server-" + p.replace('/', '-')));
.collect(Collectors.toMap(p -> p, p -> "server-" + p.replace('/', '-')));

// list of all ports with refName (known/unknown)
this.portsToRefName = new HashMap(portsToKnownRefName);
Expand All @@ -304,9 +395,9 @@ protected void initPortMapping() {
/**
* Gets default external address.
*/
protected String getExternalAddress() {
return externalAddressProperty != null ?
externalAddressProperty : internalAddressProperty;
public String getExternalAddress() {
return cheDockerIpExternal != null ?
cheDockerIpExternal : cheDockerIp;
}

/**
Expand All @@ -315,14 +406,16 @@ protected String getExternalAddress() {
protected void populateGlobalProperties() {
String externalAddress = getExternalAddress();
String externalIP = getExternalIp(externalAddress);
globalPropertiesMap.put("internalIp", internalAddressProperty);
globalPropertiesMap.put("internalIp", cheDockerIp);
globalPropertiesMap.put("externalAddress", externalAddress);
globalPropertiesMap.put("externalIP", externalIP);
globalPropertiesMap.put("workspaceId", getWorkspaceId());
globalPropertiesMap.put("workspaceIdWithoutPrefix", getWorkspaceId().replaceFirst(CHE_WORKSPACE_ID_PREFIX,""));
globalPropertiesMap.put("machineName", getMachineName());
globalPropertiesMap.put("wildcardNipDomain", getWildcardNipDomain(externalAddress));
globalPropertiesMap.put("wildcardXipDomain", getWildcardXipDomain(externalAddress));
globalPropertiesMap.put("chePort", chePort);
globalPropertiesMap.put(IS_DEV_MACHINE_MACRO, getIsDevMachine());
}

/**
Expand All @@ -335,11 +428,25 @@ public String render(String template, String port) {
this.initialized = true;
}
ST stringTemplate = new ST(template);
globalPropertiesMap.forEach((key, value) -> stringTemplate.add(key, value));
globalPropertiesMap.forEach((key, value) -> stringTemplate.add(key,
IS_DEV_MACHINE_MACRO.equals(key) ?
Boolean.parseBoolean(value)
: value));
stringTemplate.add("serverName", portsToRefName.get(port));
return stringTemplate.render();
}

/**
* returns if the current machine is the dev machine
*
* @return true if the curent machine is the dev machine
*/
protected String getIsDevMachine() {
return Arrays.stream(env).filter(env -> env.startsWith(CHE_IS_DEV_MACHINE_PROPERTY))
.map(s -> s.substring(CHE_IS_DEV_MACHINE_PROPERTY.length()))
.findFirst().get();
}

/**
* Gets the workspace ID from the config of the given container
*
Expand Down Expand Up @@ -371,8 +478,11 @@ protected String getExternalIp(String externalAddress) {
try {
return InetAddress.getByName(externalAddress).getHostAddress();
} catch (UnknownHostException e) {
throw new UnsupportedOperationException("Unable to find the IP for the address '" + externalAddress + "'", e);
if (throwOnUnknownHost) {
throw new UnsupportedOperationException("Unable to find the IP for the address '" + externalAddress + "'", e);
}
}
return null;
}

/**
Expand All @@ -395,4 +505,13 @@ protected String getWildcardXipDomain(String externalAddress) {

}

@Override
protected boolean useHttpsForExternalUrls() {
return "https".equals(cheDockerCustomExternalProtocol);
}

public CustomServerEvaluationStrategy withThrowOnUnknownHost(boolean throwOnUnknownHost) {
this.throwOnUnknownHost = throwOnUnknownHost;
return this;
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -31,48 +31,11 @@
* @author Alexander Garagatyi
* @see ServerEvaluationStrategy
*/
public class DefaultServerEvaluationStrategy extends ServerEvaluationStrategy {

/**
* Used to store the address set by property {@code che.docker.ip}, if applicable.
*/
protected String internalAddressProperty;

/**
* Used to store the address set by property {@code che.docker.ip.external}. if applicable.
*/
protected String externalAddressProperty;
public class DefaultServerEvaluationStrategy extends CustomServerEvaluationStrategy {

@Inject
public DefaultServerEvaluationStrategy(@Nullable @Named("che.docker.ip") String internalAddress,
@Nullable @Named("che.docker.ip.external") String externalAddress) {
this.internalAddressProperty = internalAddress;
this.externalAddressProperty = externalAddress;
}

@Override
protected Map<String, String> getInternalAddressesAndPorts(ContainerInfo containerInfo, String internalHost) {
String internalAddress = internalAddressProperty != null ?
internalAddressProperty :
internalHost;

return getExposedPortsToAddressPorts(internalAddress, containerInfo.getNetworkSettings().getPorts());
}

@Override
protected Map<String, String> getExternalAddressesAndPorts(ContainerInfo containerInfo,
String internalHost) {
String externalAddress = externalAddressProperty != null ?
externalAddressProperty :
internalAddressProperty != null ?
internalAddressProperty :
internalHost;

return super.getExposedPortsToAddressPorts(externalAddress, containerInfo.getNetworkSettings().getPorts());
}

@Override
protected boolean useHttpsForExternalUrls() {
return false;
super(internalAddress, externalAddress, null, null, null, false);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -68,6 +68,11 @@ public class DockerInstanceRuntimeInfo implements MachineRuntimeInfo {
*/
public static final String CHE_MACHINE_NAME = "CHE_MACHINE_NAME";

/**
* Environment variable that will contain Name of the machine
*/
public static final String CHE_IS_DEV_MACHINE = "CHE_IS_DEV_MACHINE";

/**
* Default HOSTNAME that will be added in all docker containers that are started. This host will container the Docker host's ip
* reachable inside the container.
Expand Down
Loading

0 comments on commit a822958

Please sign in to comment.