mirror of https://github.com/apache/cassandra
Merge branch 'cassandra-2.2' into cassandra-3.0
This commit is contained in:
commit
6e716c6da4
|
|
@ -18,6 +18,7 @@
|
|||
* Prevent reloading of logback.xml from UDF sandbox (CASSANDRA-12535)
|
||||
* Reenable HeapPool (CASSANDRA-12900)
|
||||
Merged from 2.2:
|
||||
* Remove support for non-JavaScript UDFs (CASSANDRA-12883)
|
||||
* Fix DynamicEndpointSnitch noop in multi-datacenter situations (CASSANDRA-13074)
|
||||
* cqlsh copy-from: encode column names to avoid primary key parsing errors (CASSANDRA-12909)
|
||||
* Temporarily fix bug that creates commit log when running offline tools (CASSANDRA-8616)
|
||||
|
|
|
|||
3
NEWS.txt
3
NEWS.txt
|
|
@ -23,6 +23,9 @@ Upgrading
|
|||
- Specifying the default_time_to_live option when creating or altering a
|
||||
materialized view was erroneously accepted (and ignored). It is now
|
||||
properly rejected.
|
||||
- Only Java and JavaScript are now supported UDF languages.
|
||||
The sandbox in 3.0 already prevented the use of script languages except Java
|
||||
and JavaScript.
|
||||
|
||||
3.0.10
|
||||
=====
|
||||
|
|
|
|||
|
|
@ -1977,7 +1977,7 @@ SELECT AVG(players) FROM plays;
|
|||
|
||||
h2(#udfs). User-Defined Functions
|
||||
|
||||
User-defined functions allow execution of user-provided code in Cassandra. By default, Cassandra supports defining functions in _Java_ and _JavaScript_. Support for other JSR 223 compliant scripting languages (such as Python, Ruby, and Scala) can be added by adding a JAR to the classpath.
|
||||
User-defined functions allow execution of user-provided code in Cassandra. By default, Cassandra supports defining functions in _Java_ and _JavaScript_. Support for other JSR 223 compliant scripting languages (such as Python, Ruby, and Scala) has been removed in 3.0.11.
|
||||
|
||||
UDFs are part of the Cassandra schema. As such, they are automatically propagated to all nodes in the cluster.
|
||||
|
||||
|
|
|
|||
|
|
@ -1,8 +0,0 @@
|
|||
Apache Cassandra User-Defined-Functions JSR 223 scripting
|
||||
=========================================================
|
||||
|
||||
Unfortunately the JSR-223 support provided by the project https://github.com/ato/clojure-jsr223
|
||||
and the related ones do not provide compileable script support.
|
||||
|
||||
The JSR-223 javax.script.Compilable implementation takes source file names or readers but not script sources
|
||||
as all other JSR-223 implementations do.
|
||||
|
|
@ -1,35 +0,0 @@
|
|||
Apache Cassandra User-Defined-Functions JSR 223 scripting
|
||||
=========================================================
|
||||
|
||||
Using JSR-223 capable Groovy
|
||||
|
||||
Tested with version 2.3.6
|
||||
|
||||
Installation
|
||||
------------
|
||||
|
||||
1. Download Groovy binary release
|
||||
2. Unpack the downloaded archive into a temporary directory
|
||||
3. Copy the jar groovy-all-2.3.6-indy.jar from the Groovy embeddable directory to $CASSANDRA_HOME/lib/jsr223/groovy
|
||||
"indy" means "invokedynamic" and is a JVM instruction for scripting languages new to Java 7.
|
||||
4. Restart your Cassandra daemon if it's already running
|
||||
|
||||
Cassandra log should contain a line like this:
|
||||
INFO 10:49:45 Found scripting engine Groovy Scripting Engine 2.0 - Groovy 2.3.6 - language names: [groovy, Groovy]
|
||||
Such a line appears when you already have scripted UDFs in your system or add a scripted UDF for the first time (see below).
|
||||
|
||||
Smoke Test
|
||||
----------
|
||||
|
||||
To test Groovy functionality, open cqlsh and execute the following command:
|
||||
CREATE OR REPLACE FUNCTION foobar ( input text ) RETURNS text LANGUAGE groovy AS 'return "foo";' ;
|
||||
|
||||
If you get the error
|
||||
code=2200 [Invalid query] message="Invalid language groovy for 'foobar'"
|
||||
Groovy for Apache Cassandra has not been installed correctly.
|
||||
|
||||
Notes / Java7 invokedynamic
|
||||
---------------------------
|
||||
|
||||
Groovy provides jars that support invokedynamic bytecode instruction. These jars are whose ending with
|
||||
"-indy.jar".
|
||||
|
|
@ -1,5 +0,0 @@
|
|||
Apache Cassandra User-Defined-Functions JSR 223 scripting
|
||||
=========================================================
|
||||
|
||||
Unfortunately Jaskell JSR-223 support is quite old and the Jaskell engine seems to be quite
|
||||
unsupported. If you find a solution, please open a ticket at Apache Cassandra JIRA.
|
||||
|
|
@ -1,54 +0,0 @@
|
|||
Apache Cassandra User-Defined-Functions JSR 223 scripting
|
||||
=========================================================
|
||||
|
||||
Using JSR-223 capable JRuby
|
||||
|
||||
Tested with version 1.7.15
|
||||
|
||||
Installation
|
||||
------------
|
||||
|
||||
1. Download JRuby binary release
|
||||
2. Unpack the downloaded archive into a temporary directory
|
||||
3. Copy everything from the JRuby lib directory to $CASSANDRA_HOME/lib/jsr223/jruby
|
||||
4. Restart your Cassandra daemon if it's already running
|
||||
|
||||
Cassandra log should contain a line like this:
|
||||
INFO 10:29:03 Found scripting engine JSR 223 JRuby Engine 1.7.15 - ruby jruby 1.7.15 - language names: [ruby, jruby]
|
||||
Such a line appears when you already have scripted UDFs in your system or add a scripted UDF for the first time (see below).
|
||||
|
||||
|
||||
Smoke Test
|
||||
----------
|
||||
|
||||
To test JRuby functionality, open cqlsh and execute the following command:
|
||||
CREATE OR REPLACE FUNCTION foobar ( input text ) RETURNS text LANGUAGE ruby AS 'return "foo";' ;
|
||||
|
||||
If you get the error
|
||||
code=2200 [Invalid query] message="Invalid language ruby for 'foobar'"
|
||||
JRuby for Apache Cassandra has not been installed correctly.
|
||||
|
||||
|
||||
Ruby require/include
|
||||
--------------------
|
||||
|
||||
You can use Ruby require and include in your scripts as in the following example:
|
||||
|
||||
|
||||
CREATE OR REPLACE FUNCTION foobar ( input text ) RETURNS text LANGUAGE ruby AS '
|
||||
require "bigdecimal"
|
||||
require "bigdecimal/math"
|
||||
|
||||
include BigMath
|
||||
|
||||
a = BigDecimal((PI(100)/2).to_s)
|
||||
|
||||
return "foo " + a.to_s;
|
||||
' ;
|
||||
|
||||
|
||||
Notes / Java7 invokedynamic
|
||||
---------------------------
|
||||
|
||||
See JRuby wiki pages https://github.com/jruby/jruby/wiki/ConfiguringJRuby and
|
||||
https://github.com/jruby/jruby/wiki/PerformanceTuning for more information and optimization tips.
|
||||
|
|
@ -1,33 +0,0 @@
|
|||
Apache Cassandra User-Defined-Functions JSR 223 scripting
|
||||
=========================================================
|
||||
|
||||
Using JSR-223 capable Jython
|
||||
|
||||
Tested with version 2.3.5
|
||||
|
||||
Installation
|
||||
------------
|
||||
|
||||
1. Download Jython binary release
|
||||
2. Unpack the downloaded archive into a temporary directory
|
||||
3. Copy the jar jython.jar from the Jython directory to $CASSANDRA_HOME/lib/jsr223/jython
|
||||
4. Restart your Cassandra daemon if it's already running
|
||||
|
||||
Cassandra log should contain a line like this:
|
||||
INFO 10:58:18 Found scripting engine jython 2.5.3 - python 2.5 - language names: [python, jython]
|
||||
Such a line appears when you already have scripted UDFs in your system or add a scripted UDF for the first time (see below).
|
||||
|
||||
Smoke Test
|
||||
----------
|
||||
|
||||
To test Jython functionality, open cqlsh and execute the following command:
|
||||
CREATE OR REPLACE FUNCTION foobar ( input text ) RETURNS text LANGUAGE python AS '''foo''' ;
|
||||
|
||||
If you get the error
|
||||
code=2200 [Invalid query] message="Invalid language python for 'foobar'"
|
||||
Jython for Apache Cassandra has not been installed correctly.
|
||||
|
||||
Notes / Java7 invokedynamic
|
||||
---------------------------
|
||||
|
||||
Jython currently targets Java6 only. They want to switch to Java7 + invokedynamic in Jython 3.
|
||||
|
|
@ -1,37 +0,0 @@
|
|||
Apache Cassandra User-Defined-Functions JSR 223 scripting
|
||||
=========================================================
|
||||
|
||||
Using JSR-223 capable Scala
|
||||
|
||||
Tested with version 2.11.2
|
||||
|
||||
Installation
|
||||
------------
|
||||
|
||||
1. Download Scala binary release
|
||||
2. Unpack the downloaded archive into a temporary directory
|
||||
3. Copy the following jars from the Scala lib directory to $CASSANDRA_HOME/lib/jsr223/scala
|
||||
scala-compiler.jar
|
||||
scala-library.jar
|
||||
scala-reflect.jar
|
||||
4. Restart your Cassandra daemon if it's already running
|
||||
|
||||
Cassandra log should contain a line like this:
|
||||
INFO 11:42:35 Found scripting engine Scala Interpreter 1.0 - Scala version 2.11.2 - language names: [scala]
|
||||
Such a line appears when you already have scripted UDFs in your system or add a scripted UDF for the first time (see below).
|
||||
|
||||
Smoke Test
|
||||
----------
|
||||
|
||||
To test Scala functionality, open cqlsh and execute the following command:
|
||||
CREATE OR REPLACE FUNCTION foobar ( input text ) RETURNS text LANGUAGE scala AS 'return "foo";' ;
|
||||
|
||||
If you get the error
|
||||
code=2200 [Invalid query] message="Invalid language scala for 'foobar'"
|
||||
Scala for Apache Cassandra has not been installed correctly.
|
||||
|
||||
Notes / Java7 invokedynamic
|
||||
---------------------------
|
||||
|
||||
Scala 2.10 has Java6 support only. 2.11 has experimental invokedynamic support (use at your own risk!).
|
||||
2.12 introduces an upgrade directly to Java8 - see https://stackoverflow.com/questions/14285894/advantages-of-scala-emitting-bytecode-for-the-jvm-1-7
|
||||
|
|
@ -27,6 +27,9 @@ import java.util.*;
|
|||
import java.util.concurrent.ExecutorService;
|
||||
import javax.script.*;
|
||||
|
||||
import jdk.nashorn.api.scripting.ClassFilter;
|
||||
import jdk.nashorn.api.scripting.NashornScriptEngine;
|
||||
import jdk.nashorn.api.scripting.NashornScriptEngineFactory;
|
||||
import org.apache.cassandra.concurrent.NamedThreadFactory;
|
||||
import org.apache.cassandra.cql3.ColumnIdentifier;
|
||||
import org.apache.cassandra.db.marshal.AbstractType;
|
||||
|
|
@ -34,8 +37,6 @@ import org.apache.cassandra.exceptions.InvalidRequestException;
|
|||
|
||||
final class ScriptBasedUDFunction extends UDFunction
|
||||
{
|
||||
static final Map<String, Compilable> scriptEngines = new HashMap<>();
|
||||
|
||||
private static final ProtectionDomain protectionDomain;
|
||||
private static final AccessControlContext accessControlContext;
|
||||
|
||||
|
|
@ -91,23 +92,17 @@ final class ScriptBasedUDFunction extends UDFunction
|
|||
UDFunction::initializeThread)),
|
||||
"userscripts");
|
||||
|
||||
private static final ClassFilter classFilter = clsName -> secureResource(clsName.replace('.', '/') + ".class");
|
||||
|
||||
private static final NashornScriptEngine scriptEngine;
|
||||
|
||||
|
||||
static
|
||||
{
|
||||
ScriptEngineManager scriptEngineManager = new ScriptEngineManager();
|
||||
for (ScriptEngineFactory scriptEngineFactory : scriptEngineManager.getEngineFactories())
|
||||
{
|
||||
ScriptEngine scriptEngine = scriptEngineFactory.getScriptEngine();
|
||||
boolean compilable = scriptEngine instanceof Compilable;
|
||||
if (compilable)
|
||||
{
|
||||
logger.info("Found scripting engine {} {} - {} {} - language names: {}",
|
||||
scriptEngineFactory.getEngineName(), scriptEngineFactory.getEngineVersion(),
|
||||
scriptEngineFactory.getLanguageName(), scriptEngineFactory.getLanguageVersion(),
|
||||
scriptEngineFactory.getNames());
|
||||
for (String name : scriptEngineFactory.getNames())
|
||||
scriptEngines.put(name, (Compilable) scriptEngine);
|
||||
}
|
||||
}
|
||||
ScriptEngine engine = scriptEngineManager.getEngineByName("nashorn");
|
||||
NashornScriptEngineFactory factory = engine != null ? (NashornScriptEngineFactory) engine.getFactory() : null;
|
||||
scriptEngine = factory != null ? (NashornScriptEngine) factory.getScriptEngine(new String[]{}, udfClassLoader, classFilter) : null;
|
||||
|
||||
try
|
||||
{
|
||||
|
|
@ -138,8 +133,7 @@ final class ScriptBasedUDFunction extends UDFunction
|
|||
{
|
||||
super(name, argNames, argTypes, returnType, calledOnNullInput, language, body);
|
||||
|
||||
Compilable scriptEngine = scriptEngines.get(language);
|
||||
if (scriptEngine == null)
|
||||
if (!"JavaScript".equalsIgnoreCase(language) || scriptEngine == null)
|
||||
throw new InvalidRequestException(String.format("Invalid language '%s' for function '%s'", language, name));
|
||||
|
||||
// execute compilation with no-permissions to prevent evil code e.g. via "static code blocks" / "class initialization"
|
||||
|
|
|
|||
|
|
@ -391,8 +391,7 @@ public class UFScriptTest extends CQLTester
|
|||
DatabaseDescriptor.enableScriptedUserDefinedFunctions(false);
|
||||
try
|
||||
{
|
||||
assertInvalid("double",
|
||||
"CREATE OR REPLACE FUNCTION " + KEYSPACE + ".assertNotEnabled(val double) " +
|
||||
assertInvalid("CREATE OR REPLACE FUNCTION " + KEYSPACE + ".assertNotEnabled(val double) " +
|
||||
"RETURNS NULL ON NULL INPUT " +
|
||||
"RETURNS double " +
|
||||
"LANGUAGE javascript\n" +
|
||||
|
|
|
|||
|
|
@ -149,7 +149,6 @@ public class UFSecurityTest extends CQLTester
|
|||
"new java.net.ServerSocket().bind(null); 0;",
|
||||
"var thread = new java.lang.Thread(); thread.start(); 0;",
|
||||
"java.lang.System.getProperty(\"foo.bar.baz\"); 0;",
|
||||
"java.lang.Class.forName(\"java.lang.System\"); 0;",
|
||||
"java.lang.Runtime.getRuntime().exec(\"/tmp/foo\"); 0;",
|
||||
"java.lang.Runtime.getRuntime().loadLibrary(\"foobar\"); 0;",
|
||||
"java.lang.Runtime.getRuntime().loadLibrary(\"foobar\"); 0;",
|
||||
|
|
@ -177,6 +176,17 @@ public class UFSecurityTest extends CQLTester
|
|||
assertAccessControlException(script, e);
|
||||
}
|
||||
}
|
||||
|
||||
String script = "java.lang.Class.forName(\"java.lang.System\"); 0;";
|
||||
String fName = createFunction(KEYSPACE_PER_TEST, "double",
|
||||
"CREATE OR REPLACE FUNCTION %s(val double) " +
|
||||
"RETURNS NULL ON NULL INPUT " +
|
||||
"RETURNS double " +
|
||||
"LANGUAGE javascript\n" +
|
||||
"AS '" + script + "';");
|
||||
assertInvalidThrowMessage("Java reflection not supported when class filter is present",
|
||||
FunctionExecutionException.class,
|
||||
"SELECT " + fName + "(dval) FROM %s WHERE key=1");
|
||||
}
|
||||
|
||||
private static void assertAccessControlException(String script, FunctionExecutionException e)
|
||||
|
|
|
|||
Loading…
Reference in New Issue