├── .asf.yaml ├── .github └── workflows │ └── maven.yml ├── .gitignore ├── BUILDING.md ├── CHANGES.md ├── README.md ├── RELEASENOTES.md ├── bin ├── argparse-1.4.0 │ └── argparse.py ├── daemon.py ├── log4j2.properties ├── phoenix_queryserver_utils.py ├── queryserver.py └── sqlline-thin.py ├── dev └── code-coverage │ ├── README.md │ └── run-coverage.sh ├── phoenix-queryserver-assembly ├── pom.xml └── src │ ├── assembly │ └── cluster.xml │ └── scripts │ └── replace_jars_with_symlinks.sh ├── phoenix-queryserver-client ├── pom.xml └── src │ └── main │ ├── java │ └── org │ │ └── apache │ │ └── phoenix │ │ └── queryserver │ │ └── client │ │ ├── Driver.java │ │ ├── KerberosLoginFromTicketCache.java │ │ └── SqllineWrapper.java │ └── resources │ ├── META-INF │ └── services │ │ └── java.sql.Driver │ └── version │ └── org-apache-phoenix-remote-jdbc.properties ├── phoenix-queryserver-it ├── pom.xml └── src │ └── it │ ├── bin │ ├── test_phoenixdb.py │ └── test_phoenixdb.sh │ ├── java │ └── org │ │ └── apache │ │ └── phoenix │ │ ├── end2end │ │ ├── HttpParamImpersonationQueryServerIT.java │ │ ├── QueryServerBasicsIT.java │ │ ├── QueryServerEnvironment.java │ │ ├── QueryServerTestUtil.java │ │ ├── QueryServerThread.java │ │ ├── SecureQueryServerIT.java │ │ ├── SecureQueryServerPhoenixDBIT.java │ │ ├── ServerCustomizersIT.java │ │ └── TlsUtil.java │ │ └── tool │ │ └── ParameterizedPhoenixCanaryToolIT.java │ └── resources │ ├── hbase-site.xml │ └── log4j2.properties ├── phoenix-queryserver-load-balancer ├── pom.xml └── src │ ├── it │ └── java │ │ └── org │ │ └── apache │ │ └── phoenix │ │ └── end2end │ │ └── LoadBalancerEnd2EndIT.java │ ├── main │ ├── java │ │ └── org │ │ │ └── apache │ │ │ └── phoenix │ │ │ ├── loadbalancer │ │ │ └── service │ │ │ │ ├── LoadBalanceZookeeperConfImpl.java │ │ │ │ └── LoadBalancer.java │ │ │ └── queryserver │ │ │ └── register │ │ │ └── ZookeeperRegistry.java │ └── resources │ │ └── META-INF │ │ └── services │ │ ├── org.apache.phoenix.loadbalancer.service.LoadBalanceZookeeperConf │ │ └── org.apache.phoenix.queryserver.register.Registry │ └── test │ └── java │ └── org │ └── apache │ └── phoenix │ └── loadbalancer │ └── service │ └── LoadBalanceZookeeperConfImplTest.java ├── phoenix-queryserver-orchestrator ├── pom.xml └── src │ ├── main │ └── java │ │ └── org │ │ └── apache │ │ └── phoenix │ │ ├── queryserver │ │ └── orchestrator │ │ │ ├── QueryServerCanaryOrchestrator.java │ │ │ ├── TestExecutorClient.java │ │ │ └── ToolWrapper.java │ │ └── tool │ │ ├── CanaryTestResult.java │ │ └── PhoenixCanaryTool.java │ └── test │ └── java │ └── org │ └── apache │ └── phoenix │ └── tool │ └── PhoenixCanaryToolTest.java ├── phoenix-queryserver ├── pom.xml └── src │ ├── build │ └── query-server-runnable.xml │ ├── main │ └── java │ │ └── org │ │ └── apache │ │ └── phoenix │ │ ├── loadbalancer │ │ └── service │ │ │ └── LoadBalanceZookeeperConf.java │ │ ├── queryserver │ │ ├── QueryServerOptions.java │ │ ├── QueryServerProperties.java │ │ ├── register │ │ │ └── Registry.java │ │ └── server │ │ │ ├── AvaticaServerConfigurationFactory.java │ │ │ ├── PhoenixMetaFactory.java │ │ │ ├── PhoenixMetaFactoryImpl.java │ │ │ ├── QueryServer.java │ │ │ ├── RemoteUserExtractorFactory.java │ │ │ ├── ServerCustomizersFactory.java │ │ │ └── customizers │ │ │ ├── BasicAuthenticationServerCustomizer.java │ │ │ ├── HostedClientJarsServerCustomizer.java │ │ │ └── JMXJsonEndpointServerCustomizer.java │ │ └── util │ │ ├── HostAndPort.java │ │ ├── InstanceResolver.java │ │ ├── SimpleLRUCache.java │ │ └── ThinClientUtil.java │ └── test │ └── java │ └── org │ └── apache │ └── phoenix │ ├── DriverCohabitationTest.java │ └── queryserver │ ├── server │ ├── CustomAvaticaServerConfigurationTest.java │ ├── PhoenixDoAsCallbackTest.java │ ├── PhoenixRemoteUserExtractorTest.java │ ├── QueryServerConfigurationTest.java │ ├── QueryServerTest.java │ ├── RemoteUserExtractorFactoryTest.java │ ├── ServerCustomizersTest.java │ └── customizers │ │ └── HostedClientJarsServerCustomizerTest.java │ └── util │ └── SimpleLRUCacheTest.java ├── pom.xml └── python-phoenixdb ├── .gitignore ├── .gitlab-ci.yml ├── Dockerfile ├── Dockerfile-pqs ├── LICENSE ├── NEWS.rst ├── NOTICE ├── README.rst ├── RELEASING.rst ├── ci ├── build-env │ └── Dockerfile └── phoenix │ ├── Dockerfile │ ├── docker-entrypoint.sh │ └── hbase-site.xml ├── dev-support ├── cache-apache-project-artifact.sh ├── make_rc.sh ├── rat-excludes.txt └── run-source-ratcheck.sh ├── doc ├── Makefile ├── api.rst ├── conf.py ├── index.rst └── versions.rst ├── docker-entrypoint.sh ├── examples └── basic.py ├── gen-protobuf.sh ├── phoenixdb ├── __init__.py ├── avatica │ ├── __init__.py │ ├── client.py │ └── proto │ │ ├── __init__.py │ │ ├── common_pb2.py │ │ ├── requests_pb2.py │ │ └── responses_pb2.py ├── connection.py ├── cursor.py ├── errors.py ├── meta.py ├── sqlalchemy_phoenix.py ├── tests │ ├── __init__.py │ ├── dbapi20.py │ ├── test_avatica.py │ ├── test_db.py │ ├── test_dbapi20.py │ ├── test_errors.py │ ├── test_sqlalchemy.py │ └── test_types.py └── types.py ├── requirements.txt ├── setup.cfg ├── setup.py └── tox.ini /.asf.yaml: -------------------------------------------------------------------------------- 1 | # Licensed to the Apache Software Foundation (ASF) under one 2 | # or more contributor license agreements. See the NOTICE file 3 | # distributed with this work for additional information 4 | # regarding copyright ownership. The ASF licenses this file 5 | # to you under the Apache License, Version 2.0 (the 6 | # "License"); you may not use this file except in compliance 7 | # with the License. You may obtain a copy of the License at 8 | # 9 | # http://www.apache.org/licenses/LICENSE-2.0 10 | # 11 | # Unless required by applicable law or agreed to in writing, software 12 | # distributed under the License is distributed on an "AS IS" BASIS, 13 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 | # See the License for the specific language governing permissions and 15 | # limitations under the License. 16 | 17 | # This file controls the integration of the Phoenix Queryserver repo with ASF 18 | # infrastructure. Refer to 19 | # https://cwiki.apache.org/confluence/display/INFRA/git+-+.asf.yaml+features 20 | # for details. Be careful when changing the contents of this file since it 21 | # may affect many developers of the project and make sure to discuss the 22 | # changes with dev@ before committing. 23 | 24 | notifications: 25 | commits: commits@phoenix.apache.org 26 | issues: issues@phoenix.apache.org 27 | pullrequests: issues@phoenix.apache.org 28 | jira_options: link label comment 29 | 30 | github: 31 | enabled_merge_buttons: 32 | squash: true 33 | merge: false 34 | rebase: false 35 | -------------------------------------------------------------------------------- /.github/workflows/maven.yml: -------------------------------------------------------------------------------- 1 | # Licensed to the Apache Software Foundation (ASF) under one or more 2 | # contributor license agreements. See the NOTICE file distributed with 3 | # this work for additional information regarding copyright ownership. 4 | # The ASF licenses this file to You under the Apache License, Version 2.0 5 | # (the "License"); you may not use this file except in compliance with 6 | # the License. You may obtain a copy of the License at 7 | # 8 | # http://www.apache.org/licenses/LICENSE-2.0 9 | # 10 | # Unless required by applicable law or agreed to in writing, software 11 | # distributed under the License is distributed on an "AS IS" BASIS, 12 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | # See the License for the specific language governing permissions and 14 | # limitations under the License. 15 | 16 | name: phoenix-queryserver preCommit Build 17 | 18 | on: 19 | pull_request: 20 | 21 | jobs: 22 | build: 23 | runs-on: ubuntu-latest 24 | steps: 25 | - uses: actions/checkout@v1 26 | - name: Set up JDK 1.8 27 | uses: actions/setup-java@v1 28 | with: 29 | java-version: 1.8 30 | - name: Build with Maven 31 | run: mvn -B clean verify 32 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | #general java 2 | *.class 3 | *.war 4 | *.jar 5 | dependency-reduced-pom.xml 6 | 7 | # python 8 | *.pyc 9 | .checkstyle 10 | 11 | # eclipse stuffs 12 | .settings/* 13 | */.settings/ 14 | .classpath 15 | .project 16 | */.externalToolBuilders 17 | */maven-eclipse.xml 18 | 19 | # intellij stuff 20 | .idea/ 21 | *.iml 22 | *.ipr 23 | *.iws 24 | 25 | #maven stuffs 26 | target/ 27 | release/ 28 | RESULTS/ 29 | CSV_EXPORT/ 30 | .DS_Store 31 | -------------------------------------------------------------------------------- /BUILDING.md: -------------------------------------------------------------------------------- 1 | 17 | 18 | ![logo](https://phoenix.apache.org/images/phoenix-logo-small.png) 19 | 20 | [Apache Phoenix](http://phoenix.apache.org/) enables OLTP and operational analytics in Hadoop for low latency applications. Visit the Apache Phoenix website [here](http://phoenix.apache.org/). This is the repo for the Phoenix Query Server (PQS). 21 | 22 | Copyright ©2020 [Apache Software Foundation](http://www.apache.org/). All Rights Reserved. 23 | 24 | ## Building 25 | 26 | This repository will build a tarball which is capable of running the Phoenix Query Server. 27 | 28 | By default, this tarball does not contain a Phoenix client jar as it is meant to be agnostic 29 | of Phoenix version (one PQS release should be usable against any Phoenix version). 30 | 31 | However, due to an incompatible change in the relocations used in the phoenix-client JAR, you need to build 32 | Phoenix Query Server with the `shade-javax-servlet` maven profile if you use Phoenix versions 33 | 5.1.1, 5.1.2, 5.1.3 or 4.16.x with it. (See PHOENIX-6861 for more details) 34 | This applies whether you bundle the Phoenix client into the assembly or add it separately. 35 | Phoenix 5.2.0 and later requires that PQS is built WITHOUT the `shade-javax-servlet` maven profile. 36 | 37 | In order to use Phoenix Query Server, you need to copy the phoenix-client-embedded jar appropriate 38 | for your cluster into the Queryserver root directory. 39 | 40 | Note that the resulting Query Server binaries are not tied to any Phoenix, Hbase or Hadoop versions, 41 | apart from the exception above. 42 | 43 | 44 | ``` 45 | $ mvn clean package -Pshade-javax-servlet 46 | ``` 47 | 48 | For other Phoenix versions build with the default settings 49 | 50 | ``` 51 | $ mvn clean package 52 | ``` 53 | 54 | ### Bundling a Phoenix Client 55 | 56 | To build a release of PQS which packages a specific version of Phoenix, specify the `package-phoenix-client` system property 57 | and specify the `phoenix.version` system property to indicate a specific Phoenix version, as well as 58 | the `phoenix.client.artifactid` to choose the phoenix-client HBase variant. 59 | You need to bundle the embedded client variant, to avoid conflicts with the logging libraries. 60 | 61 | ``` 62 | $ mvn clean package -Dpackage.phoenix.client -Dphoenix.version=5.1.1 -Dphoenix.client.artifactid=phoenix-client-embedded-hbase-2.4 -Pshade-javax-servlet -pl '!phoenix-queryserver-it' 63 | ``` 64 | 65 | ### Running integration tests 66 | 67 | `mvn package` will run the unit tests while building, but it will not run the integration test suite. 68 | 69 | The integration tests will run with the default Phoenix and HBase version. 70 | Running the integration tests with non-default Phoenix and HBase versions may or may not work. 71 | 72 | ``` 73 | $ mvn clean verify 74 | ``` 75 | 76 | 77 | If a different Phoenix version is used for testing, then at least the *hbase.version* 78 | and *hadoop.version* properties must be set to the versions used to build phoenix-client-embdedd, 79 | but other changes may also be needed, or there may be un-resolvable conflicts. 80 | 81 | ``` 82 | $ mvn clean verify -Dphoenix.version=5.1.3 -Pshade-javax-servlet -Dphoenix.client.artifactid=phoenix-client-embedded-hbase-2.4 -Dhadoop.version=3.1.3 -Dhbase.version=2.4.15 -DforkCount=6' 83 | ``` 84 | 85 | (At the time of writing, the above will run, but fail because 5.1.3 does not have PHOENIX-5066 86 | required by the failing test) 87 | 88 | ### Running project reports 89 | 90 | Phoenix-queryserver currently supports generating the standard set of Maven Project Info Reports, 91 | as well as Spotbugs, Apache Creadur RAT, OWASP Dependency-Check, and Jacoco Code Coverage reports. 92 | 93 | To run all available reports 94 | `$ mvn clean verify site -Dspotbugs.site` 95 | 96 | To run OWASP, RAT and Spotbugs, but not Jacoco 97 | `$ mvn clean compile test-compile site -Dspotbugs.site` 98 | 99 | The reports are accessible via `target/site/index.html`, under the main project, 100 | as well as each of the subprojects. (not every project has all reports) 101 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | 17 | 18 | ![logo](https://phoenix.apache.org/images/phoenix-logo-small.png) 19 | 20 | [Apache Phoenix](http://phoenix.apache.org/) enables OLTP and operational analytics in Hadoop for low latency applications. Visit the Apache Phoenix website [here](http://phoenix.apache.org/). This is the repo for the Phoenix Query Server (PQS). 21 | 22 | Copyright ©2020 [Apache Software Foundation](http://www.apache.org/). All Rights Reserved. 23 | 24 | ## Introduction 25 | 26 | The Phoenix Query Server is an JDBC over HTTP abstraction. The Phoenix Query Server proxies the standard 27 | Phoenix JDBC driver and provides a backwards-compatible wire protocol to invoke that JDBC driver. This is 28 | all done via the Apache Avatica project (sub-project of Apache Calcite). 29 | 30 | The reference client implementation for PQS is a "thin" JDBC driver which can communicate with PQS. There 31 | are drivers in other languages which exist in varying levels of maturity including Python, Golang, and .NET. 32 | 33 | The Python driver is maintained by the Phoenix project, and is available in the python-phoenixdb 34 | directory of the phoenix-queryserver repository. -------------------------------------------------------------------------------- /RELEASENOTES.md: -------------------------------------------------------------------------------- 1 | 2 | 19 | # PHOENIX queryserver-6.0.0 Release Notes 20 | 21 | These release notes cover new developer and user-facing incompatibilities, important issues, features, and major improvements. 22 | 23 | 24 | --- 25 | 26 | * [PHOENIX-6488](https://issues.apache.org/jira/browse/PHOENIX-6488) | *Major* | **Bump Avatica version to 1.18.0 in queryserver** 27 | 28 | Avatica version has been update to 1.18.0 29 | 30 | 31 | --- 32 | 33 | * [PHOENIX-6473](https://issues.apache.org/jira/browse/PHOENIX-6473) | *Major* | **Add Hadoop JMXServlet as /jmx endpoint** 34 | 35 | New HTTP endpoint is available at \/jmx to expose all read-only JMX values in JSON format. 36 | 37 | 38 | --- 39 | 40 | * [PHOENIX-5446](https://issues.apache.org/jira/browse/PHOENIX-5446) | *Major* | **Support Protobuf shaded clients (thin + thick)** 41 | 42 | **WARNING: No release note provided for this change.** 43 | 44 | 45 | --- 46 | 47 | * [PHOENIX-5772](https://issues.apache.org/jira/browse/PHOENIX-5772) | *Major* | **Streamline the kerberos logic in thin client java code** 48 | 49 | The java thin client library has been refactored. It no longer includes Hadoop libraries, and uses the Java SE Kerberos implementation directly. 50 | 51 | The sqlline library has also been removed from the thin client JAR. 52 | 53 | The standalone sqlline JAR is now included in the lib/ directory, and is now added to the classpath by the sqlline-thin.py script. 54 | 55 | Some default parameters that were picked up from hbase-site.xml by the java thin client are now also handled by sqlline-thin.py 56 | 57 | 58 | 59 | -------------------------------------------------------------------------------- /bin/log4j2.properties: -------------------------------------------------------------------------------- 1 | #/** 2 | # * Licensed to the Apache Software Foundation (ASF) under one 3 | # * or more contributor license agreements. See the NOTICE file 4 | # * distributed with this work for additional information 5 | # * regarding copyright ownership. The ASF licenses this file 6 | # * to you under the Apache License, Version 2.0 (the 7 | # * "License"); you may not use this file except in compliance 8 | # * with the License. You may obtain a copy of the License at 9 | # * 10 | # * http://www.apache.org/licenses/LICENSE-2.0 11 | # * 12 | # * Unless required by applicable law or agreed to in writing, software 13 | # * distributed under the License is distributed on an "AS IS" BASIS, 14 | # * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 15 | # * See the License for the specific language governing permissions and 16 | # * limitations under the License. 17 | # */ 18 | 19 | # This config is used by sqlline, pherf and psql 20 | 21 | status = warn 22 | dest = err 23 | name = PropertiesConfig 24 | 25 | # Console appender 26 | appender.console.type = Console 27 | appender.console.target = SYSTEM_ERR 28 | appender.console.name = console 29 | appender.console.layout.type = PatternLayout 30 | appender.console.layout.pattern = %d{ISO8601} %-5p [%t] %c{2}: %.1000m%n 31 | 32 | # Not used by default 33 | # Daily Rolling File Appender 34 | appender.DRFA.type = RollingFile 35 | appender.DRFA.name = DRFA 36 | appender.DRFA.fileName = ${sys:psql.log.dir:-.}/${sys:psql.log.file:-psql.log} 37 | appender.DRFA.filePattern = ${sys:psql.log.dir:-.}/${sys:psql.log.file:-psql.log}.%d{yyyy-MM-dd} 38 | appender.DRFA.createOnDemand = true 39 | appender.DRFA.layout.type = PatternLayout 40 | appender.DRFA.layout.pattern = %d{ISO8601} %-5p [%t] %c{2}: %.1000m%n 41 | appender.DRFA.policies.type = Policies 42 | appender.DRFA.policies.time.type = TimeBasedTriggeringPolicy 43 | appender.DRFA.policies.time.interval = 1 44 | appender.DRFA.policies.time.modulate = true 45 | appender.DRFA.policies.size.type = SizeBasedTriggeringPolicy 46 | appender.DRFA.policies.size.size = ${sys:psql.log.maxfilesize:-256MB} 47 | appender.DRFA.strategy.type = DefaultRolloverStrategy 48 | appender.DRFA.strategy.max = ${sys:psql.log.maxbackupindex:-20} 49 | 50 | # Null Appender 51 | appender.NullAppender.type = Null 52 | appender.NullAppender.name = NullAppender 53 | 54 | rootLogger = ${sys:psql.root.logger:-WARN,console} 55 | 56 | # Custom Logging levels 57 | logger.zookeeper.name = org.apache.zookeeper 58 | logger.zookeeper.level = ERROR 59 | 60 | logger.hbase_zk_rzk.name = org.apache.hadoop.hbase.zookeeper.RecoverableZooKeeper 61 | logger.hbase_zk_rzk.level = ERROR 62 | 63 | logger.hbase_zk_zku.name = org.apache.hadoop.hbase.zookeeper.ZKUtil 64 | logger.hbase_zk_zku.level = ERROR 65 | 66 | logger.hbase_conf.name = org.apache.hadoop.hbase.HBaseConfiguration 67 | logger.hbase_conf.level = ERROR 68 | 69 | 70 | # query server custom logging levels 71 | logger.calcite_avatica.name = org.apache.calcite.avatica 72 | logger.calcite_avatica.level = INFO 73 | 74 | logger.phoenix_queryserver_server.name = org.apache.phoenix.queryserver.server 75 | logger.phoenix_queryserver_server.level = INFO 76 | 77 | logger.eclipse_jetty.name = org.eclipse.jetty.server 78 | logger.eclipse_jetty.level = INFO 79 | -------------------------------------------------------------------------------- /dev/code-coverage/README.md: -------------------------------------------------------------------------------- 1 | 18 | 19 | # Code analysis 20 | 21 | The `run-coverage.sh` script runs maven with the **codecoverage** profile 22 | which generates the test coverage data for the java classes. 23 | If the required parameters are given it also runs the sonar code analysis 24 | and uploads the results to the given SonarQube Server. 25 | 26 | ## Running code analysis 27 | 28 | After running the script the reports generated by the JaCoCo code coverage 29 | library can be found in the modules under the `/target/site/jacoco/` folder. 30 | 31 | Here is how you can generate the code coverage report: 32 | 33 | ```./dev/code-coverage/run-coverage.sh``` 34 | 35 | ## Publishing coverage results to SonarQube 36 | 37 | The required parameters for publishing the results to SonarQube are: 38 | 39 | - host URL, 40 | - login credentials, 41 | - project key 42 | 43 | The project name is an optional parameter. 44 | 45 | Here is an example command for running and publishing the coverage data: 46 | 47 | `./dev/code-coverage/run-coverage.sh -l ProjectCredentials 48 | -u https://exampleserver.com -k Project_Key -n Project_Name` 49 | -------------------------------------------------------------------------------- /dev/code-coverage/run-coverage.sh: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | # Licensed under the Apache License, Version 2.0 (the "License"); 3 | # you may not use this file except in compliance with the License. 4 | # You may obtain a copy of the License at 5 | # 6 | # http://www.apache.org/licenses/LICENSE-2.0 7 | # 8 | # Unless required by applicable law or agreed to in writing, software 9 | # distributed under the License is distributed on an "AS IS" BASIS, 10 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 11 | # See the License for the specific language governing permissions and 12 | # limitations under the License. 13 | 14 | usage() { 15 | echo 16 | echo "options:" 17 | echo " -h Display help" 18 | echo " -u SonarQube Host URL" 19 | echo " -l SonarQube Login Credentials" 20 | echo " -k SonarQube Project Key" 21 | echo " -n SonarQube Project Name" 22 | echo " -t Number of threads (example: 1 or 2C)." 23 | echo 24 | echo "Important:" 25 | echo " The required parameters for publishing the coverage results to SonarQube:" 26 | echo " - Host URL" 27 | echo " - Login Credentials" 28 | echo " - Project Key" 29 | echo 30 | } 31 | 32 | execute() { 33 | SCRIPT_DIR="$(cd -- "$(dirname -- "${BASH_SOURCE[0]}")" &>/dev/null && pwd)" 34 | MAIN_POM="${SCRIPT_DIR}/../../pom.xml" 35 | # Check the syntax for the THREAD_COUNT variable 36 | if [[ "$THREAD_COUNT" =~ ^[0-9]+([.][0-9]+)?$ ]] || [[ "$THREAD_COUNT" =~ ^[0-9]+([.][0-9]+)+[C]?$ ]]; then 37 | THREADS="${THREAD_COUNT}" 38 | else 39 | THREADS=1 40 | fi 41 | 42 | mvn -B -e -f "$MAIN_POM" clean verify -Pcodecoverage -fn -Dmaven.javadoc.skip=true -DskipShade -T "$THREADS" 43 | 44 | # If the required parameters are given, the code coverage results are uploaded to the SonarQube Server 45 | if [ -n "$SONAR_LOGIN" ] && [ -n "$SONAR_PROJECT_KEY" ] && [ -n "$SONAR_URL" ]; then 46 | mvn -B -e -Pcodecoverage -f "$MAIN_POM" sonar:sonar -Dsonar.projectName="$SONAR_PROJECT_NAME" \ 47 | -Dsonar.host.url="$SONAR_URL" -Dsonar.login="$SONAR_LOGIN" -Dsonar.projectKey="$SONAR_PROJECT_KEY" -T "$THREADS" 48 | fi 49 | } 50 | 51 | while getopts ":u:l:k:n:t:h" option; do 52 | case $option in 53 | u) SONAR_URL=${OPTARG:-} ;; 54 | l) SONAR_LOGIN=${OPTARG:-} ;; 55 | k) SONAR_PROJECT_KEY=${OPTARG:-} ;; 56 | n) SONAR_PROJECT_NAME=${OPTARG:-} ;; 57 | t) THREAD_COUNT=${OPTARG:-} ;; 58 | h) # Display usage 59 | usage 60 | exit 61 | ;; 62 | \?) # Invalid option 63 | echo "Error: Invalid option" 64 | exit 65 | ;; 66 | esac 67 | done 68 | 69 | # Start code analysis 70 | execute 71 | -------------------------------------------------------------------------------- /phoenix-queryserver-assembly/src/assembly/cluster.xml: -------------------------------------------------------------------------------- 1 | 2 | 20 | 22 | cluster 23 | / 24 | 25 | tar.gz 26 | 27 | 28 | 29 | ${project.basedir}/../bin 30 | phoenix-queryserver-${project.parent.version}/bin 31 | 32 | __pycache__ 33 | __pycache__/* 34 | *.pyc 35 | 36 | 37 | 38 | ${project.basedir}/../phoenix-queryserver/target 39 | phoenix-queryserver-${project.parent.version}/ 40 | 41 | phoenix-queryserver-${project.parent.version}.jar 42 | 43 | 44 | 45 | ${project.basedir}/../phoenix-queryserver-client/target 46 | phoenix-queryserver-${project.parent.version}/ 47 | 48 | phoenix-queryserver-client-${project.parent.version}.jar 49 | 50 | 51 | 52 | ${project.build.directory}/maven-repo 53 | phoenix-queryserver-${project.parent.version}/maven 54 | 55 | 56 | 57 | 58 | false 59 | phoenix-queryserver-${project.parent.version}/lib 60 | 61 | sqlline:sqlline:jar:jar-with-dependencies 62 | org.apache.logging.log4j:log4j-slf4j-impl 63 | org.apache.logging.log4j:log4j-api 64 | org.apache.logging.log4j:log4j-core 65 | org.apache.logging.log4j:log4j-1.2-api 66 | org.slf4j:jcl-over-slf4j 67 | 68 | 69 | 70 | false 71 | phoenix-queryserver-${project.parent.version}/ 72 | 73 | org.apache.phoenix:${phoenix.client.artifactid}:jar 74 | 75 | 76 | 77 | 78 | -------------------------------------------------------------------------------- /phoenix-queryserver-assembly/src/scripts/replace_jars_with_symlinks.sh: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | # 3 | ############################################################################ 4 | # 5 | # Licensed to the Apache Software Foundation (ASF) under one 6 | # or more contributor license agreements. See the NOTICE file 7 | # distributed with this work for additional information 8 | # regarding copyright ownership. The ASF licenses this file 9 | # to you under the Apache License, Version 2.0 (the 10 | # "License"); you may not use this file except in compliance 11 | # with the License. You may obtain a copy of the License at 12 | # 13 | # http://www.apache.org/licenses/LICENSE-2.0 14 | # 15 | # Unless required by applicable law or agreed to in writing, software 16 | # distributed under the License is distributed on an "AS IS" BASIS, 17 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 18 | # See the License for the specific language governing permissions and 19 | # limitations under the License. 20 | # 21 | ############################################################################ 22 | 23 | REPO_ROOT=$1 24 | for linksource in $(find $REPO_ROOT -name \*.jar); do 25 | linkfile=$(basename $linksource) 26 | linkdir=$(dirname $linksource) 27 | targetdir=$(realpath $REPO_ROOT/.. --relative-to=$linkdir) 28 | target="$targetdir/$linkfile" 29 | cd $linkdir 30 | #The copy is necessary, as maven won't add dangling symlinks to the assmebly 31 | cp $linkfile $target 32 | ln -sf $target $linkfile 33 | done -------------------------------------------------------------------------------- /phoenix-queryserver-client/pom.xml: -------------------------------------------------------------------------------- 1 | 2 | 22 | 23 | 26 | 27 | 4.0.0 28 | 29 | 30 | org.apache.phoenix 31 | phoenix-queryserver-parent 32 | 6.0.1-SNAPSHOT 33 | 34 | 35 | phoenix-queryserver-client 36 | Phoenix Query Server Client 37 | A thin JDBC client for interacting with the query server 38 | 39 | 40 | 41 | The Apache Software License, Version 2.0 42 | http://www.apache.org/licenses/LICENSE-2.0.txt 43 | repo 44 | 45 | 46 | 47 | 48 | 49 | Apache Software Foundation 50 | http://www.apache.org 51 | 52 | 53 | 54 | ${project.basedir}/.. 55 | 56 | 57 | 58 | 59 | 60 | maven-assembly-plugin 61 | 62 | true 63 | 64 | 65 | 66 | org.apache.maven.plugins 67 | maven-shade-plugin 68 | 69 | 70 | thin-client 71 | package 72 | 73 | shade 74 | 75 | 76 | false 77 | 78 | 80 | README.md 81 | ${project.basedir}/../README.md 82 | 83 | 85 | LICENSE.txt 86 | ${project.basedir}/../LICENSE 87 | 88 | 90 | NOTICE 91 | ${project.basedir}/../NOTICE 92 | 93 | 94 | 95 | 96 | 97 | *:* 98 | 99 | META-INF/*.SF 100 | META-INF/*.DSA 101 | META-INF/*.RSA 102 | META-INF/license/* 103 | LICENSE.* 104 | NOTICE.* 105 | 106 | 107 | 108 | 109 | 110 | 111 | 112 | 113 | org.apache.rat 114 | apache-rat-plugin 115 | 116 | 117 | src/main/resources/META-INF/services/java.sql.Driver 118 | 119 | 120 | 121 | 122 | 123 | 124 | 125 | 126 | org.apache.calcite.avatica 127 | avatica 128 | 129 | 130 | sqlline 131 | sqlline 132 | provided 133 | jar-with-dependencies 134 | 135 | 136 | 137 | -------------------------------------------------------------------------------- /phoenix-queryserver-client/src/main/java/org/apache/phoenix/queryserver/client/Driver.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Licensed to the Apache Software Foundation (ASF) under one 3 | * or more contributor license agreements. See the NOTICE file 4 | * distributed with this work for additional information 5 | * regarding copyright ownership. The ASF licenses this file 6 | * to you under the Apache License, Version 2.0 (the 7 | * "License"); you may not use this file except in compliance 8 | * with the License. You may obtain a copy of the License at 9 | * 10 | * http://www.apache.org/licenses/LICENSE-2.0 11 | * 12 | * Unless required by applicable law or agreed to in writing, software 13 | * distributed under the License is distributed on an "AS IS" BASIS, 14 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 15 | * See the License for the specific language governing permissions and 16 | * limitations under the License. 17 | */ 18 | package org.apache.phoenix.queryserver.client; 19 | 20 | import org.apache.calcite.avatica.DriverVersion; 21 | 22 | public class Driver extends org.apache.calcite.avatica.remote.Driver { 23 | 24 | public static final String CONNECT_STRING_PREFIX = "jdbc:phoenix:thin:"; 25 | 26 | static { 27 | new Driver().register(); 28 | } 29 | 30 | public Driver() { 31 | super(); 32 | } 33 | 34 | @Override 35 | protected DriverVersion createDriverVersion() { 36 | return DriverVersion.load( 37 | Driver.class, 38 | "org-apache-phoenix-remote-jdbc.properties", 39 | "Phoenix Remote JDBC Driver", 40 | "unknown version", 41 | "Phoenix", 42 | "unknown version"); 43 | } 44 | 45 | @Override 46 | protected String getConnectStringPrefix() { 47 | return CONNECT_STRING_PREFIX; 48 | } 49 | } 50 | -------------------------------------------------------------------------------- /phoenix-queryserver-client/src/main/java/org/apache/phoenix/queryserver/client/KerberosLoginFromTicketCache.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Licensed to the Apache Software Foundation (ASF) under one 3 | * or more contributor license agreements. See the NOTICE file 4 | * distributed with this work for additional information 5 | * regarding copyright ownership. The ASF licenses this file 6 | * to you under the Apache License, Version 2.0 (the 7 | * "License"); you may not use this file except in compliance 8 | * with the License. You may obtain a copy of the License at 9 | * 10 | * http://www.apache.org/licenses/LICENSE-2.0 11 | * 12 | * Unless required by applicable law or agreed to in writing, software 13 | * distributed under the License is distributed on an "AS IS" BASIS, 14 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 15 | * See the License for the specific language governing permissions and 16 | * limitations under the License. 17 | */ 18 | package org.apache.phoenix.queryserver.client; 19 | 20 | import java.io.IOException; 21 | import java.util.HashMap; 22 | 23 | import javax.security.auth.Subject; 24 | import javax.security.auth.callback.Callback; 25 | import javax.security.auth.callback.CallbackHandler; 26 | import javax.security.auth.callback.UnsupportedCallbackException; 27 | import javax.security.auth.login.AppConfigurationEntry; 28 | import javax.security.auth.login.Configuration; 29 | import javax.security.auth.login.LoginContext; 30 | import javax.security.auth.login.LoginException; 31 | 32 | public class KerberosLoginFromTicketCache { 33 | 34 | public static Subject login() throws LoginException { 35 | 36 | Configuration kerberosConfig = new KerberosConfiguration(); 37 | Subject subject = new Subject(); 38 | 39 | LoginContext lc = new LoginContext("PhoenixThinClient", subject, new CallbackHandler() { 40 | @Override 41 | public void handle(Callback[] callbacks) 42 | throws IOException, UnsupportedCallbackException { 43 | throw new UnsupportedCallbackException(callbacks[0], 44 | "Only ticket cache is supported"); 45 | } 46 | }, kerberosConfig); 47 | 48 | lc.login(); 49 | return subject; 50 | } 51 | 52 | private static class KerberosConfiguration extends Configuration { 53 | private static final String IBM_KRB5_LOGIN_MODULE = 54 | "com.ibm.security.auth.module.Krb5LoginModule"; 55 | private static final String SUN_KRB5_LOGIN_MODULE = 56 | "com.sun.security.auth.module.Krb5LoginModule"; 57 | 58 | private static final String JAVA_VENDOR_NAME = System.getProperty("java.vendor"); 59 | private static final boolean IS_IBM_JAVA = JAVA_VENDOR_NAME.contains("IBM"); 60 | 61 | @Override 62 | public AppConfigurationEntry[] getAppConfigurationEntry(String name) { 63 | HashMap options = new HashMap<>(); 64 | 65 | if(IS_IBM_JAVA) { 66 | //Also see https://www.ibm.com/support/pages/how-enable-strong-encryption-128-bit 67 | 68 | // This is inferior to the sun class, as it won't work if the kerberos and unix 69 | // users don't match, while that one take any principal from the cache 70 | options.put("principal", System.getProperty("user.name")); 71 | options.put("useDefaultCcache", "true"); 72 | return new AppConfigurationEntry[] { new AppConfigurationEntry( 73 | IBM_KRB5_LOGIN_MODULE, AppConfigurationEntry.LoginModuleControlFlag.REQUIRED, 74 | options) }; 75 | } else { 76 | options.put("useTicketCache", "true"); 77 | options.put("doNotPrompt", "true"); 78 | return new AppConfigurationEntry[] { new AppConfigurationEntry( 79 | SUN_KRB5_LOGIN_MODULE, AppConfigurationEntry.LoginModuleControlFlag.REQUIRED, 80 | options) }; 81 | } 82 | } 83 | } 84 | 85 | } 86 | -------------------------------------------------------------------------------- /phoenix-queryserver-client/src/main/java/org/apache/phoenix/queryserver/client/SqllineWrapper.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Licensed to the Apache Software Foundation (ASF) under one or more 3 | * contributor license agreements. See the NOTICE file distributed with 4 | * this work for additional information regarding copyright ownership. 5 | * The ASF licenses this file to you under the Apache License, Version 2.0 6 | * (the "License"); you may not use this file except in compliance with 7 | * the License. You may obtain a copy of the License at 8 | * 9 | * http://www.apache.org/licenses/LICENSE-2.0 10 | * 11 | * Unless required by applicable law or agreed to in writing, software 12 | * distributed under the License is distributed on an "AS IS" BASIS, 13 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 | * See the License for the specific language governing permissions and 15 | * limitations under the License. 16 | */ 17 | package org.apache.phoenix.queryserver.client; 18 | 19 | import java.security.PrivilegedExceptionAction; 20 | 21 | import javax.security.auth.Subject; 22 | import javax.security.auth.login.LoginException; 23 | 24 | import sqlline.SqlLine; 25 | 26 | /** 27 | * Utility class which automatically performs a Kerberos login and then launches sqlline. Tries to 28 | * make a pre-populated ticket cache (via kinit before launching) transparently work. 29 | */ 30 | public class SqllineWrapper { 31 | 32 | public static String getUrl(String[] args) { 33 | for (int i = 0; i < args.length; i++) { 34 | String arg = args[i]; 35 | args[i] = arg; 36 | if (arg.equals("-u") && args.length > i+1) { 37 | return args[i+1]; 38 | } 39 | } 40 | return null; 41 | } 42 | 43 | public static void main(String[] args) throws Exception { 44 | String url = getUrl(args); 45 | 46 | if(url.contains(";authentication=SPNEGO") && !url.contains(";principal=")) { 47 | try { 48 | Subject subject = KerberosLoginFromTicketCache.login(); 49 | System.out.println("Kerberos login from ticket cache successful"); 50 | Subject.doAs(subject, new PrivilegedExceptionAction() { 51 | @Override 52 | public Void run() throws Exception { 53 | SqlLine.main(args); 54 | return null; 55 | } 56 | }); 57 | return; 58 | } catch (LoginException e) { 59 | System.out.print("Kerberos login from ticket cache not successful"); 60 | e.printStackTrace(); 61 | } 62 | } 63 | 64 | SqlLine.main(args); 65 | } 66 | 67 | } 68 | -------------------------------------------------------------------------------- /phoenix-queryserver-client/src/main/resources/META-INF/services/java.sql.Driver: -------------------------------------------------------------------------------- 1 | org.apache.phoenix.queryserver.client.Driver 2 | -------------------------------------------------------------------------------- /phoenix-queryserver-client/src/main/resources/version/org-apache-phoenix-remote-jdbc.properties: -------------------------------------------------------------------------------- 1 | # Licensed to the Apache Software Foundation (ASF) under one or more 2 | # contributor license agreements. See the NOTICE file distributed with 3 | # this work for additional information regarding copyright ownership. 4 | # The ASF licenses this file to you under the Apache License, Version 2.0 5 | # (the "License"); you may not use this file except in compliance with 6 | # the License. You may obtain a copy of the License at 7 | # 8 | # http://www.apache.org/licenses/LICENSE-2.0 9 | # 10 | # Unless required by applicable law or agreed to in writing, software 11 | # distributed under the License is distributed on an "AS IS" BASIS, 12 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | # See the License for the specific language governing permissions and 14 | # limitations under the License. 15 | # 16 | driver.name=Apache Phoenix Remote JDBC Driver 17 | driver.version=${pom.version} 18 | product.name=Apache Phoenix 19 | product.version=${pom.version} 20 | jdbc.compliant=true 21 | driver.version.major=${version.major} 22 | driver.version.minor=${version.minor} 23 | database.version.major=${version.major} 24 | database.version.minor=${version.minor} 25 | build.timestamp=${build.timestamp} 26 | -------------------------------------------------------------------------------- /phoenix-queryserver-it/src/it/bin/test_phoenixdb.py: -------------------------------------------------------------------------------- 1 | ############################################################################ 2 | # 3 | # Licensed to the Apache Software Foundation (ASF) under one 4 | # or more contributor license agreements. See the NOTICE file 5 | # distributed with this work for additional information 6 | # regarding copyright ownership. The ASF licenses this file 7 | # to you under the Apache License, Version 2.0 (the 8 | # "License"); you may not use this file except in compliance 9 | # with the License. You may obtain a copy of the License at 10 | # 11 | # http://www.apache.org/licenses/LICENSE-2.0 12 | # 13 | # Unless required by applicable law or agreed to in writing, software 14 | # distributed under the License is distributed on an "AS IS" BASIS, 15 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 16 | # See the License for the specific language governing permissions and 17 | # limitations under the License. 18 | # 19 | ############################################################################ 20 | 21 | import phoenixdb 22 | import phoenixdb.cursor 23 | import sys 24 | import os 25 | 26 | 27 | if __name__ == '__main__': 28 | database_url = os.environ.get('PHOENIXDB_TEST_DB_URL') 29 | 30 | print("CREATING PQS CONNECTION") 31 | conn = phoenixdb.connect(database_url, autocommit=True, auth="SPNEGO") 32 | cursor = conn.cursor() 33 | 34 | cursor.execute("CREATE TABLE users (id INTEGER PRIMARY KEY, username VARCHAR)") 35 | cursor.execute("UPSERT INTO users VALUES (?, ?)", (1, 'admin')) 36 | cursor.execute("UPSERT INTO users VALUES (?, ?)", (2, 'user')) 37 | cursor.execute("SELECT * FROM users") 38 | print("RESULTS") 39 | print(cursor.fetchall()) 40 | -------------------------------------------------------------------------------- /phoenix-queryserver-it/src/it/bin/test_phoenixdb.sh: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | # 3 | ############################################################################ 4 | # 5 | # Licensed to the Apache Software Foundation (ASF) under one 6 | # or more contributor license agreements. See the NOTICE file 7 | # distributed with this work for additional information 8 | # regarding copyright ownership. The ASF licenses this file 9 | # to you under the Apache License, Version 2.0 (the 10 | # "License"); you may not use this file except in compliance 11 | # with the License. You may obtain a copy of the License at 12 | # 13 | # http://www.apache.org/licenses/LICENSE-2.0 14 | # 15 | # Unless required by applicable law or agreed to in writing, software 16 | # distributed under the License is distributed on an "AS IS" BASIS, 17 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 18 | # See the License for the specific language governing permissions and 19 | # limitations under the License. 20 | # 21 | ############################################################################ 22 | 23 | set -u 24 | set -x 25 | set -e 26 | 27 | function cleanup { 28 | # Capture last command status 29 | RCODE=$? 30 | set +e 31 | set +u 32 | kdestroy 33 | rm -rf $PY_ENV_PATH 34 | exit $RCODE 35 | } 36 | 37 | trap cleanup EXIT 38 | 39 | echo "LAUNCHING SCRIPT" 40 | 41 | LOCAL_PY=$1 42 | PRINC=$2 43 | KEYTAB_LOC=$3 44 | KRB5_CFG_FILE=$4 45 | PQS_PORT=$5 46 | 47 | shift 5 48 | 49 | PY_ENV_PATH=$( mktemp -d ) 50 | 51 | virtualenv $PY_ENV_PATH 52 | 53 | pushd ${PY_ENV_PATH}/bin 54 | 55 | # conda activate does stuff with unbound variables :( 56 | set +u 57 | . ./activate "" 58 | 59 | popd 60 | 61 | set -u 62 | echo "INSTALLING COMPONENTS" 63 | pip install -e file:///${LOCAL_PY}/ 64 | 65 | export KRB5_CONFIG=$KRB5_CFG_FILE 66 | cat $KRB5_CONFIG 67 | export KRB5_TRACE=/dev/stdout 68 | 69 | echo "RUNNING KINIT" 70 | kinit -kt $KEYTAB_LOC $PRINC 71 | klist 72 | 73 | unset http_proxy 74 | unset https_proxy 75 | 76 | echo "Working Directory is ${PWD}" 77 | 78 | cat > target/krb_setup.sh << EOF 79 | #!/bin/sh 80 | export KRB5_CONFIG=$KRB5_CFG_FILE 81 | export KRB5_TRACE=/dev/stdout 82 | kinit -kt $KEYTAB_LOC $PRINC 83 | klist 84 | 85 | export PHOENIXDB_TEST_DB_URL="http://localhost:$PQS_PORT" 86 | export PHOENIXDB_TEST_DB_AUTHENTICATION="SPNEGO" 87 | 88 | EOF 89 | 90 | 91 | export PHOENIXDB_TEST_DB_URL="http://localhost:$PQS_PORT" 92 | export PHOENIXDB_TEST_DB_AUTHENTICATION="SPNEGO" 93 | 94 | echo "RUN test: $@" 95 | "$@" > >(tee -a target/python-stdout.log) 2> >(tee -a target/python-stderr.log >&2) 96 | 97 | -------------------------------------------------------------------------------- /phoenix-queryserver-it/src/it/java/org/apache/phoenix/end2end/QueryServerThread.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Licensed to the Apache Software Foundation (ASF) under one 3 | * or more contributor license agreements. See the NOTICE file 4 | * distributed with this work for additional information 5 | * regarding copyright ownership. The ASF licenses this file 6 | * to you under the Apache License, Version 2.0 (the 7 | * "License"); you may not use this file except in compliance 8 | * with the License. You may obtain a copy of the License at 9 | * 10 | * http://www.apache.org/licenses/LICENSE-2.0 11 | * 12 | * Unless required by applicable law or agreed to in writing, software 13 | * distributed under the License is distributed on an "AS IS" BASIS, 14 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 15 | * See the License for the specific language governing permissions and 16 | * limitations under the License. 17 | */ 18 | package org.apache.phoenix.end2end; 19 | 20 | import org.apache.hadoop.conf.Configuration; 21 | import org.apache.phoenix.queryserver.server.QueryServer; 22 | 23 | /** Wraps up the query server for tests. */ 24 | public class QueryServerThread extends Thread { 25 | 26 | private final QueryServer main; 27 | 28 | public QueryServerThread(String[] argv, Configuration conf) { 29 | this(argv, conf, null); 30 | } 31 | 32 | public QueryServerThread(String[] argv, Configuration conf, String name) { 33 | this(new QueryServer(argv, conf), name); 34 | } 35 | 36 | private QueryServerThread(QueryServer m, String name) { 37 | super(m, "query server" + (name == null ? "" : (" - " + name))); 38 | this.main = m; 39 | setDaemon(true); 40 | } 41 | 42 | public QueryServer getQueryServer() { 43 | return main; 44 | } 45 | } 46 | -------------------------------------------------------------------------------- /phoenix-queryserver-it/src/it/java/org/apache/phoenix/end2end/SecureQueryServerIT.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Licensed to the Apache Software Foundation (ASF) under one or more 3 | * contributor license agreements. See the NOTICE file distributed with 4 | * this work for additional information regarding copyright ownership. 5 | * The ASF licenses this file to you under the Apache License, Version 2.0 6 | * (the "License"); you may not use this file except in compliance with 7 | * the License. You may obtain a copy of the License at 8 | * 9 | * http://www.apache.org/licenses/LICENSE-2.0 10 | * 11 | * Unless required by applicable law or agreed to in writing, software 12 | * distributed under the License is distributed on an "AS IS" BASIS, 13 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 | * See the License for the specific language governing permissions and 15 | * limitations under the License. 16 | */ 17 | package org.apache.phoenix.end2end; 18 | 19 | import static org.junit.Assert.assertEquals; 20 | import static org.junit.Assert.assertFalse; 21 | import static org.junit.Assert.assertTrue; 22 | 23 | import java.io.File; 24 | import java.security.PrivilegedExceptionAction; 25 | import java.sql.DriverManager; 26 | import java.sql.ResultSet; 27 | import java.sql.Statement; 28 | import java.util.Arrays; 29 | import java.util.Map.Entry; 30 | 31 | import org.apache.hadoop.conf.Configuration; 32 | import org.apache.hadoop.hbase.coprocessor.CoprocessorHost; 33 | import org.apache.hadoop.hbase.security.token.TokenProvider; 34 | import org.apache.hadoop.security.UserGroupInformation; 35 | import org.junit.AfterClass; 36 | import org.junit.Test; 37 | import org.junit.experimental.categories.Category; 38 | import org.junit.runner.RunWith; 39 | import org.junit.runners.Parameterized; 40 | import org.junit.runners.Parameterized.Parameters; 41 | import org.slf4j.Logger; 42 | import org.slf4j.LoggerFactory; 43 | 44 | @RunWith(Parameterized.class) 45 | @Category(NeedsOwnMiniClusterTest.class) 46 | public class SecureQueryServerIT { 47 | private static final Logger LOG = LoggerFactory.getLogger(SecureQueryServerIT.class); 48 | private static QueryServerEnvironment environment; 49 | 50 | @Parameters(name = "tls = {0}") 51 | public static synchronized Iterable data() { 52 | return Arrays.asList(new Boolean[] {false, true}); 53 | } 54 | 55 | public SecureQueryServerIT(Boolean tls) throws Exception { 56 | //Clean up previous environment if any (Junit 4.13 @BeforeParam / @AfterParam would be an alternative) 57 | if(environment != null) { 58 | stopEnvironment(); 59 | } 60 | 61 | final Configuration conf = new Configuration(); 62 | conf.setStrings(CoprocessorHost.REGION_COPROCESSOR_CONF_KEY, 63 | TokenProvider.class.getName()); 64 | environment = new QueryServerEnvironment(conf, 3, tls); 65 | } 66 | 67 | 68 | @AfterClass 69 | public static synchronized void stopEnvironment() throws Exception { 70 | environment.stop(); 71 | } 72 | 73 | @Test 74 | public void testBasicReadWrite() throws Exception { 75 | final Entry user1 = environment.getUser(1); 76 | UserGroupInformation user1Ugi = UserGroupInformation.loginUserFromKeytabAndReturnUGI(user1.getKey(), user1.getValue().getAbsolutePath()); 77 | user1Ugi.doAs(new PrivilegedExceptionAction() { 78 | @Override public Void run() throws Exception { 79 | // Phoenix 80 | final String tableName = "phx_table1"; 81 | try (java.sql.Connection conn = DriverManager.getConnection(environment.getPqsUrl()); 82 | Statement stmt = conn.createStatement()) { 83 | conn.setAutoCommit(true); 84 | assertFalse(stmt.execute("CREATE TABLE " + tableName + "(pk integer not null primary key)")); 85 | final int numRows = 5; 86 | for (int i = 0; i < numRows; i++) { 87 | assertEquals(1, stmt.executeUpdate("UPSERT INTO " + tableName + " values(" + i + ")")); 88 | } 89 | 90 | try (ResultSet rs = stmt.executeQuery("SELECT * FROM " + tableName)) { 91 | for (int i = 0; i < numRows; i++) { 92 | assertTrue(rs.next()); 93 | assertEquals(i, rs.getInt(1)); 94 | } 95 | assertFalse(rs.next()); 96 | } 97 | } 98 | return null; 99 | } 100 | }); 101 | } 102 | } 103 | -------------------------------------------------------------------------------- /phoenix-queryserver-it/src/it/java/org/apache/phoenix/end2end/ServerCustomizersIT.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Licensed to the Apache Software Foundation (ASF) under one or more 3 | * contributor license agreements. See the NOTICE file distributed with 4 | * this work for additional information regarding copyright ownership. 5 | * The ASF licenses this file to you under the Apache License, Version 2.0 6 | * (the "License"); you may not use this file except in compliance with 7 | * the License. You may obtain a copy of the License at 8 | * 9 | * http://www.apache.org/licenses/LICENSE-2.0 10 | * 11 | * Unless required by applicable law or agreed to in writing, software 12 | * distributed under the License is distributed on an "AS IS" BASIS, 13 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 | * See the License for the specific language governing permissions and 15 | * limitations under the License. 16 | */ 17 | package org.apache.phoenix.end2end; 18 | 19 | import java.sql.Connection; 20 | import java.sql.DriverManager; 21 | import java.sql.Statement; 22 | import java.util.HashMap; 23 | import java.util.Map; 24 | 25 | import org.apache.hadoop.conf.Configuration; 26 | import org.apache.phoenix.query.BaseTest; 27 | import org.apache.phoenix.queryserver.QueryServerProperties; 28 | import org.apache.phoenix.queryserver.server.ServerCustomizersFactory; 29 | import org.apache.phoenix.queryserver.server.customizers.BasicAuthenticationServerCustomizer; 30 | import org.apache.phoenix.queryserver.server.customizers.BasicAuthenticationServerCustomizer.BasicAuthServerCustomizerFactory; 31 | import org.apache.phoenix.util.InstanceResolver; 32 | import org.apache.phoenix.util.ReadOnlyProps; 33 | import org.junit.AfterClass; 34 | import org.junit.Assert; 35 | import org.junit.BeforeClass; 36 | import org.junit.Rule; 37 | import org.junit.Test; 38 | import org.junit.rules.ExpectedException; 39 | import org.slf4j.Logger; 40 | import org.slf4j.LoggerFactory; 41 | 42 | public class ServerCustomizersIT extends BaseTest { 43 | private static final Logger LOG = LoggerFactory.getLogger(ServerCustomizersIT.class); 44 | private static final String USER_NOT_AUTHORIZED = "user1"; 45 | 46 | private static QueryServerTestUtil PQS_UTIL; 47 | 48 | @Rule 49 | public ExpectedException expected = ExpectedException.none(); 50 | 51 | @BeforeClass 52 | public static synchronized void setup() throws Exception { 53 | setUpTestDriver(ReadOnlyProps.EMPTY_PROPS); 54 | 55 | Configuration conf = config; 56 | if(System.getProperty("do.not.randomize.pqs.port") == null) { 57 | conf.setInt(QueryServerProperties.QUERY_SERVER_HTTP_PORT_ATTRIB, 0); 58 | } 59 | PQS_UTIL = new QueryServerTestUtil(conf); 60 | PQS_UTIL.startLocalHBaseCluster(ServerCustomizersIT.class); 61 | // Register a test jetty server customizer 62 | InstanceResolver.clearSingletons(); 63 | InstanceResolver.getSingleton(ServerCustomizersFactory.class, new BasicAuthServerCustomizerFactory()); 64 | PQS_UTIL.startQueryServer(); 65 | } 66 | 67 | @AfterClass 68 | public static synchronized void teardown() throws Exception { 69 | // Remove custom singletons for future tests 70 | InstanceResolver.clearSingletons(); 71 | if (PQS_UTIL != null) { 72 | PQS_UTIL.stopQueryServer(); 73 | PQS_UTIL.stopLocalHBaseCluster(); 74 | } 75 | } 76 | 77 | @Test 78 | public void testUserAuthorized() throws Exception { 79 | try (Connection conn = DriverManager.getConnection(PQS_UTIL.getUrl( 80 | getBasicAuthParams(BasicAuthenticationServerCustomizer.USER_AUTHORIZED))); 81 | Statement stmt = conn.createStatement()) { 82 | Assert.assertFalse("user3 should have access", stmt.execute( 83 | "create table "+ServerCustomizersIT.class.getSimpleName()+" (pk integer not null primary key)")); 84 | } 85 | } 86 | 87 | @Test 88 | public void testUserNotAuthorized() throws Exception { 89 | expected.expect(RuntimeException.class); 90 | expected.expectMessage("HTTP/401"); 91 | try (Connection conn = DriverManager.getConnection(PQS_UTIL.getUrl( 92 | getBasicAuthParams(USER_NOT_AUTHORIZED))); 93 | Statement stmt = conn.createStatement()) { 94 | Assert.assertFalse(stmt.execute( 95 | "select access from database")); 96 | } 97 | } 98 | 99 | private Map getBasicAuthParams(String user) { 100 | Map params = new HashMap<>(); 101 | params.put("authentication", "BASIC"); 102 | params.put("avatica_user", user); 103 | params.put("avatica_password", BasicAuthenticationServerCustomizer.USER_PW); 104 | return params; 105 | } 106 | } 107 | -------------------------------------------------------------------------------- /phoenix-queryserver-it/src/it/resources/hbase-site.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 22 | 23 | 24 | hbase.regionserver.wal.codec 25 | org.apache.hadoop.hbase.regionserver.wal.IndexedWALEditCodec 26 | 27 | 28 | phoenix.query.applyTimeZoneDisplacement 29 | true 30 | 31 | 32 | -------------------------------------------------------------------------------- /phoenix-queryserver-load-balancer/pom.xml: -------------------------------------------------------------------------------- 1 | 2 | 22 | 23 | 26 | 4.0.0 27 | 28 | org.apache.phoenix 29 | phoenix-queryserver-parent 30 | 6.0.1-SNAPSHOT 31 | 32 | phoenix-queryserver-load-balancer 33 | Phoenix Query Server Load Balancer 34 | A Load balancer which routes calls to Phoenix Query Server 35 | 36 | 37 | 38 | 39 | org.apache.maven.plugins 40 | maven-jar-plugin 41 | 42 | 43 | prepare-package 44 | 45 | test-jar 46 | 47 | 48 | 49 | 50 | true 51 | 52 | 53 | 54 | maven-source-plugin 55 | 56 | 57 | attach-test-sources 58 | prepare-package 59 | 60 | test-jar-no-fork 61 | 62 | 63 | 64 | 65 | 66 | org.apache.maven.plugins 67 | maven-dependency-plugin 68 | 69 | 70 | 71 | 72 | org.slf4j:slf4j-api 73 | 74 | 75 | 76 | 77 | 78 | org.apache.rat 79 | apache-rat-plugin 80 | 81 | 82 | src/main/resources/META-INF/services/org.apache.phoenix.loadbalancer.service.LoadBalanceZookeeperConf 83 | src/main/resources/META-INF/services/org.apache.phoenix.queryserver.register.Registry 84 | 85 | 86 | 87 | 88 | 89 | 90 | 91 | 92 | org.apache.phoenix 93 | phoenix-queryserver 94 | 95 | 96 | org.apache.hbase 97 | hbase-common 98 | 99 | 100 | org.apache.hadoop 101 | hadoop-common 102 | 103 | 104 | org.apache.zookeeper 105 | zookeeper 106 | 107 | 108 | org.apache.zookeeper 109 | zookeeper-jute 110 | 111 | 112 | org.apache.curator 113 | curator-client 114 | 115 | 116 | org.apache.curator 117 | curator-recipes 118 | 119 | 120 | org.apache.curator 121 | curator-framework 122 | 123 | 124 | org.slf4j 125 | slf4j-api 126 | 127 | 128 | 129 | 130 | junit 131 | junit 132 | test 133 | 134 | 135 | org.apache.curator 136 | curator-test 137 | test 138 | 139 | 140 | 141 | 142 | -------------------------------------------------------------------------------- /phoenix-queryserver-load-balancer/src/main/java/org/apache/phoenix/loadbalancer/service/LoadBalanceZookeeperConfImpl.java: -------------------------------------------------------------------------------- 1 | /** 2 | * 3 | * Licensed to the Apache Software Foundation (ASF) under one 4 | * or more contributor license agreements. See the NOTICE file 5 | * distributed with this work for additional information 6 | * regarding copyright ownership. The ASF licenses this file 7 | * to you under the Apache License, Version 2.0 (the 8 | * "License"); you may not use this file except in compliance 9 | * with the License. You may obtain a copy of the License at 10 | * 11 | * http://www.apache.org/licenses/LICENSE-2.0 12 | * 13 | * Unless required by applicable law or agreed to in writing, software 14 | * distributed under the License is distributed on an "AS IS" BASIS, 15 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 16 | * See the License for the specific language governing permissions and 17 | * limitations under the License. 18 | */ 19 | 20 | package org.apache.phoenix.loadbalancer.service; 21 | 22 | import org.apache.hadoop.conf.Configuration; 23 | import org.apache.hadoop.hbase.HBaseConfiguration; 24 | import org.apache.hadoop.hbase.zookeeper.ZKConfig; 25 | import org.apache.phoenix.queryserver.QueryServerOptions; 26 | import org.apache.phoenix.queryserver.QueryServerProperties; 27 | import org.apache.phoenix.util.HostAndPort; 28 | import org.apache.zookeeper.ZooDefs; 29 | import org.apache.zookeeper.data.ACL; 30 | import org.apache.zookeeper.data.Id; 31 | 32 | import java.util.Arrays; 33 | import java.util.List; 34 | 35 | 36 | 37 | public class LoadBalanceZookeeperConfImpl implements LoadBalanceZookeeperConf { 38 | 39 | private Configuration configuration; 40 | 41 | public LoadBalanceZookeeperConfImpl() { 42 | this.configuration = HBaseConfiguration.create(); 43 | } 44 | 45 | public LoadBalanceZookeeperConfImpl(Configuration configuration) { 46 | this.configuration = configuration; 47 | } 48 | 49 | //@VisibleForTesting 50 | public void setConfiguration(Configuration configuration) { 51 | this.configuration = configuration; 52 | } 53 | 54 | @Override 55 | public String getQueryServerBasePath(){ 56 | return configuration.get(QueryServerProperties.PHOENIX_QUERY_SERVER_CLUSTER_BASE_PATH, 57 | QueryServerOptions.DEFAULT_PHOENIX_QUERY_SERVER_CLUSTER_BASE_PATH); 58 | } 59 | 60 | @Override 61 | public String getServiceName(){ 62 | return configuration.get(QueryServerProperties.PHOENIX_QUERY_SERVER_SERVICE_NAME, 63 | QueryServerOptions.DEFAULT_PHOENIX_QUERY_SERVER_SERVICE_NAME); 64 | } 65 | 66 | @Override 67 | public String getZkConnectString(){ 68 | return ZKConfig.standardizeZKQuorumServerString(configuration.get(QueryServerProperties.ZOOKEEPER_QUORUM_ATTRIB, 69 | "localhost"), configuration.get(QueryServerProperties.ZOOKEEPER_PORT_ATTRIB, "2181")); 70 | } 71 | 72 | private String getZkLbUserName(){ 73 | return configuration.get(QueryServerProperties.PHOENIX_QUERY_SERVER_ZK_ACL_USERNAME, 74 | QueryServerOptions.DEFAULT_PHOENIX_QUERY_SERVER_ZK_ACL_USERNAME); 75 | } 76 | 77 | private String getZkLbPassword(){ 78 | return configuration.get(QueryServerProperties.PHOENIX_QUERY_SERVER_ZK_ACL_PASSWORD, 79 | QueryServerOptions.DEFAULT_PHOENIX_QUERY_SERVER_ZK_ACL_PASSWORD); 80 | } 81 | 82 | @Override 83 | public List getAcls() { 84 | ACL acl = new ACL(); 85 | acl.setId(new Id("digest",getZkLbUserName()+":"+getZkLbPassword())); 86 | acl.setPerms(ZooDefs.Perms.READ); 87 | return Arrays.asList(acl); 88 | } 89 | 90 | @Override 91 | public String getParentPath() { 92 | String path = String.format("%s/%s",getQueryServerBasePath(),getServiceName()); 93 | return path; 94 | } 95 | 96 | @Override 97 | public String getFullPathToNode(HostAndPort hostAndPort) { 98 | String path = String.format("%s/%s",getParentPath() 99 | ,hostAndPort.toString()); 100 | return path; 101 | } 102 | } 103 | 104 | -------------------------------------------------------------------------------- /phoenix-queryserver-load-balancer/src/main/java/org/apache/phoenix/queryserver/register/ZookeeperRegistry.java: -------------------------------------------------------------------------------- 1 | /** 2 | * 3 | * Licensed to the Apache Software Foundation (ASF) under one 4 | * or more contributor license agreements. See the NOTICE file 5 | * distributed with this work for additional information 6 | * regarding copyright ownership. The ASF licenses this file 7 | * to you under the Apache License, Version 2.0 (the 8 | * "License"); you may not use this file except in compliance 9 | * with the License. You may obtain a copy of the License at 10 | * 11 | * http://www.apache.org/licenses/LICENSE-2.0 12 | * 13 | * Unless required by applicable law or agreed to in writing, software 14 | * distributed under the License is distributed on an "AS IS" BASIS, 15 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 16 | * See the License for the specific language governing permissions and 17 | * limitations under the License. 18 | */ 19 | package org.apache.phoenix.queryserver.register; 20 | 21 | 22 | import org.apache.curator.framework.CuratorFramework; 23 | import org.apache.curator.framework.CuratorFrameworkFactory; 24 | import org.apache.curator.retry.ExponentialBackoffRetry; 25 | import org.apache.curator.utils.CloseableUtils; 26 | import org.apache.phoenix.loadbalancer.service.LoadBalanceZookeeperConf; 27 | import org.apache.phoenix.util.HostAndPort; 28 | import org.apache.zookeeper.CreateMode; 29 | import org.apache.zookeeper.data.Stat; 30 | import org.slf4j.Logger; 31 | import org.slf4j.LoggerFactory; 32 | 33 | import java.nio.charset.StandardCharsets; 34 | 35 | 36 | public class ZookeeperRegistry implements Registry { 37 | 38 | private static final Logger LOG = LoggerFactory.getLogger(ZookeeperRegistry.class); 39 | private CuratorFramework client; 40 | 41 | public ZookeeperRegistry(){} 42 | 43 | @Override 44 | public void registerServer(LoadBalanceZookeeperConf configuration, int pqsPort, 45 | String zookeeperConnectString, String pqsHost) 46 | throws Exception { 47 | 48 | this.client = CuratorFrameworkFactory.newClient(zookeeperConnectString, 49 | new ExponentialBackoffRetry(1000,10)); 50 | this.client.start(); 51 | HostAndPort hostAndPort = HostAndPort.fromParts(pqsHost,pqsPort); 52 | String path = configuration.getFullPathToNode(hostAndPort); 53 | String node = hostAndPort.toString(); 54 | this.client.create().creatingParentsIfNeeded().withMode(CreateMode.EPHEMERAL).forPath(path 55 | ,node.getBytes(StandardCharsets.UTF_8)); 56 | Stat stat = this.client.setACL().withACL(configuration.getAcls()).forPath(path); 57 | if (stat != null) { 58 | LOG.info(" node created with right ACL"); 59 | } 60 | else { 61 | LOG.error("could not create node with right ACL. So, system would exit now."); 62 | throw new RuntimeException(" Unable to connect to Zookeeper"); 63 | } 64 | 65 | } 66 | 67 | @Override 68 | public void unRegisterServer() throws Exception { 69 | CloseableUtils.closeQuietly(this.client); 70 | } 71 | } 72 | -------------------------------------------------------------------------------- /phoenix-queryserver-load-balancer/src/main/resources/META-INF/services/org.apache.phoenix.loadbalancer.service.LoadBalanceZookeeperConf: -------------------------------------------------------------------------------- 1 | org.apache.phoenix.loadbalancer.service.LoadBalanceZookeeperConfImpl -------------------------------------------------------------------------------- /phoenix-queryserver-load-balancer/src/main/resources/META-INF/services/org.apache.phoenix.queryserver.register.Registry: -------------------------------------------------------------------------------- 1 | org.apache.phoenix.queryserver.register.ZookeeperRegistry -------------------------------------------------------------------------------- /phoenix-queryserver-load-balancer/src/test/java/org/apache/phoenix/loadbalancer/service/LoadBalanceZookeeperConfImplTest.java: -------------------------------------------------------------------------------- 1 | /** 2 | * 3 | * Licensed to the Apache Software Foundation (ASF) under one 4 | * or more contributor license agreements. See the NOTICE file 5 | * distributed with this work for additional information 6 | * regarding copyright ownership. The ASF licenses this file 7 | * to you under the Apache License, Version 2.0 (the 8 | * "License"); you may not use this file except in compliance 9 | * with the License. You may obtain a copy of the License at 10 | * 11 | * http://www.apache.org/licenses/LICENSE-2.0 12 | * 13 | * Unless required by applicable law or agreed to in writing, software 14 | * distributed under the License is distributed on an "AS IS" BASIS, 15 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 16 | * See the License for the specific language governing permissions and 17 | * limitations under the License. 18 | */ 19 | package org.apache.phoenix.loadbalancer.service; 20 | 21 | import org.apache.hadoop.conf.Configuration; 22 | import org.apache.hadoop.hbase.HBaseConfiguration; 23 | import org.apache.phoenix.queryserver.QueryServerProperties; 24 | import org.junit.Assert; 25 | import org.junit.Test; 26 | 27 | public class LoadBalanceZookeeperConfImplTest { 28 | @Test 29 | public void testZkConnectString() { 30 | // server port is different from the port which is set by user 31 | testZKClusterKey("server:2183", "2182"); 32 | // multiple servers have their own port 33 | testZKClusterKey("server1:2182,server2:2183,server3:2184", "2181"); 34 | // some servers no specified port 35 | testZKClusterKey("server1,server2:2181,server3:2182", "2181"); 36 | testZKClusterKey("server1:2182,server2,server3:2183", "2181"); 37 | testZKClusterKey("server1:2182,server2:2183,server3", "2181"); 38 | testZKClusterKey("server1:2182,server2,server3:2183", "2184"); 39 | // no port set 40 | testZKClusterKey("server1,server2,server3", ""); 41 | testZKClusterKey("server1:2182,server2,server3:2183", ""); 42 | } 43 | 44 | private void testZKClusterKey(String quorum, String port) { 45 | final Configuration conf = HBaseConfiguration.create(); 46 | conf.set(QueryServerProperties.ZOOKEEPER_QUORUM_ATTRIB, quorum); 47 | conf.set(QueryServerProperties.ZOOKEEPER_PORT_ATTRIB, port); 48 | final LoadBalanceZookeeperConfImpl loadBalanceZookeeperConf = new LoadBalanceZookeeperConfImpl(conf); 49 | String[] connectStrings = loadBalanceZookeeperConf.getZkConnectString().split(","); 50 | String[] quorums = quorum.split(","); 51 | Assert.assertTrue( connectStrings.length == quorums.length); 52 | for (int i = 0; i< connectStrings.length; ++i) { 53 | if (quorums[i].contains(":")) { 54 | Assert.assertEquals(quorums[i], connectStrings[i]); 55 | } else { 56 | Assert.assertEquals(quorums[i] + ":" + port, connectStrings[i]); 57 | } 58 | } 59 | } 60 | } 61 | -------------------------------------------------------------------------------- /phoenix-queryserver-orchestrator/pom.xml: -------------------------------------------------------------------------------- 1 | 2 | 22 | 25 | 26 | 4.0.0 27 | 28 | 29 | phoenix-queryserver-parent 30 | org.apache.phoenix 31 | 6.0.1-SNAPSHOT 32 | 33 | 34 | phoenix-queryserver-orchestrator 35 | Phoenix Query Server Orchestrator 36 | 37 | 38 | 39 | 40 | org.apache.maven.plugins 41 | maven-dependency-plugin 42 | 43 | 44 | 45 | 46 | org.apache.hbase:hbase-testing-util 47 | 48 | 49 | org.apache.hbase:hbase-it 50 | 51 | 52 | 53 | true 54 | 55 | 56 | 57 | 58 | 59 | 60 | 61 | org.slf4j 62 | slf4j-api 63 | 64 | 65 | org.slf4j 66 | jcl-over-slf4j 67 | test 68 | 69 | 70 | net.sourceforge.argparse4j 71 | argparse4j 72 | 73 | 74 | org.apache.curator 75 | curator-client 76 | 77 | 78 | org.apache.curator 79 | curator-framework 80 | 81 | 82 | org.apache.curator 83 | curator-recipes 84 | 85 | 86 | org.apache.hbase 87 | hbase-common 88 | 89 | 90 | org.apache.hadoop 91 | hadoop-common 92 | 93 | 94 | com.google.code.gson 95 | gson 96 | 97 | 98 | 99 | junit 100 | junit 101 | test 102 | 103 | 104 | org.mockito 105 | mockito-core 106 | test 107 | 108 | 109 | org.apache.hbase 110 | hbase-it 111 | test-jar 112 | test 113 | 114 | 115 | org.apache.hbase 116 | hbase-testing-util 117 | test 118 | 119 | 120 | 121 | -------------------------------------------------------------------------------- /phoenix-queryserver-orchestrator/src/main/java/org/apache/phoenix/queryserver/orchestrator/ToolWrapper.java: -------------------------------------------------------------------------------- 1 | /** 2 | * 3 | * Licensed to the Apache Software Foundation (ASF) under one 4 | * or more contributor license agreements. See the NOTICE file 5 | * distributed with this work for additional information 6 | * regarding copyright ownership. The ASF licenses this file 7 | * to you under the Apache License, Version 2.0 (the 8 | * "License"); you may not use this file except in compliance 9 | * with the License. You may obtain a copy of the License at 10 | * 11 | * http://www.apache.org/licenses/LICENSE-2.0 12 | * 13 | * Unless required by applicable law or agreed to in writing, software 14 | * distributed under the License is distributed on an "AS IS" BASIS, 15 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 16 | * See the License for the specific language governing permissions and 17 | * limitations under the License. 18 | */ 19 | package org.apache.phoenix.queryserver.orchestrator; 20 | 21 | import org.apache.phoenix.tool.PhoenixCanaryTool; 22 | import org.slf4j.Logger; 23 | import org.slf4j.LoggerFactory; 24 | 25 | import java.util.Arrays; 26 | 27 | /* 28 | This is a wrapper class runs the PhoenixCanaryTool. 29 | */ 30 | public class ToolWrapper { 31 | 32 | private static final Logger LOGGER = LoggerFactory.getLogger(ToolWrapper.class); 33 | 34 | public void executeMain(String [] args){ 35 | if(Arrays.asList(args).contains(null)){ 36 | LOGGER.error("Bad argument list passed to executeMain. Skipping QueryServerCanaryTool."); 37 | return; 38 | } 39 | LOGGER.info("Passing args to QueryServerCanaryTool: " + String.join(",",args)); 40 | PhoenixCanaryTool.main(args); 41 | } 42 | } 43 | -------------------------------------------------------------------------------- /phoenix-queryserver-orchestrator/src/main/java/org/apache/phoenix/tool/CanaryTestResult.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Licensed to the Apache Software Foundation (ASF) under one 3 | * or more contributor license agreements. See the NOTICE file 4 | * distributed with this work for additional information 5 | * regarding copyright ownership. The ASF licenses this file 6 | * to you under the Apache License, Version 2.0 (the 7 | * "License"); you may not use this file except in compliance 8 | * with the License. You may obtain a copy of the License at 9 | * 10 | * http://www.apache.org/licenses/LICENSE-2.0 11 | * 12 | * Unless required by applicable law or agreed to in writing, software 13 | * distributed under the License is distributed on an "AS IS" BASIS, 14 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 15 | * See the License for the specific language governing permissions and 16 | * limitations under the License. 17 | */ 18 | package org.apache.phoenix.tool; 19 | 20 | public class CanaryTestResult { 21 | 22 | private boolean isSuccessful; 23 | private long startTime; 24 | private long executionTime; 25 | private String message; 26 | private String testName; 27 | private String timestamp; 28 | private Object miscellaneous; 29 | 30 | public Object getMiscellaneous() { 31 | return miscellaneous; 32 | } 33 | 34 | public void setMiscellaneous(Object miscellaneous) { 35 | this.miscellaneous = miscellaneous; 36 | } 37 | 38 | public long getStartTime() { 39 | return startTime; 40 | } 41 | 42 | public void setStartTime(long startTime) { 43 | this.startTime = startTime; 44 | } 45 | 46 | public String getTimestamp() { 47 | return timestamp; 48 | } 49 | 50 | public void setTimestamp(String timestamp) { 51 | this.timestamp = timestamp; 52 | } 53 | 54 | public boolean isSuccessful() { 55 | return isSuccessful; 56 | } 57 | 58 | public void setSuccessful(boolean successful) { 59 | isSuccessful = successful; 60 | } 61 | 62 | public long getExecutionTime() { 63 | return executionTime; 64 | } 65 | 66 | public void setExecutionTime(long executionTime) { 67 | this.executionTime = executionTime; 68 | } 69 | 70 | public String getMessage() { 71 | return message; 72 | } 73 | 74 | public void setMessage(String message) { 75 | this.message = message; 76 | } 77 | 78 | public String getTestName() { 79 | return testName; 80 | } 81 | 82 | public void setTestName(String testName) { 83 | this.testName = testName; 84 | } 85 | 86 | } 87 | -------------------------------------------------------------------------------- /phoenix-queryserver-orchestrator/src/test/java/org/apache/phoenix/tool/PhoenixCanaryToolTest.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Licensed to the Apache Software Foundation (ASF) under one 3 | * or more contributor license agreements. See the NOTICE file 4 | * distributed with this work for additional information 5 | * regarding copyright ownership. The ASF licenses this file 6 | * to you under the Apache License, Version 2.0 (the 7 | * "License"); you may not use this file except in compliance 8 | * with the License. You may obtain a copy of the License at 9 | * 10 | * http://www.apache.org/licenses/LICENSE-2.0 11 | * 12 | * Unless required by applicable law or agreed to in writing, software 13 | * distributed under the License is distributed on an "AS IS" BASIS, 14 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 15 | * See the License for the specific language governing permissions and 16 | * limitations under the License. 17 | */ 18 | package org.apache.phoenix.tool; 19 | 20 | import static org.junit.Assert.assertEquals; 21 | 22 | import org.junit.Before; 23 | import org.junit.Test; 24 | import org.mockito.Mock; 25 | import org.mockito.Mockito; 26 | import static org.mockito.Mockito.when; 27 | import org.mockito.MockitoAnnotations; 28 | import java.sql.Connection; 29 | import java.sql.DatabaseMetaData; 30 | import java.sql.PreparedStatement; 31 | import java.sql.ResultSet; 32 | import java.sql.Statement; 33 | 34 | public class PhoenixCanaryToolTest { 35 | 36 | @Mock 37 | private Connection connection; 38 | 39 | @Mock 40 | private Statement statement; 41 | 42 | @Mock 43 | private PreparedStatement ps; 44 | 45 | @Mock 46 | private ResultSet rs; 47 | 48 | @Mock 49 | private DatabaseMetaData dbm; 50 | 51 | @Before 52 | public void setUp() { 53 | MockitoAnnotations.initMocks(this); 54 | } 55 | 56 | @Test 57 | public void upsertTableTest() throws Exception { 58 | when(connection.createStatement()).thenReturn(statement); 59 | when(connection.prepareStatement(Mockito.anyString())).thenReturn(ps); 60 | when(statement.executeUpdate(Mockito.anyString())).thenReturn(1); 61 | CanaryTestResult result = new PhoenixCanaryTool.UpsertTableTest().runTest(connection); 62 | assertEquals(true, result.isSuccessful()); 63 | assertEquals("Test upsertTable successful", result.getMessage()); 64 | } 65 | 66 | @Test 67 | public void readTableTest() throws Exception { 68 | when(connection.prepareStatement(Mockito.anyString())).thenReturn(ps); 69 | when(ps.executeQuery()).thenReturn(rs); 70 | when(rs.next()).thenReturn(true).thenReturn(false); 71 | when(rs.getInt(1)).thenReturn(1); 72 | when(rs.getString(2)).thenReturn("Hello World"); 73 | CanaryTestResult result = new PhoenixCanaryTool.ReadTableTest().runTest(connection); 74 | assertEquals(true, result.isSuccessful()); 75 | assertEquals("Test readTable successful", result.getMessage()); 76 | } 77 | 78 | @Test 79 | public void failTest() throws Exception { 80 | when(connection.prepareStatement(Mockito.anyString())).thenReturn(ps); 81 | when(ps.executeQuery()).thenReturn(rs); 82 | when(rs.getInt(1)).thenReturn(3); 83 | when(rs.getString(2)).thenReturn("Incorrect data"); 84 | when(rs.next()).thenReturn(true).thenReturn(false); 85 | CanaryTestResult result = new PhoenixCanaryTool.ReadTableTest().runTest(connection); 86 | assertEquals(false, result.isSuccessful()); 87 | assert (result.getMessage().contains("Retrieved values do not match the inserted values")); 88 | } 89 | } -------------------------------------------------------------------------------- /phoenix-queryserver/src/build/query-server-runnable.xml: -------------------------------------------------------------------------------- 1 | 2 | 22 | 23 | 26 | runnable 27 | 28 | jar 29 | 30 | false 31 | 32 | 33 | 37 | metaInf-services 38 | 39 | 40 | 41 | 42 | true 43 | runtime 44 | / 45 | 46 | org.apache.phoenix:phoenix-queryserver 47 | org.apache.phoenix:phoenix-queryserver-client 48 | org.apache.calcite.avatica:* 49 | 50 | 51 | 52 | 53 | -------------------------------------------------------------------------------- /phoenix-queryserver/src/main/java/org/apache/phoenix/loadbalancer/service/LoadBalanceZookeeperConf.java: -------------------------------------------------------------------------------- 1 | /** 2 | * 3 | * Licensed to the Apache Software Foundation (ASF) under one 4 | * or more contributor license agreements. See the NOTICE file 5 | * distributed with this work for additional information 6 | * regarding copyright ownership. The ASF licenses this file 7 | * to you under the Apache License, Version 2.0 (the 8 | * "License"); you may not use this file except in compliance 9 | * with the License. You may obtain a copy of the License at 10 | * 11 | * http://www.apache.org/licenses/LICENSE-2.0 12 | * 13 | * Unless required by applicable law or agreed to in writing, software 14 | * distributed under the License is distributed on an "AS IS" BASIS, 15 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 16 | * See the License for the specific language governing permissions and 17 | * limitations under the License. 18 | */ 19 | package org.apache.phoenix.loadbalancer.service; 20 | 21 | import org.apache.phoenix.util.HostAndPort; 22 | import org.apache.zookeeper.data.ACL; 23 | 24 | import java.util.List; 25 | 26 | 27 | public interface LoadBalanceZookeeperConf { 28 | 29 | String getQueryServerBasePath(); 30 | 31 | String getServiceName(); 32 | 33 | String getZkConnectString(); 34 | 35 | List getAcls(); 36 | 37 | String getParentPath(); 38 | 39 | String getFullPathToNode(HostAndPort hostAndPort); 40 | 41 | 42 | } 43 | -------------------------------------------------------------------------------- /phoenix-queryserver/src/main/java/org/apache/phoenix/queryserver/register/Registry.java: -------------------------------------------------------------------------------- 1 | /** 2 | * 3 | * Licensed to the Apache Software Foundation (ASF) under one 4 | * or more contributor license agreements. See the NOTICE file 5 | * distributed with this work for additional information 6 | * regarding copyright ownership. The ASF licenses this file 7 | * to you under the Apache License, Version 2.0 (the 8 | * "License"); you may not use this file except in compliance 9 | * with the License. You may obtain a copy of the License at 10 | * 11 | * http://www.apache.org/licenses/LICENSE-2.0 12 | * 13 | * Unless required by applicable law or agreed to in writing, software 14 | * distributed under the License is distributed on an "AS IS" BASIS, 15 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 16 | * See the License for the specific language governing permissions and 17 | * limitations under the License. 18 | */ 19 | package org.apache.phoenix.queryserver.register; 20 | 21 | 22 | import org.apache.phoenix.loadbalancer.service.LoadBalanceZookeeperConf; 23 | 24 | /** 25 | * Registry interface for implementing registering 26 | * and un-registering to service locator. 27 | */ 28 | public interface Registry { 29 | 30 | /** 31 | * Unreqister the server with zookeeper. All Cleanup 32 | * is done in this method. 33 | * @throws Exception 34 | */ 35 | void unRegisterServer() throws Exception; 36 | 37 | /** 38 | * Registers the server with the service locator ( zookeeper). 39 | * @param configuration - Hbase Configuration 40 | * @param port - port for PQS server 41 | * @param connectString - zookeeper connect string 42 | * @param pqsHost - host for PQS server. 43 | * @throws Exception 44 | */ 45 | void registerServer(LoadBalanceZookeeperConf configuration, int port 46 | , String connectString, String pqsHost) throws Exception ; 47 | 48 | } 49 | -------------------------------------------------------------------------------- /phoenix-queryserver/src/main/java/org/apache/phoenix/queryserver/server/AvaticaServerConfigurationFactory.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Licensed to the Apache Software Foundation (ASF) under one 3 | * or more contributor license agreements. See the NOTICE file 4 | * distributed with this work for additional information 5 | * regarding copyright ownership. The ASF licenses this file 6 | * to you under the Apache License, Version 2.0 (the 7 | * "License"); you may not use this file except in compliance 8 | * with the License. You may obtain a copy of the License at 9 | * 10 | * http://www.apache.org/licenses/LICENSE-2.0 11 | * 12 | * Unless required by applicable law or agreed to in writing, software 13 | * distributed under the License is distributed on an "AS IS" BASIS, 14 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 15 | * See the License for the specific language governing permissions and 16 | * limitations under the License. 17 | */ 18 | package org.apache.phoenix.queryserver.server; 19 | 20 | import org.apache.calcite.avatica.server.AvaticaServerConfiguration; 21 | import org.apache.hadoop.conf.Configuration; 22 | import org.apache.hadoop.security.UserGroupInformation; 23 | 24 | 25 | public interface AvaticaServerConfigurationFactory { 26 | 27 | AvaticaServerConfiguration getAvaticaServerConfiguration(Configuration conf, UserGroupInformation ugi); 28 | 29 | class AvaticaServerConfigurationFactoryImpl implements AvaticaServerConfigurationFactory { 30 | 31 | @Override 32 | public AvaticaServerConfiguration getAvaticaServerConfiguration(Configuration conf, UserGroupInformation ugi) { 33 | return null; 34 | } 35 | } 36 | 37 | } 38 | -------------------------------------------------------------------------------- /phoenix-queryserver/src/main/java/org/apache/phoenix/queryserver/server/PhoenixMetaFactory.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Licensed to the Apache Software Foundation (ASF) under one 3 | * or more contributor license agreements. See the NOTICE file 4 | * distributed with this work for additional information 5 | * regarding copyright ownership. The ASF licenses this file 6 | * to you under the Apache License, Version 2.0 (the 7 | * "License"); you may not use this file except in compliance 8 | * with the License. You may obtain a copy of the License at 9 | * 10 | * http://www.apache.org/licenses/LICENSE-2.0 11 | * 12 | * Unless required by applicable law or agreed to in writing, software 13 | * distributed under the License is distributed on an "AS IS" BASIS, 14 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 15 | * See the License for the specific language governing permissions and 16 | * limitations under the License. 17 | */ 18 | package org.apache.phoenix.queryserver.server; 19 | 20 | import org.apache.calcite.avatica.Meta; 21 | import org.apache.hadoop.conf.Configurable; 22 | 23 | /** 24 | * A @{link Meta.Factory} that can also respect Hadoop 25 | * {@link org.apache.hadoop.conf.Configuration} objects. 26 | */ 27 | public interface PhoenixMetaFactory extends Meta.Factory, Configurable { 28 | } 29 | -------------------------------------------------------------------------------- /phoenix-queryserver/src/main/java/org/apache/phoenix/queryserver/server/RemoteUserExtractorFactory.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Licensed to the Apache Software Foundation (ASF) under one 3 | * or more contributor license agreements. See the NOTICE file 4 | * distributed with this work for additional information 5 | * regarding copyright ownership. The ASF licenses this file 6 | * to you under the Apache License, Version 2.0 (the 7 | * "License"); you may not use this file except in compliance 8 | * with the License. You may obtain a copy of the License at 9 | * 10 | * http://www.apache.org/licenses/LICENSE-2.0 11 | * 12 | * Unless required by applicable law or agreed to in writing, software 13 | * distributed under the License is distributed on an "AS IS" BASIS, 14 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 15 | * See the License for the specific language governing permissions and 16 | * limitations under the License. 17 | */ 18 | package org.apache.phoenix.queryserver.server; 19 | 20 | import org.apache.calcite.avatica.server.RemoteUserExtractor; 21 | import org.apache.hadoop.conf.Configuration; 22 | 23 | /** 24 | * Creates remote user extractors. 25 | */ 26 | public interface RemoteUserExtractorFactory { 27 | 28 | RemoteUserExtractor createRemoteUserExtractor(Configuration conf); 29 | 30 | class RemoteUserExtractorFactoryImpl implements RemoteUserExtractorFactory { 31 | @Override 32 | public RemoteUserExtractor createRemoteUserExtractor(Configuration conf) { 33 | return new QueryServer.PhoenixRemoteUserExtractor(conf); 34 | } 35 | } 36 | } 37 | -------------------------------------------------------------------------------- /phoenix-queryserver/src/main/java/org/apache/phoenix/queryserver/server/ServerCustomizersFactory.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Licensed to the Apache Software Foundation (ASF) under one 3 | * or more contributor license agreements. See the NOTICE file 4 | * distributed with this work for additional information 5 | * regarding copyright ownership. The ASF licenses this file 6 | * to you under the Apache License, Version 2.0 (the 7 | * "License"); you may not use this file except in compliance 8 | * with the License. You may obtain a copy of the License at 9 | * 10 | * http://www.apache.org/licenses/LICENSE-2.0 11 | * 12 | * Unless required by applicable law or agreed to in writing, software 13 | * distributed under the License is distributed on an "AS IS" BASIS, 14 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 15 | * See the License for the specific language governing permissions and 16 | * limitations under the License. 17 | */ 18 | package org.apache.phoenix.queryserver.server; 19 | 20 | import java.io.File; 21 | import java.util.ArrayList; 22 | import java.util.Collections; 23 | import java.util.List; 24 | 25 | import org.apache.calcite.avatica.server.AvaticaServerConfiguration; 26 | import org.apache.calcite.avatica.server.ServerCustomizer; 27 | import org.apache.hadoop.conf.Configuration; 28 | import org.apache.phoenix.queryserver.QueryServerOptions; 29 | import org.apache.phoenix.queryserver.QueryServerProperties; 30 | import org.apache.phoenix.queryserver.server.customizers.HostedClientJarsServerCustomizer; 31 | import org.apache.phoenix.queryserver.server.customizers.JMXJsonEndpointServerCustomizer; 32 | import org.eclipse.jetty.server.Server; 33 | import org.slf4j.Logger; 34 | import org.slf4j.LoggerFactory; 35 | 36 | /** 37 | * Creates customizers for the underlying Avatica HTTP server. 38 | * Allows for fine grained control of authentication, etc. 39 | */ 40 | public interface ServerCustomizersFactory { 41 | /** 42 | * Creates a list of customizers that will customize the server. 43 | * @param conf Configuration to use 44 | * @param avaticaServerConfiguration to use in case custom-auth is enabled 45 | * @return List of server suctomizers 46 | */ 47 | List> createServerCustomizers(Configuration conf, AvaticaServerConfiguration avaticaServerConfiguration); 48 | 49 | /** 50 | * Factory that creates an empty list of customizers. 51 | */ 52 | class ServerCustomizersFactoryImpl implements ServerCustomizersFactory { 53 | private static final Logger LOG = LoggerFactory.getLogger(ServerCustomizersFactoryImpl.class); 54 | @Override 55 | public List> createServerCustomizers(Configuration conf, 56 | AvaticaServerConfiguration avaticaServerConfiguration) { 57 | List> customizers = new ArrayList<>(); 58 | if (conf.getBoolean(QueryServerProperties.CLIENT_JARS_ENABLED_ATTRIB, QueryServerOptions.DEFAULT_CLIENT_JARS_ENABLED)) { 59 | String repoLocation = conf.get(QueryServerProperties.CLIENT_JARS_REPO_ATTRIB, 60 | QueryServerOptions.DEFAULT_CLIENT_JARS_REPO); 61 | if (repoLocation != null && !repoLocation.isEmpty()) { 62 | File repo = new File(repoLocation); 63 | if (!repo.isDirectory()) { 64 | throw new IllegalArgumentException("Provided maven repository is not a directory. " + repo); 65 | } 66 | String contextPath = conf.get(QueryServerProperties.CLIENT_JARS_CONTEXT_ATTRIB, 67 | QueryServerOptions.DEFAULT_CLIENT_JARS_CONTEXT); 68 | LOG.info("Creating ServerCustomizer to host client jars from {} at HTTP endpoint {}", repo, contextPath); 69 | HostedClientJarsServerCustomizer customizer = new HostedClientJarsServerCustomizer(repo, contextPath); 70 | customizers.add(customizer); 71 | } else { 72 | LOG.warn("Empty value provided for {}, ignoring", QueryServerProperties.CLIENT_JARS_REPO_ATTRIB); 73 | } 74 | } 75 | if (!conf.getBoolean(QueryServerProperties.QUERY_SERVER_JMX_JSON_ENDPOINT_DISABLED, 76 | QueryServerOptions.DEFAULT_QUERY_SERVER_JMXJSONENDPOINT_DISABLED)) { 77 | customizers.add(new JMXJsonEndpointServerCustomizer()); 78 | } 79 | return Collections.unmodifiableList(customizers); 80 | } 81 | } 82 | } 83 | -------------------------------------------------------------------------------- /phoenix-queryserver/src/main/java/org/apache/phoenix/queryserver/server/customizers/BasicAuthenticationServerCustomizer.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Licensed to the Apache Software Foundation (ASF) under one 3 | * or more contributor license agreements. See the NOTICE file 4 | * distributed with this work for additional information 5 | * regarding copyright ownership. The ASF licenses this file 6 | * to you under the Apache License, Version 2.0 (the 7 | * "License"); you may not use this file except in compliance 8 | * with the License. You may obtain a copy of the License at 9 | * 10 | * http://www.apache.org/licenses/LICENSE-2.0 11 | * 12 | * Unless required by applicable law or agreed to in writing, software 13 | * distributed under the License is distributed on an "AS IS" BASIS, 14 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 15 | * See the License for the specific language governing permissions and 16 | * limitations under the License. 17 | */ 18 | package org.apache.phoenix.queryserver.server.customizers; 19 | 20 | import java.util.Collections; 21 | import java.util.List; 22 | 23 | import org.apache.calcite.avatica.server.AvaticaServerConfiguration; 24 | import org.apache.calcite.avatica.server.ServerCustomizer; 25 | import org.apache.hadoop.conf.Configuration; 26 | import org.apache.phoenix.queryserver.server.ServerCustomizersFactory; 27 | import org.eclipse.jetty.security.ConstraintMapping; 28 | import org.eclipse.jetty.security.ConstraintSecurityHandler; 29 | import org.eclipse.jetty.security.HashLoginService; 30 | import org.eclipse.jetty.security.UserStore; 31 | import org.eclipse.jetty.security.authentication.BasicAuthenticator; 32 | import org.eclipse.jetty.server.Server; 33 | import org.eclipse.jetty.util.security.Constraint; 34 | import org.eclipse.jetty.util.security.Credential; 35 | import org.slf4j.Logger; 36 | import org.slf4j.LoggerFactory; 37 | 38 | /** 39 | * Avatica ServerCustomizer which performs HTTP Basic authentication against a static user database. 40 | * 41 | * For testing ONLY. 42 | */ 43 | public class BasicAuthenticationServerCustomizer implements ServerCustomizer { 44 | private static final Logger LOG = LoggerFactory.getLogger(BasicAuthenticationServerCustomizer.class); 45 | 46 | public static final String USER_AUTHORIZED = "user3"; 47 | public static final String USER_PW = "s3cr3t"; 48 | 49 | public static class BasicAuthServerCustomizerFactory implements ServerCustomizersFactory { 50 | @Override 51 | public List> createServerCustomizers( 52 | Configuration conf, AvaticaServerConfiguration avaticaServerConfiguration) { 53 | return Collections.>singletonList(new BasicAuthenticationServerCustomizer()); 54 | } 55 | } 56 | 57 | @Override 58 | public void customize(Server server) { 59 | LOG.debug("Customizing server to allow requests for {}", USER_AUTHORIZED); 60 | 61 | UserStore store = new UserStore(); 62 | store.addUser(USER_AUTHORIZED, Credential.getCredential(USER_PW), new String[] {"users"}); 63 | HashLoginService login = new HashLoginService(); 64 | login.setName("users"); 65 | login.setUserStore(store); 66 | 67 | Constraint constraint = new Constraint(); 68 | constraint.setName(Constraint.__BASIC_AUTH); 69 | constraint.setRoles(new String[]{"users"}); 70 | constraint.setAuthenticate(true); 71 | 72 | ConstraintMapping cm = new ConstraintMapping(); 73 | cm.setConstraint(constraint); 74 | cm.setPathSpec("/*"); 75 | 76 | ConstraintSecurityHandler security = new ConstraintSecurityHandler(); 77 | security.setAuthenticator(new BasicAuthenticator()); 78 | security.setRealmName("users"); 79 | security.addConstraintMapping(cm); 80 | security.setLoginService(login); 81 | 82 | // chain the PQS handler to security 83 | security.setHandler(server.getHandlers()[0]); 84 | server.setHandler(security); 85 | } 86 | } 87 | -------------------------------------------------------------------------------- /phoenix-queryserver/src/main/java/org/apache/phoenix/queryserver/server/customizers/HostedClientJarsServerCustomizer.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Licensed to the Apache Software Foundation (ASF) under one 3 | * or more contributor license agreements. See the NOTICE file 4 | * distributed with this work for additional information 5 | * regarding copyright ownership. The ASF licenses this file 6 | * to you under the Apache License, Version 2.0 (the 7 | * "License"); you may not use this file except in compliance 8 | * with the License. You may obtain a copy of the License at 9 | * 10 | * http://www.apache.org/licenses/LICENSE-2.0 11 | * 12 | * Unless required by applicable law or agreed to in writing, software 13 | * distributed under the License is distributed on an "AS IS" BASIS, 14 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 15 | * See the License for the specific language governing permissions and 16 | * limitations under the License. 17 | */ 18 | package org.apache.phoenix.queryserver.server.customizers; 19 | 20 | import java.io.File; 21 | import java.util.Arrays; 22 | 23 | import org.apache.calcite.avatica.server.ServerCustomizer; 24 | import org.eclipse.jetty.server.Handler; 25 | import org.eclipse.jetty.server.Server; 26 | import org.eclipse.jetty.server.handler.ContextHandler; 27 | import org.eclipse.jetty.server.handler.HandlerList; 28 | import org.eclipse.jetty.server.handler.ResourceHandler; 29 | import org.slf4j.Logger; 30 | import org.slf4j.LoggerFactory; 31 | 32 | /** 33 | * Hosts a Maven repository from local filesystem over HTTP from within PQS. 34 | */ 35 | public class HostedClientJarsServerCustomizer implements ServerCustomizer { 36 | private static final Logger LOG = LoggerFactory.getLogger(HostedClientJarsServerCustomizer.class); 37 | 38 | private final File repoRoot; 39 | private final String contextPath; 40 | 41 | /** 42 | * @param localMavenRepoRoot The path to the Phoenix-built maven repository on the local filesystem 43 | * @param contextPath The HTTP path which the repository will be hosted at 44 | */ 45 | public HostedClientJarsServerCustomizer(File localMavenRepoRoot, String contextPath) { 46 | this.repoRoot = localMavenRepoRoot; 47 | this.contextPath = contextPath; 48 | } 49 | 50 | @Override 51 | public void customize(Server server) { 52 | Handler[] handlers = server.getHandlers(); 53 | if (handlers.length != 1) { 54 | LOG.warn("Observed handlers on server {}", Arrays.toString(handlers)); 55 | throw new IllegalStateException("Expected to find one handler"); 56 | } 57 | HandlerList list = (HandlerList) handlers[0]; 58 | 59 | ContextHandler ctx = new ContextHandler(contextPath); 60 | ResourceHandler resource = new ResourceHandler(); 61 | resource.setDirAllowed(true); 62 | resource.setDirectoriesListed(false); 63 | resource.setResourceBase(repoRoot.getAbsolutePath()); 64 | ctx.setHandler(resource); 65 | 66 | Handler[] realHandlers = list.getChildHandlers(); 67 | 68 | Handler[] newHandlers = new Handler[realHandlers.length + 1]; 69 | newHandlers[0] = ctx; 70 | System.arraycopy(realHandlers, 0, newHandlers, 1, realHandlers.length); 71 | server.setHandler(new HandlerList(newHandlers)); 72 | } 73 | } 74 | -------------------------------------------------------------------------------- /phoenix-queryserver/src/main/java/org/apache/phoenix/queryserver/server/customizers/JMXJsonEndpointServerCustomizer.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Licensed to the Apache Software Foundation (ASF) under one or more 3 | * contributor license agreements. See the NOTICE file distributed with 4 | * this work for additional information regarding copyright ownership. 5 | * The ASF licenses this file to you under the Apache License, Version 2.0 6 | * (the "License"); you may not use this file except in compliance with 7 | * the License. You may obtain a copy of the License at 8 | * 9 | * http://www.apache.org/licenses/LICENSE-2.0 10 | * 11 | * Unless required by applicable law or agreed to in writing, software 12 | * distributed under the License is distributed on an "AS IS" BASIS, 13 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 | * See the License for the specific language governing permissions and 15 | * limitations under the License. 16 | */ 17 | package org.apache.phoenix.queryserver.server.customizers; 18 | 19 | import static org.apache.hadoop.http.HttpServer2.CONF_CONTEXT_ATTRIBUTE; 20 | 21 | import org.apache.calcite.avatica.server.ServerCustomizer; 22 | import org.apache.hadoop.hbase.HBaseConfiguration; 23 | import org.apache.hadoop.jmx.JMXJsonServlet; 24 | import org.eclipse.jetty.server.Handler; 25 | import org.eclipse.jetty.server.Server; 26 | import org.eclipse.jetty.server.handler.HandlerList; 27 | import org.eclipse.jetty.servlet.ServletContextHandler; 28 | import org.eclipse.jetty.servlet.ServletHolder; 29 | import org.slf4j.Logger; 30 | import org.slf4j.LoggerFactory; 31 | 32 | import java.util.Arrays; 33 | 34 | import javax.servlet.Servlet; 35 | 36 | public class JMXJsonEndpointServerCustomizer implements ServerCustomizer { 37 | private static final Logger LOG = LoggerFactory.getLogger(JMXJsonEndpointServerCustomizer.class); 38 | 39 | @Override 40 | public void customize(Server server) { 41 | Handler[] handlers = server.getHandlers(); 42 | if (handlers.length != 1) { 43 | LOG.warn("Observed handlers on server {}", Arrays.toString(handlers)); 44 | throw new IllegalStateException("Expected to find one handler"); 45 | } 46 | HandlerList list = (HandlerList) handlers[0]; 47 | 48 | ServletContextHandler ctx = new ServletContextHandler(); 49 | ctx.setContextPath("/jmx"); 50 | ctx.getServletContext().setAttribute(CONF_CONTEXT_ATTRIBUTE, HBaseConfiguration.create()); 51 | 52 | Servlet servlet = new JMXJsonServlet(); 53 | ServletHolder holder = new ServletHolder(servlet); 54 | ctx.addServlet(holder, "/"); 55 | 56 | Handler[] realHandlers = list.getChildHandlers(); 57 | Handler[] newHandlers = new Handler[realHandlers.length + 1]; 58 | newHandlers[0] = ctx; 59 | System.arraycopy(realHandlers, 0, newHandlers, 1, realHandlers.length); 60 | server.setHandler(new HandlerList(newHandlers)); 61 | } 62 | } 63 | -------------------------------------------------------------------------------- /phoenix-queryserver/src/main/java/org/apache/phoenix/util/InstanceResolver.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Licensed to the Apache Software Foundation (ASF) under one 3 | * or more contributor license agreements. See the NOTICE file 4 | * distributed with this work for additional information 5 | * regarding copyright ownership. The ASF licenses this file 6 | * to you under the Apache License, Version 2.0 (the 7 | * "License"); you may not use this file except in compliance 8 | * with the License. You may obtain a copy of the License at 9 | * 10 | * http://www.apache.org/licenses/LICENSE-2.0 11 | * 12 | * Unless required by applicable law or agreed to in writing, software 13 | * distributed under the License is distributed on an "AS IS" BASIS, 14 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 15 | * See the License for the specific language governing permissions and 16 | * limitations under the License. 17 | */ 18 | package org.apache.phoenix.util; 19 | 20 | import java.util.ArrayList; 21 | import java.util.Iterator; 22 | import java.util.List; 23 | import java.util.ServiceLoader; 24 | import java.util.concurrent.ConcurrentHashMap; 25 | 26 | /** 27 | * Resolves object instances registered using the JDK 6+ {@link java.util.ServiceLoader}. 28 | * 29 | * 30 | * @since 2.0 31 | */ 32 | public class InstanceResolver { 33 | private static final ConcurrentHashMap RESOLVED_SINGLETONS = new ConcurrentHashMap(); 34 | 35 | private InstanceResolver() {/* not allowed */} 36 | 37 | /** 38 | * Resolves an instance of the specified class if it has not already been resolved. 39 | * @param clazz The type of instance to resolve 40 | * @param defaultInstance The instance to use if a custom instance has not been registered 41 | * @return The resolved instance or the default instance provided. 42 | * {@code null} if an instance is not registered and a default is not provided. 43 | */ 44 | @SuppressWarnings("unchecked") 45 | public static T getSingleton(Class clazz, T defaultInstance) { 46 | Object obj = RESOLVED_SINGLETONS.get(clazz); 47 | if(obj != null) { 48 | return (T)obj; 49 | } 50 | if (defaultInstance != null && !clazz.isInstance(defaultInstance)) throw new IllegalArgumentException("defaultInstance is not of type " + clazz.getName()); 51 | final Object o = resolveSingleton(clazz, defaultInstance); 52 | obj = RESOLVED_SINGLETONS.putIfAbsent(clazz, o); 53 | if(obj == null) { 54 | obj = o; 55 | } 56 | return (T)obj; 57 | } 58 | 59 | /** 60 | * Resolves all instances of a specified class and add it to the list of default implementations 61 | * @param clazz Type of the instance to resolve 62 | * @param defaultInstances {@link List} of instances that match the type clazz 63 | * @param Type of class passed 64 | * @return {@link List} of instance of the specified class. Newly found instances will be added 65 | * to the existing contents of defaultInstances 66 | */ 67 | @SuppressWarnings("unchecked") 68 | public static List get(Class clazz, List defaultInstances) { 69 | Iterator iterator = ServiceLoader.load(clazz).iterator(); 70 | List instances = new ArrayList<>(); 71 | iterator.forEachRemaining(instances::add); 72 | 73 | if (defaultInstances != null) { 74 | defaultInstances.addAll(instances); 75 | } else { 76 | defaultInstances = instances; 77 | } 78 | 79 | return defaultInstances; 80 | } 81 | 82 | private synchronized static T resolveSingleton(Class clazz, T defaultInstance) { 83 | ServiceLoader loader = ServiceLoader.load(clazz); 84 | // returns the first registered instance found 85 | for (T singleton : loader) { 86 | return singleton; 87 | } 88 | return defaultInstance; 89 | } 90 | 91 | //@VisibleForTesting 92 | public static void clearSingletons() { 93 | RESOLVED_SINGLETONS.clear(); 94 | } 95 | } 96 | -------------------------------------------------------------------------------- /phoenix-queryserver/src/main/java/org/apache/phoenix/util/SimpleLRUCache.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Licensed to the Apache Software Foundation (ASF) under one 3 | * or more contributor license agreements. See the NOTICE file 4 | * distributed with this work for additional information 5 | * regarding copyright ownership. The ASF licenses this file 6 | * to you under the Apache License, Version 2.0 (the 7 | * "License"); you may not use this file except in compliance 8 | * with the License. You may obtain a copy of the License at 9 | * 10 | * http://www.apache.org/licenses/LICENSE-2.0 11 | * 12 | * Unless required by applicable law or agreed to in writing, software 13 | * distributed under the License is distributed on an "AS IS" BASIS, 14 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 15 | * See the License for the specific language governing permissions and 16 | * limitations under the License. 17 | */ 18 | package org.apache.phoenix.util; 19 | 20 | import java.util.Arrays; 21 | import java.util.Comparator; 22 | import java.util.TreeSet; 23 | import java.util.concurrent.ConcurrentHashMap; 24 | import java.util.concurrent.atomic.AtomicLong; 25 | import java.util.function.Function; 26 | import java.util.stream.Collectors; 27 | 28 | import org.slf4j.Logger; 29 | import org.slf4j.LoggerFactory; 30 | 31 | 32 | /** 33 | * Minimal Cache implementation based on ConcurrentHashMap. 34 | * 35 | * The maxSize logic will only work if all access is via the the computeIfAbsent() method. 36 | * 37 | */ 38 | public class SimpleLRUCache extends ConcurrentHashMap { 39 | 40 | protected static final Logger LOG = LoggerFactory.getLogger(SimpleLRUCache.class); 41 | 42 | int maxSize; 43 | int triggerSize; 44 | 45 | private ConcurrentHashMap accessed = 46 | new ConcurrentHashMap<>(); 47 | 48 | public SimpleLRUCache (long maxSize, int concurrencyLevel) { 49 | super((int)(maxSize * 1.1), (float)0.75, concurrencyLevel); 50 | this.maxSize = (int)maxSize; 51 | this.triggerSize = (int)(maxSize * 1.1)+1 ; 52 | } 53 | 54 | @Override 55 | public V computeIfAbsent(K key, Function mappingFunction) { 56 | V value = super.computeIfAbsent(key, mappingFunction); 57 | if (value != null) { 58 | accessed.put(key, new AtomicLong(System.currentTimeMillis())); 59 | if (this.size() > triggerSize) { 60 | evict(); 61 | } 62 | } 63 | return value; 64 | } 65 | 66 | private void evict() { 67 | synchronized(this) { 68 | int currentSize = this.size(); 69 | if (currentSize <= triggerSize) { 70 | return; 71 | } 72 | LOG.warn("UGI Cache capacity exceeded, you may want to increase its size"); 73 | TreeSet> sortedByLRU = new TreeSet<>( 74 | new Comparator>() { 75 | @Override 76 | public int compare(Entry o1, Entry o2) { 77 | int keyResult = 78 | Long.compare(o2.getValue().get(), o1.getValue().get()); 79 | if(keyResult == 0) { 80 | return o2.getKey().compareTo(o1.getKey()); 81 | } else { 82 | return keyResult; 83 | } 84 | } 85 | }); 86 | sortedByLRU.addAll(accessed.entrySet()); 87 | Entry[] toRetain = 88 | Arrays.copyOfRange(sortedByLRU.toArray(new Entry[currentSize]), 0, maxSize); 89 | java.util.List retainList = 90 | Arrays.stream(toRetain).map( f -> f.getKey()).collect(Collectors.toList()); 91 | this.keySet().retainAll(retainList); 92 | accessed.keySet().retainAll(this.keySet()); 93 | } 94 | } 95 | 96 | } 97 | -------------------------------------------------------------------------------- /phoenix-queryserver/src/main/java/org/apache/phoenix/util/ThinClientUtil.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Licensed to the Apache Software Foundation (ASF) under one 3 | * or more contributor license agreements. See the NOTICE file 4 | * distributed with this work for additional information 5 | * regarding copyright ownership. The ASF licenses this file 6 | * to you under the Apache License, Version 2.0 (the 7 | * "License"); you may not use this file except in compliance 8 | * with the License. You may obtain a copy of the License at 9 | * 10 | * http://www.apache.org/licenses/LICENSE-2.0 11 | * 12 | * Unless required by applicable law or agreed to in writing, software 13 | * distributed under the License is distributed on an "AS IS" BASIS, 14 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 15 | * See the License for the specific language governing permissions and 16 | * limitations under the License. 17 | */ 18 | package org.apache.phoenix.util; 19 | 20 | /** 21 | * Utilities for thin client tests 22 | */ 23 | public final class ThinClientUtil { 24 | // Duplicating constants from phoenix-core and queryserver-client 25 | // to avoid having to depend on them 26 | private static final String DEFAULT_SERIALIZATION = "PROTOBUF"; 27 | public static final String CONNECT_STRING_PREFIX = "jdbc:phoenix:thin:"; 28 | 29 | private ThinClientUtil() {} 30 | 31 | public static String getConnectionUrl(String hostname, int port) { 32 | return getConnectionUrl("http", hostname, port); 33 | } 34 | 35 | public static String getConnectionUrl(String protocol, String hostname, int port) { 36 | return getConnectionUrl(protocol, hostname, port, DEFAULT_SERIALIZATION); 37 | } 38 | 39 | public static String getConnectionUrl(String protocol, String hostname, int port, String serialization) { 40 | String urlFmt = CONNECT_STRING_PREFIX + "url=%s://%s:%s;serialization=%s"; 41 | return String.format(urlFmt, protocol, hostname, port, serialization); 42 | } 43 | } 44 | -------------------------------------------------------------------------------- /phoenix-queryserver/src/test/java/org/apache/phoenix/DriverCohabitationTest.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Licensed to the Apache Software Foundation (ASF) under one 3 | * or more contributor license agreements. See the NOTICE file 4 | * distributed with this work for additional information 5 | * regarding copyright ownership. The ASF licenses this file 6 | * to you under the Apache License, Version 2.0 (the 7 | * "License"); you may not use this file except in compliance 8 | * with the License. You may obtain a copy of the License at 9 | * 10 | * http://www.apache.org/licenses/LICENSE-2.0 11 | * 12 | * Unless required by applicable law or agreed to in writing, software 13 | * distributed under the License is distributed on an "AS IS" BASIS, 14 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 15 | * See the License for the specific language governing permissions and 16 | * limitations under the License. 17 | */ 18 | package org.apache.phoenix; 19 | 20 | import org.apache.phoenix.util.QueryUtil; 21 | import org.apache.phoenix.util.ThinClientUtil; 22 | import org.junit.Test; 23 | 24 | import java.sql.Driver; 25 | import java.sql.DriverManager; 26 | import java.sql.SQLException; 27 | import java.util.Collections; 28 | 29 | import static org.junit.Assert.assertFalse; 30 | import static org.junit.Assert.assertNotNull; 31 | import static org.junit.Assert.assertTrue; 32 | 33 | /** 34 | * Ensure the "thick" Phoenix driver and it's "thin" counterpart can coexist on 35 | * the same classpath. 36 | */ 37 | public class DriverCohabitationTest { 38 | 39 | @Test 40 | public void testDriverCohabitation() throws SQLException { 41 | Driver thickDriver = null; 42 | Driver thinDriver = null; 43 | 44 | for (Driver d : Collections.list(DriverManager.getDrivers())) { 45 | if (d instanceof org.apache.phoenix.jdbc.PhoenixDriver) { 46 | thickDriver = d; 47 | } else if (d instanceof org.apache.phoenix.queryserver.client.Driver) { 48 | thinDriver = d; 49 | } 50 | } 51 | assertNotNull("Thick driver not registered with DriverManager.", thickDriver); 52 | assertNotNull("Thin driver not registered with DriverManager.", thinDriver); 53 | 54 | final String thickUrl = QueryUtil.getUrl("localhost"); 55 | final String thinUrl = ThinClientUtil.getConnectionUrl("localhost", 1234); 56 | assertTrue("Thick driver should accept connections like " + thickUrl, 57 | thickDriver.acceptsURL(thickUrl)); 58 | assertFalse("Thick driver should reject connections like " + thinUrl, 59 | thickDriver.acceptsURL(thinUrl)); 60 | assertTrue("Thin driver should accept connections like " + thinUrl, 61 | thinDriver.acceptsURL(thinUrl)); 62 | assertFalse("Thin driver should reject connections like " + thickUrl, 63 | thinDriver.acceptsURL(thickUrl)); 64 | } 65 | } 66 | -------------------------------------------------------------------------------- /phoenix-queryserver/src/test/java/org/apache/phoenix/queryserver/server/CustomAvaticaServerConfigurationTest.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Licensed to the Apache Software Foundation (ASF) under one 3 | * or more contributor license agreements. See the NOTICE file 4 | * distributed with this work for additional information 5 | * regarding copyright ownership. The ASF licenses this file 6 | * to you under the Apache License, Version 2.0 (the 7 | * "License"); you may not use this file except in compliance 8 | * with the License. You may obtain a copy of the License at 9 | * 10 | * http://www.apache.org/licenses/LICENSE-2.0 11 | * 12 | * Unless required by applicable law or agreed to in writing, software 13 | * distributed under the License is distributed on an "AS IS" BASIS, 14 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 15 | * See the License for the specific language governing permissions and 16 | * limitations under the License. 17 | */ 18 | package org.apache.phoenix.queryserver.server; 19 | 20 | import org.apache.calcite.avatica.server.AvaticaServerConfiguration; 21 | import org.apache.hadoop.conf.Configuration; 22 | import org.apache.hadoop.security.UserGroupInformation; 23 | import org.junit.Assert; 24 | import org.junit.Test; 25 | 26 | import java.io.IOException; 27 | 28 | public class CustomAvaticaServerConfigurationTest { 29 | @Test 30 | public void testDefaultFactory() throws IOException { 31 | QueryServer queryServer = new QueryServer(); 32 | UserGroupInformation ugi = queryServer.getUserGroupInformation(); 33 | // the default factory creates null object 34 | AvaticaServerConfiguration avaticaServerConfiguration = queryServer.createAvaticaServerConfig(new Configuration(), ugi); 35 | Assert.assertNull(avaticaServerConfiguration); 36 | } 37 | } 38 | -------------------------------------------------------------------------------- /phoenix-queryserver/src/test/java/org/apache/phoenix/queryserver/server/PhoenixDoAsCallbackTest.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Licensed to the Apache Software Foundation (ASF) under one or more 3 | * contributor license agreements. See the NOTICE file distributed with 4 | * this work for additional information regarding copyright ownership. 5 | * The ASF licenses this file to you under the Apache License, Version 2.0 6 | * (the "License"); you may not use this file except in compliance with 7 | * the License. You may obtain a copy of the License at 8 | * 9 | * http://www.apache.org/licenses/LICENSE-2.0 10 | * 11 | * Unless required by applicable law or agreed to in writing, software 12 | * distributed under the License is distributed on an "AS IS" BASIS, 13 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 | * See the License for the specific language governing permissions and 15 | * limitations under the License. 16 | */ 17 | package org.apache.phoenix.queryserver.server; 18 | 19 | import static org.junit.Assert.assertEquals; 20 | import static org.junit.Assert.assertNotEquals; 21 | import static org.junit.Assert.assertTrue; 22 | 23 | import java.util.concurrent.Callable; 24 | 25 | import org.apache.hadoop.conf.Configuration; 26 | import org.apache.hadoop.security.UserGroupInformation; 27 | import org.apache.hadoop.security.authorize.ProxyUsers; 28 | import org.apache.phoenix.queryserver.server.QueryServer.PhoenixDoAsCallback; 29 | import org.junit.Test; 30 | 31 | /** 32 | * Tests for the authorization callback hook Avatica provides for Phoenix to implement. 33 | */ 34 | public class PhoenixDoAsCallbackTest { 35 | 36 | @Test 37 | public void ugiInstancesAreCached() throws Exception { 38 | Configuration conf = new Configuration(false); 39 | UserGroupInformation serverUgi = UserGroupInformation.createUserForTesting("server", new String[0]); 40 | PhoenixDoAsCallback callback = new PhoenixDoAsCallback(serverUgi, conf); 41 | 42 | UserGroupInformation ugi1 = callback.createProxyUser("user1"); 43 | assertEquals(1, callback.getCache().size()); 44 | assertTrue(ugi1.getRealUser() == serverUgi); 45 | UserGroupInformation ugi2 = callback.createProxyUser("user2"); 46 | assertEquals(2, callback.getCache().size()); 47 | assertTrue(ugi2.getRealUser() == serverUgi); 48 | 49 | UserGroupInformation ugi1Reference = callback.createProxyUser("user1"); 50 | assertTrue(ugi1 == ugi1Reference); 51 | assertEquals(2, callback.getCache().size()); 52 | } 53 | 54 | @Test 55 | public void proxyingUsersAreCached() throws Exception { 56 | Configuration conf = new Configuration(false); 57 | // The user "server" can impersonate anyone 58 | conf.set("hadoop.proxyuser.server.groups", "*"); 59 | conf.set("hadoop.proxyuser.server.hosts", "*"); 60 | // Trigger ProxyUsers to refresh itself with the above configuration 61 | ProxyUsers.refreshSuperUserGroupsConfiguration(conf); 62 | UserGroupInformation serverUgi = UserGroupInformation.createUserForTesting("server", new String[0]); 63 | PhoenixDoAsCallback callback = new PhoenixDoAsCallback(serverUgi, conf); 64 | 65 | UserGroupInformation user1 = callback.doAsRemoteUser("user1", "localhost:1234", new Callable() { 66 | public UserGroupInformation call() throws Exception { 67 | return UserGroupInformation.getCurrentUser(); 68 | } 69 | }); 70 | 71 | UserGroupInformation user2 = callback.doAsRemoteUser("user2", "localhost:1235", new Callable() { 72 | public UserGroupInformation call() throws Exception { 73 | return UserGroupInformation.getCurrentUser(); 74 | } 75 | }); 76 | 77 | UserGroupInformation user1Reference = callback.doAsRemoteUser("user1", "localhost:1234", new Callable() { 78 | public UserGroupInformation call() throws Exception { 79 | return UserGroupInformation.getCurrentUser(); 80 | } 81 | }); 82 | 83 | // The UserGroupInformation.getCurrentUser() actually returns a new UGI instance, but the internal 84 | // subject is the same. We can verify things will work as expected that way. 85 | assertNotEquals(user1.hashCode(), user2.hashCode()); 86 | assertEquals("These should be the same (cached) instance", user1.hashCode(), user1Reference.hashCode()); 87 | assertEquals("These should be the same (cached) instance", user1, user1Reference); 88 | } 89 | } 90 | -------------------------------------------------------------------------------- /phoenix-queryserver/src/test/java/org/apache/phoenix/queryserver/server/PhoenixRemoteUserExtractorTest.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Licensed to the Apache Software Foundation (ASF) under one or more 3 | * contributor license agreements. See the NOTICE file distributed with 4 | * this work for additional information regarding copyright ownership. 5 | * The ASF licenses this file to you under the Apache License, Version 2.0 6 | * (the "License"); you may not use this file except in compliance with 7 | * the License. You may obtain a copy of the License at 8 | * 9 | * http://www.apache.org/licenses/LICENSE-2.0 10 | * 11 | * Unless required by applicable law or agreed to in writing, software 12 | * distributed under the License is distributed on an "AS IS" BASIS, 13 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 | * See the License for the specific language governing permissions and 15 | * limitations under the License. 16 | */ 17 | package org.apache.phoenix.queryserver.server; 18 | 19 | import static org.junit.Assert.assertEquals; 20 | import static org.mockito.ArgumentMatchers.any; 21 | import static org.mockito.Mockito.mock; 22 | import static org.mockito.Mockito.never; 23 | import static org.mockito.Mockito.verify; 24 | import static org.mockito.Mockito.when; 25 | 26 | import javax.servlet.http.HttpServletRequest; 27 | 28 | import org.apache.calcite.avatica.server.HttpServer; 29 | import org.apache.calcite.avatica.server.RemoteUserExtractionException; 30 | import org.apache.hadoop.conf.Configuration; 31 | import org.apache.hadoop.security.authorize.ProxyUsers; 32 | import org.apache.phoenix.queryserver.QueryServerProperties; 33 | import org.apache.phoenix.queryserver.server.QueryServer.PhoenixRemoteUserExtractor; 34 | import org.junit.Test; 35 | import org.slf4j.Logger; 36 | import org.slf4j.LoggerFactory; 37 | 38 | /** 39 | * Tests for the RemoteUserExtractor Method Avatica provides for Phoenix to implement. 40 | */ 41 | public class PhoenixRemoteUserExtractorTest { 42 | private static final Logger LOG = LoggerFactory.getLogger(PhoenixRemoteUserExtractorTest.class); 43 | 44 | @Test 45 | public void testWithRemoteUserExtractorSuccess() { 46 | HttpServletRequest request = mock(HttpServletRequest.class); 47 | when(request.getRemoteUser()).thenReturn("proxyserver"); 48 | when(request.getParameter("doAs")).thenReturn("enduser"); 49 | when(request.getRemoteAddr()).thenReturn("localhost:1234"); 50 | 51 | Configuration conf = new Configuration(false); 52 | conf.set("hadoop.proxyuser.proxyserver.groups", "*"); 53 | conf.set("hadoop.proxyuser.proxyserver.hosts", "*"); 54 | conf.set(QueryServerProperties.QUERY_SERVER_WITH_REMOTEUSEREXTRACTOR_ATTRIB, "true"); 55 | ProxyUsers.refreshSuperUserGroupsConfiguration(conf); 56 | 57 | PhoenixRemoteUserExtractor extractor = new PhoenixRemoteUserExtractor(conf); 58 | try { 59 | assertEquals("enduser", extractor.extract(request)); 60 | } catch (RemoteUserExtractionException e) { 61 | LOG.info(e.getMessage()); 62 | } 63 | } 64 | 65 | @Test 66 | public void testNoRemoteUserExtractorParam() { 67 | HttpServletRequest request = mock(HttpServletRequest.class); 68 | when(request.getRemoteUser()).thenReturn("proxyserver"); 69 | when(request.getRemoteAddr()).thenReturn("localhost:1234"); 70 | 71 | Configuration conf = new Configuration(false); 72 | conf.set("hadoop.proxyuser.proxyserver.groups", "*"); 73 | conf.set("hadoop.proxyuser.proxyserver.hosts", "*"); 74 | conf.set(QueryServerProperties.QUERY_SERVER_WITH_REMOTEUSEREXTRACTOR_ATTRIB, "true"); 75 | ProxyUsers.refreshSuperUserGroupsConfiguration(conf); 76 | 77 | PhoenixRemoteUserExtractor extractor = new PhoenixRemoteUserExtractor(conf); 78 | try { 79 | assertEquals("proxyserver", extractor.extract(request)); 80 | } catch (RemoteUserExtractionException e) { 81 | LOG.info(e.getMessage()); 82 | } 83 | } 84 | 85 | @Test 86 | public void testDoNotUseRemoteUserExtractor() { 87 | 88 | HttpServer.Builder builder = mock(HttpServer.Builder.class); 89 | Configuration conf = new Configuration(false); 90 | QueryServer queryServer = new QueryServer(); 91 | queryServer.setRemoteUserExtractorIfNecessary(builder, conf); 92 | verify(builder, never()).withRemoteUserExtractor(any(PhoenixRemoteUserExtractor.class)); 93 | } 94 | 95 | @Test 96 | public void testUseRemoteUserExtractor() { 97 | 98 | HttpServer.Builder builder = mock(HttpServer.Builder.class); 99 | Configuration conf = new Configuration(false); 100 | conf.set(QueryServerProperties.QUERY_SERVER_WITH_REMOTEUSEREXTRACTOR_ATTRIB, "true"); 101 | QueryServer queryServer = new QueryServer(); 102 | queryServer.setRemoteUserExtractorIfNecessary(builder, conf); 103 | verify(builder).withRemoteUserExtractor(any(PhoenixRemoteUserExtractor.class)); 104 | } 105 | 106 | } 107 | -------------------------------------------------------------------------------- /phoenix-queryserver/src/test/java/org/apache/phoenix/queryserver/server/QueryServerConfigurationTest.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Licensed to the Apache Software Foundation (ASF) under one 3 | * or more contributor license agreements. See the NOTICE file 4 | * distributed with this work for additional information 5 | * regarding copyright ownership. The ASF licenses this file 6 | * to you under the Apache License, Version 2.0 (the 7 | * "License"); you may not use this file except in compliance 8 | * with the License. You may obtain a copy of the License at 9 | * 10 | * http://www.apache.org/licenses/LICENSE-2.0 11 | * 12 | * Unless required by applicable law or agreed to in writing, software 13 | * distributed under the License is distributed on an "AS IS" BASIS, 14 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 15 | * See the License for the specific language governing permissions and 16 | * limitations under the License. 17 | */ 18 | package org.apache.phoenix.queryserver.server; 19 | 20 | import static org.mockito.ArgumentMatchers.any; 21 | import static org.mockito.ArgumentMatchers.anyString; 22 | import static org.mockito.ArgumentMatchers.nullable; 23 | import static org.mockito.Mockito.doReturn; 24 | import static org.mockito.Mockito.mock; 25 | import static org.mockito.Mockito.never; 26 | import static org.mockito.Mockito.verify; 27 | 28 | import java.io.File; 29 | import java.io.IOException; 30 | 31 | import org.apache.calcite.avatica.server.AvaticaServerConfiguration; 32 | import org.apache.calcite.avatica.server.DoAsRemoteUserCallback; 33 | import org.apache.calcite.avatica.server.HttpServer; 34 | import org.apache.hadoop.conf.Configuration; 35 | import org.apache.hadoop.hbase.HBaseConfiguration; 36 | import org.apache.hadoop.security.UserGroupInformation; 37 | import org.apache.phoenix.queryserver.QueryServerProperties; 38 | import org.junit.Before; 39 | import org.junit.Rule; 40 | import org.junit.Test; 41 | import org.junit.rules.TemporaryFolder; 42 | 43 | public class QueryServerConfigurationTest { 44 | private static final Configuration CONF = HBaseConfiguration.create(); 45 | 46 | @Rule public TemporaryFolder testFolder = new TemporaryFolder(); 47 | 48 | private HttpServer.Builder builder; 49 | private QueryServer queryServer; 50 | private UserGroupInformation ugi; 51 | 52 | @Before 53 | public void setup() throws IOException { 54 | builder = mock(HttpServer.Builder.class); 55 | queryServer = new QueryServer(new String[0], CONF); 56 | ugi = queryServer.getUserGroupInformation(); 57 | } 58 | 59 | @Test 60 | public void testSpnegoEnabled() throws IOException { 61 | setupKeytabForSpnego(); 62 | // SPENEGO settings will be provided to the builder when enabled 63 | doReturn(builder).when(builder).withSpnego(anyString(), nullable(String[].class)); 64 | configureAndVerifyImpersonation(builder, false); 65 | // A keytab file will also be provided for automatic login 66 | verify(builder).withAutomaticLogin(any(File.class)); 67 | verify(builder, never()).withCustomAuthentication(any(AvaticaServerConfiguration.class)); 68 | } 69 | 70 | @Test 71 | public void testSpnegoDisabled() throws IOException { 72 | setupKeytabForSpnego(); 73 | configureAndVerifyImpersonation(builder, true); 74 | verify(builder, never()).withSpnego(anyString(), any(String[].class)); 75 | verify(builder, never()).withAutomaticLogin(any(File.class)); 76 | verify(builder, never()).withCustomAuthentication(any(AvaticaServerConfiguration.class)); 77 | } 78 | 79 | @Test 80 | public void testCustomServerConfiguration() { 81 | queryServer.enableCustomAuth(builder, CONF, ugi); 82 | verify(builder).withCustomAuthentication(nullable(AvaticaServerConfiguration.class)); 83 | verify(builder, never()).withSpnego(anyString(), nullable(String[].class)); 84 | verify(builder, never()).withAutomaticLogin(any(File.class)); 85 | verify(builder, never()).withImpersonation(any(DoAsRemoteUserCallback.class)); 86 | } 87 | 88 | private void setupKeytabForSpnego() throws IOException { 89 | File keytabFile = testFolder.newFile("test.keytab"); 90 | CONF.set(QueryServerProperties.QUERY_SERVER_KEYTAB_FILENAME_ATTRIB, keytabFile.getAbsolutePath()); 91 | } 92 | 93 | private void configureAndVerifyImpersonation(HttpServer.Builder builder, boolean disableSpnego) 94 | throws IOException { 95 | queryServer.configureClientAuthentication(builder, disableSpnego, ugi); 96 | verify(builder).withImpersonation(any(DoAsRemoteUserCallback.class)); 97 | } 98 | } 99 | -------------------------------------------------------------------------------- /phoenix-queryserver/src/test/java/org/apache/phoenix/queryserver/server/QueryServerTest.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Licensed to the Apache Software Foundation (ASF) under one 3 | * or more contributor license agreements. See the NOTICE file 4 | * distributed with this work for additional information 5 | * regarding copyright ownership. The ASF licenses this file 6 | * to you under the Apache License, Version 2.0 (the 7 | * "License"); you may not use this file except in compliance 8 | * with the License. You may obtain a copy of the License at 9 | * 10 | * http://www.apache.org/licenses/LICENSE-2.0 11 | * 12 | * Unless required by applicable law or agreed to in writing, software 13 | * distributed under the License is distributed on an "AS IS" BASIS, 14 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 15 | * See the License for the specific language governing permissions and 16 | * limitations under the License. 17 | */ 18 | package org.apache.phoenix.queryserver.server; 19 | 20 | import static org.junit.Assert.assertEquals; 21 | 22 | import java.io.IOException; 23 | import java.net.InetAddress; 24 | 25 | import org.apache.hadoop.conf.Configuration; 26 | import org.apache.phoenix.queryserver.QueryServerProperties; 27 | import org.junit.Before; 28 | import org.junit.BeforeClass; 29 | import org.junit.Test; 30 | 31 | public class QueryServerTest { 32 | 33 | private static String getSpnegoPrincipal(String instance) { 34 | return "HTTP/" + instance + "@EXAMPLE.COM"; 35 | } 36 | 37 | private static String EXPECTED_HOSTNAME; 38 | private QueryServer qs; 39 | private Configuration conf; 40 | 41 | @BeforeClass 42 | public static void setupOnce() throws IOException { 43 | EXPECTED_HOSTNAME = InetAddress.getLocalHost().getCanonicalHostName().toLowerCase(); 44 | } 45 | 46 | @Before 47 | public void setup() { 48 | this.conf = new Configuration(false); 49 | this.qs = new QueryServer(); 50 | } 51 | 52 | @Test 53 | public void testHostExpansion() throws IOException { 54 | conf.set(QueryServerProperties.QUERY_SERVER_KERBEROS_HTTP_PRINCIPAL_ATTRIB, getSpnegoPrincipal("_HOST")); 55 | 56 | assertEquals(getSpnegoPrincipal(EXPECTED_HOSTNAME), qs.getSpnegoPrincipal(conf)); 57 | } 58 | 59 | @Test 60 | public void testHostExpansionWithOldName() throws IOException { 61 | conf.set(QueryServerProperties.QUERY_SERVER_KERBEROS_HTTP_PRINCIPAL_ATTRIB_LEGACY, getSpnegoPrincipal("_HOST")); 62 | 63 | assertEquals(getSpnegoPrincipal(EXPECTED_HOSTNAME), qs.getSpnegoPrincipal(conf)); 64 | } 65 | 66 | @Test 67 | public void testHostExpansionWithOldAndNewNames() throws IOException { 68 | conf.set(QueryServerProperties.QUERY_SERVER_KERBEROS_HTTP_PRINCIPAL_ATTRIB, getSpnegoPrincipal("_HOST")); 69 | // When we provide both names, the new property should take priority 70 | conf.set(QueryServerProperties.QUERY_SERVER_KERBEROS_HTTP_PRINCIPAL_ATTRIB_LEGACY, "fake_" + getSpnegoPrincipal("_HOST")); 71 | 72 | assertEquals(getSpnegoPrincipal(EXPECTED_HOSTNAME), qs.getSpnegoPrincipal(conf)); 73 | } 74 | 75 | } 76 | -------------------------------------------------------------------------------- /phoenix-queryserver/src/test/java/org/apache/phoenix/queryserver/server/RemoteUserExtractorFactoryTest.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Licensed to the Apache Software Foundation (ASF) under one 3 | * or more contributor license agreements. See the NOTICE file 4 | * distributed with this work for additional information 5 | * regarding copyright ownership. The ASF licenses this file 6 | * to you under the Apache License, Version 2.0 (the 7 | * "License"); you may not use this file except in compliance 8 | * with the License. You may obtain a copy of the License at 9 | * 10 | * http://www.apache.org/licenses/LICENSE-2.0 11 | * 12 | * Unless required by applicable law or agreed to in writing, software 13 | * distributed under the License is distributed on an "AS IS" BASIS, 14 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 15 | * See the License for the specific language governing permissions and 16 | * limitations under the License. 17 | */ 18 | package org.apache.phoenix.queryserver.server; 19 | 20 | import org.apache.calcite.avatica.server.RemoteUserExtractor; 21 | import org.apache.hadoop.conf.Configuration; 22 | import org.junit.Assert; 23 | import org.junit.Test; 24 | 25 | public class RemoteUserExtractorFactoryTest { 26 | 27 | @Test 28 | public void testProvidesDefaultFactory() { 29 | QueryServer queryServer = new QueryServer(); 30 | RemoteUserExtractor extractor = queryServer.createRemoteUserExtractor(new Configuration()); 31 | Assert.assertTrue( 32 | "Not an instance of PhoenixRemoteUserExtractor: " + extractor.getClass().getName(), 33 | extractor instanceof QueryServer.PhoenixRemoteUserExtractor); 34 | } 35 | } 36 | -------------------------------------------------------------------------------- /phoenix-queryserver/src/test/java/org/apache/phoenix/queryserver/server/ServerCustomizersTest.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Licensed to the Apache Software Foundation (ASF) under one 3 | * or more contributor license agreements. See the NOTICE file 4 | * distributed with this work for additional information 5 | * regarding copyright ownership. The ASF licenses this file 6 | * to you under the Apache License, Version 2.0 (the 7 | * "License"); you may not use this file except in compliance 8 | * with the License. You may obtain a copy of the License at 9 | * 10 | * http://www.apache.org/licenses/LICENSE-2.0 11 | * 12 | * Unless required by applicable law or agreed to in writing, software 13 | * distributed under the License is distributed on an "AS IS" BASIS, 14 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 15 | * See the License for the specific language governing permissions and 16 | * limitations under the License. 17 | */ 18 | package org.apache.phoenix.queryserver.server; 19 | 20 | import java.util.Collections; 21 | import java.util.List; 22 | 23 | import org.apache.calcite.avatica.server.HttpServer; 24 | import org.apache.calcite.avatica.server.AvaticaServerConfiguration; 25 | import org.apache.calcite.avatica.server.ServerCustomizer; 26 | import org.apache.hadoop.conf.Configuration; 27 | import org.apache.phoenix.query.QueryServices; 28 | import org.apache.phoenix.queryserver.QueryServerProperties; 29 | import org.apache.phoenix.util.InstanceResolver; 30 | import org.eclipse.jetty.server.Server; 31 | import org.junit.After; 32 | import org.junit.Assert; 33 | import org.junit.Before; 34 | import org.junit.Test; 35 | 36 | import static org.mockito.ArgumentMatchers.*; 37 | import static org.mockito.Mockito.mock; 38 | import static org.mockito.Mockito.verify; 39 | 40 | public class ServerCustomizersTest { 41 | @Before @After 42 | public void clearSingletons() { 43 | // clean up singletons 44 | InstanceResolver.clearSingletons(); 45 | } 46 | 47 | @Test 48 | public void testDefaultFactory() { 49 | QueryServer queryServer = new QueryServer(); 50 | AvaticaServerConfiguration avaticaServerConfiguration = null; 51 | // the default factory creates an empty list of server customizers 52 | List> customizers = 53 | queryServer.createServerCustomizers(new Configuration(), avaticaServerConfiguration); 54 | Assert.assertEquals(1, customizers.size()); 55 | } 56 | 57 | @Test 58 | public void testUseProvidedCustomizers() { 59 | AvaticaServerConfiguration avaticaServerConfiguration = null; 60 | final List> expected = 61 | Collections.> singletonList(new ServerCustomizer() { 62 | @Override 63 | public void customize(Server server) { 64 | // no-op customizer 65 | } 66 | }); 67 | // Register the server customizer list 68 | InstanceResolver.getSingleton(ServerCustomizersFactory.class, new ServerCustomizersFactory() { 69 | @Override 70 | public List> createServerCustomizers(Configuration conf, 71 | AvaticaServerConfiguration avaticaServerConfiguration) { 72 | return expected; 73 | } 74 | }); 75 | Configuration conf = new Configuration(false); 76 | QueryServer queryServer = new QueryServer(); 77 | List> actual = queryServer.createServerCustomizers(conf, avaticaServerConfiguration); 78 | Assert.assertEquals("Customizers are different", expected, actual); 79 | } 80 | } 81 | -------------------------------------------------------------------------------- /phoenix-queryserver/src/test/java/org/apache/phoenix/queryserver/server/customizers/HostedClientJarsServerCustomizerTest.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Licensed to the Apache Software Foundation (ASF) under one 3 | * or more contributor license agreements. See the NOTICE file 4 | * distributed with this work for additional information 5 | * regarding copyright ownership. The ASF licenses this file 6 | * to you under the Apache License, Version 2.0 (the 7 | * "License"); you may not use this file except in compliance 8 | * with the License. You may obtain a copy of the License at 9 | * 10 | * http://www.apache.org/licenses/LICENSE-2.0 11 | * 12 | * Unless required by applicable law or agreed to in writing, software 13 | * distributed under the License is distributed on an "AS IS" BASIS, 14 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 15 | * See the License for the specific language governing permissions and 16 | * limitations under the License. 17 | */ 18 | package org.apache.phoenix.queryserver.server.customizers; 19 | 20 | import static org.junit.Assert.assertEquals; 21 | import static org.junit.Assert.assertTrue; 22 | 23 | import java.io.File; 24 | 25 | import org.eclipse.jetty.server.Handler; 26 | import org.eclipse.jetty.server.Server; 27 | import org.eclipse.jetty.server.handler.ContextHandler; 28 | import org.eclipse.jetty.server.handler.HandlerList; 29 | import org.eclipse.jetty.server.handler.ResourceHandler; 30 | import org.junit.Test; 31 | import org.mockito.Mockito; 32 | 33 | public class HostedClientJarsServerCustomizerTest { 34 | 35 | @Test 36 | public void testHandlerIsPrefixed() { 37 | final Handler handler1 = Mockito.mock(Handler.class); 38 | final Handler handler2 = Mockito.mock(Handler.class); 39 | 40 | Server svr = new Server(); 41 | svr.setHandler(new HandlerList(handler1, handler2)); 42 | 43 | File f = new File("/for-test"); 44 | String context = "/my-context"; 45 | HostedClientJarsServerCustomizer customizer = new HostedClientJarsServerCustomizer(f, context); 46 | customizer.customize(svr); 47 | 48 | assertEquals(1, svr.getHandlers().length); 49 | Handler actualHandler = svr.getHandler(); 50 | assertTrue("Handler was " + actualHandler.getClass(), actualHandler instanceof HandlerList); 51 | 52 | HandlerList actualHandlerList = (HandlerList) actualHandler; 53 | assertEquals(3, actualHandlerList.getHandlers().length); 54 | assertEquals(handler1, actualHandlerList.getHandlers()[1]); 55 | assertEquals(handler2, actualHandlerList.getHandlers()[2]); 56 | 57 | Handler injectedHandler = actualHandlerList.getHandlers()[0]; 58 | assertTrue("Handler was " + injectedHandler.getClass(), injectedHandler instanceof ContextHandler); 59 | ContextHandler ctx = (ContextHandler) injectedHandler; 60 | assertTrue("Handler was " + ctx.getHandler().getClass(), ctx.getHandler() instanceof ResourceHandler); 61 | assertEquals(context, ctx.getContextPath()); 62 | ResourceHandler res = (ResourceHandler) ctx.getHandler(); 63 | // Jetty puts in a proper URI for the file we give it 64 | assertEquals("file://" + f.getAbsolutePath(), res.getResourceBase()); 65 | } 66 | 67 | } 68 | -------------------------------------------------------------------------------- /phoenix-queryserver/src/test/java/org/apache/phoenix/queryserver/util/SimpleLRUCacheTest.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Licensed to the Apache Software Foundation (ASF) under one 3 | * or more contributor license agreements. See the NOTICE file 4 | * distributed with this work for additional information 5 | * regarding copyright ownership. The ASF licenses this file 6 | * to you under the Apache License, Version 2.0 (the 7 | * "License"); you may not use this file except in compliance 8 | * with the License. You may obtain a copy of the License at 9 | * 10 | * http://www.apache.org/licenses/LICENSE-2.0 11 | * 12 | * Unless required by applicable law or agreed to in writing, software 13 | * distributed under the License is distributed on an "AS IS" BASIS, 14 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 15 | * See the License for the specific language governing permissions and 16 | * limitations under the License. 17 | */ 18 | package org.apache.phoenix.queryserver.util; 19 | 20 | import static org.junit.Assert.assertTrue; 21 | 22 | import org.apache.phoenix.util.SimpleLRUCache; 23 | import org.junit.Test; 24 | 25 | public class SimpleLRUCacheTest { 26 | 27 | @Test 28 | public void testCache() throws InterruptedException { 29 | SimpleLRUCache cache = new SimpleLRUCache<>(10, 1); 30 | 31 | String zero = access(cache, "0"); 32 | //Make sure we actually cache objects 33 | assertTrue(zero == access(cache, "0")); 34 | 35 | for(int c=1; c<9; c++) { 36 | access(cache, Integer.toString(c)); 37 | Thread.sleep(5); 38 | } 39 | 40 | //Access these to make sure that they don't get evicted. 41 | String one = access(cache, "1"); 42 | String two = access(cache, "2"); 43 | 44 | for(int c=10; c<13; c++) { 45 | access(cache, Integer.toString(c)); 46 | Thread.sleep(5); 47 | } 48 | 49 | assertTrue(one == access(cache, one)); 50 | assertTrue(two == access(cache, two)); 51 | 52 | assertTrue(cache.size() <= 12); 53 | } 54 | 55 | private String access(SimpleLRUCache cache, String key) { 56 | return cache.computeIfAbsent(key, k -> new String(key)); 57 | } 58 | } 59 | -------------------------------------------------------------------------------- /python-phoenixdb/.gitignore: -------------------------------------------------------------------------------- 1 | /dist/ 2 | /build/ 3 | /doc/_build/ 4 | /doc/build/ 5 | *.pyc 6 | *.egg-info/ 7 | .vagrant/ 8 | .tox 9 | dev-support/artifacts 10 | dev-support/work 11 | phoenixdb/.eggs 12 | phoenixdb/build 13 | phoenixdb/e 14 | phoenixdb/.python-version 15 | -------------------------------------------------------------------------------- /python-phoenixdb/.gitlab-ci.yml: -------------------------------------------------------------------------------- 1 | # Licensed to the Apache Software Foundation (ASF) under one or more 2 | # contributor license agreements. See the NOTICE file distributed with 3 | # this work for additional information regarding copyright ownership. 4 | # The ASF licenses this file to You under the Apache License, Version 2.0 5 | # (the "License"); you may not use this file except in compliance with 6 | # the License. You may obtain a copy of the License at 7 | # 8 | # http://www.apache.org/licenses/LICENSE-2.0 9 | # 10 | # Unless required by applicable law or agreed to in writing, software 11 | # distributed under the License is distributed on an "AS IS" BASIS, 12 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | # See the License for the specific language governing permissions and 14 | # limitations under the License. 15 | 16 | stages: 17 | - prepare 18 | - test 19 | 20 | build build-env image: 21 | stage: prepare 22 | script: 23 | - cd ci/build-env 24 | - docker build -t ${CI_REGISTRY_IMAGE}/build-env . 25 | - docker login -u gitlab-ci-token -p $CI_BUILD_TOKEN $CI_REGISTRY 26 | - docker push $CI_REGISTRY_IMAGE/build-env 27 | tags: 28 | - docker-host 29 | only: 30 | - master@lukas/python-phoenixdb 31 | 32 | .build-phoenix-image: &build_phoenix_image 33 | stage: prepare 34 | script: 35 | - JOB_NAME=($CI_JOB_NAME) 36 | - cd ci/phoenix 37 | - docker build -t ${CI_REGISTRY_IMAGE}/phoenix:${JOB_NAME[2]} 38 | --build-arg PHOENIX_VERSION=$PHOENIX_VERSION 39 | --build-arg HBASE_VERSION=$HBASE_VERSION 40 | --build-arg HBASE_DIR=$HBASE_DIR 41 | . 42 | - docker login -u gitlab-ci-token -p $CI_BUILD_TOKEN $CI_REGISTRY 43 | - docker push $CI_REGISTRY_IMAGE/phoenix:${JOB_NAME[2]} 44 | tags: 45 | - docker-host 46 | 47 | build phoenix 5.0.0-alpha-HBase-2.0 image: 48 | <<: *build_phoenix_image 49 | variables: 50 | PHOENIX_VERSION: 5.0.0-alpha-HBase-2.0 51 | HBASE_VERSION: 2.0.0-beta-1 52 | HBASE_DIR: hbase-2.0.0-beta-1 53 | 54 | build phoenix 4.13 image: 55 | <<: *build_phoenix_image 56 | variables: 57 | PHOENIX_VERSION: 4.13.1-HBase-1.3 58 | HBASE_VERSION: 1.3.1 59 | HBASE_DIR: 1.3.1 60 | 61 | build phoenix 4.12 image: 62 | <<: *build_phoenix_image 63 | variables: 64 | PHOENIX_VERSION: 4.12.0-HBase-1.3 65 | HBASE_VERSION: 1.3.1 66 | HBASE_DIR: 1.3.1 67 | 68 | build phoenix 4.11 image: 69 | <<: *build_phoenix_image 70 | variables: 71 | PHOENIX_VERSION: 4.11.0-HBase-1.3 72 | HBASE_VERSION: 1.3.1 73 | HBASE_DIR: 1.3.1 74 | 75 | build phoenix 4.10 image: 76 | <<: *build_phoenix_image 77 | variables: 78 | PHOENIX_VERSION: 4.10.0-HBase-1.2 79 | HBASE_VERSION: 1.2.6 80 | HBASE_DIR: 1.2.6 81 | 82 | build phoenix 4.9 image: 83 | <<: *build_phoenix_image 84 | variables: 85 | PHOENIX_VERSION: 4.9.0-HBase-1.2 86 | HBASE_VERSION: 1.2.6 87 | HBASE_DIR: 1.2.6 88 | 89 | build phoenix 4.8 image: 90 | <<: *build_phoenix_image 91 | variables: 92 | PHOENIX_VERSION: 4.8.2-HBase-1.2 93 | HBASE_VERSION: 1.2.6 94 | HBASE_DIR: 1.2.6 95 | 96 | .test: &test 97 | image: $CI_REGISTRY_IMAGE/build-env 98 | variables: 99 | PHOENIXDB_TEST_DB_URL: http://phoenix:8765/ 100 | PIP_CACHE_DIR: $CI_PROJECT_DIR/cache/ 101 | script: 102 | - tox -e py27,py35 103 | cache: 104 | paths: 105 | - cache/ 106 | tags: 107 | - docker 108 | 109 | test phoenix 5.0.0-alpha-HBase-2.0: 110 | <<: *test 111 | services: 112 | - name: $CI_REGISTRY_IMAGE/phoenix:5.0.0-alpha-HBase-2.0 113 | alias: phoenix 114 | 115 | test phoenix 4.13: 116 | <<: *test 117 | services: 118 | - name: $CI_REGISTRY_IMAGE/phoenix:4.13 119 | alias: phoenix 120 | 121 | test phoenix 4.12: 122 | <<: *test 123 | services: 124 | - name: $CI_REGISTRY_IMAGE/phoenix:4.12 125 | alias: phoenix 126 | 127 | test phoenix 4.11: 128 | <<: *test 129 | services: 130 | - name: $CI_REGISTRY_IMAGE/phoenix:4.11 131 | alias: phoenix 132 | 133 | test phoenix 4.10: 134 | <<: *test 135 | services: 136 | - name: $CI_REGISTRY_IMAGE/phoenix:4.10 137 | alias: phoenix 138 | 139 | test phoenix 4.9: 140 | <<: *test 141 | services: 142 | - name: $CI_REGISTRY_IMAGE/phoenix:4.9 143 | alias: phoenix 144 | 145 | test phoenix 4.8: 146 | <<: *test 147 | services: 148 | - name: $CI_REGISTRY_IMAGE/phoenix:4.8 149 | alias: phoenix 150 | -------------------------------------------------------------------------------- /python-phoenixdb/Dockerfile: -------------------------------------------------------------------------------- 1 | # Licensed to the Apache Software Foundation (ASF) under one or more 2 | # contributor license agreements. See the NOTICE file distributed with 3 | # this work for additional information regarding copyright ownership. 4 | # The ASF licenses this file to You under the Apache License, Version 2.0 5 | # (the "License"); you may not use this file except in compliance with 6 | # the License. You may obtain a copy of the License at 7 | # 8 | # http://www.apache.org/licenses/LICENSE-2.0 9 | # 10 | # Unless required by applicable law or agreed to in writing, software 11 | # distributed under the License is distributed on an "AS IS" BASIS, 12 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | # See the License for the specific language governing permissions and 14 | # limitations under the License. 15 | 16 | from advian/tox-base:ubuntu-jammy-2024-10-10 as tox 17 | 18 | ########################### 19 | # Prebuild given versions # 20 | ########################### 21 | ARG BUILD_PYTHON_VERSIONS="3.13 3.12 3.11 3.10 3.9" #Can we take this from the parent image ? 22 | ARG EXTRA_PYTHON_VERSIONS="3.5 3.6 3.7 3.8 2.7" 23 | RUN export RESOLVED_VERSIONS=`pyenv_resolve $BUILD_PYTHON_VERSIONS` \ 24 | && export EXTRA_RESOLVED_VERSIONS=`pyenv_resolve $EXTRA_PYTHON_VERSIONS` \ 25 | && for pyver in $EXTRA_RESOLVED_VERSIONS; do pyenv install $pyver; done \ 26 | && pyenv global $RESOLVED_VERSIONS $EXTRA_RESOLVED_VERSIONS \ 27 | && pyenv local --unset \ 28 | && python -m pip install -U tox \ 29 | && apt-get update \ 30 | && apt-get install -y krb5-user libkrb5-dev 31 | 32 | ENV PHOENIXDB_TEST_DB_URL=http://host.docker.internal:8765 33 | ENV PHOENIXDB_TEST_DB_TRUSTSTORE= 34 | ENV PHOENIXDB_TEST_DB_AUTHENTICATION= 35 | ENV PHOENIXDB_TEST_DB_AVATICA_USER= 36 | ENV PHOENIXDB_TEST_DB_AVATICA_PASSWORD= 37 | 38 | WORKDIR /app 39 | VOLUME /src 40 | 41 | COPY docker-entrypoint.sh / 42 | 43 | ENTRYPOINT ["/docker-entrypoint.sh"] -------------------------------------------------------------------------------- /python-phoenixdb/Dockerfile-pqs: -------------------------------------------------------------------------------- 1 | # Licensed to the Apache Software Foundation (ASF) under one or more 2 | # contributor license agreements. See the NOTICE file distributed with 3 | # this work for additional information regarding copyright ownership. 4 | # The ASF licenses this file to You under the Apache License, Version 2.0 5 | # (the "License"); you may not use this file except in compliance with 6 | # the License. You may obtain a copy of the License at 7 | # 8 | # http://www.apache.org/licenses/LICENSE-2.0 9 | # 10 | # Unless required by applicable law or agreed to in writing, software 11 | # distributed under the License is distributed on an "AS IS" BASIS, 12 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | # See the License for the specific language governing permissions and 14 | # limitations under the License. 15 | 16 | from maven:3-jdk-8 17 | 18 | RUN apt-get update && DEBIAN_FRONTEND=noninteractive apt-get install -yq krb5-user libkrb5-dev 19 | 20 | EXPOSE 8765 21 | 22 | # copy all the files to the container 23 | 24 | CMD mvn clean verify -am -pl queryserver-it -Dtest=foo -Dit.test=QueryServerBasicsIT#startLocalPQS -Ddo.not.randomize.pqs.port=true -Dstart.unsecure.pqs=true 25 | -------------------------------------------------------------------------------- /python-phoenixdb/NEWS.rst: -------------------------------------------------------------------------------- 1 | Changelog 2 | ========= 3 | 4 | Version 1.2.2 5 | ------------- 6 | - Update python-phoenixdb/RELEASING.rst (PHOENIX-6820) 7 | - Crash Due to Unhandled JDBC Type Code 0 for NULL Values (PHOENIX-7246) 8 | - Manage requests-gssapi version for Phython 3.7 and lower (PHOENIX-7221) 9 | - Add Python 3.11 to supported languages and update docker test image for phoenixdb (PHOENIX-6858) 10 | - Add Python 3.12 to supported versions and the test matrix (PHOENIX-7222) 11 | - Document workaround for PhoenixDB 1.2+ not working with Python2 on some systems (PHOENIX-6863) 12 | - Update install instructions in README.rst (PHOENIX-6812) 13 | - Add support for SQLAlchemy 2.0 (PHOENIX-6892) 14 | - SQLAlchemy is no longer an install dependency (PHOENIX-6892) 15 | - Run tests with all supported Python + SqlAlchemy versions (1.3, 1.4, 2.0) (PHOENIX-6892) 16 | - Replace deprecated failUnless methods in tests (PHOENIX-6892) 17 | - Add support for specifying custom HTTP headers (PHOENIX-6921) 18 | - Use JDBC/Avatica column label as column name when set (PHOENIX-6917) 19 | - Do not throw exception when shutting down Python with open connections (PHOENIX-6926) 20 | - Fix twine check error and add a steps to Releasing guide (PHOENIX-7323) 21 | 22 | Version 1.2.1 23 | ------------- 24 | - Defined authentication mechanism for SPNEGO explicitly (PHOENIX-6781) 25 | - Fixed failing docker build because of missing files (PHOENIX-6801) 26 | - Fixed make_rc.sh script on mac (PHOENIX-6803) 27 | - Fixed flaky tests 28 | 29 | Version 1.2.0 30 | ------------- 31 | 32 | - Updated test environment to support Python 3.9 and 3.10 (PHOENIX-6737) 33 | - Fixed get_view_names() in SqlAlchemy driver (PHOENIX-6727) 34 | - Added supports_statement_cache attribute for SqlAlchemy dialect to avoid warnings (PHOENIX-6735) 35 | - Re-generated the protobuf Python files with protoc 3.19 from the Avatica 1.21 descriptors (PHOENIX-6731) 36 | - Re-added phoenixdb requirements (PHOENIX-6811) 37 | - Dropped support for Python 3.4 (PHOENIX-6731) 38 | 39 | Version 1.1.0 40 | ------------- 41 | 42 | - Implemented get_primary_keys() and get_index_info() methods in meta object (PHOENIX-6410) 43 | - Fixed broken SqlAlchemy get_pk_constraint() method to use meta.get_primary_keys() (PHOENIX-6410) 44 | - Implemented SqlAlchemy get_indexes() method to expose meta.get_index_info() (PHOENIX-6410) 45 | - Fixed empty array column handling in result set (PHOENIX-6484) 46 | 47 | Version 1.0.1 48 | ------------- 49 | 50 | - Use HTTP sessions to enable sticky load balancers (PHOENIX-6459) 51 | - Revert default GSSAPI OID to SPNEGO to improve compatibility (PHOENIX-6414) 52 | 53 | Version 1.0.0 54 | ------------- 55 | 56 | - Replaced bundled requests_kerberos with request_gssapi library 57 | - Use default SPNEGO Auth settings from request_gssapi 58 | - Refactored authentication code 59 | - Added support for specifying server certificate 60 | - Added support for BASIC and DIGEST authentication 61 | - Fixed HTTP error parsing 62 | - Added transaction support 63 | - Added list support 64 | - Rewritten type handling 65 | - Refactored test suite 66 | - Removed shell example, as it was python2 only 67 | - Updated documentation 68 | - Added SQLAlchemy dialect 69 | - Implemented Avatica Metadata API 70 | - Misc fixes 71 | - Licensing cleanup 72 | 73 | Version 0.7 74 | ----------- 75 | 76 | - Added DictCursor for easier access to columns by their names. 77 | - Support for Phoenix versions from 4.8 to 4.11. 78 | 79 | Version 0.6 80 | ----------- 81 | 82 | - Fixed result fetching when using a query with parameters. 83 | - Support for Phoenix 4.9. 84 | 85 | Version 0.5 86 | ----------- 87 | 88 | - Added support for Python 3. 89 | - Switched from the JSON serialization to Protocol Buffers, improved compatibility with Phoenix 4.8. 90 | - Phoenix 4.6 and older are no longer supported. 91 | 92 | Version 0.4 93 | ----------- 94 | 95 | - Fixes for the final version of Phoenix 4.7. 96 | 97 | Version 0.3 98 | ----------- 99 | 100 | - Compatible with Phoenix 4.7. 101 | 102 | Version 0.2 103 | ----------- 104 | 105 | - Added (configurable) retry on connection errors. 106 | - Added Vagrantfile for easier testing. 107 | - Compatible with Phoenix 4.6. 108 | 109 | Version 0.1 110 | ----------- 111 | 112 | - Initial release. 113 | - Compatible with Phoenix 4.4. 114 | -------------------------------------------------------------------------------- /python-phoenixdb/NOTICE: -------------------------------------------------------------------------------- 1 | Apache Phoenix -- PhoenixDB 2 | Copyright 2020 The Apache Software Foundation 3 | 4 | This product includes software developed by The Apache Software 5 | Foundation (http://www.apache.org/). 6 | 7 | This project was originally created by Lukas Lalinsky, copyright 2015. 8 | 9 | This project contains phoenixdb/phoenixdb/sqlalchemy_phoenix.py which is a modification from 10 | https://github.com/Pirionfr/pyPhoenix, authored by Dimitri Capitaine, copyright 2017. 11 | -------------------------------------------------------------------------------- /python-phoenixdb/RELEASING.rst: -------------------------------------------------------------------------------- 1 | Releasing a new version 2 | ======================= 3 | 4 | Refer to the Phoenix release docs https://phoenix.apache.org/release.html for additinal information 5 | 6 | Pre-requisites 7 | -------------- 8 | 9 | You need to be a Phoenix PMC to be able to upload the RC and final releases to dist.apache.org 10 | 11 | Make sure your gpg is set up, and that the default key is your code signing key. 12 | See http://www.apache.org/dev/release-signing.html 13 | 14 | Make sure that your git remote ``origin`` points to either the main gitbox or the main github 15 | phoenix-queryserver repo. 16 | 17 | Make sure that you have a PyPI account, and that you can publish to the 18 | https://pypi.org/project/phoenixdb/ project. If not, then reach out to one of the maintainers listed there for permission. 19 | 20 | For instructions on the PyPi registration and publishing process, see 21 | https://kynan.github.io/blog/2020/05/23/how-to-upload-your-package-to-the-python-package-index-pypi-test-server 22 | 23 | Prepare the RC 24 | -------------- 25 | 26 | #. Make sure the dockerized tests described in README.rst run successfully 27 | 28 | #. Make sure to run twine check on the phoenixdb package files for python 2 and 3 and ensure they pass: 29 | 30 | python setup.py sdist bdist_wheel 31 | twine check dist/* 32 | 33 | #. Discuss release plans on dev@phoenix.a.o 34 | 35 | #. Open a ticket like https://issues.apache.org/jira/browse/PHOENIX-6529 36 | 37 | #. Change the version number in ``setup.py`` and ``NEWS.rst``. 38 | 39 | #. Add the changes since the last release to ``NEWS.rst`` 40 | 41 | #. Make a PR form the changes get it reviewed, and commit it 42 | 43 | #. Run the dev_support/make_rc.sh script, and choose the option to tag the release:: 44 | 45 | cd python-phoenixdb 46 | ./dev-support/make_rc.sh 47 | 48 | #. The distribution will be generated under the python-phoenixdb/release directory. Upload the directory to https://dist.apache.org/repos/dist/dev/phoenix/ with SVN:: 49 | 50 | cd workdir 51 | svn co https://dist.apache.org/repos/dist/dev/phoenix --depth empty 52 | cd phoenix 53 | cp -r /python-phoenixdb/release/ . 54 | svn add 55 | svn commit 56 | 57 | Voting 58 | ------ 59 | 60 | #. Follow the Voting section in https://phoenix.apache.org/release.html 61 | 62 | You can use http://mail-archives.us.apache.org/mod_mbox/phoenix-dev/202108.mbox/%3CCAJ0%2BiOs2P8EQq_GEGwb%2BVyWur_HyvUGRgVvrD55Xh249QNUcNQ%40mail.gmail.com%3E 63 | as an email template. 64 | 65 | Publishing 66 | ---------- 67 | 68 | #. If the vote passes, upload the package to PyPI (using the instructions linked above, and some extra notes here) 69 | * Make sure to run the ``python setup.py sdist bdist_wheel`` with python 2 and 3 as well. 70 | * To verify it you should have two ``.whl`` files under ``dist/`` folder 71 | * ``pip install --index-url https://test.pypi.org/simple/ phoenixdb`` might not work for python2 because the test repo tends to miss the older versions of dependencies required for Python2. 72 | 73 | #. Bump the package version to ...dev0 in ``setup.py``, and commit the change 74 | 75 | #. Follow the steps from the ``Release`` section in https://phoenix.apache.org/release.html , but skip the following steps: 76 | * maven release 77 | * new branch creation 78 | * mvn version set 79 | 80 | Congratulations! -------------------------------------------------------------------------------- /python-phoenixdb/ci/build-env/Dockerfile: -------------------------------------------------------------------------------- 1 | # Licensed to the Apache Software Foundation (ASF) under one or more 2 | # contributor license agreements. See the NOTICE file distributed with 3 | # this work for additional information regarding copyright ownership. 4 | # The ASF licenses this file to You under the Apache License, Version 2.0 5 | # (the "License"); you may not use this file except in compliance with 6 | # the License. You may obtain a copy of the License at 7 | # 8 | # http://www.apache.org/licenses/LICENSE-2.0 9 | # 10 | # Unless required by applicable law or agreed to in writing, software 11 | # distributed under the License is distributed on an "AS IS" BASIS, 12 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | # See the License for the specific language governing permissions and 14 | # limitations under the License. 15 | 16 | FROM ubuntu:xenial 17 | 18 | RUN apt-get update && \ 19 | DEBIAN_FRONTEND=noninteractive apt-get install -y python-dev python3-dev tox 20 | 21 | RUN apt-get update && \ 22 | DEBIAN_FRONTEND=noninteractive apt-get install -y git 23 | -------------------------------------------------------------------------------- /python-phoenixdb/ci/phoenix/Dockerfile: -------------------------------------------------------------------------------- 1 | # Licensed to the Apache Software Foundation (ASF) under one or more 2 | # contributor license agreements. See the NOTICE file distributed with 3 | # this work for additional information regarding copyright ownership. 4 | # The ASF licenses this file to You under the Apache License, Version 2.0 5 | # (the "License"); you may not use this file except in compliance with 6 | # the License. You may obtain a copy of the License at 7 | # 8 | # http://www.apache.org/licenses/LICENSE-2.0 9 | # 10 | # Unless required by applicable law or agreed to in writing, software 11 | # distributed under the License is distributed on an "AS IS" BASIS, 12 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | # See the License for the specific language governing permissions and 14 | # limitations under the License. 15 | 16 | FROM openjdk:8 17 | 18 | ARG HBASE_VERSION 19 | ARG HBASE_DIR 20 | ARG PHOENIX_VERSION 21 | ARG PHOENIX_NAME=apache-phoenix 22 | 23 | ENV HBASE_URL https://archive.apache.org/dist/hbase/$HBASE_DIR/hbase-$HBASE_VERSION-bin.tar.gz 24 | 25 | RUN wget --no-verbose -O hbase.tar.gz "$HBASE_URL" && \ 26 | mkdir /opt/hbase && \ 27 | tar xf hbase.tar.gz --strip-components=1 -C /opt/hbase && \ 28 | rm hbase.tar.gz 29 | 30 | ENV PHOENIX_URL https://archive.apache.org/dist/phoenix/apache-phoenix-$PHOENIX_VERSION/bin/apache-phoenix-$PHOENIX_VERSION-bin.tar.gz 31 | 32 | RUN wget --no-verbose -O phoenix.tar.gz "$PHOENIX_URL" && \ 33 | mkdir /opt/phoenix && \ 34 | tar xf phoenix.tar.gz --strip-components=1 -C /opt/phoenix && \ 35 | rm phoenix.tar.gz 36 | 37 | RUN ln -sv /opt/phoenix/phoenix-*-server.jar /opt/hbase/lib/ 38 | 39 | ADD hbase-site.xml /opt/hbase/conf/hbase-site.xml 40 | 41 | ENV HBASE_CONF_DIR /opt/hbase/conf 42 | ENV HBASE_CP /opt/hbase/lib 43 | ENV HBASE_HOME /opt/hbase 44 | 45 | EXPOSE 8765 46 | 47 | COPY docker-entrypoint.sh /usr/local/bin/ 48 | ENTRYPOINT ["docker-entrypoint.sh"] 49 | -------------------------------------------------------------------------------- /python-phoenixdb/ci/phoenix/docker-entrypoint.sh: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | # Licensed to the Apache Software Foundation (ASF) under one or more 3 | # contributor license agreements. See the NOTICE file distributed with 4 | # this work for additional information regarding copyright ownership. 5 | # The ASF licenses this file to You under the Apache License, Version 2.0 6 | # (the "License"); you may not use this file except in compliance with 7 | # the License. You may obtain a copy of the License at 8 | # 9 | # http://www.apache.org/licenses/LICENSE-2.0 10 | # 11 | # Unless required by applicable law or agreed to in writing, software 12 | # distributed under the License is distributed on an "AS IS" BASIS, 13 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 | # See the License for the specific language governing permissions and 15 | # limitations under the License. 16 | 17 | 18 | pids=() 19 | 20 | /opt/hbase/bin/hbase-daemon.sh foreground_start master & 21 | pids+=($!) 22 | 23 | /opt/phoenix/bin/queryserver.py & 24 | pids+=($!) 25 | 26 | cleanup() { 27 | if [ ${#pids[@]} -ne 0 ] 28 | then 29 | pids=($(ps -o pid= -p "${pids[@]}")) 30 | if [ ${#pids[@]} -ne 0 ] 31 | then 32 | kill "${pids[@]}" 33 | fi 34 | fi 35 | } 36 | 37 | trap cleanup SIGCHLD SIGINT SIGTERM 38 | 39 | wait 40 | -------------------------------------------------------------------------------- /python-phoenixdb/ci/phoenix/hbase-site.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 20 | 21 | 22 | hbase.regionserver.wal.codec 23 | org.apache.hadoop.hbase.regionserver.wal.IndexedWALEditCodec 24 | 25 | 26 | phoenix.schema.isNamespaceMappingEnabled 27 | true 28 | 29 | 30 | -------------------------------------------------------------------------------- /python-phoenixdb/dev-support/cache-apache-project-artifact.sh: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | # Licensed to the Apache Software Foundation (ASF) under one 3 | # or more contributor license agreements. See the NOTICE file 4 | # distributed with this work for additional information 5 | # regarding copyright ownership. The ASF licenses this file 6 | # to you under the Apache License, Version 2.0 (the 7 | # "License"); you may not use this file except in compliance 8 | # with the License. You may obtain a copy of the License at 9 | # 10 | # http://www.apache.org/licenses/LICENSE-2.0 11 | # 12 | # Unless required by applicable law or agreed to in writing, 13 | # software distributed under the License is distributed on an 14 | # "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY 15 | # KIND, either express or implied. See the License for the 16 | # specific language governing permissions and limitations 17 | # under the License. 18 | 19 | # This was lovingly copied from Apache HBase 20 | 21 | set -e 22 | function usage { 23 | echo "Usage: ${0} [options] /path/to/download/file.tar.gz download/fragment/eg/project/subdir/some-artifact-version.tar.gz" 24 | echo "" 25 | echo " --force for a redownload even if /path/to/download/file.tar.gz exists." 26 | echo " --working-dir /path/to/use Path for writing tempfiles. must exist." 27 | echo " defaults to making a directory via mktemp that we clean." 28 | echo " --keys url://to/project/KEYS where to get KEYS. needed to check signature on download." 29 | echo "" 30 | exit 1 31 | } 32 | # if no args specified, show usage 33 | if [ $# -lt 2 ]; then 34 | usage 35 | fi 36 | 37 | 38 | # Get arguments 39 | declare done_if_cached="true" 40 | declare working_dir 41 | declare cleanup="true" 42 | declare keys 43 | while [ $# -gt 0 ] 44 | do 45 | case "$1" in 46 | --force) shift; done_if_cached="false";; 47 | --working-dir) shift; working_dir=$1; cleanup="false"; shift;; 48 | --keys) shift; keys=$1; shift;; 49 | --) shift; break;; 50 | -*) usage ;; 51 | *) break;; # terminate while loop 52 | esac 53 | done 54 | 55 | # should still have required args 56 | if [ $# -lt 2 ]; then 57 | usage 58 | fi 59 | 60 | target="$1" 61 | artifact="$2" 62 | 63 | if [ -f "${target}" ] && [ "true" = "${done_if_cached}" ]; then 64 | echo "Reusing existing download of '${artifact}'." 65 | exit 0 66 | fi 67 | 68 | if [ -z "${working_dir}" ]; then 69 | if ! working_dir="$(mktemp -d -t hbase-download-apache-artifact)" ; then 70 | echo "Failed to create temporary working directory. Please specify via --working-dir" >&2 71 | exit 1 72 | fi 73 | else 74 | # absolutes please 75 | working_dir="$(cd "$(dirname "${working_dir}")"; pwd)/$(basename "${working_dir}")" 76 | if [ ! -d "${working_dir}" ]; then 77 | echo "passed working directory '${working_dir}' must already exist." >&2 78 | exit 1 79 | fi 80 | fi 81 | 82 | function cleanup { 83 | if [ -n "${keys}" ]; then 84 | echo "Stopping gpg agent daemon" 85 | gpgconf --homedir "${working_dir}/.gpg" --kill gpg-agent 86 | echo "Stopped gpg agent daemon" 87 | fi 88 | 89 | if [ "true" = "${cleanup}" ]; then 90 | echo "cleaning up temp space." 91 | rm -rf "${working_dir}" 92 | fi 93 | } 94 | trap cleanup EXIT SIGQUIT 95 | 96 | echo "New download of '${artifact}'" 97 | 98 | # N.B. this comes first so that if gpg falls over we skip the expensive download. 99 | if [ -n "${keys}" ]; then 100 | if [ ! -d "${working_dir}/.gpg" ]; then 101 | rm -rf "${working_dir}/.gpg" 102 | mkdir -p "${working_dir}/.gpg" 103 | chmod -R 700 "${working_dir}/.gpg" 104 | fi 105 | 106 | echo "installing project KEYS" 107 | curl -L --fail -o "${working_dir}/KEYS" "${keys}" 108 | if ! gpg --homedir "${working_dir}/.gpg" --import "${working_dir}/KEYS" ; then 109 | echo "ERROR importing the keys via gpg failed. If the output above mentions this error:" >&2 110 | echo " gpg: can't connect to the agent: File name too long" >&2 111 | # we mean to give them the command to run, not to run it. 112 | #shellcheck disable=SC2016 113 | echo 'then you prolly need to create /var/run/user/$(id -u)' >&2 114 | echo "see this thread on gnupg-users: https://s.apache.org/uI7x" >&2 115 | exit 2 116 | fi 117 | 118 | echo "downloading signature" 119 | curl -L --fail -o "${working_dir}/artifact.asc" "https://archive.apache.org/dist/${artifact}.asc" 120 | fi 121 | 122 | echo "downloading artifact" 123 | if ! curl --dump-header "${working_dir}/artifact_download_headers.txt" -L --fail -o "${working_dir}/artifact" "https://www.apache.org/dyn/closer.lua?filename=${artifact}&action=download" ; then 124 | echo "Artifact wasn't in mirror system. falling back to archive.a.o." 125 | curl --dump-header "${working_dir}/artifact_fallback_headers.txt" -L --fail -o "${working_dir}/artifact" "http://archive.apache.org/dist/${artifact}" 126 | fi 127 | 128 | if [ -n "${keys}" ]; then 129 | echo "verifying artifact signature" 130 | gpg --homedir "${working_dir}/.gpg" --verify "${working_dir}/artifact.asc" 131 | echo "signature good." 132 | fi 133 | 134 | echo "moving artifact into place at '${target}'" 135 | # ensure we're on the same filesystem 136 | mv "${working_dir}/artifact" "${target}.copying" 137 | # attempt atomic move 138 | mv "${target}.copying" "${target}" 139 | echo "all done!" 140 | -------------------------------------------------------------------------------- /python-phoenixdb/dev-support/make_rc.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | ############################################################################ 3 | # 4 | # Licensed to the Apache Software Foundation (ASF) under one 5 | # or more contributor license agreements. See the NOTICE file 6 | # distributed with this work for additional information 7 | # regarding copyright ownership. The ASF licenses this file 8 | # to you under the Apache License, Version 2.0 (the 9 | # "License"); you may not use this file except in compliance 10 | # with the License. You may obtain a copy of the License at 11 | # 12 | # http://www.apache.org/licenses/LICENSE-2.0 13 | # 14 | # Unless required by applicable law or agreed to in writing, software 15 | # distributed under the License is distributed on an "AS IS" BASIS, 16 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 17 | # See the License for the specific language governing permissions and 18 | # limitations under the License. 19 | # 20 | ############################################################################ 21 | set -e 22 | 23 | echo "Script that assembles all you need to make an RC." 24 | echo "It generates source tar in release directory" 25 | echo "Presumes that you can sign a release as described at https://www.apache.org/dev/release-signing.html" 26 | echo "" 27 | echo "Continuing will overwrite all uncommitted changes under the phoenix-queryserver repository." 28 | 29 | read -p "Y to continue or any other key to quit " prompt 30 | if [[ ! $prompt =~ [yY](es)* ]] 31 | then 32 | echo "Aborting." 33 | exit 34 | fi 35 | 36 | echo "Starting...";sleep 2 37 | 38 | # Set directory variables 39 | DIR_ROOT="$(cd $(dirname $0);pwd)/.." 40 | cd $DIR_ROOT 41 | 42 | VERSION=$(grep '^version = ".*"$' setup.py | grep -o '".*"' | sed 's/"//g') 43 | 44 | DIR_REL_BASE=$DIR_ROOT/release 45 | DIR_REL_ROOT=$DIR_REL_BASE/python-phoenixdb-$VERSION 46 | REL_SRC=python-phoenixdb-$VERSION-src 47 | DIR_REL_SRC_TAR_PATH=$DIR_REL_ROOT/src 48 | 49 | git clean -fx . 50 | 51 | # Generate src tar 52 | ln -s . $REL_SRC; tar cvzf $REL_SRC.tar.gz --exclude="$REL_SRC/$REL_SRC" $REL_SRC/*; rm $REL_SRC; 53 | 54 | # Generate directory structure 55 | mkdir $DIR_REL_BASE; 56 | mkdir $DIR_REL_ROOT; 57 | mkdir $DIR_REL_SRC_TAR_PATH; 58 | 59 | # Move src tar 60 | mv $REL_SRC.tar.gz $DIR_REL_SRC_TAR_PATH; 61 | 62 | echo "DONE generating source tar in release directory." 63 | echo "Now signing source tar" 64 | 65 | # Sign 66 | function_sign() { 67 | phoenix_tar=$(find python-phoenixdb-*.gz); 68 | 69 | # if on MAC OS 70 | if [[ "$OSTYPE" == "darwin"* ]]; then 71 | gpg --armor --output $phoenix_tar.asc --detach-sig $phoenix_tar; 72 | openssl dgst -sha512 $phoenix_tar > $phoenix_tar.sha512; 73 | # all other OS 74 | else 75 | gpg --armor --output $phoenix_tar.asc --detach-sig $phoenix_tar; 76 | sha512sum -b $phoenix_tar > $phoenix_tar.sha512; 77 | fi 78 | } 79 | 80 | cd $DIR_REL_SRC_TAR_PATH; function_sign; 81 | 82 | # Tag 83 | read -p "Do you want add tag for this RC in GIT? (Y for yes or any other key to continue) " prompt 84 | if [[ $prompt =~ [yY](es)* ]] 85 | then 86 | echo "Tagging..." 87 | read -p "Enter tag (Example python-phoenixdb-1.0.0.rc0):" prompt 88 | echo "Setting tag: $prompt";sleep 5 89 | git tag -a $prompt -m "$prompt"; git push origin $prompt 90 | mv $DIR_REL_ROOT $DIR_REL_BASE/$prompt 91 | fi 92 | 93 | echo "DONE." 94 | echo "If all looks good in release directory then commit RC at https://dist.apache.org/repos/dist/dev/phoenix/python-phoenixdb" 95 | -------------------------------------------------------------------------------- /python-phoenixdb/dev-support/rat-excludes.txt: -------------------------------------------------------------------------------- 1 | .*\.pyc 2 | NEWS\.rst 3 | RELEASING\.rst 4 | README\.rst 5 | -------------------------------------------------------------------------------- /python-phoenixdb/dev-support/run-source-ratcheck.sh: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | ############################################################################ 3 | # 4 | # Licensed to the Apache Software Foundation (ASF) under one 5 | # or more contributor license agreements. See the NOTICE file 6 | # distributed with this work for additional information 7 | # regarding copyright ownership. The ASF licenses this file 8 | # to you under the Apache License, Version 2.0 (the 9 | # "License"); you may not use this file except in compliance 10 | # with the License. You may obtain a copy of the License at 11 | # 12 | # http://www.apache.org/licenses/LICENSE-2.0 13 | # 14 | # Unless required by applicable law or agreed to in writing, software 15 | # distributed under the License is distributed on an "AS IS" BASIS, 16 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 17 | # See the License for the specific language governing permissions and 18 | # limitations under the License. 19 | # 20 | ############################################################################ 21 | 22 | # Catch some more errors 23 | set -eu 24 | set -o pipefail 25 | 26 | # The name of the Apache RAT CLI binary file 27 | RAT_BINARY_NAME="apache-rat-0.13-bin.tar.gz" 28 | # The relative path on the ASF mirrors for the RAT binary file 29 | RAT_BINARY_MIRROR_NAME="creadur/apache-rat-0.13/$RAT_BINARY_NAME" 30 | RAT_BINARY_DIR="apache-rat-0.13" 31 | RAT_JAR="$RAT_BINARY_DIR.jar" 32 | 33 | # Constants 34 | DEV_SUPPORT="$( cd "$( dirname "${BASH_SOURCE[0]}" )" >/dev/null 2>&1 && pwd )" 35 | ARTIFACTS_DIR="$DEV_SUPPORT/artifacts" 36 | WORK_DIR="$DEV_SUPPORT/work" 37 | 38 | mkdir -p "$WORK_DIR" "$ARTIFACTS_DIR" 39 | 40 | # Cache the RAT binary artifacts 41 | if [[ ! -f "$ARTIFACTS_DIR/$RAT_BINARY_NAME" ]]; then 42 | echo "$ARTIFACTS_DIR/$RAT_BINARY_NAME does not exist, downloading it" 43 | $DEV_SUPPORT/cache-apache-project-artifact.sh --working-dir "$WORK_DIR" --keys https://www.apache.org/dist/creadur/KEYS \ 44 | "$ARTIFACTS_DIR/$RAT_BINARY_NAME" "$RAT_BINARY_MIRROR_NAME" 45 | fi 46 | 47 | # Extract the RAT binary artifacts 48 | if [[ ! -d "$ARTIFACTS_DIR/$RAT_BINARY_DIR" ]]; then 49 | echo "$ARTIFACTS_DIR/$RAT_BINARY_DIR does not exist, extracting $ARTIFACTS_DIR/$RAT_BINARY_NAME" 50 | tar xf $ARTIFACTS_DIR/$RAT_BINARY_NAME -C $ARTIFACTS_DIR 51 | fi 52 | 53 | echo "RAT binary installation localized, running RAT check" 54 | 55 | # Run the RAT check, excluding pyc files 56 | for src in 'phoenixdb' 'ci' 'examples' 'doc'; do 57 | echo "Running RAT check over $src" 58 | java -jar "$ARTIFACTS_DIR/$RAT_BINARY_DIR/$RAT_JAR" -d "$DEV_SUPPORT/../$src" -E "$DEV_SUPPORT/rat-excludes.txt" 59 | if [[ $? -ne 0 ]]; then 60 | echo "Failed RAT check over $src" 61 | exit 1 62 | fi 63 | done 64 | -------------------------------------------------------------------------------- /python-phoenixdb/doc/api.rst: -------------------------------------------------------------------------------- 1 | .. 2 | Licensed to the Apache Software Foundation (ASF) under one or more 3 | contributor license agreements. See the NOTICE file distributed with 4 | this work for additional information regarding copyright ownership. 5 | The ASF licenses this file to You under the Apache License, Version 2.0 6 | (the "License"); you may not use this file except in compliance with 7 | the License. You may obtain a copy of the License at 8 | 9 | http://www.apache.org/licenses/LICENSE-2.0 10 | 11 | Unless required by applicable law or agreed to in writing, software 12 | distributed under the License is distributed on an "AS IS" BASIS, 13 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 | See the License for the specific language governing permissions and 15 | limitations under the License. 16 | 17 | API Reference 18 | ============= 19 | 20 | phoenixdb module 21 | ---------------- 22 | 23 | .. automodule:: phoenixdb 24 | :members: 25 | :undoc-members: 26 | 27 | phoenixdb.connection module 28 | --------------------------- 29 | 30 | .. automodule:: phoenixdb.connection 31 | :members: 32 | :undoc-members: 33 | 34 | phoenixdb.cursor module 35 | ----------------------- 36 | 37 | .. automodule:: phoenixdb.cursor 38 | :members: 39 | :undoc-members: 40 | 41 | phoenixdb.avatica module 42 | ------------------------ 43 | 44 | .. automodule:: phoenixdb.avatica 45 | :members: 46 | :undoc-members: 47 | -------------------------------------------------------------------------------- /python-phoenixdb/doc/index.rst: -------------------------------------------------------------------------------- 1 | .. 2 | Licensed to the Apache Software Foundation (ASF) under one or more 3 | contributor license agreements. See the NOTICE file distributed with 4 | this work for additional information regarding copyright ownership. 5 | The ASF licenses this file to You under the Apache License, Version 2.0 6 | (the "License"); you may not use this file except in compliance with 7 | the License. You may obtain a copy of the License at 8 | 9 | http://www.apache.org/licenses/LICENSE-2.0 10 | 11 | Unless required by applicable law or agreed to in writing, software 12 | distributed under the License is distributed on an "AS IS" BASIS, 13 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 | See the License for the specific language governing permissions and 15 | limitations under the License... include:: ../README.rst 16 | 17 | API Reference 18 | ------------- 19 | 20 | .. toctree:: 21 | :maxdepth: 2 22 | 23 | api 24 | 25 | Changelog 26 | ------------- 27 | 28 | .. toctree:: 29 | :maxdepth: 2 30 | 31 | versions 32 | 33 | Indices and tables 34 | ================== 35 | 36 | * :ref:`genindex` 37 | * :ref:`modindex` 38 | * :ref:`search` 39 | 40 | 41 | .. _ 42 | -------------------------------------------------------------------------------- /python-phoenixdb/doc/versions.rst: -------------------------------------------------------------------------------- 1 | .. 2 | Licensed to the Apache Software Foundation (ASF) under one or more 3 | contributor license agreements. See the NOTICE file distributed with 4 | this work for additional information regarding copyright ownership. 5 | The ASF licenses this file to You under the Apache License, Version 2.0 6 | (the "License"); you may not use this file except in compliance with 7 | the License. You may obtain a copy of the License at 8 | 9 | http://www.apache.org/licenses/LICENSE-2.0 10 | 11 | Unless required by applicable law or agreed to in writing, software 12 | distributed under the License is distributed on an "AS IS" BASIS, 13 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 | See the License for the specific language governing permissions and 15 | limitations under the License. 16 | 17 | .. include:: ../NEWS.rst 18 | 19 | .. _ 20 | -------------------------------------------------------------------------------- /python-phoenixdb/docker-entrypoint.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash -l 2 | 3 | # Licensed to the Apache Software Foundation (ASF) under one or more 4 | # contributor license agreements. See the NOTICE file distributed with 5 | # this work for additional information regarding copyright ownership. 6 | # The ASF licenses this file to You under the Apache License, Version 2.0 7 | # (the "License"); you may not use this file except in compliance with 8 | # the License. You may obtain a copy of the License at 9 | # 10 | # http://www.apache.org/licenses/LICENSE-2.0 11 | # 12 | # Unless required by applicable law or agreed to in writing, software 13 | # distributed under the License is distributed on an "AS IS" BASIS, 14 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 15 | # See the License for the specific language governing permissions and 16 | # limitations under the License. 17 | 18 | set -e 19 | if [ "$#" -eq 0 ]; then 20 | find /src -mindepth 1 -maxdepth 1 \( -type d -name ".*" -prune \) -o -exec cp -r --target-directory=/app -- {} + 21 | # Then run tox 22 | tox 23 | else 24 | exec "$@" 25 | fi 26 | -------------------------------------------------------------------------------- /python-phoenixdb/examples/basic.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | 3 | # Licensed to the Apache Software Foundation (ASF) under one or more 4 | # contributor license agreements. See the NOTICE file distributed with 5 | # this work for additional information regarding copyright ownership. 6 | # The ASF licenses this file to You under the Apache License, Version 2.0 7 | # (the "License"); you may not use this file except in compliance with 8 | # the License. You may obtain a copy of the License at 9 | # 10 | # http://www.apache.org/licenses/LICENSE-2.0 11 | # 12 | # Unless required by applicable law or agreed to in writing, software 13 | # distributed under the License is distributed on an "AS IS" BASIS, 14 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 15 | # See the License for the specific language governing permissions and 16 | # limitations under the License. 17 | 18 | import phoenixdb 19 | 20 | with phoenixdb.connect('http://localhost:8765/', autocommit=True) as connection: 21 | with connection.cursor() as cursor: 22 | cursor.execute("DROP TABLE IF EXISTS test") 23 | cursor.execute("CREATE TABLE test (id INTEGER PRIMARY KEY, text VARCHAR)") 24 | cursor.executemany("UPSERT INTO test VALUES (?, ?)", [[1, 'hello'], [2, 'world']]) 25 | cursor.execute("SELECT * FROM test ORDER BY id") 26 | for row in cursor: 27 | print(row) 28 | -------------------------------------------------------------------------------- /python-phoenixdb/gen-protobuf.sh: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | 3 | # Licensed to the Apache Software Foundation (ASF) under one or more 4 | # contributor license agreements. See the NOTICE file distributed with 5 | # this work for additional information regarding copyright ownership. 6 | # The ASF licenses this file to You under the Apache License, Version 2.0 7 | # (the "License"); you may not use this file except in compliance with 8 | # the License. You may obtain a copy of the License at 9 | # 10 | # http://www.apache.org/licenses/LICENSE-2.0 11 | # 12 | # Unless required by applicable law or agreed to in writing, software 13 | # distributed under the License is distributed on an "AS IS" BASIS, 14 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 15 | # See the License for the specific language governing permissions and 16 | # limitations under the License. 17 | 18 | set -x 19 | AVATICA_VER=1.21.0 20 | 21 | set -e 22 | 23 | rm -rf avatica-tmp 24 | 25 | mkdir avatica-tmp 26 | cd avatica-tmp 27 | 28 | wget -O avatica.tar.gz https://dlcdn.apache.org/calcite/apache-calcite-avatica-$AVATICA_VER/apache-calcite-avatica-$AVATICA_VER-src.tar.gz 29 | tar -x --strip-components=1 -f avatica.tar.gz 30 | 31 | cd .. 32 | rm -f phoenixdb/avatica/proto/*_pb2.py 33 | protoc --proto_path=avatica-tmp/core/src/main/protobuf/ --python_out=phoenixdb/avatica/proto avatica-tmp/core/src/main/protobuf/*.proto 34 | if [[ "$(uname)" == "Darwin" ]]; then 35 | sed -i '' 's/import common_pb2/from . import common_pb2/' phoenixdb/avatica/proto/*_pb2.py 36 | else 37 | sed -i 's/import common_pb2/from . import common_pb2/' phoenixdb/avatica/proto/*_pb2.py 38 | fi 39 | 40 | for f in $(find phoenixdb/avatica/proto -name '*.py'); do 41 | cat << EOF > ${f}-with-header 42 | # Licensed to the Apache Software Foundation (ASF) under one or more 43 | # contributor license agreements. See the NOTICE file distributed with 44 | # this work for additional information regarding copyright ownership. 45 | # The ASF licenses this file to You under the Apache License, Version 2.0 46 | # (the "License"); you may not use this file except in compliance with 47 | # the License. You may obtain a copy of the License at 48 | # 49 | # http://www.apache.org/licenses/LICENSE-2.0 50 | # 51 | # Unless required by applicable law or agreed to in writing, software 52 | # distributed under the License is distributed on an "AS IS" BASIS, 53 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 54 | # See the License for the specific language governing permissions and 55 | # limitations under the License. 56 | EOF 57 | cat $f >> ${f}-with-header 58 | done 59 | 60 | rm -rf avatica-tmp 61 | -------------------------------------------------------------------------------- /python-phoenixdb/phoenixdb/avatica/__init__.py: -------------------------------------------------------------------------------- 1 | # Licensed to the Apache Software Foundation (ASF) under one or more 2 | # contributor license agreements. See the NOTICE file distributed with 3 | # this work for additional information regarding copyright ownership. 4 | # The ASF licenses this file to You under the Apache License, Version 2.0 5 | # (the "License"); you may not use this file except in compliance with 6 | # the License. You may obtain a copy of the License at 7 | # 8 | # http://www.apache.org/licenses/LICENSE-2.0 9 | # 10 | # Unless required by applicable law or agreed to in writing, software 11 | # distributed under the License is distributed on an "AS IS" BASIS, 12 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | # See the License for the specific language governing permissions and 14 | # limitations under the License. 15 | 16 | from .client import AvaticaClient # noqa: F401 17 | -------------------------------------------------------------------------------- /python-phoenixdb/phoenixdb/avatica/proto/__init__.py: -------------------------------------------------------------------------------- 1 | # Licensed to the Apache Software Foundation (ASF) under one or more 2 | # contributor license agreements. See the NOTICE file distributed with 3 | # this work for additional information regarding copyright ownership. 4 | # The ASF licenses this file to You under the Apache License, Version 2.0 5 | # (the "License"); you may not use this file except in compliance with 6 | # the License. You may obtain a copy of the License at 7 | # 8 | # http://www.apache.org/licenses/LICENSE-2.0 9 | # 10 | # Unless required by applicable law or agreed to in writing, software 11 | # distributed under the License is distributed on an "AS IS" BASIS, 12 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | # See the License for the specific language governing permissions and 14 | # limitations under the License. 15 | -------------------------------------------------------------------------------- /python-phoenixdb/phoenixdb/errors.py: -------------------------------------------------------------------------------- 1 | # Licensed to the Apache Software Foundation (ASF) under one or more 2 | # contributor license agreements. See the NOTICE file distributed with 3 | # this work for additional information regarding copyright ownership. 4 | # The ASF licenses this file to You under the Apache License, Version 2.0 5 | # (the "License"); you may not use this file except in compliance with 6 | # the License. You may obtain a copy of the License at 7 | # 8 | # http://www.apache.org/licenses/LICENSE-2.0 9 | # 10 | # Unless required by applicable law or agreed to in writing, software 11 | # distributed under the License is distributed on an "AS IS" BASIS, 12 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | # See the License for the specific language governing permissions and 14 | # limitations under the License. 15 | 16 | __all__ = [ 17 | 'Warning', 'Error', 'InterfaceError', 'DatabaseError', 'DataError', 18 | 'OperationalError', 'IntegrityError', 'InternalError', 19 | 'ProgrammingError', 'NotSupportedError', 20 | ] 21 | 22 | try: 23 | _StandardError = StandardError 24 | except NameError: 25 | _StandardError = Exception 26 | 27 | 28 | class Warning(_StandardError): 29 | """Not used by this package, only defined for compatibility 30 | with DB API 2.0.""" 31 | 32 | 33 | class Error(_StandardError): 34 | """Exception that is the base class of all other error exceptions. 35 | You can use this to catch all errors with one single except statement.""" 36 | 37 | def __init__(self, message, code=None, sqlstate=None, cause=None): 38 | super(_StandardError, self).__init__(message, code, sqlstate, cause) 39 | 40 | @property 41 | def message(self): 42 | return self.args[0] 43 | 44 | @property 45 | def code(self): 46 | return self.args[1] 47 | 48 | @property 49 | def sqlstate(self): 50 | return self.args[2] 51 | 52 | @property 53 | def cause(self): 54 | return self.args[3] 55 | 56 | 57 | class InterfaceError(Error): 58 | """Exception raised for errors that are related to the database 59 | interface rather than the database itself.""" 60 | 61 | 62 | class DatabaseError(Error): 63 | """Exception raised for errors that are related to the database.""" 64 | 65 | 66 | class DataError(DatabaseError): 67 | """Exception raised for errors that are due to problems with the 68 | processed data like division by zero, numeric value out of range, 69 | etc.""" 70 | 71 | 72 | class OperationalError(DatabaseError): 73 | """Raised for errors that are related to the database's operation and not 74 | necessarily under the control of the programmer, e.g. an unexpected 75 | disconnect occurs, the data source name is not found, a transaction could 76 | not be processed, a memory allocation error occurred during 77 | processing, etc.""" 78 | 79 | 80 | class IntegrityError(DatabaseError): 81 | """Raised when the relational integrity of the database is affected, e.g. a foreign key check fails.""" 82 | 83 | 84 | class InternalError(DatabaseError): 85 | """Raised when the database encounters an internal problem.""" 86 | 87 | 88 | class ProgrammingError(DatabaseError): 89 | """Raises for programming errors, e.g. table not found, syntax error, etc.""" 90 | 91 | 92 | class NotSupportedError(DatabaseError): 93 | """Raised when using an API that is not supported by the database.""" 94 | -------------------------------------------------------------------------------- /python-phoenixdb/phoenixdb/tests/__init__.py: -------------------------------------------------------------------------------- 1 | # Licensed to the Apache Software Foundation (ASF) under one or more 2 | # contributor license agreements. See the NOTICE file distributed with 3 | # this work for additional information regarding copyright ownership. 4 | # The ASF licenses this file to You under the Apache License, Version 2.0 5 | # (the "License"); you may not use this file except in compliance with 6 | # the License. You may obtain a copy of the License at 7 | # 8 | # http://www.apache.org/licenses/LICENSE-2.0 9 | # 10 | # Unless required by applicable law or agreed to in writing, software 11 | # distributed under the License is distributed on an "AS IS" BASIS, 12 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | # See the License for the specific language governing permissions and 14 | # limitations under the License. 15 | 16 | import os 17 | import unittest 18 | 19 | import phoenixdb 20 | 21 | TEST_DB_URL = os.environ.get('PHOENIXDB_TEST_DB_URL', "http://localhost:8765") 22 | TEST_DB_TRUSTSTORE = os.environ.get('PHOENIXDB_TEST_DB_TRUSTSTORE') 23 | TEST_DB_AUTHENTICATION = os.environ.get('PHOENIXDB_TEST_DB_AUTHENTICATION') 24 | TEST_DB_AVATICA_USER = os.environ.get('PHOENIXDB_TEST_DB_AVATICA_USER') 25 | TEST_DB_AVATICA_PASSWORD = os.environ.get('PHOENIXDB_TEST_DB_AVATICA_PASSWORD') 26 | 27 | httpArgs = {} 28 | if TEST_DB_TRUSTSTORE is not None: 29 | httpArgs.update(verify=TEST_DB_TRUSTSTORE) 30 | if TEST_DB_AUTHENTICATION is not None: 31 | httpArgs.update(authentication=TEST_DB_AUTHENTICATION) 32 | if TEST_DB_AVATICA_USER is not None: 33 | httpArgs.update(avatica_user=TEST_DB_AVATICA_USER) 34 | if TEST_DB_AVATICA_PASSWORD is not None: 35 | httpArgs.update(avatica_password=TEST_DB_AVATICA_PASSWORD) 36 | 37 | 38 | @unittest.skipIf(TEST_DB_URL is None, "these tests require the PHOENIXDB_TEST_DB_URL environment variable set to a clean database") 39 | class DatabaseTestCase(unittest.TestCase): 40 | 41 | def setUp(self): 42 | self.conn = phoenixdb.connect(TEST_DB_URL, autocommit=True, **httpArgs) 43 | 44 | def closeDb(): 45 | self.conn.close() 46 | self.addCleanup(closeDb) 47 | 48 | def reopen(self, **avaticaArgs): 49 | self.conn.close() 50 | kwargs = avaticaArgs.copy() 51 | kwargs.update(httpArgs) 52 | self.conn = phoenixdb.connect(TEST_DB_URL, **kwargs) 53 | 54 | def addTableCleanup(self, name): 55 | def dropTable(): 56 | with self.conn.cursor() as cursor: 57 | cursor.execute("DROP TABLE IF EXISTS {table}".format(table=name)) 58 | self.addCleanup(dropTable) 59 | 60 | def createTable(self, name, statement): 61 | with self.conn.cursor() as cursor: 62 | cursor.execute("DROP TABLE IF EXISTS {table}".format(table=name)) 63 | cursor.execute(statement.format(table=name)) 64 | self.addTableCleanup(name) 65 | -------------------------------------------------------------------------------- /python-phoenixdb/phoenixdb/tests/test_avatica.py: -------------------------------------------------------------------------------- 1 | # Licensed to the Apache Software Foundation (ASF) under one or more 2 | # contributor license agreements. See the NOTICE file distributed with 3 | # this work for additional information regarding copyright ownership. 4 | # The ASF licenses this file to You under the Apache License, Version 2.0 5 | # (the "License"); you may not use this file except in compliance with 6 | # the License. You may obtain a copy of the License at 7 | # 8 | # http://www.apache.org/licenses/LICENSE-2.0 9 | # 10 | # Unless required by applicable law or agreed to in writing, software 11 | # distributed under the License is distributed on an "AS IS" BASIS, 12 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | # See the License for the specific language governing permissions and 14 | # limitations under the License. 15 | 16 | import unittest 17 | 18 | import phoenixdb 19 | from phoenixdb.avatica.client import parse_url, urlparse 20 | 21 | from requests.auth import HTTPBasicAuth 22 | 23 | 24 | class ParseUrlTest(unittest.TestCase): 25 | 26 | def test_parse_url(self): 27 | self.assertEqual(urlparse.urlparse('http://localhost:8765/'), parse_url('localhost')) 28 | # Python 3.9 will interpret "localhost:" as a scheme. Argueably,it is right 29 | # self.assertEqual(urlparse.urlparse('http://localhost:2222/'), parse_url('localhost:2222')) 30 | self.assertEqual(urlparse.urlparse('http://localhost:2222/'), parse_url('http://localhost:2222/')) 31 | 32 | def test_url_params(self): 33 | (url, auth, verify) = phoenixdb._process_args(( 34 | "https://localhost:8765?authentication=BASIC&" 35 | "avatica_user=user&avatica_password=password&truststore=truststore")) 36 | self.assertEqual("https://localhost:8765", url) 37 | self.assertEqual("truststore", verify) 38 | self.assertEqual(auth, HTTPBasicAuth("user", "password")) 39 | 40 | (url, auth, verify) = phoenixdb._process_args( 41 | "http://localhost:8765", authentication='BASIC', user='user', password='password', 42 | truststore='truststore') 43 | self.assertEqual("http://localhost:8765", url) 44 | self.assertEqual("truststore", verify) 45 | self.assertEqual(auth, HTTPBasicAuth("user", "password")) 46 | 47 | (url, auth, verify) = phoenixdb._process_args( 48 | "https://localhost:8765", authentication='SPNEGO', user='user', truststore='truststore') 49 | self.assertEqual("https://localhost:8765?doAs=user", url) 50 | self.assertEqual("truststore", verify) 51 | # SPNEGO auth objects seem to have no working __eq__ 52 | # self.assertEqual(auth, HTTPSPNEGOAuth(opportunistic_auth=True)) 53 | -------------------------------------------------------------------------------- /python-phoenixdb/phoenixdb/tests/test_dbapi20.py: -------------------------------------------------------------------------------- 1 | # Licensed to the Apache Software Foundation (ASF) under one or more 2 | # contributor license agreements. See the NOTICE file distributed with 3 | # this work for additional information regarding copyright ownership. 4 | # The ASF licenses this file to You under the Apache License, Version 2.0 5 | # (the "License"); you may not use this file except in compliance with 6 | # the License. You may obtain a copy of the License at 7 | # 8 | # http://www.apache.org/licenses/LICENSE-2.0 9 | # 10 | # Unless required by applicable law or agreed to in writing, software 11 | # distributed under the License is distributed on an "AS IS" BASIS, 12 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | # See the License for the specific language governing permissions and 14 | # limitations under the License. 15 | 16 | import unittest 17 | 18 | import phoenixdb 19 | from phoenixdb.tests import TEST_DB_URL, httpArgs 20 | 21 | from . import dbapi20 22 | 23 | 24 | @unittest.skipIf(TEST_DB_URL is None, "these tests require the PHOENIXDB_TEST_DB_URL environment variable set to a clean database") 25 | class PhoenixDatabaseAPI20Test(dbapi20.DatabaseAPI20Test): 26 | driver = phoenixdb 27 | connect_args = (TEST_DB_URL,) 28 | connect_kw_args = httpArgs 29 | 30 | ddl1 = 'create table %sbooze (name varchar(20) primary key)' % dbapi20.DatabaseAPI20Test.table_prefix 31 | ddl2 = 'create table %sbarflys (name varchar(20) primary key, drink varchar(30))' % dbapi20.DatabaseAPI20Test.table_prefix 32 | insert = 'upsert' 33 | 34 | def test_nextset(self): 35 | pass 36 | 37 | def test_setoutputsize(self): 38 | pass 39 | 40 | def _connect(self): 41 | con = dbapi20.DatabaseAPI20Test._connect(self) 42 | con.autocommit = True 43 | return con 44 | 45 | def test_None(self): 46 | con = self._connect() 47 | try: 48 | cur = con.cursor() 49 | self.executeDDL2(cur) 50 | cur.execute("%s into %sbarflys values ('a', NULL)" % (self.insert, self.table_prefix)) 51 | cur.execute('select drink from %sbarflys' % self.table_prefix) 52 | r = cur.fetchall() 53 | self.assertEqual(len(r), 1) 54 | self.assertEqual(len(r[0]), 1) 55 | self.assertEqual(r[0][0], None, 'NULL value not returned as None') 56 | finally: 57 | con.close() 58 | 59 | def test_autocommit(self): 60 | con = dbapi20.DatabaseAPI20Test._connect(self) 61 | self.assertFalse(con.autocommit) 62 | con.autocommit = True 63 | self.assertTrue(con.autocommit) 64 | con.autocommit = False 65 | self.assertFalse(con.autocommit) 66 | con.close() 67 | 68 | def test_readonly(self): 69 | con = dbapi20.DatabaseAPI20Test._connect(self) 70 | self.assertFalse(con.readonly) 71 | con.readonly = True 72 | self.assertTrue(con.readonly) 73 | con.readonly = False 74 | self.assertFalse(con.readonly) 75 | con.close() 76 | 77 | def test_iter(self): 78 | # https://www.python.org/dev/peps/pep-0249/#iter 79 | con = self._connect() 80 | try: 81 | cur = con.cursor() 82 | if hasattr(cur, '__iter__'): 83 | self.assertIs(cur, iter(cur)) 84 | finally: 85 | con.close() 86 | 87 | def test_next(self): 88 | # https://www.python.org/dev/peps/pep-0249/#next 89 | con = self._connect() 90 | try: 91 | cur = con.cursor() 92 | if not hasattr(cur, 'next'): 93 | return 94 | 95 | # cursor.next should raise an Error if called before 96 | # executing a select-type query 97 | self.assertRaises(self.driver.Error, cur.next) 98 | 99 | # cursor.next should raise an Error if called after 100 | # executing a query that cannnot return rows 101 | self.executeDDL1(cur) 102 | self.assertRaises(self.driver.Error, cur.next) 103 | 104 | # cursor.next should return None if a query retrieves ' 105 | # no rows 106 | cur.execute('select name from %sbooze' % self.table_prefix) 107 | self.assertRaises(StopIteration, cur.next) 108 | self.assertTrue(cur.rowcount in (-1, 0)) 109 | 110 | # cursor.next should raise an Error if called after 111 | # executing a query that cannnot return rows 112 | cur.execute("%s into %sbooze values ('Victoria Bitter')" % ( 113 | self.insert, self.table_prefix 114 | )) 115 | self.assertRaises(self.driver.Error, cur.next) 116 | 117 | cur.execute('select name from %sbooze' % self.table_prefix) 118 | r = cur.next() 119 | self.assertEqual(len(r), 1, 'cursor.next should have retrieved a row with one column') 120 | self.assertEqual(r[0], 'Victoria Bitter', 'cursor.next retrieved incorrect data') 121 | # cursor.next should raise StopIteration if no more rows available 122 | self.assertRaises(StopIteration, cur.next) 123 | self.assertTrue(cur.rowcount in (-1, 1)) 124 | finally: 125 | con.close() 126 | -------------------------------------------------------------------------------- /python-phoenixdb/phoenixdb/tests/test_errors.py: -------------------------------------------------------------------------------- 1 | # Licensed to the Apache Software Foundation (ASF) under one or more 2 | # contributor license agreements. See the NOTICE file distributed with 3 | # this work for additional information regarding copyright ownership. 4 | # The ASF licenses this file to You under the Apache License, Version 2.0 5 | # (the "License"); you may not use this file except in compliance with 6 | # the License. You may obtain a copy of the License at 7 | # 8 | # http://www.apache.org/licenses/LICENSE-2.0 9 | # 10 | # Unless required by applicable law or agreed to in writing, software 11 | # distributed under the License is distributed on an "AS IS" BASIS, 12 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | # See the License for the specific language governing permissions and 14 | # limitations under the License. 15 | 16 | from phoenixdb.tests import DatabaseTestCase 17 | 18 | 19 | class ProgrammingErrorTest(DatabaseTestCase): 20 | 21 | def test_invalid_sql(self): 22 | with self.conn.cursor() as cursor: 23 | with self.assertRaises(self.conn.ProgrammingError) as cm: 24 | cursor.execute("UPS") 25 | self.assertEqual("Syntax error. Encountered \"UPS\" at line 1, column 1.", cm.exception.message) 26 | self.assertEqual(601, cm.exception.code) 27 | self.assertEqual("42P00", cm.exception.sqlstate) 28 | 29 | 30 | class IntegrityErrorTest(DatabaseTestCase): 31 | 32 | def test_null_in_pk(self): 33 | self.createTable("phoenixdb_test_tbl1", "CREATE TABLE {table} (id integer primary key)") 34 | with self.conn.cursor() as cursor: 35 | with self.assertRaises(self.conn.IntegrityError) as cm: 36 | cursor.execute("UPSERT INTO phoenixdb_test_tbl1 VALUES (NULL)") 37 | self.assertEqual("Constraint violation. PHOENIXDB_TEST_TBL1.ID may not be null", cm.exception.message) 38 | self.assertEqual(218, cm.exception.code) 39 | self.assertIn(cm.exception.sqlstate, ("22018", "23018")) 40 | 41 | 42 | class DataErrorTest(DatabaseTestCase): 43 | 44 | def test_number_outside_of_range(self): 45 | self.createTable("phoenixdb_test_tbl1", "CREATE TABLE {table} (id tinyint primary key)") 46 | with self.conn.cursor() as cursor: 47 | with self.assertRaises(self.conn.DataError) as cm: 48 | cursor.execute("UPSERT INTO phoenixdb_test_tbl1 VALUES (10000)") 49 | self.assertEqual("Type mismatch. TINYINT and INTEGER for 10000", cm.exception.message) 50 | self.assertEqual(203, cm.exception.code) 51 | self.assertEqual("22005", cm.exception.sqlstate) 52 | 53 | def test_division_by_zero(self): 54 | self.createTable("phoenixdb_test_tbl1", "CREATE TABLE {table} (id integer primary key)") 55 | with self.conn.cursor() as cursor: 56 | with self.assertRaises(self.conn.DataError) as cm: 57 | cursor.execute("UPSERT INTO phoenixdb_test_tbl1 VALUES (2/0)") 58 | self.assertEqual("Divide by zero.", cm.exception.message) 59 | self.assertEqual(202, cm.exception.code) 60 | self.assertEqual("22012", cm.exception.sqlstate) 61 | -------------------------------------------------------------------------------- /python-phoenixdb/requirements.txt: -------------------------------------------------------------------------------- 1 | # 2 | # Licensed to the Apache Software Foundation (ASF) under one 3 | # or more contributor license agreements. See the NOTICE file 4 | # distributed with this work for additional information 5 | # regarding copyright ownership. The ASF licenses this file 6 | # to you under the Apache License, Version 2.0 (the 7 | # "License"); you may not use this file except in compliance 8 | # with the License. You may obtain a copy of the License at 9 | # 10 | # http://www.apache.org/licenses/LICENSE-2.0 11 | # 12 | # Unless required by applicable law or agreed to in writing, 13 | # software distributed under the License is distributed on an 14 | # "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY 15 | # KIND, either express or implied. See the License for the 16 | # specific language governing permissions and limitations 17 | # under the License. 18 | # 19 | protobuf>=3.0.0 20 | requests 21 | requests-gssapi -------------------------------------------------------------------------------- /python-phoenixdb/setup.cfg: -------------------------------------------------------------------------------- 1 | # Licensed to the Apache Software Foundation (ASF) under one or more 2 | # contributor license agreements. See the NOTICE file distributed with 3 | # this work for additional information regarding copyright ownership. 4 | # The ASF licenses this file to You under the Apache License, Version 2.0 5 | # (the "License"); you may not use this file except in compliance with 6 | # the License. You may obtain a copy of the License at 7 | # 8 | # http://www.apache.org/licenses/LICENSE-2.0 9 | # 10 | # Unless required by applicable law or agreed to in writing, software 11 | # distributed under the License is distributed on an "AS IS" BASIS, 12 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | # See the License for the specific language governing permissions and 14 | # limitations under the License. 15 | 16 | 17 | [build_sphinx] 18 | source-dir = doc 19 | build-dir = doc/build 20 | all_files = 1 21 | 22 | [upload_sphinx] 23 | upload-dir = doc/build/html 24 | 25 | [flake8] 26 | max-line-length = 140 27 | exclude = 28 | e,e3,env,venv,doc,build,dist,.tox,.idea, 29 | ./phoenixdb/tests/dbapi20.py, 30 | ./phoenixdb/avatica/proto/*_pb2.py 31 | -------------------------------------------------------------------------------- /python-phoenixdb/setup.py: -------------------------------------------------------------------------------- 1 | # 2 | # Licensed to the Apache Software Foundation (ASF) under one 3 | # or more contributor license agreements. See the NOTICE file 4 | # distributed with this work for additional information 5 | # regarding copyright ownership. The ASF licenses this file 6 | # to you under the Apache License, Version 2.0 (the 7 | # "License"); you may not use this file except in compliance 8 | # with the License. You may obtain a copy of the License at 9 | # 10 | # http://www.apache.org/licenses/LICENSE-2.0 11 | # 12 | # Unless required by applicable law or agreed to in writing, 13 | # software distributed under the License is distributed on an 14 | # "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY 15 | # KIND, either express or implied. See the License for the 16 | # specific language governing permissions and limitations 17 | # under the License. 18 | # 19 | from setuptools import setup, find_packages 20 | import setuptools 21 | import sys 22 | 23 | cmdclass = {} 24 | 25 | try: 26 | from sphinx.setup_command import BuildDoc 27 | cmdclass['build_sphinx'] = BuildDoc 28 | except ImportError: 29 | pass 30 | 31 | 32 | def readme(): 33 | with open('README.rst') as f: 34 | return f.read() 35 | 36 | 37 | if setuptools.__version__ < '20.8.1': 38 | # Workaround for source install on old setuptools 39 | # This won't be able to create a proper multi-version pacakage 40 | install_requires=[ 41 | 'protobuf>=3.0.0', 42 | 'requests', 43 | ] 44 | if sys.version_info < (3,8): 45 | install_requires.append('requests-gssapi<1.3.0') 46 | else: 47 | install_requires.append('requests-gssapi') 48 | if sys.version_info < (3,6): 49 | install_requires.append('gssapi<1.6.0') 50 | #Don't build the docs on an old stack 51 | setup_requires=[] 52 | else: 53 | install_requires=[ 54 | 'protobuf>=3.0.0', 55 | 'requests', 56 | 'requests-gssapi; python_version>="3.8.0"', 57 | 'requests-gssapi<1.3.0; python_version<"3.8.0"', 58 | 'gssapi<1.6.0; python_version<"3.6.0"', 59 | ] 60 | setup_requires=[ 61 | 'Sphinx;python_version>="3.6"', 62 | ], 63 | 64 | version = "1.2.3.dev0" 65 | 66 | setup( 67 | name="phoenixdb", 68 | version=version, 69 | description="Phoenix database adapter for Python", 70 | long_description_content_type="text/x-rst", 71 | long_description=readme(), 72 | author="Apache Software Foundation", 73 | author_email="dev@phoenix.apache.org", 74 | url="http://phoenix.apache.org/python.html", 75 | license="Apache 2", 76 | packages=find_packages(), 77 | include_package_data=True, 78 | cmdclass=cmdclass, 79 | command_options={ 80 | 'build_sphinx': { 81 | 'version': ('setup.py', version), 82 | 'release': ('setup.py', version), 83 | }, 84 | }, 85 | classifiers=[ 86 | 'Programming Language :: Python', 87 | 'Programming Language :: Python :: 2', 88 | 'Programming Language :: Python :: 2.7', 89 | 'Programming Language :: Python :: 3', 90 | 'Programming Language :: Python :: 3.5', 91 | 'Programming Language :: Python :: 3.6', 92 | 'Programming Language :: Python :: 3.7', 93 | 'Programming Language :: Python :: 3.8', 94 | 'Programming Language :: Python :: 3.9', 95 | 'Programming Language :: Python :: 3.10', 96 | 'Programming Language :: Python :: 3.11', 97 | 'Programming Language :: Python :: 3.12', 98 | 'Programming Language :: Python :: 3.13' 99 | ], 100 | install_requires=install_requires, 101 | tests_require=[ 102 | 'SQLAlchemy', 103 | 'nose', 104 | 'flake8' 105 | ], 106 | setup_requires=setup_requires, 107 | entry_points={ 108 | "sqlalchemy.dialects": [ 109 | "phoenix = phoenixdb.sqlalchemy_phoenix:PhoenixDialect" 110 | ] 111 | }, 112 | ) 113 | -------------------------------------------------------------------------------- /python-phoenixdb/tox.ini: -------------------------------------------------------------------------------- 1 | # Licensed to the Apache Software Foundation (ASF) under one or more 2 | # contributor license agreements. See the NOTICE file distributed with 3 | # this work for additional information regarding copyright ownership. 4 | # The ASF licenses this file to You under the Apache License, Version 2.0 5 | # (the "License"); you may not use this file except in compliance with 6 | # the License. You may obtain a copy of the License at 7 | # 8 | # http://www.apache.org/licenses/LICENSE-2.0 9 | # 10 | # Unless required by applicable law or agreed to in writing, software 11 | # distributed under the License is distributed on an "AS IS" BASIS, 12 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | # See the License for the specific language governing permissions and 14 | # limitations under the License. 15 | 16 | [tox] 17 | # See https://tox.wiki/en/latest/faq.html#testing-end-of-life-python-versions 18 | requires = virtualenv<20.22.0 19 | envlist = py27-SQLAlchemy{13,14}, 20 | py35-SQLAlchemy{13}, 21 | py36-SQLAlchemy{13,14}, 22 | py37-SQLAlchemy{13,14,20}, 23 | py38-SQLAlchemy{13,14,20}, 24 | py39-SQLAlchemy{13,14,20}, 25 | py310-SQLAlchemy{13,14,20}, 26 | py311-SQLAlchemy{13,14,20}, 27 | py312-SQLAlchemy{13,14,20}, 28 | py313-SQLAlchemy{13,14,20} 29 | [testenv] 30 | passenv = PHOENIXDB_TEST_DB_URL 31 | commands = 32 | flake8 phoenixdb 33 | pytest {posargs} 34 | deps = -rrequirements.txt 35 | pytest 36 | flake8 37 | SQLAlchemy13: SQLAlchemy >=1.3.0, < 1.4.0 38 | SQLAlchemy14: SQLAlchemy >=1.4.0, < 2.0.0 39 | SQLAlchemy20: SQLAlchemy >= 2.0.0 40 | [pytest] 41 | testpaths = 42 | phoenixdb/tests --------------------------------------------------------------------------------