You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@accumulo.apache.org by ct...@apache.org on 2020/01/10 04:32:58 UTC

[accumulo-proxy] branch master updated: Documentation and code updates (#17)

This is an automated email from the ASF dual-hosted git repository.

ctubbsii pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/accumulo-proxy.git


The following commit(s) were added to refs/heads/master by this push:
     new db3a4b2  Documentation and code updates (#17)
db3a4b2 is described below

commit db3a4b2958d36e738dcdee00ca9e9441a31695b0
Author: Mike Walch <mw...@apache.org>
AuthorDate: Thu Jan 9 23:32:52 2020 -0500

    Documentation and code updates (#17)
    
    * Moved namespace code from the Accumulo website to namespace_client.py
    * Renamed existing python client to basic_client.py
    * Moved Java client code/docs from website to docs/java_client.md
    * Updated README.md
---
 README.md                                       |  14 +-
 docs/java_client.md                             |  80 +++++++++++
 src/main/python/{example.py => basic_client.py} |   0
 src/main/python/namespace_client.py             | 171 ++++++++++++++++++++++++
 4 files changed, 261 insertions(+), 4 deletions(-)

diff --git a/README.md b/README.md
index 943ed5b..a2a9120 100644
--- a/README.md
+++ b/README.md
@@ -43,7 +43,7 @@ Thrift language binding).
 
 # Build language specific bindings
 
-Bindings have been built in `src/main/` for Java, python, and ruby.
+Bindings have been built in `src/main/` for Java, Python, and Ruby.
 
 Bindings for other languages can be built using the Thrift compiler. Follow the [Thrift tutorial]
 to install a Thrift compiler and use the following command to generate language bindings.
@@ -62,10 +62,10 @@ cd accumulo-client/
 pipenv --python 2.7
 pipenv install thrift
 pipenv install -e /path/to/accumulo-proxy/src/main/python
-cp /path/to/accumulo-proxy/src/main/python/example.py .
+cp /path/to/accumulo-proxy/src/main/python/basic_client.py .
 # Edit credentials if needed
-vim example.py
-pipenv run python2 example.py
+vim basic_client.py
+pipenv run python2 basic_client.py
 ```
 
 # Create an Accumulo client using Ruby
@@ -83,6 +83,12 @@ bundle install
 bundle exec client.rb
 ```
 
+# Java clients to Proxy
+
+[Java clients] to the Proxy can be written to limit access to the cluster. The proxy can be placed
+on a server in the cluster and clients can communicate with proxy from outside of the cluster.
+
+[Java clients]: docs/java_client.md
 [accumulo]: https://accumulo.apache.org
 [Thrift]: https://thrift.apache.org
 [Thrift tutorial]: https://thrift.apache.org/tutorial/
diff --git a/docs/java_client.md b/docs/java_client.md
new file mode 100644
index 0000000..18b2c6c
--- /dev/null
+++ b/docs/java_client.md
@@ -0,0 +1,80 @@
+<!--
+Licensed to the Apache Software Foundation (ASF) under one or more
+contributor license agreements.  See the NOTICE file distributed with
+this work for additional information regarding copyright ownership.
+The ASF licenses this file to You under the Apache License, Version 2.0
+(the "License"); you may not use this file except in compliance with
+the License.  You may obtain a copy of the License at
+
+    http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing, software
+distributed under the License is distributed on an "AS IS" BASIS,
+WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+See the License for the specific language governing permissions and
+limitations under the License.
+-->
+
+# Java client
+
+After initiating a connection to the Proxy (see Apache Thrift's documentation for examples
+of connecting to a Thrift service), the methods on the proxy client will be available. The
+first thing to do is log in:
+
+```java
+Map password = new HashMap<String,String>();
+password.put("password", "secret");
+ByteBuffer token = client.login("root", password);
+```
+
+Once logged in, the token returned will be used for most subsequent calls to the client.
+Let's create a table, add some data, scan the table, and delete it.
+
+First, create a table.
+
+```java
+client.createTable(token, "myTable", true, TimeType.MILLIS);
+```
+
+Next, add some data:
+
+```java
+// first, create a writer on the server
+String writer = client.createWriter(token, "myTable", new WriterOptions());
+
+//rowid
+ByteBuffer rowid = ByteBuffer.wrap("UUID".getBytes());
+
+//mutation like class
+ColumnUpdate cu = new ColumnUpdate();
+cu.setColFamily("MyFamily".getBytes());
+cu.setColQualifier("MyQualifier".getBytes());
+cu.setColVisibility("VisLabel".getBytes());
+cu.setValue("Some Value.".getBytes());
+
+List<ColumnUpdate> updates = new ArrayList<ColumnUpdate>();
+updates.add(cu);
+
+// build column updates
+Map<ByteBuffer, List<ColumnUpdate>> cellsToUpdate = new HashMap<ByteBuffer, List<ColumnUpdate>>();
+cellsToUpdate.put(rowid, updates);
+
+// send updates to the server
+client.updateAndFlush(writer, "myTable", cellsToUpdate);
+
+client.closeWriter(writer);
+```
+
+Scan for the data and batch the return of the results on the server:
+
+```java
+String scanner = client.createScanner(token, "myTable", new ScanOptions());
+ScanResult results = client.nextK(scanner, 100);
+
+for(KeyValue keyValue : results.getResultsIterator()) {
+  // do something with results
+}
+
+client.closeScanner(scanner);
+```
+
diff --git a/src/main/python/example.py b/src/main/python/basic_client.py
similarity index 100%
rename from src/main/python/example.py
rename to src/main/python/basic_client.py
diff --git a/src/main/python/namespace_client.py b/src/main/python/namespace_client.py
new file mode 100644
index 0000000..1e7e230
--- /dev/null
+++ b/src/main/python/namespace_client.py
@@ -0,0 +1,171 @@
+# Licensed to the Apache Software Foundation (ASF) under one or more
+# contributor license agreements.  See the NOTICE file distributed with
+# this work for additional information regarding copyright ownership.
+# The ASF licenses this file to You under the Apache License, Version 2.0
+# (the "License"); you may not use this file except in compliance with
+# the License.  You may obtain a copy of the License at
+#
+#     http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+#! /usr/bin/env python
+
+from thrift.protocol import TCompactProtocol
+from thrift.transport import TSocket, TTransport
+
+from accumulo import AccumuloProxy
+from accumulo.ttypes import NamespacePermission, IteratorSetting, IteratorScope, AccumuloException
+
+def main():
+    transport = TSocket.TSocket('localhost', 42424)
+    transport = TTransport.TFramedTransport(transport)
+    protocol = TCompactProtocol.TCompactProtocol(transport)
+    client = AccumuloProxy.Client(protocol)
+    transport.open()
+    login = client.login('root', {'password': 'secret'})
+
+    client.createLocalUser(login, 'user1', 'password1')
+
+    print client.listNamespaces(login)
+
+    # create a namespace and give the user1 all permissions
+    print 'creating namespace testing'
+    client.createNamespace(login, 'testing')
+    assert client.namespaceExists(login, 'testing')
+    print client.listNamespaces(login)
+
+    print 'testing namespace renaming'
+    client.renameNamespace(login, 'testing', 'testing2')
+    assert not client.namespaceExists(login, 'testing')
+    assert client.namespaceExists(login, 'testing2')
+    client.renameNamespace(login, 'testing2', 'testing')
+    assert not client.namespaceExists(login, 'testing2')
+    assert client.namespaceExists(login, 'testing')
+
+    print 'granting all namespace permissions to user1'
+    for k, v in NamespacePermission._VALUES_TO_NAMES.iteritems():
+        client.grantNamespacePermission(login, 'user1', 'testing', k)
+
+    # make sure the last operation worked
+    for k, v in NamespacePermission._VALUES_TO_NAMES.iteritems():
+        assert client.hasNamespacePermission(login, 'user1', 'testing', k), \
+            'user1 does\'nt have namespace permission %s' % v
+
+    print 'default namespace: ' + client.defaultNamespace()
+    print 'system namespace: ' + client.systemNamespace()
+
+    # grab the namespace properties
+    print 'retrieving namespace properties'
+    props = client.getNamespaceProperties(login, 'testing')
+    assert props and props['table.compaction.major.ratio'] == '3'
+
+    # update a property and verify it is good
+    print 'setting namespace property table.compaction.major.ratio = 4'
+    client.setNamespaceProperty(login, 'testing', 'table.compaction.major.ratio', '4')
+    props = client.getNamespaceProperties(login, 'testing')
+    assert props and props['table.compaction.major.ratio'] == '4'
+
+    print 'retrieving namespace ID map'
+    nsids = client.namespaceIdMap(login)
+    assert nsids and 'accumulo' in nsids
+
+    print 'attaching debug iterator to namespace testing'
+    setting = IteratorSetting(priority=40, name='DebugTheThings',
+                              iteratorClass='org.apache.accumulo.core.iterators.DebugIterator', properties={})
+    client.attachNamespaceIterator(login, 'testing', setting, [IteratorScope.SCAN])
+    setting = client.getNamespaceIteratorSetting(login, 'testing', 'DebugTheThings', IteratorScope.SCAN)
+    assert setting and setting.name == 'DebugTheThings'
+
+    # make sure the iterator is in the list
+    iters = client.listNamespaceIterators(login, 'testing')
+    found = False
+    for name, scopes in iters.iteritems():
+        if name == 'DebugTheThings':
+            found = True
+            break
+    assert found
+
+    print 'checking for iterator conflicts'
+
+    # this next statment should be fine since we are on a different scope
+    client.checkNamespaceIteratorConflicts(login, 'testing', setting, [IteratorScope.MINC])
+
+    # this time it should throw an exception since we have already added the iterator with this scope
+    try:
+        client.checkNamespaceIteratorConflicts(login, 'testing', setting, [IteratorScope.SCAN, IteratorScope.MINC])
+    except AccumuloException:
+        pass
+    else:
+        assert False, 'There should have been a namespace iterator conflict!'
+
+    print 'removing debug iterator from namespace testing'
+    client.removeNamespaceIterator(login, 'testing', 'DebugTheThings', [IteratorScope.SCAN])
+
+    # make sure the iterator is NOT in the list anymore
+    iters = client.listNamespaceIterators(login, 'testing')
+    found = False
+    for name, scopes in iters.iteritems():
+        if name == 'DebugTheThings':
+            found = True
+            break
+    assert not found
+
+    print 'adding max mutation size namespace constraint'
+    constraintid = client.addNamespaceConstraint(login, 'testing',
+                                                 'org.apache.accumulo.test.constraints.MaxMutationSize')
+
+    print 'make sure constraint was added'
+    constraints = client.listNamespaceConstraints(login, 'testing')
+    found = False
+    for name, cid in constraints.iteritems():
+        if cid == constraintid and name == 'org.apache.accumulo.test.constraints.MaxMutationSize':
+            found = True
+            break
+    assert found
+
+    print 'remove max mutation size namespace constraint'
+    client.removeNamespaceConstraint(login, 'testing', constraintid)
+
+    print 'make sure constraint was removed'
+    constraints = client.listNamespaceConstraints(login, 'testing')
+    found = False
+    for name, cid in constraints.iteritems():
+        if cid == constraintid and name == 'org.apache.accumulo.test.constraints.MaxMutationSize':
+            found = True
+            break
+    assert not found
+
+    print 'test a namespace class load of the VersioningIterator'
+    res = client.testNamespaceClassLoad(login, 'testing', 'org.apache.accumulo.core.iterators.user.VersioningIterator',
+                                        'org.apache.accumulo.core.iterators.SortedKeyValueIterator')
+    assert res
+
+    print 'test a bad namespace class load of the VersioningIterator'
+    res = client.testNamespaceClassLoad(login, 'testing', 'org.apache.accumulo.core.iterators.user.VersioningIterator',
+                                        'dummy')
+    assert not res
+
+    # revoke the permissions
+    print 'revoking namespace permissions for user1'
+    for k, v in NamespacePermission._VALUES_TO_NAMES.iteritems():
+        client.revokeNamespacePermission(login, 'user1', 'testing', k)
+
+    # make sure the last operation worked
+    for k, v in NamespacePermission._VALUES_TO_NAMES.iteritems():
+        assert not client.hasNamespacePermission(login, 'user1', 'testing', k), \
+            'user1 does\'nt have namespace permission %s' % v
+
+    print 'deleting namespace testing'
+    client.deleteNamespace(login, 'testing')
+    assert not client.namespaceExists(login, 'testing')
+
+    print 'deleting user1'
+    client.dropLocalUser(login, 'user1')
+
+if __name__ == "__main__":
+    main()