Skip to content
Snippets Groups Projects
Commit 35b451bf authored by Nicola Fulvio Calabria's avatar Nicola Fulvio Calabria
Browse files

Added LinkNodes management to PullFromVoSpace

parent bd64b755
No related branches found
No related tags found
No related merge requests found
...@@ -49,6 +49,9 @@ public class UriService { ...@@ -49,6 +49,9 @@ public class UriService {
@Value("${file-service-url}") @Value("${file-service-url}")
private String fileServiceUrl; private String fileServiceUrl;
@Value("${link-max-depth}")
private int linkMaxDepth;
@Autowired @Autowired
private NodeDAO nodeDao; private NodeDAO nodeDao;
...@@ -175,6 +178,8 @@ public class UriService { ...@@ -175,6 +178,8 @@ public class UriService {
break; break;
case pullFromVoSpace: case pullFromVoSpace:
// Refresh relative path: it can differ in case of links
relativePath = NodeUtils.getVosPath(node);
if (!NodeUtils.checkIfReadable(node, creator, groups)) { if (!NodeUtils.checkIfReadable(node, creator, groups)) {
throw PermissionDeniedException.forPath(relativePath); throw PermissionDeniedException.forPath(relativePath);
} }
...@@ -278,9 +283,25 @@ public class UriService { ...@@ -278,9 +283,25 @@ public class UriService {
} }
private Node followLink(LinkNode linkNode) { private Node followLink(LinkNode linkNode) {
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); String targetPath = URIUtils.returnVosPathFromNodeURI(linkNode.getTarget(), authority);
Optional<Node> targetNode = nodeDao.listNode(targetPath);
return targetNode.orElseThrow(() -> new InternalFaultException("Broken Link to target: " + targetPath));
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 ...@@ -18,4 +18,7 @@ logging.level.org.springframework.web=TRACE
vospace-authority=example.com!vospace vospace-authority=example.com!vospace
#tune max depth for chained links
link-max-depth=10
file-service-url=http://localhost:8087 file-service-url=http://localhost:8087
...@@ -114,7 +114,7 @@ public class TransferControllerTest { ...@@ -114,7 +114,7 @@ public class TransferControllerTest {
@Test @Test
public void testPullFromVoSpaceSync() throws Exception { 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)); when(nodeDao.listNode(eq("/mynode"))).thenReturn(Optional.of(node));
String requestBody = getResourceFileContent("pullFromVoSpace.xml"); String requestBody = getResourceFileContent("pullFromVoSpace.xml");
...@@ -198,7 +198,7 @@ public class TransferControllerTest { ...@@ -198,7 +198,7 @@ public class TransferControllerTest {
private void testVoSpaceAsyncTransfer(String path, String requestBody) throws Exception { 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)); when(nodeDao.listNode(eq(path))).thenReturn(Optional.of(node));
String redirect = mockMvc.perform(post("/transfers?PHASE=RUN") String redirect = mockMvc.perform(post("/transfers?PHASE=RUN")
...@@ -216,7 +216,7 @@ public class TransferControllerTest { ...@@ -216,7 +216,7 @@ public class TransferControllerTest {
@Test @Test
public void testSetJobPhase() throws Exception { 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)); when(nodeDao.listNode(eq("/mynode"))).thenReturn(Optional.of(node));
JobSummary job = getFakePendingJob(); JobSummary job = getFakePendingJob();
...@@ -268,8 +268,9 @@ public class TransferControllerTest { ...@@ -268,8 +268,9 @@ public class TransferControllerTest {
assertEquals("PENDING", phase); assertEquals("PENDING", phase);
} }
private Node mockPublicDataNode() { private Node mockPublicDataNode(String nodeURI) {
Node node = new DataNode(); Node node = new DataNode();
node.setUri(nodeURI);
Property property = new Property(); Property property = new Property();
property.setUri("ivo://ivoa.net/vospace/core#publicread"); property.setUri("ivo://ivoa.net/vospace/core#publicread");
property.setValue("true"); property.setValue("true");
...@@ -415,7 +416,7 @@ public class TransferControllerTest { ...@@ -415,7 +416,7 @@ public class TransferControllerTest {
@Test @Test
public void testSyncTransferUrlParamsMode() throws Exception { 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)); when(nodeDao.listNode(eq("/mynode"))).thenReturn(Optional.of(node));
mockMvc.perform(get("/synctrans") mockMvc.perform(get("/synctrans")
......
...@@ -8,7 +8,9 @@ package it.inaf.oats.vospace; ...@@ -8,7 +8,9 @@ package it.inaf.oats.vospace;
import it.inaf.ia2.aa.ServletRapClient; import it.inaf.ia2.aa.ServletRapClient;
import it.inaf.ia2.aa.data.User; import it.inaf.ia2.aa.data.User;
import it.inaf.oats.vospace.datamodel.NodeProperties; 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.datamodel.Views;
import it.inaf.oats.vospace.exception.InternalFaultException;
import it.inaf.oats.vospace.exception.InvalidArgumentException; import it.inaf.oats.vospace.exception.InvalidArgumentException;
import it.inaf.oats.vospace.exception.NodeBusyException; import it.inaf.oats.vospace.exception.NodeBusyException;
import it.inaf.oats.vospace.exception.PermissionDeniedException; import it.inaf.oats.vospace.exception.PermissionDeniedException;
...@@ -22,6 +24,7 @@ import javax.servlet.http.HttpServletRequest; ...@@ -22,6 +24,7 @@ import javax.servlet.http.HttpServletRequest;
import net.ivoa.xml.uws.v1.JobSummary; import net.ivoa.xml.uws.v1.JobSummary;
import net.ivoa.xml.vospace.v2.ContainerNode; import net.ivoa.xml.vospace.v2.ContainerNode;
import net.ivoa.xml.vospace.v2.DataNode; 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.Node;
import net.ivoa.xml.vospace.v2.Param; import net.ivoa.xml.vospace.v2.Param;
import net.ivoa.xml.vospace.v2.Property; import net.ivoa.xml.vospace.v2.Property;
...@@ -102,7 +105,10 @@ public class UriServiceTest { ...@@ -102,7 +105,10 @@ public class UriServiceTest {
@Test @Test
public void testPublicUrl() { public void testPublicUrl() {
String dataUri = "vos://example.com!vospace/mydata1";
Node node = new DataNode(); Node node = new DataNode();
node.setUri(dataUri);
Property property = new Property(); Property property = new Property();
property.setUri(NodeProperties.PUBLIC_READ_URI); property.setUri(NodeProperties.PUBLIC_READ_URI);
property.setValue("true"); property.setValue("true");
...@@ -119,7 +125,10 @@ public class UriServiceTest { ...@@ -119,7 +125,10 @@ public class UriServiceTest {
@Test @Test
public void testPrivateUrl() { public void testPrivateUrl() {
String dataUri = "vos://example.com!vospace/mydata1";
Node node = new DataNode(); Node node = new DataNode();
node.setUri(dataUri);
Property creator = new Property(); Property creator = new Property();
creator.setUri(NodeProperties.CREATOR_URI); creator.setUri(NodeProperties.CREATOR_URI);
creator.setValue("user1"); creator.setValue("user1");
...@@ -154,7 +163,10 @@ public class UriServiceTest { ...@@ -154,7 +163,10 @@ public class UriServiceTest {
@Test @Test
public void testPrivateUrlPermissionDenied() { public void testPrivateUrlPermissionDenied() {
String dataUri = "vos://example.com!vospace/mydata1";
Node node = new DataNode(); Node node = new DataNode();
node.setUri(dataUri);
Property creator = new Property(); Property creator = new Property();
creator.setUri(NodeProperties.CREATOR_URI); creator.setUri(NodeProperties.CREATOR_URI);
creator.setValue("user3"); creator.setValue("user3");
...@@ -188,8 +200,10 @@ public class UriServiceTest { ...@@ -188,8 +200,10 @@ public class UriServiceTest {
@Test @Test
public void testPrivateUrlNodeBusy() { public void testPrivateUrlNodeBusy() {
String dataUri = "vos://example.com!vospace/mydata1";
DataNode node = new DataNode(); DataNode node = new DataNode();
node.setUri(dataUri);
Property creator = new Property(); Property creator = new Property();
creator.setUri(NodeProperties.CREATOR_URI); creator.setUri(NodeProperties.CREATOR_URI);
creator.setValue("user1"); creator.setValue("user1");
...@@ -275,6 +289,114 @@ public class UriServiceTest { ...@@ -275,6 +289,114 @@ public class UriServiceTest {
assertEquals("http://file-service/mydata1/mydata2?jobId=job-id2&token=<new-token>", negotiatedTransfer.getProtocols().get(0).getEndpoint()); 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 @Test
public void setNodeRemoteLocationTest() { public void setNodeRemoteLocationTest() {
...@@ -526,4 +648,23 @@ public class UriServiceTest { ...@@ -526,4 +648,23 @@ public class UriServiceTest {
return job; 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;
}
} }
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Please register or to comment