Skip to content

Commit

Permalink
Merge pull request #1717 from eclipse/CODENVY-556-2
Browse files Browse the repository at this point in the history
CODENVY-556 Add service for fetching recipe script
  • Loading branch information
Michail Kuznetsov authored Jul 15, 2016
2 parents c45d3a9 + 411dd89 commit e8ff05f
Show file tree
Hide file tree
Showing 12 changed files with 212 additions and 38 deletions.
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
/*******************************************************************************
* Copyright (c) 2012-2016 Codenvy, S.A.
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the Eclipse Public License v1.0
* which accompanies this distribution, and is available at
* http://www.eclipse.org/legal/epl-v10.html
*
* Contributors:
* Codenvy, S.A. - initial API and implementation
*******************************************************************************/
package org.eclipse.che.ide.extension.machine.client;

import org.eclipse.che.api.promises.client.Promise;
import org.eclipse.che.ide.extension.machine.client.machine.Machine;

/**
* @author Mihail Kuznyetsov.
*/
public interface RecipeScriptDownloadServiceClient {

/**
* Fetch recipe script for machine source location
*
* @param machine
* machine to fetch script for
* @return content of the recipe script
*/
Promise<String> getRecipeScript(Machine machine);
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
/*******************************************************************************
* Copyright (c) 2012-2016 Codenvy, S.A.
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the Eclipse Public License v1.0
* which accompanies this distribution, and is available at
* http://www.eclipse.org/legal/epl-v10.html
*
* Contributors:
* Codenvy, S.A. - initial API and implementation
*******************************************************************************/
package org.eclipse.che.ide.extension.machine.client;

import org.eclipse.che.api.promises.client.Promise;
import org.eclipse.che.ide.extension.machine.client.machine.Machine;
import org.eclipse.che.ide.rest.AsyncRequestFactory;
import org.eclipse.che.ide.rest.RestContext;
import org.eclipse.che.ide.rest.StringUnmarshaller;

import javax.inject.Inject;

/**
* @author Mihail Kuznyetsov.
*/
public class RecipeScriptDownloadServiceClientImpl implements RecipeScriptDownloadServiceClient {

private final String restContext;
private final AsyncRequestFactory asyncRequestFactory;

@Inject
public RecipeScriptDownloadServiceClientImpl(@RestContext String restContext, AsyncRequestFactory asyncRequestFactory) {
this.restContext = restContext;
this.asyncRequestFactory = asyncRequestFactory;
}

@Override
public Promise<String> getRecipeScript(Machine machine) {
return asyncRequestFactory
.createGetRequest(restContext + "/recipe/script/" + machine.getId())
.send(new StringUnmarshaller());
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,8 @@
import org.eclipse.che.ide.api.machine.MachineManager;
import org.eclipse.che.ide.api.outputconsole.OutputConsole;
import org.eclipse.che.ide.api.parts.Perspective;
import org.eclipse.che.ide.extension.machine.client.RecipeScriptDownloadServiceClient;
import org.eclipse.che.ide.extension.machine.client.RecipeScriptDownloadServiceClientImpl;
import org.eclipse.che.ide.extension.machine.client.command.CommandType;
import org.eclipse.che.ide.extension.machine.client.command.custom.CustomCommandType;
import org.eclipse.che.ide.extension.machine.client.command.edit.EditCommandsView;
Expand Down Expand Up @@ -129,6 +131,8 @@ protected void configure() {

bind(Target.class).to(BaseTarget.class);

bind(RecipeScriptDownloadServiceClient.class).to(RecipeScriptDownloadServiceClientImpl.class).in(Singleton.class);

final GinMultibinder<CategoryPage> categoryPageBinder = GinMultibinder.newSetBinder(binder(), CategoryPage.class);
categoryPageBinder.addBinding().to(SshCategoryPresenter.class);
categoryPageBinder.addBinding().to(DockerCategoryPresenter.class);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -10,23 +10,20 @@
*******************************************************************************/
package org.eclipse.che.ide.extension.machine.client.perspective.widgets.machine.appliance.recipe;

import com.google.gwt.http.client.Request;
import com.google.gwt.http.client.RequestBuilder;
import com.google.gwt.http.client.RequestCallback;
import com.google.gwt.http.client.RequestException;
import com.google.gwt.http.client.Response;
import com.google.gwt.user.client.ui.AcceptsOneWidget;
import com.google.gwt.user.client.ui.IsWidget;
import com.google.inject.Inject;

import org.eclipse.che.api.promises.client.Operation;
import org.eclipse.che.api.promises.client.OperationException;
import org.eclipse.che.api.promises.client.PromiseError;
import org.eclipse.che.ide.extension.machine.client.RecipeScriptDownloadServiceClient;
import org.eclipse.che.ide.extension.machine.client.machine.Machine;
import org.eclipse.che.ide.extension.machine.client.perspective.widgets.tab.content.TabPresenter;
import org.eclipse.che.ide.util.loging.Log;

import javax.validation.constraints.NotNull;

import static com.google.common.base.Strings.isNullOrEmpty;

/**
* The class contains business logic which allows update a recipe for current machine. The class is a tab presenter and
* shows current machine recipe.
Expand All @@ -35,11 +32,13 @@
*/
public class RecipeTabPresenter implements TabPresenter {

private final RecipeView view;
private final RecipeView view;
private final RecipeScriptDownloadServiceClient recipeScriptClient;

@Inject
public RecipeTabPresenter(RecipeView view) {
public RecipeTabPresenter(RecipeView view, RecipeScriptDownloadServiceClient recipeScriptClient) {
this.view = view;
this.recipeScriptClient = recipeScriptClient;
}

/**
Expand All @@ -48,28 +47,19 @@ public RecipeTabPresenter(RecipeView view) {
* @param machine
* machine for which need update information
*/
public void updateInfo(@NotNull Machine machine) {
String scriptLocation = machine.getRecipeLocation();
if (!isNullOrEmpty(scriptLocation)) { //TODO : need to add test this block
RequestBuilder requestBuilder = new RequestBuilder(RequestBuilder.GET, scriptLocation);
try {
requestBuilder.sendRequest(null, new RequestCallback() {
public void updateInfo(@NotNull final Machine machine) {
recipeScriptClient.getRecipeScript(machine).then(new Operation<String>() {
@Override
public void onResponseReceived(Request request, Response response) {
view.setScript(response.getText());
}

@Override
public void onError(Request request, Throwable exception) {

public void apply(String recipe) throws OperationException {
view.setScript(recipe);
}
});
} catch (RequestException exception) {
Log.error(getClass(), exception);
}).catchError(new Operation<PromiseError>() {
@Override
public void apply(PromiseError error) throws OperationException {
Log.error(RecipeTabPresenter.class,
"Failed to get recipe script for machine " + machine.getId() + ": " + error.getMessage());
}
} else if (!isNullOrEmpty(machine.getRecipeContent())) {
view.setScript(machine.getRecipeContent());
}
});
}

/** {@inheritDoc} */
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -11,9 +11,9 @@
package org.eclipse.che.ide.extension.machine.client.perspective.widgets.machine.appliance.recipe;

import org.eclipse.che.api.promises.client.Operation;
import org.eclipse.che.api.promises.client.PromiseError;
import org.eclipse.che.api.promises.client.Promise;
import org.eclipse.che.ide.extension.machine.client.RecipeScriptDownloadServiceClient;
import org.eclipse.che.ide.extension.machine.client.machine.Machine;
import org.eclipse.che.ide.websocket.rest.RequestCallback;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.mockito.ArgumentCaptor;
Expand All @@ -23,7 +23,7 @@
import org.mockito.runners.MockitoJUnitRunner;

import static org.junit.Assert.assertEquals;
import static org.mockito.Matchers.anyString;
import static org.mockito.Matchers.any;
import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.when;

Expand All @@ -33,12 +33,17 @@
@RunWith(MockitoJUnitRunner.class)
public class RecipeTabPresenterTest {
@Mock
private RecipeView view;
private RecipeView view;
@Mock
private Machine machine;
private Machine machine;
@Mock
private RecipeScriptDownloadServiceClient recipeScriptClient;

@Mock
private Promise<String> recipePromise;

@Captor
private ArgumentCaptor<RequestCallback> argumentCaptor;
private ArgumentCaptor<Operation<String>> argumentCaptor;

@InjectMocks
private RecipeTabPresenter presenter;
Expand All @@ -64,8 +69,13 @@ public void tabShouldBeVisible() throws Exception {

@Test
public void tabGetScriptAsContent() throws Exception {
when(machine.getRecipeContent()).thenReturn("test content");
when(recipeScriptClient.getRecipeScript(any(Machine.class))).thenReturn(recipePromise);
when(recipePromise.then(any(Operation.class))).thenReturn(recipePromise);

presenter.updateInfo(machine);

verify(recipePromise).then(argumentCaptor.capture());
argumentCaptor.getValue().apply("test content");
verify(view).setScript("test content");
}

Expand Down
4 changes: 4 additions & 0 deletions plugins/plugin-machine/che-plugin-machine-ext-server/pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,10 @@
<groupId>javax.inject</groupId>
<artifactId>javax.inject</artifactId>
</dependency>
<dependency>
<groupId>javax.ws.rs</groupId>
<artifactId>javax.ws.rs-api</artifactId>
</dependency>
<dependency>
<groupId>org.eclipse.che.core</groupId>
<artifactId>che-core-api-core</artifactId>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -12,12 +12,15 @@

import com.google.inject.AbstractModule;

import org.eclipse.che.api.machine.server.MachineService;
import org.eclipse.che.ide.ext.machine.server.ssh.KeysInjector;
import org.eclipse.che.inject.DynaModule;

@DynaModule
public class MachineModule extends AbstractModule {
protected void configure() {
bind(KeysInjector.class).asEagerSingleton();

bind(RecipeScriptDownloadService.class);
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,50 @@
/*******************************************************************************
* Copyright (c) 2012-2016 Codenvy, S.A.
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the Eclipse Public License v1.0
* which accompanies this distribution, and is available at
* http://www.eclipse.org/legal/epl-v10.html
*
* Contributors:
* Codenvy, S.A. - initial API and implementation
*******************************************************************************/
package org.eclipse.che.ide.ext.machine.server;


import org.eclipse.che.api.core.NotFoundException;
import org.eclipse.che.api.core.ServerException;
import org.eclipse.che.api.core.rest.Service;
import org.eclipse.che.api.machine.server.MachineManager;
import org.eclipse.che.api.machine.server.util.RecipeRetriever;

import javax.inject.Inject;
import javax.ws.rs.GET;
import javax.ws.rs.Path;
import javax.ws.rs.PathParam;
import javax.ws.rs.Produces;
import javax.ws.rs.core.MediaType;

/**
* Service for downloading recipe script for machine.
*
* @author Mihail Kuznyetsov.
*/
@Path("/recipe/script")
public class RecipeScriptDownloadService extends Service {

private final MachineManager machineManager;
private final RecipeRetriever recipeRetriever;

@Inject
public RecipeScriptDownloadService(MachineManager machineManager, RecipeRetriever recipeRetriever) {
this.machineManager = machineManager;
this.recipeRetriever = recipeRetriever;
}

@GET
@Path("/{machineId}")
@Produces(MediaType.TEXT_PLAIN)
public String getRecipeScript(@PathParam("machineId") String machineId) throws ServerException, NotFoundException {
return recipeRetriever.getRecipe(machineManager.getMachine(machineId).getConfig()).getScript();
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -47,6 +47,8 @@
*/
@Listeners(MockitoTestNGListener.class)
public class SshMachineInstanceProviderTest {
private static final String RECIPE_SCRIPT = new Gson().toJson(new SshMachineRecipe("localhost", 22, "user", "password"));

@Mock
private RecipeDownloader recipeDownloader;

Expand All @@ -70,7 +72,7 @@ public void setUp() throws Exception {
"user",
"password");
recipe = new RecipeImpl().withType("ssh-config")
.withScript(new Gson().toJson(sshMachineRecipe));
.withScript(RECIPE_SCRIPT);
}

@Test
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -77,7 +77,7 @@ public RecipeImpl getRecipe(MachineConfig machineConfig) throws MachineException
return new RecipeImpl().withType(machineConfig.getSource().getType())
.withScript(IoUtil.readAndCloseQuietly(new FileInputStream(file)));
} catch (IOException | IllegalArgumentException e) {
throw new MachineException(format("Can't start machine %s because machine recipe downloading failed. Recipe url %s. Error: %s",
throw new MachineException(format("Failed to download recipe for machine %s. Recipe url %s. Error: %s",
machineConfig.getName(),
location,
e.getLocalizedMessage()));
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,8 @@

import javax.inject.Inject;
import javax.inject.Singleton;
import java.net.MalformedURLException;
import java.net.URL;
import java.util.Map;
import java.util.regex.Pattern;

Expand Down Expand Up @@ -126,13 +128,26 @@ private void validateMachine(MachineConfig machineCfg, String envName) throws Ba
checkArgument(!(machineCfg.getSource().getContent() == null && machineCfg.getSource().getLocation() == null),
"Environment " + envName + " contains machine with source but this source doesn't define a location or content");


checkArgument(machineInstanceProviders.hasProvider(machineCfg.getType()),
"Type %s of machine %s in environment %s is not supported. Supported values: %s.",
machineCfg.getType(),
machineCfg.getName(),
envName,
Joiner.on(", ").join(machineInstanceProviders.getProviderTypes()));

if (machineCfg.getSource().getType().equals("dockerfile") && machineCfg.getSource().getLocation() != null) {
try {
final String protocol = new URL(machineCfg.getSource().getLocation()).getProtocol();
checkArgument(protocol.equals("http") || protocol.equals("https"),
"Environment " + envName + " contains machine with invalid source location protocol: " +
machineCfg.getSource().getLocation());
} catch (MalformedURLException e) {
throw new BadRequestException("Environment " + envName + " contains machine with invalid source location: " +
machineCfg.getSource().getLocation());
}
}

for (ServerConf serverConf : machineCfg.getServers()) {
checkArgument(serverConf.getPort() != null && SERVER_PORT.matcher(serverConf.getPort()).matches(),
"Machine %s contains server conf with invalid port %s",
Expand Down
Loading

0 comments on commit e8ff05f

Please sign in to comment.