Skip to content

Commit

Permalink
[JBIDE-21625] Enable debug mode for OpenShift 3 server adapter
Browse files Browse the repository at this point in the history
Signed-off-by: Fred Bricon <fbricon@gmail.com>
  • Loading branch information
fbricon committed Mar 24, 2016
1 parent 06dd9f6 commit fe7a8c2
Show file tree
Hide file tree
Showing 14 changed files with 1,046 additions and 20 deletions.
5 changes: 4 additions & 1 deletion plugins/org.jboss.tools.openshift.core/META-INF/MANIFEST.MF
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,8 @@ Require-Bundle: org.jboss.tools.openshift.client;bundle-version="[3.0.0,4.0.0)",
org.apache.commons.lang;bundle-version="2.6.0",
org.eclipse.core.variables,
org.eclipse.jst.j2ee;bundle-version="1.1.850",
org.jboss.tools.runtime.core;bundle-version="3.1.1"
org.jboss.tools.runtime.core;bundle-version="3.1.1",
org.eclipse.jdt.core
Bundle-RequiredExecutionEnvironment: JavaSE-1.8
Bundle-ActivationPolicy: lazy
Export-Package: org.jboss.tools.openshift.core;x-friends:="org.jboss.tools.openshift.test,org.jboss.tools.openshift.ui",
Expand All @@ -36,8 +37,10 @@ Export-Package: org.jboss.tools.openshift.core;x-friends:="org.jboss.tools.opens
org.jboss.tools.openshift.core.server.behavior,
org.jboss.tools.openshift.core.util;x-friends:="org.jboss.tools.openshift.test,org.jboss.tools.openshift.ui",
org.jboss.tools.openshift.internal.core;x-friends:="org.jboss.tools.openshift.test,org.jboss.tools.openshift.ui",
org.jboss.tools.openshift.internal.core.models;x-friends:="org.jboss.tools.openshift.test,org.jboss.tools.openshift.ui",
org.jboss.tools.openshift.internal.core.portforwarding;x-friends:="org.jboss.tools.openshift.test,org.jboss.tools.openshift.ui",
org.jboss.tools.openshift.internal.core.preferences;x-friends:="org.jboss.tools.openshift.test,org.jboss.tools.openshift.ui",
org.jboss.tools.openshift.internal.core.server.debug;x-friends:="org.jboss.tools.openshift.test,org.jboss.tools.openshift.ui",
org.jboss.tools.openshift.internal.core.util;x-friends:="org.jboss.tools.openshift.test,org.jboss.tools.openshift.ui"
Service-Component: META-INF/connectionFactory.xml

Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,7 @@
import org.osgi.service.prefs.BackingStoreException;

import com.openshift.restclient.ResourceKind;
import com.openshift.restclient.model.IDeploymentConfig;
import com.openshift.restclient.model.IService;
import com.openshift.restclient.model.route.IRoute;

Expand All @@ -48,6 +49,8 @@
*/
public class OpenShiftServerUtils {

private static final String DEPLOYMENT_CONFIG_KEY = "deploymentconfig";

private static final String LIVERELOAD_PORT_KEY = "port";//Key to the port # of the host the LiveReload server need to proxy

public static final String SERVER_PROJECT_QUALIFIER = "org.jboss.tools.openshift.core"; //$NON-NLS-1$
Expand Down Expand Up @@ -327,4 +330,25 @@ public static String getProjectAttribute(String name, String defaultValue, IServ
public static String getProjectAttribute(String name, String defaultValue, IProject project) {
return ServerUtils.getProjectAttribute(name, defaultValue, SERVER_PROJECT_QUALIFIER, project);
}

public static IDeploymentConfig getDeploymentConfig(IServerAttributes attributes) {
IService service = getService(attributes);
if (service == null) {
return null;
}
//TODO use annotations instead of labels
String dcName = service.getPods().stream().filter(p -> p.getLabels().containsKey(DEPLOYMENT_CONFIG_KEY))
.findFirst()
.map(p -> p.getLabels().get(DEPLOYMENT_CONFIG_KEY))
.orElse(null);
if (dcName == null) {
return null;
}
Connection connection = getConnection(attributes);
if (connection == null) {
return null;
}
IDeploymentConfig dc = connection.getResource(ResourceKind.DEPLOYMENT_CONFIG, service.getNamespace(), dcName);
return dc;
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -10,29 +10,47 @@
*******************************************************************************/
package org.jboss.tools.openshift.core.server.behavior;

import java.io.IOException;
import java.util.Optional;
import java.util.Set;

import org.eclipse.core.resources.IProject;
import org.eclipse.core.runtime.CoreException;
import org.eclipse.core.runtime.IProgressMonitor;
import org.eclipse.core.runtime.IStatus;
import org.eclipse.core.runtime.NullProgressMonitor;
import org.eclipse.core.runtime.Status;
import org.eclipse.debug.core.ILaunch;
import org.eclipse.debug.core.ILaunchConfiguration;
import org.eclipse.debug.core.ILaunchConfigurationWorkingCopy;
import org.eclipse.jdt.core.JavaCore;
import org.eclipse.jdt.launching.SocketUtil;
import org.eclipse.wst.server.core.IServer;
import org.eclipse.wst.server.core.ServerUtil;
import org.jboss.ide.eclipse.as.wtp.core.server.behavior.AbstractSubsystemController;
import org.jboss.ide.eclipse.as.wtp.core.server.behavior.ControllableServerBehavior;
import org.jboss.ide.eclipse.as.wtp.core.server.behavior.IControllableServerBehavior;
import org.jboss.ide.eclipse.as.wtp.core.server.behavior.ILaunchServerController;
import org.jboss.ide.eclipse.as.wtp.core.server.behavior.ISubsystemController;
import org.jboss.tools.foundation.core.plugin.log.StatusFactory;
import org.jboss.tools.openshift.core.server.OpenShiftServerUtils;
import org.jboss.tools.openshift.internal.core.OpenShiftCoreActivator;
import org.jboss.tools.openshift.internal.core.portforwarding.PortForwardingUtils;
import org.jboss.tools.openshift.internal.core.server.debug.DebuggingContext;
import org.jboss.tools.openshift.internal.core.server.debug.IDebugListener;
import org.jboss.tools.openshift.internal.core.server.debug.OpenShiftDebugUtils;

import com.openshift.restclient.OpenShiftException;
import com.openshift.restclient.capability.resources.IPortForwardable;
import com.openshift.restclient.capability.resources.IPortForwardable.PortPair;
import com.openshift.restclient.model.IDeploymentConfig;
import com.openshift.restclient.model.IPod;
import com.openshift.restclient.model.IService;

public class OpenShiftLaunchController extends AbstractSubsystemController
implements ISubsystemController, ILaunchServerController {

private static final String DEBUG_MODE = "debug";

/**
* Get access to the ControllableServerBehavior
Expand All @@ -50,22 +68,89 @@ protected static IControllableServerBehavior getServerBehavior(ILaunchConfigurat
@Override
public void launch(ILaunchConfiguration configuration, String mode,
ILaunch launch, IProgressMonitor monitor) throws CoreException {
IControllableServerBehavior beh = getServerBehavior(configuration);
if( beh != null ) {
((ControllableServerBehavior)beh).setServerStarting();
int state = pollState();
if( state == IServer.STATE_STARTED) {
((ControllableServerBehavior)beh).setServerStarted();
((ControllableServerBehavior)getControllableBehavior()).setRunMode(mode);
} else {
((ControllableServerBehavior)beh).setServerStopped();
((ControllableServerBehavior)getControllableBehavior()).setRunMode(null);
}
IControllableServerBehavior serverBehavior = getServerBehavior(configuration);
if( !(serverBehavior instanceof ControllableServerBehavior )) {
throw toCoreException("Unable to find a IControllableServerBehavior instance");
}
ControllableServerBehavior beh = (ControllableServerBehavior) serverBehavior;

beh.setServerStarting();

IServer server = beh.getServer();

IDeploymentConfig dc = OpenShiftServerUtils.getDeploymentConfig(server);
if (dc == null) {
throw toCoreException("No deployment config was found for "+server.getName());
}

DebuggingContext debugContext = OpenShiftDebugUtils.get().getDebuggingContext(dc);
if( DEBUG_MODE.equals(mode)) {
startDebugging(server, dc, debugContext, monitor);
} else {//run, profile
stopDebugging(dc, debugContext, monitor);
}

int state = pollState();
if( state == IServer.STATE_STARTED) {
beh.setServerStarted();
beh.setRunMode(mode);
} else {
// TODO throw error
beh.setServerStopped();
((ControllableServerBehavior)getControllableBehavior()).setRunMode(null);
}
}


private void startDebugging(IServer server, IDeploymentConfig dc, DebuggingContext debugContext,
IProgressMonitor monitor) throws CoreException {
int remotePort = debugContext.getDebugPort();
if( remotePort == -1 ) {
debugContext.setDebugPort(8787);//TODO get default port from server settings?
}
IDebugListener listener = new IDebugListener() {

public void onDebugChange(DebuggingContext debuggingContext, IProgressMonitor monitor)
throws CoreException {
if (debuggingContext.getPod() == null) {
throw toCoreException("Unable to connect to remote pod");
}
int localPort = mapPortForwarding(debuggingContext, monitor);

if(isJavaProject(server)) {
attachRemoteDebugger(server, localPort, monitor);
}
}

@Override
public void onPodRestart(DebuggingContext debuggingContext, IProgressMonitor monitor)
throws CoreException {
onDebugChange(debuggingContext, monitor);
}
};
debugContext.setDebugListener(listener);
OpenShiftDebugUtils.get().enableDebugMode(dc, debugContext, monitor);
}


private void stopDebugging(IDeploymentConfig dc, DebuggingContext debugContext, IProgressMonitor monitor)
throws CoreException {
IDebugListener listener = new IDebugListener() {

public void onDebugChange(DebuggingContext debuggingContext, IProgressMonitor monitor)
throws CoreException {
//that will automatically kill the remote debugger
unMapPortForwarding(debuggingContext.getPod());
}

@Override
public void onPodRestart(DebuggingContext debuggingContext, IProgressMonitor monitor)
throws CoreException {
}
};
debugContext.setDebugListener(listener);
OpenShiftDebugUtils.get().disableDebugMode(dc, debugContext, monitor);
}

protected int pollState() {
IService service = null;
Exception e = null;
Expand All @@ -92,5 +177,131 @@ public void setupLaunchConfiguration(
IProgressMonitor monitor) throws CoreException {
// Do Nothing
}

private boolean isJavaProject(IServer server) {
IProject p = OpenShiftServerUtils.getDeployProject(server);
try {
return p != null && p.isAccessible() && p.hasNature(JavaCore.NATURE_ID);
} catch (CoreException e) {
OpenShiftCoreActivator.pluginLog().logError(e);
}
return false;
}

/**
* Unmap the port forwarding.
* @throws CoreException
*/
private void unMapPortForwarding(IPod pod) throws CoreException {
if (pod != null) {
try {
PortForwardingUtils.stopPortForwarding(pod, null);
} catch (IOException e) {
throw toCoreException("Unable to stop port forawrding", e);
}
}
}

/**
* Map the remote port to a local port.
* Return the local port in use, or -1 if failed
* @param server
* @param remotePort
* @return the local debug port or -1 if port forwarding did not start or was cancelled.
*/
private int mapPortForwarding(DebuggingContext debuggingContext, IProgressMonitor monitor) {

monitor.subTask("Enabling port forwarding");
IPod pod = debuggingContext.getPod();
int remotePort = debuggingContext.getDebugPort();
if (pod == null || remotePort < 1) {
//nothing we can do
return -1;
}
Set<PortPair> ports = PortForwardingUtils.getForwardablePorts(pod);
Optional<PortPair> debugPort = ports.stream().filter(p -> remotePort == p.getRemotePort()).findFirst();
if (!debugPort.isPresent() || monitor.isCanceled()) {
return -1;
}

if (PortForwardingUtils.isPortForwardingStarted(pod)) {
int p = debugPort.get().getLocalPort();
return p;
}

for (IPortForwardable.PortPair port : ports) {
if(monitor.isCanceled()) {
return -1;
}
port.setLocalPort(SocketUtil.findFreePort());
monitor.worked(1);
}

PortForwardingUtils.startPortForwarding(pod, ports);

if (PortForwardingUtils.isPortForwardingStarted(pod)) {
int p = debugPort.get().getLocalPort();
return p;
}
//maybe throw exception?
return -1;
}

private void attachRemoteDebugger(IServer server, int localDebugPort, IProgressMonitor monitor) throws CoreException {
monitor.subTask("Attaching remote debugger");

OpenShiftDebugUtils debugUtils = OpenShiftDebugUtils.get();
ILaunchConfiguration debuggerLaunchConfig = debugUtils.getRemoteDebuggerLaunchConfiguration(server);
ILaunchConfigurationWorkingCopy workingCopy;
if (debuggerLaunchConfig == null) {
workingCopy = debugUtils.createRemoteDebuggerLaunchConfiguration(server);
} else {
if (debugUtils.isRunning(debuggerLaunchConfig, localDebugPort)) {
return;
}
workingCopy = debuggerLaunchConfig.getWorkingCopy();
}


IProject project = OpenShiftServerUtils.getDeployProject(server);
debugUtils.setupRemoteDebuggerLaunchConfiguration(workingCopy, project, localDebugPort);
debuggerLaunchConfig = workingCopy.doSave();

long elapsed = 0;
long increment = 1_000;
long maxWait = 60_000; //TODO Get from server settings?
boolean launched = false;
monitor.subTask("Waiting for remote debug port availability");
while(!launched && elapsed < maxWait) {
try {
//TODO That's fugly. ideally we should see if socket on debug port is responsive instead
debuggerLaunchConfig.launch(DEBUG_MODE, new NullProgressMonitor());
launched = true;
} catch (Exception e) {
if (monitor.isCanceled()) {
break;
}
try {
Thread.sleep(increment);
elapsed+=increment;
} catch (InterruptedException ie) {
}
}
}

if (!launched){
throw toCoreException("Unable to start a remote debugger to localhost:"+localDebugPort);
}

monitor.worked(10);
}


private CoreException toCoreException(String msg, Exception e) {
return new CoreException(StatusFactory.errorStatus(OpenShiftCoreActivator.PLUGIN_ID, msg, e));
}

private CoreException toCoreException(String msg) {
return toCoreException(msg, null);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@
* Contributors:
* Red Hat, Inc. - initial API and implementation
******************************************************************************/
package org.jboss.tools.openshift.internal.ui.wizard.deployimage;
package org.jboss.tools.openshift.internal.core.models;

import org.apache.commons.lang.StringUtils;
import org.eclipse.osgi.util.NLS;
Expand Down Expand Up @@ -38,7 +38,16 @@ public PortSpecAdapter(String spec){
}
port = Integer.valueOf(parts[0]);
protocol = parts[1].toUpperCase();
name = NLS.bind("{0}-{1}", port, protocol.toLowerCase());
name = getName(port, protocol);
}

public PortSpecAdapter(String name, String protocol, int port){
if(StringUtils.isBlank(protocol)){
throw new IllegalArgumentException("protocol must be set");
}
this.port = port;
this.protocol = protocol;
this.name = (name == null)?getName(port, protocol):name;
}

@Override
Expand Down Expand Up @@ -92,4 +101,8 @@ public boolean equals(Object obj) {



private String getName(int port, String protocol) {
return NLS.bind("{0}-{1}", port, protocol.toLowerCase());
}

}

0 comments on commit fe7a8c2

Please sign in to comment.