/* * * * RHQ Management Platform * * Copyright (C) 2005-2012 Red Hat, Inc. * * All rights reserved. * * * * This program is free software; you can redistribute it and/or modify * * it under the terms of the GNU General Public License, version 2, as * * published by the Free Software Foundation, and/or the GNU Lesser * * General Public License, version 2.1, also as published by the Free * * Software Foundation. * * * * 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 and the GNU Lesser General Public License * * for more details. * * * * You should have received a copy of the GNU General Public License * * and the GNU Lesser General Public License along with this program; * * if not, write to the Free Software Foundation, Inc., * * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. * */ package org.rhq.plugins.cassandra; import java.io.File; import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; import org.rhq.core.domain.configuration.Configuration; import org.rhq.core.domain.configuration.Property; import org.rhq.core.domain.configuration.PropertyList; import org.rhq.core.domain.configuration.PropertyMap; import org.rhq.core.domain.configuration.PropertySimple; import org.rhq.core.pluginapi.configuration.ConfigurationUpdateReport; import org.rhq.core.pluginapi.inventory.ResourceContext; import org.rhq.core.pluginapi.operation.OperationResult; import org.rhq.core.util.file.FileUtil; /** * @author John Sanda */ public class ColumnFamilyComponent extends ComplexConfigurationResourceComponent { private Log log = LogFactory.getLog(ColumnFamilyComponent.class); @Override public Configuration loadResourceConfiguration() { Configuration config = super.loadResourceConfiguration(); if (log.isDebugEnabled()) { ResourceContext<?> context = getResourceContext(); log.debug("Loading resource context for column family " + context.getResourceKey()); } config.put(this.getSnapshotsWithDetails()); return config; } @Override public OperationResult invokeOperation(String name, Configuration parameters) throws Exception { String columnFamilyName = this.getResourceContext().getResourceKey(); if (name.equals("repair")) { return this.getParentKeyspace().repairKeyspace(columnFamilyName); } else if (name.equals("compact")) { return this.getParentKeyspace().compactKeyspace(columnFamilyName); } else if (name.equals("takeSnapshot")) { return this.getParentKeyspace().takeSnapshot(parameters, columnFamilyName); } else if (name.equals("restoreSnapshot")){ return this.restoreSnapshot(parameters); } return super.invokeOperation(name, parameters); }; @Override public void updateResourceConfiguration(ConfigurationUpdateReport report) { if (log.isDebugEnabled()) { log.debug("Updating resource configuration for column family " + getResourceContext().getResourceKey()); } report.getConfiguration().remove("snapshots"); super.updateResourceConfiguration(report); } private PropertyList getSnapshotsWithDetails() { PropertyList listOfSnapshots = new PropertyList("snapshots"); KeyspaceComponent parentKeyspace = this.getParentKeyspace(); PropertyList parentDataFileLocations = parentKeyspace.getKeySpaceDataFileLocations(); for (Property directory : parentDataFileLocations.getList()) { String directoryName = ((PropertySimple) directory).getStringValue(); directoryName += "/" + this.getResourceContext().getPluginConfiguration().getSimpleValue("name"); directoryName += "/snapshots"; File snapshotDirectory = new File(directoryName); if (snapshotDirectory.exists()) { File[] files = snapshotDirectory.listFiles(); for (File individualSnapshot : files) { if (individualSnapshot.isDirectory()) { PropertyMap snapshotDetails = new PropertyMap("snapshot"); snapshotDetails.put(new PropertySimple("name", individualSnapshot.getName())); snapshotDetails.put(new PropertySimple("folder", individualSnapshot.getAbsolutePath())); listOfSnapshots.add(snapshotDetails); } } } } return listOfSnapshots; } private OperationResult restoreSnapshot(Configuration parameters) { OperationResult result = new OperationResult(); //1. Find the list of snapshots discovered String requestedSnapshotName = parameters.getSimpleValue("snapshotName"); PropertyList listOfSnapShots = this.getSnapshotsWithDetails(); String snapshotDirectoryName = null; for (Property property : listOfSnapShots.getList()) { String snapshotName = ((PropertyMap) property).getSimpleValue("name", null); if (requestedSnapshotName.equals(snapshotName)) { snapshotDirectoryName = ((PropertyMap) property).getSimpleValue("folder", null); break; } } //2. Find out if the discovered snapshot still exists on disk if (snapshotDirectoryName == null) { result.setErrorMessage("Restore failed! The snapshot does not exist!"); return result; } File snapshotDirectory = new File(snapshotDirectoryName); if (!snapshotDirectory.exists() || !snapshotDirectory.isDirectory()) { result.setErrorMessage("Restore failed! The snapshot does not exist on disk!"); return result; } //3. Shutdown Cassandra CassandraNodeComponent node = this.getParentKeyspace().getCassandraNodeComponent(); node.shutdownNode(); //4. Remove the entire commit log KeyspaceComponent parentKeyspace = this.getParentKeyspace(); parentKeyspace.clearCommitLog(); //5. Copy the snapshot files to the column family folders PropertyList parentDataFileLocations = parentKeyspace.getKeySpaceDataFileLocations(); for (Property dataFileDirectoryProperty : parentDataFileLocations.getList()) { String columnFamilyDirectoryName = ((PropertySimple) dataFileDirectoryProperty).getStringValue(); columnFamilyDirectoryName += "/" + this.getResourceContext().getPluginConfiguration().getSimpleValue("name"); File columnFamilyDirectory = new File(columnFamilyDirectoryName); if(columnFamilyDirectory.exists()){ //5.1 Remove existing data files File[] originalColumnFamilyDataFiles = columnFamilyDirectory.listFiles(); if (originalColumnFamilyDataFiles != null) { for (File file : originalColumnFamilyDataFiles) { if (file.isFile()) { file.delete(); } } } //5.2 Copy snapshots files to column family folder File[] filesToBeRestored = snapshotDirectory.listFiles(); if (filesToBeRestored != null) { for (File fileToBeRestored : filesToBeRestored) { if (fileToBeRestored.isFile()) { File destinationFile = new File(columnFamilyDirectory, fileToBeRestored.getName()); try { FileUtil.copyFile(fileToBeRestored, destinationFile); } catch (Exception e) { result.setErrorMessage("Restore failed! The file copying process failed!"); return result; } } } } } } //6. Restart Cassandra node.startNode(); result.setSimpleResult("Snapshot restored succesfully..."); return result; } /** * @return parent resource component */ private KeyspaceComponent getParentKeyspace() { return (KeyspaceComponent) this.getResourceContext().getParentResourceComponent(); } }