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

feat(rest.packages.provider): add endpoint for .dp upload #4894

Merged
merged 24 commits into from
Oct 30, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
24 commits
Select commit Hold shift + click to select a range
a72ee84
feat: new implementation
mattdibi Oct 12, 2023
53fd86e
fix: use Jersey instead
mattdibi Oct 26, 2023
fad8913
build: use version range
mattdibi Oct 26, 2023
0f3090e
feat: use tmpdir + random file name for upload
mattdibi Oct 26, 2023
b386c64
refactor: use IOUtils for file upload
mattdibi Oct 26, 2023
e41cfb7
chore: remove unnecessary file
mattdibi Oct 26, 2023
3d30588
fix: manifest syntax
mattdibi Oct 26, 2023
27dabd9
docs: add TODOs so that Sonar gets triggered
mattdibi Oct 26, 2023
6c01379
refactor: use FileServlet.java as blueprint
mattdibi Oct 26, 2023
2bb091b
build: fix integration tests
mattdibi Oct 27, 2023
f4d07c3
test: added integration test
mattdibi Oct 27, 2023
a1d2928
fix: make sonar happy
mattdibi Oct 27, 2023
e6d0473
fix: remove commented out code
mattdibi Oct 27, 2023
6c1699b
fix: use Use "java.nio.file.Files#delete" for better messages on erro…
mattdibi Oct 27, 2023
b563f75
docs: add docs about new method
mattdibi Oct 27, 2023
7dac34c
refactor: use nio.Files
mattdibi Oct 27, 2023
dc857ad
test: actually check response body, some refactoring
mattdibi Oct 27, 2023
a04d14e
test: add unhappy path test
mattdibi Oct 27, 2023
41da2d8
refactor: remove unnecessary part
mattdibi Oct 27, 2023
4096a10
style: consistent formatting
mattdibi Oct 27, 2023
91c871b
test: added unit tests
mattdibi Oct 27, 2023
e276b8a
refactor: simpler way to check local path
mattdibi Oct 27, 2023
e55c14a
test: check that local url is used
mattdibi Oct 27, 2023
cffbcb0
test: added missing "then" statements in unit tests
mattdibi Oct 27, 2023
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
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