Skip to content

Commit

Permalink
feat(rest.packages.provider): add endpoint for .dp upload (#4894)
Browse files Browse the repository at this point in the history
* feat: new implementation

WARNING: not completely working

* fix: use Jersey instead

* build: use version range

* feat: use tmpdir + random file name for upload

* refactor: use IOUtils for file upload

* chore: remove unnecessary file

* fix: manifest syntax

* docs: add TODOs so that Sonar gets triggered

* refactor: use FileServlet.java as blueprint

* build: fix integration tests

P.s. I have no idea what I'm doing

* test: added integration test

Still WIP

* fix: make sonar happy

* fix: remove commented out code

* fix: use Use "java.nio.file.Files#delete" for better messages on error conditions

* docs: add docs about new method

* refactor: use nio.Files

* test: actually check response body, some refactoring

* test: add unhappy path test

* refactor: remove unnecessary part

* style: consistent formatting

* test: added unit tests

* refactor: simpler way to check local path

* test: check that local url is used

* test: added missing "then" statements in unit tests
  • Loading branch information
mattdibi authored Oct 30, 2023
1 parent 6da1ed9 commit d74484b
Show file tree
Hide file tree
Showing 6 changed files with 1,030 additions and 9 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -12,8 +12,10 @@ Import-Package: com.google.gson;version="2.7.0",
javax.ws.rs;version="2.0.1",
javax.ws.rs.core;version="2.0.1",
javax.ws.rs.ext;version="2.0.1",
org.apache.commons.io;version="[2.0,3.0)",
org.eclipse.kura;version="[1.3,2.0)",
org.eclipse.kura.deployment.agent;version="[1.0,2.0)",
org.glassfish.jersey.media.multipart;version="[2.0,3.0)",
org.osgi.framework;version="1.8.0",
org.osgi.service.component;version="1.3.0",
org.osgi.service.deploymentadmin;version="1.0.0",
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -14,11 +14,19 @@

import static org.eclipse.kura.rest.deployment.agent.api.Validable.validate;

import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.nio.file.Files;
import java.nio.file.Paths;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.UUID;

import javax.annotation.security.RolesAllowed;
import javax.ws.rs.Consumes;
import javax.ws.rs.DELETE;
import javax.ws.rs.GET;
import javax.ws.rs.POST;
Expand All @@ -29,17 +37,26 @@
import javax.ws.rs.core.MediaType;
import javax.ws.rs.core.Response;

import org.apache.commons.io.IOUtils;
import org.eclipse.kura.deployment.agent.DeploymentAgentService;
import org.eclipse.kura.rest.deployment.agent.api.DeploymentRequestStatus;
import org.eclipse.kura.rest.deployment.agent.api.InstallRequest;
import org.glassfish.jersey.media.multipart.FormDataContentDisposition;
import org.glassfish.jersey.media.multipart.FormDataParam;
import org.osgi.service.deploymentadmin.DeploymentAdmin;
import org.osgi.service.deploymentadmin.DeploymentPackage;
import org.osgi.service.useradmin.Role;
import org.osgi.service.useradmin.UserAdmin;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

@Path("/deploy/v2")
public class DeploymentRestService {

private static final Logger logger = LoggerFactory.getLogger(DeploymentRestService.class);

private static final String JAVA_IO_TMPDIR = "java.io.tmpdir";

private static final String KURA_PERMISSION_REST_DEPLOY_ROLE = "kura.permission.rest.deploy";
private static final String ERROR_INSTALLING_PACKAGE = "Error installing deployment package: ";
private static final String ERROR_UNINSTALLING_PACKAGE = "Error uninstalling deployment package: ";
Expand Down Expand Up @@ -114,6 +131,72 @@ public DeploymentRequestStatus installDeploymentPackage(InstallRequest installRe
return DeploymentRequestStatus.REQUEST_RECEIVED;
}

/**
* POST method.
*
* Installs the deployment package uploaded through HTTP POST method (multipart/form-data).
*
* @param uploadedInputStread
* @param fileDetails
* @return a {@link DeploymentRequestStatus} object that represents the status
* of the installation request
*/
@POST
@RolesAllowed("deploy")
@Path("/_upload")
@Produces(MediaType.APPLICATION_JSON)
@Consumes(MediaType.MULTIPART_FORM_DATA)
public DeploymentRequestStatus installUploadedDeploymentPackage(
@FormDataParam("file") InputStream uploadedInputStream,
@FormDataParam("file") FormDataContentDisposition fileDetails) {

final String uploadedFileName = fileDetails.getFileName();
final String uploadedFileLocation = System.getProperty(JAVA_IO_TMPDIR) + File.separator + UUID.randomUUID()
+ ".dp";

try {
Files.deleteIfExists(Paths.get(uploadedFileLocation));
} catch (IOException e) {
logger.warn("Cannot delete file: {}", uploadedFileLocation);
throw new WebApplicationException(Response.status(Response.Status.INTERNAL_SERVER_ERROR)
.type(MediaType.TEXT_PLAIN).entity(ERROR_INSTALLING_PACKAGE + uploadedFileName).build());
}

File file = new File(uploadedFileLocation);
try {
if (!file.createNewFile()) {
throw new IOException("File " + uploadedFileLocation + " was not created");
}
file.deleteOnExit();
} catch (IOException e) {
logger.warn("Cannot create file: {}, caused by", file, e);
throw new WebApplicationException(Response.status(Response.Status.INTERNAL_SERVER_ERROR)
.type(MediaType.TEXT_PLAIN).entity(ERROR_INSTALLING_PACKAGE + uploadedFileName).build());
}

try {
FileOutputStream os = new FileOutputStream(file);
IOUtils.copy(uploadedInputStream, os);
os.close();
} catch (IOException e) {
logger.warn("Error writing file to : {}, caused by", file.getAbsolutePath(), e);
throw new WebApplicationException(Response.status(Response.Status.INTERNAL_SERVER_ERROR)
.type(MediaType.TEXT_PLAIN).entity(ERROR_INSTALLING_PACKAGE + uploadedFileName).build());
}
logger.info("Deployment package \"{}\" uploaded to: {}", uploadedFileName, file.getAbsolutePath());

try {
String fileUrl = file.toURI().toURL().toString();
this.deploymentAgentService.installDeploymentPackageAsync(fileUrl);
} catch (Exception e) {
logger.warn("Cannot install deployment package : {}, caused by", uploadedFileName, e);
throw new WebApplicationException(Response.status(Response.Status.INTERNAL_SERVER_ERROR)
.type(MediaType.TEXT_PLAIN).entity(ERROR_INSTALLING_PACKAGE + uploadedFileName).build());
}

return DeploymentRequestStatus.REQUEST_RECEIVED;
}

/**
* DELETE method.
*
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ Require-Capability: osgi.ee;filter:="(&(osgi.ee=JavaSE)(version=1.8))"
Bundle-ActivationPolicy: lazy
Fragment-Host: org.eclipse.kura.rest.packages.provider
Import-Package: com.eclipsesource.json;version="0.9.5",
javax.ws.rs.client;version="2.0.1",
org.apache.commons.io;version="2.4.0",
org.eclipse.kura;version="1.6.0",
org.eclipse.kura.core.testutil.json;version="1.0.0",
Expand All @@ -18,15 +19,17 @@ Import-Package: com.eclipsesource.json;version="0.9.5",
org.eclipse.kura.data.transport.listener;version="1.0.1",
org.eclipse.kura.marshalling;version="1.0.0",
org.eclipse.kura.message;version="1.4.0",
org.glassfish.jersey.client.authentication;version="2.22.2",
org.glassfish.jersey.media.multipart.file;version="2.22.2",
org.junit;version="[4.12.0,5.0.0)",
org.junit.runner;version="[4.12.0,5.0.0)",
org.junit.runners;version="[4.12.0,5.0.0)",
org.mockito;version="[4.0.0,5.0.0)",
org.mockito.invocation;version="[4.0.0,5.0.0)",
org.mockito.stubbing;version="[4.0.0,5.0.0)",
org.osgi.service.deploymentadmin;version="1.0.0",
org.osgi.framework;version="1.10.0",
org.osgi.service.cm;version="1.6.0",
org.osgi.service.deploymentadmin;version="1.0.0",
org.osgi.util.tracker;version="1.5.2",
org.slf4j;version="1.7.25"
Require-Bundle: org.eclipse.kura.http.server.manager;bundle-version="1.1.0",
Expand Down
Loading

0 comments on commit d74484b

Please sign in to comment.