diff --git a/.classpath b/.classpath new file mode 100644 index 0000000..fae1a2b --- /dev/null +++ b/.classpath @@ -0,0 +1,36 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..b83d222 --- /dev/null +++ b/.gitignore @@ -0,0 +1 @@ +/target/ diff --git a/.project b/.project new file mode 100644 index 0000000..295896d --- /dev/null +++ b/.project @@ -0,0 +1,23 @@ + + + orientdb-bug-reports + + + + + + org.eclipse.jdt.core.javabuilder + + + + + org.eclipse.m2e.core.maven2Builder + + + + + + org.eclipse.jdt.core.javanature + org.eclipse.m2e.core.maven2Nature + + diff --git a/.settings/org.eclipse.core.resources.prefs b/.settings/org.eclipse.core.resources.prefs new file mode 100644 index 0000000..29abf99 --- /dev/null +++ b/.settings/org.eclipse.core.resources.prefs @@ -0,0 +1,6 @@ +eclipse.preferences.version=1 +encoding//src/main/java=UTF-8 +encoding//src/main/resources=UTF-8 +encoding//src/test/java=UTF-8 +encoding//src/test/resources=UTF-8 +encoding/=UTF-8 diff --git a/.settings/org.eclipse.jdt.core.prefs b/.settings/org.eclipse.jdt.core.prefs new file mode 100644 index 0000000..714351a --- /dev/null +++ b/.settings/org.eclipse.jdt.core.prefs @@ -0,0 +1,5 @@ +eclipse.preferences.version=1 +org.eclipse.jdt.core.compiler.codegen.targetPlatform=1.8 +org.eclipse.jdt.core.compiler.compliance=1.8 +org.eclipse.jdt.core.compiler.problem.forbiddenReference=warning +org.eclipse.jdt.core.compiler.source=1.8 diff --git a/.settings/org.eclipse.m2e.core.prefs b/.settings/org.eclipse.m2e.core.prefs new file mode 100644 index 0000000..f897a7f --- /dev/null +++ b/.settings/org.eclipse.m2e.core.prefs @@ -0,0 +1,4 @@ +activeProfiles= +eclipse.preferences.version=1 +resolveWorkspaceProjects=true +version=1 diff --git a/pom.xml b/pom.xml new file mode 100644 index 0000000..c7854cb --- /dev/null +++ b/pom.xml @@ -0,0 +1,39 @@ + + 4.0.0 + org.gcube.orientdb + orientdb-bug-reports + 0.0.1-SNAPSHOT + OrientDB Bug Reports + This project is used to create reproducibility tests for bugs opened to orientdb project + + + + 1.8 + UTF-8 + + + + + com.orientechnologies + orientdb-graphdb + 2.2.18 + + + + + + + + + org.apache.maven.plugins + maven-compiler-plugin + + ${java_version} + ${java_version} + + + + + + + \ No newline at end of file diff --git a/src/main/java/org/gcube/orientdb/ReproduceBug7354.java b/src/main/java/org/gcube/orientdb/ReproduceBug7354.java new file mode 100644 index 0000000..dc159f2 --- /dev/null +++ b/src/main/java/org/gcube/orientdb/ReproduceBug7354.java @@ -0,0 +1,169 @@ +/** + * + */ +package org.gcube.orientdb; + +import java.io.IOException; +import java.util.ArrayList; +import java.util.List; +import java.util.UUID; + +import com.orientechnologies.orient.client.remote.OServerAdmin; +import com.orientechnologies.orient.client.remote.OStorageRemote; +import com.orientechnologies.orient.core.metadata.OMetadata; +import com.orientechnologies.orient.core.metadata.schema.OClass; +import com.orientechnologies.orient.core.metadata.schema.OSchema; +import com.orientechnologies.orient.core.metadata.schema.OType; +import com.orientechnologies.orient.core.record.impl.ODocument; +import com.tinkerpop.blueprints.Vertex; +import com.tinkerpop.blueprints.impls.orient.OrientEdgeType; +import com.tinkerpop.blueprints.impls.orient.OrientGraph; +import com.tinkerpop.blueprints.impls.orient.OrientGraphFactory; +import com.tinkerpop.blueprints.impls.orient.OrientGraphNoTx; +import com.tinkerpop.blueprints.impls.orient.OrientVertex; +import com.tinkerpop.blueprints.impls.orient.OrientVertexType; + +/** + * @author Luca Frosini (ISTI - CNR) + * This class reproduce orient issue 7354 - https://github.com/orientechnologies/orientdb/issues/7354 + */ +public class ReproduceBug7354 { + + private static final String HOST = "remote:node01.acme.org;node02.acme.org;node03.acme.org"; + private static final String ROOT_USERNAME = "root"; + private static final String ROOT_PASSWORD = "ROOT_PWD"; + + private static final String ADMIN_USERNAME = "admin"; + private static final String ADMIN_PASSWORD = "admin"; + + private static final String DB_NAME = "mydb"; + + private static final String DATABASE_TYPE = "graph"; + private static final String STORAGE_MODE = "plocal"; + + public static final String MEMORY_FACET = "MemoryFacet"; + + public UUID createDBTypesAndContext() throws IOException{ + + System.out.println("Going to create DB " + DB_NAME); + + OServerAdmin serverAdmin = new OServerAdmin(HOST) + .connect(ROOT_USERNAME,ROOT_PASSWORD); + + serverAdmin.createDatabase(DB_NAME, DATABASE_TYPE, + STORAGE_MODE); + + OrientGraphFactory factory = new OrientGraphFactory(HOST + "/" + DB_NAME, + ADMIN_USERNAME, ADMIN_PASSWORD).setupPool(1, 10); + + OrientGraphNoTx orientGraphNoTx = factory.getNoTx(); + + OMetadata oMetadata = orientGraphNoTx.getRawGraph().getMetadata(); + + OSchema oSchema = oMetadata.getSchema(); + OClass oRestricted = oSchema.getClass("ORestricted"); + + OrientVertexType v = orientGraphNoTx.getVertexBaseType(); + v.addSuperClass(oRestricted); + + OrientEdgeType e = orientGraphNoTx.getEdgeBaseType(); + e.addSuperClass(oRestricted); + + orientGraphNoTx.createVertexType(MEMORY_FACET); + + orientGraphNoTx.shutdown(); + + System.out.println("DB " + DB_NAME + " has been created. Going to create security Context"); + + OrientGraph orientGraph = factory.getTx(); + + UUID contextUUID = UUID.randomUUID(); + // Create Reader and Writers Roles and Users for Context identified by provided UUID + SecurityContext.createSecurityContext(orientGraph, contextUUID); + orientGraph.commit(); + orientGraph.shutdown(); + + return contextUUID; + } + + public OrientGraphFactory getFactory(UUID contextUUID){ + + String username = SecurityContext.getSecurityRoleOrUserName( + SecurityContext.PermissionMode.WRITER, + SecurityContext.SecurityType.USER, contextUUID); + + String password = SecurityContext.WRITER_PASSWORD; + + OrientGraphFactory factory = new OrientGraphFactory(HOST + "/" + DB_NAME, + username, password).setupPool(1, 10); + factory.setConnectionStrategy(OStorageRemote.CONNECTION_STRATEGY + .ROUND_ROBIN_CONNECT.toString()); + + return factory; + } + + public void createVertex(OrientGraphFactory factory, UUID contextUUID){ + + System.out.println("Going to create " + MEMORY_FACET + " instance"); + + OrientGraph orientGraph = factory.getTx(); + + OrientVertex memory = orientGraph.addVertex("class:" + MEMORY_FACET); + SecurityContext.addToSecurityContext(orientGraph, memory, contextUUID); + + List list = new ArrayList<>(); + ODocument oDocument1 = new ODocument(); + oDocument1 = oDocument1.fromJSON("{\"key1\":\"Value1\"}"); + list.add(oDocument1); + + ODocument oDocument2 = new ODocument(); + oDocument2 = oDocument2.fromJSON("{\"key2\":\"Value2\"}"); + list.add(oDocument2); + memory.setProperty("test", list, OType.EMBEDDEDLIST); + memory.save(); + + orientGraph.commit(); + orientGraph.shutdown(); + } + + + public void updateVertex(OrientGraphFactory factory, UUID contextUUID){ + System.out.println("Going to update " + MEMORY_FACET + " instance."); + + OrientGraph orientGraph = factory.getTx(); + Iterable vertexes = orientGraph.getVerticesOfClass(MEMORY_FACET); + + Vertex v = vertexes.iterator().next(); + + List list2 = new ArrayList<>(); + ODocument oDocument3 = new ODocument(); + oDocument3 = oDocument3.fromJSON("{\"key3\":\"Value3\"}"); + list2.add(oDocument3); + + ODocument oDocument4 = new ODocument(); + oDocument4 = oDocument4.fromJSON("{\"key4\":\"Value4\"}"); + list2.add(oDocument4); + ((OrientVertex) v).setProperty("test", list2, OType.EMBEDDEDLIST); + + orientGraph.commit(); + + System.out.println("Changes to " + MEMORY_FACET + " committed."); + + orientGraph.shutdown(); + + } + + public void execute() throws IOException { + UUID contextUUID = createDBTypesAndContext(); + OrientGraphFactory factory = getFactory(contextUUID); + createVertex(factory, contextUUID); + updateVertex(factory, contextUUID); + System.out.println("DONE"); + } + + public static void main(String args[]) throws Exception { + ReproduceBug7354 reproduceBug7354 = new ReproduceBug7354(); + reproduceBug7354.execute(); + } + +} diff --git a/src/main/java/org/gcube/orientdb/SecurityContext.java b/src/main/java/org/gcube/orientdb/SecurityContext.java new file mode 100644 index 0000000..89f73f9 --- /dev/null +++ b/src/main/java/org/gcube/orientdb/SecurityContext.java @@ -0,0 +1,163 @@ +/** + * + */ +package org.gcube.orientdb; + +import java.util.Iterator; +import java.util.UUID; + +import com.orientechnologies.orient.core.db.document.ODatabaseDocumentTx; +import com.orientechnologies.orient.core.metadata.security.ORestrictedOperation; +import com.orientechnologies.orient.core.metadata.security.ORole; +import com.orientechnologies.orient.core.metadata.security.OSecurity; +import com.orientechnologies.orient.core.metadata.security.OSecurityRole.ALLOW_MODES; +import com.orientechnologies.orient.core.metadata.security.OUser; +import com.orientechnologies.orient.core.record.impl.ODocument; +import com.tinkerpop.blueprints.Direction; +import com.tinkerpop.blueprints.Edge; +import com.tinkerpop.blueprints.Vertex; +import com.tinkerpop.blueprints.impls.orient.OrientBaseGraph; +import com.tinkerpop.blueprints.impls.orient.OrientEdge; +import com.tinkerpop.blueprints.impls.orient.OrientGraph; +import com.tinkerpop.blueprints.impls.orient.OrientVertex; + +/** + * @author Luca Frosini (ISTI - CNR) + * + */ +public class SecurityContext { + + public static final String DEFAULT_WRITER_ROLE = "writer"; + public static final String DEFAULT_READER_ROLE = "reader"; + + public static final String READER_PASSSWORD = "reader"; + public static final String WRITER_PASSWORD = "writer"; + + public static void addToSecurityContext(OrientGraph orientGraph, Edge edge, + UUID context) { + OSecurity oSecurity = orientGraph.getRawGraph().getMetadata() + .getSecurity(); + OrientEdge orientEdge = (OrientEdge) edge; + SecurityContext.allowSecurityContextRoles(oSecurity, + orientEdge.getRecord(), context); + } + + public static void addToSecurityContext(OrientGraph orientGraph, + Vertex vertex, UUID context) { + OSecurity oSecurity = orientGraph.getRawGraph().getMetadata() + .getSecurity(); + OrientVertex orientVertex = (OrientVertex) vertex; + + SecurityContext.allowSecurityContextRoles(oSecurity, + orientVertex.getRecord(), context); + orientVertex.save(); + + Iterable iterable = vertex.getEdges(Direction.BOTH); + Iterator iterator = iterable.iterator(); + while (iterator.hasNext()) { + OrientEdge edge = (OrientEdge) iterator.next(); + SecurityContext.allowSecurityContextRoles(oSecurity, + edge.getRecord(), context); + edge.save(); + } + } + + private static void allowSecurityContextRoles(OSecurity oSecurity, + ODocument oDocument, UUID context) { + oSecurity.allowRole( + oDocument, + ORestrictedOperation.ALLOW_ALL, + getSecurityRoleOrUserName(PermissionMode.WRITER, + SecurityType.ROLE, context)); + + oSecurity.allowRole( + oDocument, + ORestrictedOperation.ALLOW_READ, + getSecurityRoleOrUserName(PermissionMode.READER, + SecurityType.ROLE, context)); + + oDocument.save(); + } + + + public static String getSecurityRoleOrUserName( + PermissionMode permissionMode, SecurityType securityType, + UUID context) { + StringBuilder stringBuilder = new StringBuilder(); + stringBuilder.append(permissionMode); + stringBuilder.append(securityType); + stringBuilder.append("_"); + stringBuilder.append(context.toString()); + return stringBuilder.toString(); + } + + public enum SecurityType { + ROLE("Role"), USER("User"); + + private final String name; + + private SecurityType(String name) { + this.name = name; + } + + public String toString() { + return name; + } + } + + public enum PermissionMode { + READER("Reader"), WRITER("Writer"); + + private final String name; + + private PermissionMode(String name) { + this.name = name; + } + + public String toString() { + return name; + } + } + + + + + + public static void createSecurityContext(OrientBaseGraph orientBaseGraph, + UUID context) { + + ODatabaseDocumentTx oDatabaseDocumentTx = orientBaseGraph.getRawGraph(); + OSecurity oSecurity = oDatabaseDocumentTx.getMetadata().getSecurity(); + + ORole writer = oSecurity.getRole(DEFAULT_WRITER_ROLE); + ORole reader = oSecurity.getRole(DEFAULT_READER_ROLE); + + String writeRoleName = getSecurityRoleOrUserName(PermissionMode.WRITER, + SecurityType.ROLE, context); + ORole writerRole = oSecurity.createRole(writeRoleName, writer, + ALLOW_MODES.DENY_ALL_BUT); + writerRole.save(); + + String readerRoleName = getSecurityRoleOrUserName( + PermissionMode.READER, SecurityType.ROLE, context); + ORole readerRole = oSecurity.createRole(readerRoleName, reader, + ALLOW_MODES.DENY_ALL_BUT); + readerRole.save(); + + String writerUserName = getSecurityRoleOrUserName( + PermissionMode.WRITER, SecurityType.USER, context); + OUser writerUser = oSecurity.createUser(writerUserName, + WRITER_PASSWORD, writerRole); + writerUser.save(); + + String readerUserName = getSecurityRoleOrUserName( + PermissionMode.READER, SecurityType.USER, context); + OUser readerUser = oSecurity.createUser(readerUserName, + READER_PASSSWORD, readerRole); + readerUser.save(); + + oDatabaseDocumentTx.commit(); + + } + +} diff --git a/src/main/resources/Bug7354_StackTrace.txt b/src/main/resources/Bug7354_StackTrace.txt new file mode 100644 index 0000000..eed1d54 --- /dev/null +++ b/src/main/resources/Bug7354_StackTrace.txt @@ -0,0 +1,36 @@ +Going to create DB mydb +DB mydb has been created. Going to create security Context +Going to create MemoryFacet instance +Going to update MemoryFacet instance. +Exception in thread "main" com.orientechnologies.orient.server.distributed.task.ODistributedOperationException: Quorum 3 not reached for request (id=0.29 task=tx[1]{record_update(#25:0 v.1)} user=#5:4). Elapsed=20ms. Servers in timeout/conflict are: + - node03: TX[1]{1} +Received: + - node01: TX[1]{2} + - node02: TX[1]{2} + - node03: TX[1]{1} + DB name="mydb" + DB name="mydb" + at sun.reflect.NativeConstructorAccessorImpl.newInstance0(Native Method) + at sun.reflect.NativeConstructorAccessorImpl.newInstance(NativeConstructorAccessorImpl.java:62) + at sun.reflect.DelegatingConstructorAccessorImpl.newInstance(DelegatingConstructorAccessorImpl.java:45) + at java.lang.reflect.Constructor.newInstance(Constructor.java:423) + at com.orientechnologies.orient.client.binary.OChannelBinaryAsynchClient.throwSerializedException(OChannelBinaryAsynchClient.java:442) + at com.orientechnologies.orient.client.binary.OChannelBinaryAsynchClient.handleStatus(OChannelBinaryAsynchClient.java:393) + at com.orientechnologies.orient.client.binary.OChannelBinaryAsynchClient.beginResponse(OChannelBinaryAsynchClient.java:275) + at com.orientechnologies.orient.client.binary.OChannelBinaryAsynchClient.beginResponse(OChannelBinaryAsynchClient.java:167) + at com.orientechnologies.orient.client.remote.OStorageRemote.beginResponse(OStorageRemote.java:2225) + at com.orientechnologies.orient.client.remote.OStorageRemote$28.execute(OStorageRemote.java:1396) + at com.orientechnologies.orient.client.remote.OStorageRemote$28.execute(OStorageRemote.java:1368) + at com.orientechnologies.orient.client.remote.OStorageRemote$2.execute(OStorageRemote.java:198) + at com.orientechnologies.orient.client.remote.OStorageRemote.baseNetworkOperation(OStorageRemote.java:243) + at com.orientechnologies.orient.client.remote.OStorageRemote.networkOperationRetry(OStorageRemote.java:195) + at com.orientechnologies.orient.client.remote.OStorageRemote.networkOperation(OStorageRemote.java:206) + at com.orientechnologies.orient.client.remote.OStorageRemote.commit(OStorageRemote.java:1368) + at com.orientechnologies.orient.core.tx.OTransactionOptimistic.doCommit(OTransactionOptimistic.java:533) + at com.orientechnologies.orient.core.tx.OTransactionOptimistic.commit(OTransactionOptimistic.java:104) + at com.orientechnologies.orient.core.db.document.ODatabaseDocumentTx.commit(ODatabaseDocumentTx.java:2840) + at com.orientechnologies.orient.core.db.document.ODatabaseDocumentTx.commit(ODatabaseDocumentTx.java:2809) + at com.tinkerpop.blueprints.impls.orient.OrientTransactionalGraph.commit(OrientTransactionalGraph.java:182) + at org.acme.ReproduceBug7354.updateVertex(ReproduceBug7354.java:148) + at org.acme.ReproduceBug7354.execute(ReproduceBug7354.java:160) + at org.acme.ReproduceBug7354.main(ReproduceBug7354.java:166) \ No newline at end of file