blob: db46ba9c923d11fd0ec3e6d6417d16bcaa621d94 [file] [log] [blame]
/*
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
*/
package org.apache.uima.ducc.database;
import java.util.List;
import java.util.UUID;
import org.apache.uima.ducc.common.utils.DuccLogger;
import com.datastax.driver.core.AuthProvider;
import com.datastax.driver.core.Cluster;
import com.datastax.driver.core.Host;
import com.datastax.driver.core.Metadata;
import com.datastax.driver.core.PlainTextAuthProvider;
import com.datastax.driver.core.Session;
import com.datastax.driver.core.SimpleStatement;
import com.datastax.driver.core.exceptions.AuthenticationException;
import com.datastax.driver.core.exceptions.NoHostAvailableException;
public class DbCreate
{
static final String DUCC_KEYSPACE = "ducc";
static final String PASSWORD_KEY = "db_password";
static final String PASSWORD_FILE = "ducc.private.properties";
int RETRY = 10;
DuccLogger logger = null;
String dburl;
String adminid = null;
String adminpw = null;
boolean useNewPw = false;
private Cluster cluster;
private Session session = null;
DbCreate(String dburl, DuccLogger logger, String adminid, String adminpw)
{
this.dburl = dburl;
this.logger = logger;
this.adminid = adminid;
this.adminpw = adminpw;
}
DbCreate(String dburl, String adminid, String adminpw)
{
this.dburl = dburl;
this.adminid = adminid;
this.adminpw = adminpw;
}
void close()
{
if ( cluster != null ) cluster.close();
session = null;
cluster = null;
}
boolean connect()
throws Exception
{
String methodName = "connect";
String dh = System.getProperty("DUCC_HOME");
if ( dh == null ) {
throw new IllegalArgumentException("DUCC_HOME must be set as a system property: -DDUCC_HOME=whatever");
}
// If we're here, we must first of all get rid of the cassandra su and set up our own
for ( int i = 0; i < RETRY; i++ ) {
try {
// First time, we nuke the default id / pw and install our own.
AuthProvider auth = new PlainTextAuthProvider("cassandra", "cassandra");
cluster = Cluster.builder()
.withAuthProvider(auth)
.addContactPoint(dburl)
.build();
session = cluster.connect();
session.execute("CREATE USER IF NOT EXISTS " + adminid + " with password '" + adminpw + "' SUPERUSER");
cluster.close();
doLog(methodName, "Created database super user " + adminid);
auth = new PlainTextAuthProvider(adminid, adminpw);
cluster = Cluster.builder()
.withAuthProvider(auth)
.addContactPoint(dburl)
.build();
session = cluster.connect();
String uglypw = UUID.randomUUID().toString();
session.execute("ALTER USER cassandra with password '" + uglypw + "' NOSUPERUSER");
doLog(methodName, "Changed default database super user's password and revoked its superuser authority.");
doLog(methodName, "From this point, this DB can only be accessed in super user mode by user 'ducc'");
break;
} catch ( NoHostAvailableException e ) {
doLog("Waiting for database to boot ...");
session = null;
cluster = null;
} catch ( AuthenticationException e ) {
// The default userid/pw failed, so we try again with the user-supplied one
RETRY += i; // we'll extend the retry for a bit in case db took a while to start
doLog(methodName, "Initial DB connection failed with AuthorizationException. Retrying database connection with your supplied userid and password.");
try {
AuthProvider auth = new PlainTextAuthProvider(adminid, adminpw);
cluster = Cluster.builder()
.withAuthProvider(auth)
.addContactPoint(dburl)
.build();
session = cluster.connect();
// if this works we assume the DB user base is ok and continue
break; // no crash, we're outta here
} catch ( Exception ee ) {
doLog(methodName, "Authorization fails with both the default userid/password and the new userid/password.");
doLog(methodName, "Retrying, as first-time database may take a few moments to initialize.");
}
session = null;
cluster = null;
} catch ( Exception e ) {
doLog("Unknown problem contacting database.");
session = null;
cluster = null;
e.printStackTrace();
return false;
}
Thread.sleep(3000);
}
if ( cluster == null ) {
doLog(methodName, "Excessive retries. Database may not be initialized.");
return false;
}
Metadata metadata = cluster.getMetadata();
doLog(methodName, "Connected to cluster:", metadata.getClusterName());
for ( Host host : metadata.getAllHosts() ) {
doLog(methodName, "Datatacenter:", host.getDatacenter(), "Host:", host.getAddress(), "Rack:", host.getRack());
}
return true;
}
void doLog(String methodName, Object ... msg)
{
if ( logger == null ) {
StringBuffer buf = new StringBuffer(methodName);
for ( Object o : msg ) {
buf.append(" ");
if ( o == null ) {
buf.append("<null>");
} else {
buf.append(o.toString());
}
}
System.out.println(buf);
} else {
logger.info(methodName, null, msg);
return;
}
}
// String mkTableCreate(String tableName, String[] fields)
// {
// int max = fields.length - 1;
// int current = 0;
// StringBuffer buf = new StringBuffer("CREATE TABLE IF NOT EXISTS ");
// buf.append(tableName);
// buf.append(" (");
// for (String s : fields) {
// buf.append(s);
// if ( current++ < max) buf.append(", ");
// }
// buf.append(") WITH CLUSTERING ORDER BY (ducc_dbid desc)");
// return buf.toString();
// }
void createSchema()
{
String methodName = "createSchema";
// A 'keyspace' is what we usually think of as a database.
session.execute("CREATE KEYSPACE IF NOT EXISTS ducc WITH replication = {'class':'SimpleStrategy', 'replication_factor':1};");
session.execute("CREATE USER IF NOT EXISTS guest WITH PASSWORD 'guest' NOSUPERUSER");
session.execute("GRANT SELECT ON KEYSPACE ducc TO guest");
session.execute("REVOKE SELECT ON KEYSPACE system FROM guest");
session.execute("REVOKE SELECT ON KEYSPACE system_auth FROM guest");
session.execute("REVOKE SELECT ON KEYSPACE system_traces FROM guest");
doLog(methodName, "Created database user 'guest' with SELECT priveleges on DUCC tables.");
session.execute("USE " + DUCC_KEYSPACE);
try {
List<SimpleStatement>rmSchema = RmStatePersistence.mkSchema();
for ( SimpleStatement s : rmSchema ) {
doLog(methodName, "EXECUTE STATEMENT:", s.toString());
session.execute(s);
}
List<SimpleStatement>smSchema = StateServicesDb.mkSchema();
for ( SimpleStatement s : smSchema ) {
doLog(methodName, "EXECUTE STATEMENT:", s.toString());
session.execute(s);
}
List<SimpleStatement>orSchema = HistoryManagerDb.mkSchema();
for ( SimpleStatement s : orSchema ) {
doLog(methodName, "EXECUTE STATEMENT:", s.toString());
session.execute(s);
}
} catch ( Exception e ) {
doLog(methodName, "Cannot create schema:", e);
}
}
/**
* Create the database and initialize the schema. This is intended to be called only from Main at
* system startup, to insure all users of the db have a db when they start.
*/
boolean createDatabase()
throws Exception
{
//String methodName = "createDatabase";
return true;
}
public static void main(String[] args)
{
if ( args.length != 3 ) {
System.out.println("Usage: DbCreate database_url db_id db_pw");
System.exit(1);
}
DbCreate client = null;
try {
client = new DbCreate(args[0], args[1], args[2]);
if ( client.connect() ) {
client.createSchema();
client.close();
} else {
System.exit(1);
}
} catch ( Throwable e ) {
System.out.println("Errors creating database");
e.printStackTrace();
System.exit(1);
}
System.exit(0);
}
}