All Downloads are FREE. Search and download functionalities are using the official Maven repository.

org.apache.uima.ducc.database.DbCreate Maven / Gradle / Ivy

The newest version!
/*
 * 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.net.InetSocketAddress;
import java.util.List;
import java.util.Map;
import java.util.Map.Entry;
import java.util.UUID;

import org.apache.uima.ducc.common.utils.DuccLogger;
import org.apache.uima.ducc.common.utils.id.DuccId;

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
{
    public 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[] db_host_list;
    String adminid = null;
    String adminpw = null;
    String replication = null;
    boolean useNewPw = false;

    private Cluster cluster;
    private Session session = null;


    DbCreate(String db_host_list, DuccLogger logger, String adminid, String adminpw)
    {
        this.db_host_list = toArray(db_host_list);
        this.logger = logger;
        this.adminid = adminid;
        this.adminpw = adminpw;
    }

    DbCreate(String db_host_list, String adminid, String adminpw)
    {
        this.db_host_list = toArray(db_host_list);
        this.adminid = adminid;
        this.adminpw = adminpw;
    }

    DbCreate(String db_host_list, String adminid, String adminpw, String replication)
    {
        this.db_host_list = toArray(db_host_list);
        this.adminid = adminid;
        this.adminpw = adminpw;
        this.replication = replication;
    }
    
    private String toString(String[] array) {
    	StringBuffer sb = new StringBuffer();
    	if(array != null) {
    		for(String item : array) {
    			sb.append(item);
    			sb.append(" ");
    		}
    	}
    	return sb.toString().trim();
    }
    
    private String[] toArray(String stringList) {
    	String methodName = "toArray";
    	String[] retVal = null;
    	if(stringList != null) {
    		retVal = stringList.split("\\s+");
        	debug(methodName, "list size =  " + retVal.length);  
            for(String item : retVal) {
            	debug(methodName, item);
            }
    	}
    	else {
    		debug(methodName, "null");
    	}
    	
    	return retVal;
    }
    
    void close()
    {
        if ( cluster != null ) cluster.close();
        session = null;
        cluster = null;
    }

    private void recommendation() {
    	doLog("Check cassandra.yaml for the following entries:");
    	doLog("> authenticator: PasswordAuthenticator");
    	doLog("> authorizer: org.apache.cassandra.auth.CassandraAuthorizer");
    }
    
    private void show(NoHostAvailableException e) {
    	String location = "show";
    	DuccId jobid = null;
    	if(logger != null) {
    		logger.debug(location, jobid, e);
    		Map map = e.getErrors();
            for(Entry entry : map.entrySet()) {
            	Throwable t = entry.getValue();
            	logger.debug(location, jobid, t);
            }
    	}
    }
    
    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
        doLog("database location(s): "+toString(db_host_list));

        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)
                    .addContactPoints(db_host_list)
                    .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)
                    .addContactPoints(db_host_list)
                    .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 ...");
                show(e);
                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)
                        .addContactPoints(db_host_list)
                        .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.");
                recommendation();
                session = null;
                cluster = null;
                e.printStackTrace();
                return false;
            } 
            Thread.sleep(3000);
        }
            
        if ( cluster == null ) {
            doLog(methodName, "Excessive retries.  Database may not be initialized.");
            recommendation();
            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;
    }

    private boolean flag_debug = false;
    
    void debug(String methodName, Object ... msg) {
    	if(flag_debug) {
    		doLog(methodName, msg);
    	}
    }
    
    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("");
                } 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";

    	String guest_pw = adminpw;
    	
        // A 'keyspace' is what we usually think of as a database.
    	String strategy = "SimpleStrategy";
		String factor = "1";
    	if(replication != null) {
    		//strategy = "NetworkTopologyStrategy";
    		factor = replication;
    	}
        session.execute("CREATE KEYSPACE IF NOT EXISTS ducc WITH replication = {'class':'"+strategy+"', 'replication_factor':"+factor+"};");
        session.execute("CREATE USER IF NOT EXISTS guest  WITH PASSWORD '"+guest_pw+"' 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 {
            ListrmSchema = RmStatePersistence.mkSchema();
            for ( SimpleStatement s : rmSchema ) {
                doLog(methodName, "EXECUTE STATEMENT:", s.toString());
                session.execute(s);
            }

            ListsmSchema = StateServicesDb.mkSchema();
            for ( SimpleStatement s : smSchema ) {
                doLog(methodName, "EXECUTE STATEMENT:", s.toString());
                session.execute(s);
            }

            ListorSchema = HistoryManagerDb.mkSchema();
            for ( SimpleStatement s : orSchema ) {
                doLog(methodName, "EXECUTE STATEMENT:", s.toString());
                session.execute(s);
            }
            
            /*
             * The following table for specifications is created by Orchestrator
             * at boot time, if not already present.  This additional table was 
             * not part of the DB in versions DUCC 2.2.1 and earlier.  In this
             * fashion, both migrated systems as well as fresh installs are able
             * to utilize this table without the need for invocation of 
             * ducc_post_install.  The commented-out code below is thus for
             * documentation purposes only.
             * 
            ListspecificationsSchema = DbDuccWorks.mkSchema();
            for ( SimpleStatement s : specificationsSchema ) {
                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)
    {
        DbCreate client = null;
        try {
        	if ( args.length == 4 ) {
        		client = new DbCreate(args[0], args[1], args[2], args[3]);
        	}
        	else if ( args.length == 3 ) {
        		client = new DbCreate(args[0], args[1], args[2]);
        	}
        	else {
                System.out.println("Usage: DbCreate database_url db_id db_pw");
                System.exit(1);
            }
            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);
    }

}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy