/*************************************************************************
* (c) Copyright 2017 Hewlett Packard Enterprise Development Company LP
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; version 3 of the License.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see http://www.gnu.org/licenses/.
************************************************************************/
package com.eucalyptus.cassandra.config;
import java.io.File;
import java.io.IOException;
import java.nio.charset.StandardCharsets;
import java.util.EnumSet;
import java.util.Set;
import org.apache.log4j.Logger;
import com.eucalyptus.cassandra.CassandraCluster;
import com.eucalyptus.cassandra.CassandraDirectory;
import com.eucalyptus.cassandra.CassandraKeyspaces;
import com.eucalyptus.system.BaseDirectory;
import com.eucalyptus.util.EucalyptusCloudException;
import com.eucalyptus.util.Internets;
import com.eucalyptus.util.Templates;
import com.google.common.base.Optional;
import com.google.common.io.Files;
import com.google.common.io.Resources;
import edu.ucsb.eucalyptus.util.SystemUtil;
/**
*
*/
class CassandraSysUtil {
private static final Logger logger = Logger.getLogger( CassandraSysUtil.class );
private static final String PATH_CASSANDRA = "/usr/sbin/cassandra";
private static final String PATH_ROOTWRAP = "/usr/lib/eucalyptus/euca_rootwrap";
private static final String PATH_EUCACASS = "/usr/libexec/eucalyptus/euca-cassandra-ctl";
private static final String YAML_RESOURCE_NAME = "cassandra.yaml";
private static final String RACKDC_RESOURCE_NAME = "cassandra-rackdc.properties";
static boolean checkCassandra( ) {
if ( !new File( PATH_CASSANDRA ).isFile( ) ||
!new File( PATH_EUCACASS ).isFile( ) ) {
return false;
}
boolean running = false;
final int code = SystemUtil.runAndGetCode( new String[]{ PATH_ROOTWRAP, PATH_EUCACASS, "status" } );
switch ( code ) {
case 0:
logger.trace( "Cassandra running" );
running = true;
break;
case 1:
case 2:
logger.warn( "Cassandra dead, performing cleanup" );
cleanup( );
return false;
case 3:
logger.trace( "Cassandra stopped" );
break;
default:
logger.warn( "Cassandra status unknown, code: " + code );
return false;
}
if ( !running ) {
return CassandraCluster.canStart( );
}
return true;
}
static void startCassandra( ) throws EucalyptusCloudException {
final int code = SystemUtil.runAndGetCode( new String[]{ PATH_ROOTWRAP, PATH_EUCACASS, "start" } );
if ( code != 0 ) {
throw new EucalyptusCloudException( "Error starting cassandra, status code: " + code );
}
}
static void stopCassandra( ) throws EucalyptusCloudException {
final int code = SystemUtil.runAndGetCode( new String[]{ PATH_ROOTWRAP, PATH_EUCACASS, "stop" } );
if ( code != 0 ) {
throw new EucalyptusCloudException( "Error stopping cassandra, status code: " + code );
}
}
static void createKeyspaces( ) {
CassandraKeyspaces.all( CassandraCluster.datacenter( ), 1 ).forEach( t -> {
final String keyspace = t._1( );
final Optional<Throwable> throwableOptional = t._2( );
if ( throwableOptional.isPresent( ) ) {
logger.error( "Error processing keyspace " + keyspace, throwableOptional.get( ) );
} else {
logger.info( "Processed keyspace " + keyspace );
}
} );
}
static void createDirectories( ) {
EnumSet.allOf( CassandraDirectory.class ).forEach( CassandraDirectory::mkdirs );
}
private static void cleanup( ) {
final int code = SystemUtil.runAndGetCode( new String[]{ PATH_ROOTWRAP, PATH_EUCACASS, "clean" } );
if ( code != 0 ) {
logger.error( "Error running cassandra clean up, status code: " + code );
}
}
static void writeConfiguration( ) throws IOException {
Files.write(
generateCassandraYaml( ),
BaseDirectory.VAR.getChildFile( "cassandra", "conf", "cassandra.yaml" ),
StandardCharsets.UTF_8 );
Files.write(
generateCassandraRackDcProperties( ),
BaseDirectory.VAR.getChildFile( "cassandra", "conf", "cassandra-rackdc.properties" ),
StandardCharsets.UTF_8 );
}
private static String generateCassandraYaml( ) throws IOException {
final String name = CassandraCluster.name( );
final String bindAddr = Internets.localHostInetAddress( ).getHostAddress( );
final Set<String> seeds = CassandraCluster.seeds( );
final String dir = BaseDirectory.VAR.toString( );
final boolean autoBootstrap = CassandraCluster.autoBootstrap( );
return generateCassandraYaml( name, bindAddr, seeds, dir, autoBootstrap );
}
private static String generateCassandraRackDcProperties( ) throws IOException {
return generateCassandraRackDcProperties(
CassandraCluster.datacenter( ),
CassandraCluster.rack( ) );
}
static String generateCassandraYaml(
final String name,
final String bindAddr,
final Set<String> seeds,
final String dir,
final boolean autoBootstrap
) throws IOException {
final String cassandraYamlTemplate =
Resources.toString( Resources.getResource( YAML_RESOURCE_NAME ), StandardCharsets.UTF_8 );
return Templates.prepare( YAML_RESOURCE_NAME )
.withProperty( "cluster_name", name )
.withProperty( "seeds", seeds )
.withProperty( "bind_addr", bindAddr )
.withProperty( "port_native", 8787 )
.withProperty( "port_storage", 8782 )
.withProperty( "port_storage_ssl", 8783 )
.withProperty( "dir_lib", dir )
.withProperty( "auto_bootstrap", autoBootstrap )
.evaluate( cassandraYamlTemplate );
}
static String generateCassandraRackDcProperties(
final String dc,
final String rack
) throws IOException {
final String cassandraRackDcTemplate =
Resources.toString( Resources.getResource( RACKDC_RESOURCE_NAME ), StandardCharsets.UTF_8 );
return Templates.prepare( RACKDC_RESOURCE_NAME )
.withProperty( "dc", dc )
.withProperty( "rack", rack )
.evaluate( cassandraRackDcTemplate );
}
}