From 0eda471cf25e02203acbe281f2e8440712ccb890 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Adrian=20G=C3=B6rler?= Date: Tue, 5 Jan 2016 13:32:47 +0100 Subject: [PATCH] Add support for SAP HANA SAP HANA [1] is now supported as a database. [1] http://help.sap.com/hana_appliance/ Depends-On: Ib733610cb826d17d72defd71a9e2c5f0fc7ce154 Change-Id: I4c46ba18f95177c832472317fa6c2cdad19749ee --- Documentation/database-setup.txt | 45 +++++++++++++++ .../gerrit/pgm/init/DatabaseConfigModule.java | 2 + .../gerrit/pgm/init/HANAInitializer.java | 43 +++++++++++++++ .../google/gerrit/pgm/init/InitDatabase.java | 2 + .../com/google/gerrit/pgm/init/Libraries.java | 1 + .../google/gerrit/pgm/init/libraries.config | 5 ++ .../server/schema/DataSourceModule.java | 1 + .../com/google/gerrit/server/schema/HANA.java | 55 +++++++++++++++++++ .../google/gerrit/server/schema/HANATest.java | 48 ++++++++++++++++ 9 files changed, 202 insertions(+) create mode 100644 gerrit-pgm/src/main/java/com/google/gerrit/pgm/init/HANAInitializer.java create mode 100644 gerrit-server/src/main/java/com/google/gerrit/server/schema/HANA.java create mode 100644 gerrit-server/src/test/java/com/google/gerrit/server/schema/HANATest.java diff --git a/Documentation/database-setup.txt b/Documentation/database-setup.txt index f19f377dd2..02074c0228 100644 --- a/Documentation/database-setup.txt +++ b/Documentation/database-setup.txt @@ -206,6 +206,51 @@ Sample database section in $site_path/etc/secure.config: password = secret_pasword ---- +[[createdb_hana]] +=== SAP HANA + +SAP HANA is a supported database for running Gerrit Code Review. However it is +recommended only for environments where you intend to run Gerrit on an existing +HANA installation to reduce administrative overhead. + +In the HANA studio or the SAP HANA Web-based Development Workbench create a user +'GERRIT2' with the role 'RESTRICTED_USER_JDBC_ACCESS' and a password +. This will also create an associated schema on the database. +As this user would be required to change the password upon first login you might +want to to disable the password lifetime check by executing +'ALTER USER GERRIT2 DISABLE PASSWORD LIFETIME'. + +To run Gerrit on HANA, you need to obtain the HANA JDBC driver. It can be found +as described +link:http://help.sap.com/saphelp_hanaplatform/helpdata/en/ff/15928cf5594d78b841fbbe649f04b4/frameset.htm[here]. +It needs to be stored in the 'lib' folder of the review site. + +In the following sample database section it is assumed that HANA is running on +the host 'hana.host' with the instance number 00 where a schema/user GERRIT2 +was created: + +In $site_path/etc/gerrit.config: + +---- +[database] + type = hana + instance = 00 + hostname = hana.host + username = GERRIT2 + +---- + +In $site_path/etc/secure.config: + +---- +[database] + password = +---- + +Visit SAP HANA's link:http://help.sap.com/hana_appliance/[documentation] for +further information regarding using SAP HANA. + + GERRIT ------ Part of link:index.html[Gerrit Code Review] diff --git a/gerrit-pgm/src/main/java/com/google/gerrit/pgm/init/DatabaseConfigModule.java b/gerrit-pgm/src/main/java/com/google/gerrit/pgm/init/DatabaseConfigModule.java index a11f56f596..9dda276eb8 100644 --- a/gerrit-pgm/src/main/java/com/google/gerrit/pgm/init/DatabaseConfigModule.java +++ b/gerrit-pgm/src/main/java/com/google/gerrit/pgm/init/DatabaseConfigModule.java @@ -45,5 +45,7 @@ public class DatabaseConfigModule extends AbstractModule { Names.named("postgresql")).to(PostgreSQLInitializer.class); bind(DatabaseConfigInitializer.class).annotatedWith( Names.named("maxdb")).to(MaxDbInitializer.class); + bind(DatabaseConfigInitializer.class).annotatedWith( + Names.named("hana")).to(HANAInitializer.class); } } diff --git a/gerrit-pgm/src/main/java/com/google/gerrit/pgm/init/HANAInitializer.java b/gerrit-pgm/src/main/java/com/google/gerrit/pgm/init/HANAInitializer.java new file mode 100644 index 0000000000..fa0acbd9d5 --- /dev/null +++ b/gerrit-pgm/src/main/java/com/google/gerrit/pgm/init/HANAInitializer.java @@ -0,0 +1,43 @@ +// Copyright (C) 2016 The Android Open Source Project +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +package com.google.gerrit.pgm.init; + +import static com.google.gerrit.pgm.init.api.InitUtil.username; + +import com.google.common.primitives.Ints; +import com.google.gerrit.pgm.init.api.InitUtil; +import com.google.gerrit.pgm.init.api.Section; + +public class HANAInitializer implements DatabaseConfigInitializer { + + @Override + public void initConfig(Section databaseSection) { + final String defInstanceNumber = "00"; + databaseSection.string("Server hostname", "hostname", "localhost"); + databaseSection.string("Instance number", "instance", defInstanceNumber, + false); + String instance = databaseSection.get("instance"); + Integer instanceNumber = Ints.tryParse(instance); + if (instanceNumber == null || instanceNumber < 0 || instanceNumber > 99) { + instanceIsInvalid(); + } + databaseSection.string("Database username", "username", username()); + databaseSection.password("username", "password"); + } + + private void instanceIsInvalid() { + throw InitUtil.die("database.instance must be in the range of 00 to 99"); + } +} diff --git a/gerrit-pgm/src/main/java/com/google/gerrit/pgm/init/InitDatabase.java b/gerrit-pgm/src/main/java/com/google/gerrit/pgm/init/InitDatabase.java index abea521eab..26b1941306 100644 --- a/gerrit-pgm/src/main/java/com/google/gerrit/pgm/init/InitDatabase.java +++ b/gerrit-pgm/src/main/java/com/google/gerrit/pgm/init/InitDatabase.java @@ -86,6 +86,8 @@ class InitDatabase implements InitStep { libraries.oracleDriver.downloadRequired(); } else if (dci instanceof DB2Initializer) { libraries.db2Driver.downloadRequired(); + } else if (dci instanceof HANAInitializer) { + libraries.hanaDriver.downloadRequired(); } dci.initConfig(database); diff --git a/gerrit-pgm/src/main/java/com/google/gerrit/pgm/init/Libraries.java b/gerrit-pgm/src/main/java/com/google/gerrit/pgm/init/Libraries.java index 7cc8f1017a..988d7ef91d 100644 --- a/gerrit-pgm/src/main/java/com/google/gerrit/pgm/init/Libraries.java +++ b/gerrit-pgm/src/main/java/com/google/gerrit/pgm/init/Libraries.java @@ -44,6 +44,7 @@ class Libraries { /* final */LibraryDownloader bouncyCastleSSL; /* final */LibraryDownloader db2Driver; /* final */LibraryDownloader db2DriverLicense; + /* final */LibraryDownloader hanaDriver; /* final */LibraryDownloader mysqlDriver; /* final */LibraryDownloader oracleDriver; diff --git a/gerrit-pgm/src/main/resources/com/google/gerrit/pgm/init/libraries.config b/gerrit-pgm/src/main/resources/com/google/gerrit/pgm/init/libraries.config index a74da30d1a..39d647d935 100644 --- a/gerrit-pgm/src/main/resources/com/google/gerrit/pgm/init/libraries.config +++ b/gerrit-pgm/src/main/resources/com/google/gerrit/pgm/init/libraries.config @@ -61,3 +61,8 @@ name = DB2 Type 4 JDBC driver license (10.5) url = file:///opt/ibm/db2/V10.5/java/db2jcc_license_cu.jar remove = db2jcc_license_cu.jar + +[library "hanaDriver"] + name = HANA JDBC driver + url = file:///usr/sap/hdbclient/ngdbc.jar + remove = ngdbc.jar diff --git a/gerrit-server/src/main/java/com/google/gerrit/server/schema/DataSourceModule.java b/gerrit-server/src/main/java/com/google/gerrit/server/schema/DataSourceModule.java index 777b5b949d..65843d8fbb 100644 --- a/gerrit-server/src/main/java/com/google/gerrit/server/schema/DataSourceModule.java +++ b/gerrit-server/src/main/java/com/google/gerrit/server/schema/DataSourceModule.java @@ -35,5 +35,6 @@ public class DataSourceModule extends AbstractModule { */ bind(DataSourceType.class).annotatedWith(Names.named("maxdb")).to(MaxDb.class); bind(DataSourceType.class).annotatedWith(Names.named("sap db")).to(MaxDb.class); + bind(DataSourceType.class).annotatedWith(Names.named("hana")).to(HANA.class); } } diff --git a/gerrit-server/src/main/java/com/google/gerrit/server/schema/HANA.java b/gerrit-server/src/main/java/com/google/gerrit/server/schema/HANA.java new file mode 100644 index 0000000000..ed4b9ba634 --- /dev/null +++ b/gerrit-server/src/main/java/com/google/gerrit/server/schema/HANA.java @@ -0,0 +1,55 @@ +// Copyright (C) 2016 The Android Open Source Project +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +package com.google.gerrit.server.schema; + +import static com.google.gerrit.server.schema.JdbcUtil.hostname; +import static com.google.gerrit.server.schema.JdbcUtil.port; + +import com.google.gerrit.server.config.ConfigSection; +import com.google.gerrit.server.config.GerritServerConfig; +import com.google.inject.Inject; + +import org.eclipse.jgit.lib.Config; + +import java.io.IOException; + +class HANA extends BaseDataSourceType { + + private Config cfg; + + @Inject + public HANA(@GerritServerConfig final Config cfg) { + super("com.sap.db.jdbc.Driver"); + this.cfg = cfg; + } + + @Override + public String getUrl() { + final StringBuilder b = new StringBuilder(); + final ConfigSection dbs = new ConfigSection(cfg, "database"); + b.append("jdbc:sap://"); + b.append(hostname(dbs.required("hostname"))); + int instance = Integer.parseInt(dbs.required("instance")); + String port = "3" + String.format("%02d", instance) + "15"; + b.append(port(port)); + return b.toString(); + } + + @Override + public ScriptRunner getIndexScript() throws IOException { + // HANA uses column tables and should not require additional indices + return ScriptRunner.NOOP; + } +} \ No newline at end of file diff --git a/gerrit-server/src/test/java/com/google/gerrit/server/schema/HANATest.java b/gerrit-server/src/test/java/com/google/gerrit/server/schema/HANATest.java new file mode 100644 index 0000000000..56f9a20f3e --- /dev/null +++ b/gerrit-server/src/test/java/com/google/gerrit/server/schema/HANATest.java @@ -0,0 +1,48 @@ +// Copyright (C) 2016 The Android Open Source Project +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and + +package com.google.gerrit.server.schema; + +import static com.google.common.truth.Truth.assertThat; +import static org.hamcrest.CoreMatchers.sameInstance; + +import org.eclipse.jgit.lib.Config; +import org.junit.Before; +import org.junit.Test; + +public class HANATest { + + private HANA hana; + private Config config; + + @Before + public void setup() { + config = new Config(); + config.setString("database", null, "hostname", "my.host"); + hana = new HANA(config); + } + + @Test + public void testGetUrl() throws Exception { + config.setString("database", null, "instance", "3"); + assertThat(hana.getUrl()).isEqualTo("jdbc:sap://my.host:30315"); + + config.setString("database", null, "instance", "77"); + assertThat(hana.getUrl()).isEqualTo("jdbc:sap://my.host:37715"); + } + + @Test + public void testGetIndexScript() throws Exception { + assertThat(hana.getIndexScript()).isEqualTo(sameInstance(ScriptRunner.NOOP)); + } +}