Commit 35b451bf authored by Nicola Fulvio Calabria's avatar Nicola Fulvio Calabria
Browse files

Added LinkNodes management to PullFromVoSpace

parent bd64b755
......@@ -49,6 +49,9 @@ public class UriService {
@Value("${file-service-url}")
private String fileServiceUrl;
@Value("${link-max-depth}")
private int linkMaxDepth;
@Autowired
private NodeDAO nodeDao;
......@@ -165,7 +168,7 @@ public class UriService {
JobService.JobDirection jobType
= JobDirection.getJobDirectionEnumFromTransfer(transfer);
Node node = this.getEndpointNode(relativePath, jobType, user);
switch (jobType) {
case pushToVoSpace:
case pullToVoSpace:
......@@ -175,6 +178,8 @@ public class UriService {
break;
case pullFromVoSpace:
// Refresh relative path: it can differ in case of links
relativePath = NodeUtils.getVosPath(node);
if (!NodeUtils.checkIfReadable(node, creator, groups)) {
throw PermissionDeniedException.forPath(relativePath);
}
......@@ -278,9 +283,25 @@ public class UriService {
}
private Node followLink(LinkNode linkNode) {
String targetPath = URIUtils.returnVosPathFromNodeURI(linkNode.getTarget(), authority);
Optional<Node> targetNode = nodeDao.listNode(targetPath);
return targetNode.orElseThrow(() -> new InternalFaultException("Broken Link to target: " + targetPath));
return this.followLinkRecursive(linkNode, 0);
}
private Node followLinkRecursive(LinkNode linkNode, int depth) {
if(depth >= linkMaxDepth) {
throw new InternalFaultException("Max link depth reached at link node: "
+ NodeUtils.getVosPath(linkNode));
}
String targetPath = URIUtils.returnVosPathFromNodeURI(linkNode.getTarget(), authority);
Optional<Node> targetNodeOpt = nodeDao.listNode(targetPath);
Node targetNode = targetNodeOpt.orElseThrow(() -> new InternalFaultException("Broken Link to target: " + targetPath));
if(targetNode instanceof LinkNode) {
return this.followLinkRecursive(linkNode, ++depth);
} else {
return targetNode;
}
}
}
......@@ -18,4 +18,7 @@ logging.level.org.springframework.web=TRACE
vospace-authority=example.com!vospace
#tune max depth for chained links
link-max-depth=10
file-service-url=http://localhost:8087
......@@ -114,7 +114,7 @@ public class TransferControllerTest {
@Test
public void testPullFromVoSpaceSync() throws Exception {
Node node = mockPublicDataNode();
Node node = mockPublicDataNode("vos://example.com!vospace/mynode");
when(nodeDao.listNode(eq("/mynode"))).thenReturn(Optional.of(node));
String requestBody = getResourceFileContent("pullFromVoSpace.xml");
......@@ -198,7 +198,7 @@ public class TransferControllerTest {
private void testVoSpaceAsyncTransfer(String path, String requestBody) throws Exception {
Node node = mockPublicDataNode();
Node node = mockPublicDataNode(path);
when(nodeDao.listNode(eq(path))).thenReturn(Optional.of(node));
String redirect = mockMvc.perform(post("/transfers?PHASE=RUN")
......@@ -216,7 +216,7 @@ public class TransferControllerTest {
@Test
public void testSetJobPhase() throws Exception {
Node node = mockPublicDataNode();
Node node = mockPublicDataNode("vos://example.com!vospace/mynode");
when(nodeDao.listNode(eq("/mynode"))).thenReturn(Optional.of(node));
JobSummary job = getFakePendingJob();
......@@ -268,8 +268,9 @@ public class TransferControllerTest {
assertEquals("PENDING", phase);
}
private Node mockPublicDataNode() {
private Node mockPublicDataNode(String nodeURI) {
Node node = new DataNode();
node.setUri(nodeURI);
Property property = new Property();
property.setUri("ivo://ivoa.net/vospace/core#publicread");
property.setValue("true");
......@@ -415,7 +416,7 @@ public class TransferControllerTest {
@Test
public void testSyncTransferUrlParamsMode() throws Exception {
Node node = mockPublicDataNode();
Node node = mockPublicDataNode("vos://example.com!vospace/mynode");
when(nodeDao.listNode(eq("/mynode"))).thenReturn(Optional.of(node));
mockMvc.perform(get("/synctrans")
......
......@@ -8,7 +8,9 @@ package it.inaf.oats.vospace;
import it.inaf.ia2.aa.ServletRapClient;
import it.inaf.ia2.aa.data.User;
import it.inaf.oats.vospace.datamodel.NodeProperties;
import it.inaf.oats.vospace.datamodel.NodeUtils;
import it.inaf.oats.vospace.datamodel.Views;
import it.inaf.oats.vospace.exception.InternalFaultException;
import it.inaf.oats.vospace.exception.InvalidArgumentException;
import it.inaf.oats.vospace.exception.NodeBusyException;
import it.inaf.oats.vospace.exception.PermissionDeniedException;
......@@ -22,6 +24,7 @@ import javax.servlet.http.HttpServletRequest;
import net.ivoa.xml.uws.v1.JobSummary;
import net.ivoa.xml.vospace.v2.ContainerNode;
import net.ivoa.xml.vospace.v2.DataNode;
import net.ivoa.xml.vospace.v2.LinkNode;
import net.ivoa.xml.vospace.v2.Node;
import net.ivoa.xml.vospace.v2.Param;
import net.ivoa.xml.vospace.v2.Property;
......@@ -101,8 +104,11 @@ public class UriServiceTest {
@Test
public void testPublicUrl() {
String dataUri = "vos://example.com!vospace/mydata1";
Node node = new DataNode();
node.setUri(dataUri);
Property property = new Property();
property.setUri(NodeProperties.PUBLIC_READ_URI);
property.setValue("true");
......@@ -118,8 +124,11 @@ public class UriServiceTest {
@Test
public void testPrivateUrl() {
String dataUri = "vos://example.com!vospace/mydata1";
Node node = new DataNode();
node.setUri(dataUri);
Property creator = new Property();
creator.setUri(NodeProperties.CREATOR_URI);
creator.setValue("user1");
......@@ -153,8 +162,11 @@ public class UriServiceTest {
@Test
public void testPrivateUrlPermissionDenied() {
String dataUri = "vos://example.com!vospace/mydata1";
Node node = new DataNode();
node.setUri(dataUri);
Property creator = new Property();
creator.setUri(NodeProperties.CREATOR_URI);
creator.setValue("user3");
......@@ -188,8 +200,10 @@ public class UriServiceTest {
@Test
public void testPrivateUrlNodeBusy() {
String dataUri = "vos://example.com!vospace/mydata1";
DataNode node = new DataNode();
node.setUri(dataUri);
Property creator = new Property();
creator.setUri(NodeProperties.CREATOR_URI);
creator.setValue("user1");
......@@ -274,7 +288,115 @@ public class UriServiceTest {
assertEquals("http://file-service/mydata1/mydata2?jobId=job-id2&token=<new-token>", negotiatedTransfer.getProtocols().get(0).getEndpoint());
}
@Test
public void pullFromLinkNode() {
// URI of pull target node
String targetOfPull = "vos://example.com!vospace/mylink1";
String targetOfLink = "vos://example.com!vospace/mydummydata1";
// Define node properties
Property creator = new Property();
creator.setUri(NodeProperties.CREATOR_URI);
creator.setValue("user1");
Property readgroup = new Property();
readgroup.setUri(NodeProperties.GROUP_READ_URI);
readgroup.setValue("group1");
// Define link node as target
LinkNode lnode = new LinkNode();
lnode.setUri(targetOfPull);
lnode.getProperties().add(creator);
lnode.getProperties().add(readgroup);
lnode.setTarget(targetOfLink);
DataNode dnode = new DataNode();
dnode.setUri(targetOfLink);
dnode.getProperties().add(creator);
dnode.getProperties().add(readgroup);
when(nodeDAO.listNode(eq(NodeUtils.getVosPath(lnode)))).thenReturn(Optional.of(lnode));
when(nodeDAO.listNode(eq(NodeUtils.getVosPath(dnode)))).thenReturn(Optional.of(dnode));
User user = mock(User.class);
when(user.getAccessToken()).thenReturn("<token>");
when(user.getName()).thenReturn("user1");
when(servletRequest.getUserPrincipal()).thenReturn(user);
when(rapClient.exchangeToken(argThat(req -> {
assertEquals("<token>", req.getSubjectToken());
assertEquals("http://file-service/mydummydata1", req.getResource());
return true;
}), any())).thenReturn("<new-token>");
JobSummary job = getPullFromVoSpaceJob(targetOfPull);
Transfer tr = uriService.getTransfer(job);
Transfer negotiatedTransfer = uriService.getNegotiatedTransfer(job, tr);
assertEquals("http://file-service"
+ NodeUtils.getVosPath(dnode) +
"?jobId=job-id-pull&token=<new-token>",
negotiatedTransfer.getProtocols().get(0).getEndpoint());
}
@Test
public void pullFromCircularLinkNode() {
// URI of pull target node
String targetOfPull = "vos://example.com!vospace/mylink1";
String targetOfLink = "vos://example.com!vospace/mylink2";
// Define node properties
Property creator = new Property();
creator.setUri(NodeProperties.CREATOR_URI);
creator.setValue("user1");
Property readgroup = new Property();
readgroup.setUri(NodeProperties.GROUP_READ_URI);
readgroup.setValue("group1");
// Define link node as target
LinkNode lnode = new LinkNode();
lnode.setUri(targetOfPull);
lnode.getProperties().add(creator);
lnode.getProperties().add(readgroup);
lnode.setTarget(targetOfLink);
LinkNode dnode = new LinkNode();
dnode.setUri(targetOfLink);
dnode.getProperties().add(creator);
dnode.getProperties().add(readgroup);
// Circular reference
dnode.setTarget(targetOfPull);
when(nodeDAO.listNode(eq(NodeUtils.getVosPath(lnode)))).thenReturn(Optional.of(lnode));
when(nodeDAO.listNode(eq(NodeUtils.getVosPath(dnode)))).thenReturn(Optional.of(dnode));
User user = mock(User.class);
when(user.getAccessToken()).thenReturn("<token>");
when(user.getName()).thenReturn("user1");
when(servletRequest.getUserPrincipal()).thenReturn(user);
when(rapClient.exchangeToken(argThat(req -> {
assertEquals("<token>", req.getSubjectToken());
assertEquals("http://file-service/mydummydata1", req.getResource());
return true;
}), any())).thenReturn("<new-token>");
JobSummary job = getPullFromVoSpaceJob(targetOfPull);
Transfer tr = uriService.getTransfer(job);
assertThrows(InternalFaultException.class, () -> {
uriService.getNegotiatedTransfer(job, tr);
});
}
@Test
public void setNodeRemoteLocationTest() {
......@@ -526,4 +648,23 @@ public class UriServiceTest {
return job;
}
private JobSummary getPullFromVoSpaceJob(String target) {
Transfer transfer = new Transfer();
transfer.setTarget(target);
transfer.setDirection(JobService.JobDirection.pullFromVoSpace.toString());
Protocol protocol = new Protocol();
protocol.setUri("ivo://ivoa.net/vospace/core#httpget");
transfer.getProtocols().add(protocol);
JobSummary job = new JobSummary();
job.setJobId("job-id-pull");
JobSummary.JobInfo jobInfo = new JobSummary.JobInfo();
jobInfo.getAny().add(transfer);
job.setJobInfo(jobInfo);
return job;
}
}
Supports Markdown
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment