From d269087b4f04ef23635581b4b5789ad486c9120c Mon Sep 17 00:00:00 2001
From: Shireesh Anjal
Date: Tue, 3 May 2011 21:45:10 +0530
Subject: Story #42 - Volume logs download
---
.../storage/management/client/AbstractClient.java | 17 +-
.../storage/management/client/VolumesClient.java | 23 +-
.../management/core/constants/RESTConstants.java | 2 +
.../storage/management/core/model/Cluster.java | 16 +
.../storage/management/core/model/Server.java | 9 +
.../storage/management/core/utils/FileUtil.java | 79 ++++
.../icons/memory.png | Bin 0 -> 349 bytes
.../icons/server-warning.png | Bin 0 -> 664 bytes
.../gui/ApplicationWorkbenchWindowAdvisor.java | 1 +
.../gluster/storage/management/gui/IImageKeys.java | 2 +
.../management/gui/utils/GlusterChartPalette.java | 479 +++++++++++++++++++++
.../management/gui/views/ClusterSummaryView.java | 148 ++++++-
.../gui/views/GlusterServerSummaryView.java | 4 +-
.../gui/views/GlusterServersSummaryView.java | 6 +-
.../management/gui/views/VolumesSummaryView.java | 6 +-
.../tabcreators/PieChartViewerComposite.java | 17 +-
.../src/nodes/PeerAgent.py | 30 +-
.../src/nodes/get_file.py | 132 ++++++
.../build/glusterserver.ant | 3 +-
.../server/resources/VolumesResource.java | 107 ++++-
.../management/server/utils/ServerUtil.java | 84 +++-
21 files changed, 1087 insertions(+), 78 deletions(-)
create mode 100644 src/com.gluster.storage.management.gui/icons/memory.png
create mode 100644 src/com.gluster.storage.management.gui/icons/server-warning.png
create mode 100644 src/com.gluster.storage.management.gui/src/com/gluster/storage/management/gui/utils/GlusterChartPalette.java
create mode 100755 src/com.gluster.storage.management.server.scripts/src/nodes/get_file.py
diff --git a/src/com.gluster.storage.management.client/src/com/gluster/storage/management/client/AbstractClient.java b/src/com.gluster.storage.management.client/src/com/gluster/storage/management/client/AbstractClient.java
index a4df0e58..f8005044 100644
--- a/src/com.gluster.storage.management.client/src/com/gluster/storage/management/client/AbstractClient.java
+++ b/src/com.gluster.storage.management.client/src/com/gluster/storage/management/client/AbstractClient.java
@@ -8,6 +8,7 @@ import javax.ws.rs.core.MultivaluedMap;
import com.gluster.storage.management.client.utils.ClientUtil;
import com.gluster.storage.management.core.constants.RESTConstants;
import com.sun.jersey.api.client.Client;
+import com.sun.jersey.api.client.ClientResponse;
import com.sun.jersey.api.client.WebResource;
import com.sun.jersey.api.client.config.DefaultClientConfig;
import com.sun.jersey.api.representation.Form;
@@ -47,6 +48,16 @@ public abstract class AbstractClient {
return res.queryParams(queryParams).header(HTTP_HEADER_AUTH, authHeader).accept(MediaType.TEXT_XML)
.get(responseClass);
}
+
+ private Object downloadResource(WebResource res, MultivaluedMap queryParams, Class responseClass) {
+ return res.queryParams(queryParams).header(HTTP_HEADER_AUTH, authHeader).accept(MediaType.TEXT_XML)
+ .get(responseClass);
+ }
+
+ protected Object downloadResource(WebResource res) {
+ ClientResponse response = res.header(HTTP_HEADER_AUTH, authHeader).accept(MediaType.APPLICATION_OCTET_STREAM).get(ClientResponse.class);
+ return response;
+ }
/**
* Fetches the default resource (the one returned by {@link AbstractClient#getResourceName()}) by dispatching a GET
@@ -92,6 +103,10 @@ public abstract class AbstractClient {
return fetchResource(resource.path(subResourceName), NO_PARAMS, responseClass);
}
+ protected Object downloadSubResource(String subResourceName) {
+ return downloadResource(resource.path(subResourceName));
+ }
+
/**
* Fetches the resource whose name is arrived at by appending the "subResourceName" parameter to the default
* resource (the one returned by {@link AbstractClient#getResourceName()})
@@ -109,7 +124,7 @@ public abstract class AbstractClient {
Class responseClass) {
return fetchResource(resource.path(subResourceName), queryParams, responseClass);
}
-
+
/**
* Submits given Form using POST method to the resource and returns the object received as response
*
diff --git a/src/com.gluster.storage.management.client/src/com/gluster/storage/management/client/VolumesClient.java b/src/com.gluster.storage.management.client/src/com/gluster/storage/management/client/VolumesClient.java
index 33a93690..4af70c5a 100644
--- a/src/com.gluster.storage.management.client/src/com/gluster/storage/management/client/VolumesClient.java
+++ b/src/com.gluster.storage.management.client/src/com/gluster/storage/management/client/VolumesClient.java
@@ -138,6 +138,10 @@ public class VolumesClient extends AbstractClient {
return (LogMessageListResponse) fetchSubResource(volumeName + "/" + RESTConstants.SUBRESOURCE_LOGS,
queryParams, LogMessageListResponse.class);
}
+
+ public void downloadLogs(String volumeName) {
+ downloadSubResource((volumeName) + "/" + RESTConstants.SUBRESOURCE_LOGS + "/" + RESTConstants.SUBRESOURCE_DOWNLOAD);
+ }
private MultivaluedMap prepareGetLogQueryParams(String diskName, String severity,
Date fromTimestamp, Date toTimestamp, int messageCount) {
@@ -222,15 +226,16 @@ public class VolumesClient extends AbstractClient {
// }
// System.out.println(client.getVolume("Volume3").getOptions());
// System.out.println(client.setVolumeOption("Volume3", "network.frame-timeout", "600").getMessage());
- List disks = new ArrayList();
- Disk disk = new Disk();
- disk.setServerName("server1");
- disk.setName("sda");
- disk.setStatus(DISK_STATUS.READY);
- disks.add(disk);
-
- Status status = client.addDisks("Volume3", disks);
- System.out.println(status.getMessage());
+// List disks = new ArrayList();
+// Disk disk = new Disk();
+// disk.setServerName("server1");
+// disk.setName("sda");
+// disk.setStatus(DISK_STATUS.READY);
+// disks.add(disk);
+//
+// Status status = client.addDisks("Volume3", disks);
+// System.out.println(status.getMessage());
+ client.downloadLogs("vol1");
}
}
}
diff --git a/src/com.gluster.storage.management.core/src/com/gluster/storage/management/core/constants/RESTConstants.java b/src/com.gluster.storage.management.core/src/com/gluster/storage/management/core/constants/RESTConstants.java
index 5da9e6b1..6c7b69da 100644
--- a/src/com.gluster.storage.management.core/src/com/gluster/storage/management/core/constants/RESTConstants.java
+++ b/src/com.gluster.storage.management.core/src/com/gluster/storage/management/core/constants/RESTConstants.java
@@ -29,6 +29,7 @@ public class RESTConstants {
public static final String SUBRESOURCE_DEFAULT_OPTIONS = "defaultoptions";
public static final String SUBRESOURCE_OPTIONS = "options";
public static final String SUBRESOURCE_LOGS = "logs";
+ public static final String SUBRESOURCE_DOWNLOAD = "download";
public static final String SUBRESOURCE_DISKS = "disks";
@@ -53,6 +54,7 @@ public class RESTConstants {
public static final String QUERY_PARAM_LOG_SEVERITY = "severity";
public static final String QUERY_PARAM_FROM_TIMESTAMP = "fromTimestamp";
public static final String QUERY_PARAM_TO_TIMESTAMP = "toTimestamp";
+ public static final String QUERY_PARAM_DOWNLOAD = "download";
// Running tasks resource
public static final String RESOURCE_PATH_RUNNING_TASKS = "/cluster/runningtasks";
diff --git a/src/com.gluster.storage.management.core/src/com/gluster/storage/management/core/model/Cluster.java b/src/com.gluster.storage.management.core/src/com/gluster/storage/management/core/model/Cluster.java
index 8fa247a1..1a62b293 100644
--- a/src/com.gluster.storage.management.core/src/com/gluster/storage/management/core/model/Cluster.java
+++ b/src/com.gluster.storage.management.core/src/com/gluster/storage/management/core/model/Cluster.java
@@ -123,4 +123,20 @@ public class Cluster extends Entity {
public void addAlert(Alert alert) {
this.alerts.add(alert);
}
+
+ public double getTotalDiskSpace() {
+ double totalDiskSpace = 0;
+ for(GlusterServer server : getServers()) {
+ totalDiskSpace += server.getTotalDiskSpace();
+ }
+ return totalDiskSpace;
+ }
+
+ public double getDiskSpaceInUse() {
+ double diskSpaceInUse = 0;
+ for(GlusterServer server : getServers()) {
+ diskSpaceInUse += server.getDiskSpaceInUse();
+ }
+ return diskSpaceInUse;
+ }
}
\ No newline at end of file
diff --git a/src/com.gluster.storage.management.core/src/com/gluster/storage/management/core/model/Server.java b/src/com.gluster.storage.management.core/src/com/gluster/storage/management/core/model/Server.java
index bc0c42bc..4f870eaf 100644
--- a/src/com.gluster.storage.management.core/src/com/gluster/storage/management/core/model/Server.java
+++ b/src/com.gluster.storage.management.core/src/com/gluster/storage/management/core/model/Server.java
@@ -102,6 +102,15 @@ public class Server extends Entity {
public double getDiskSpaceInUse() {
return diskSpaceInUse;
}
+
+ /**
+ * Total disk space in use is automatically calculated, and hence this method should never be called. It is required
+ * only to make sure that the element "diskSpaceInUse" gets added to the XML tag when jersey converts the server
+ * object to XML for sending to client.
+ */
+ public void setDiskSpaceInUse(double diskSpaceInUse) {
+ this.diskSpaceInUse = diskSpaceInUse;
+ }
@XmlElementWrapper(name = "networkInterfaces")
@XmlElement(name = "networkInterface", type = NetworkInterface.class)
diff --git a/src/com.gluster.storage.management.core/src/com/gluster/storage/management/core/utils/FileUtil.java b/src/com.gluster.storage.management.core/src/com/gluster/storage/management/core/utils/FileUtil.java
index c650d632..c6394a3e 100644
--- a/src/com.gluster.storage.management.core/src/com/gluster/storage/management/core/utils/FileUtil.java
+++ b/src/com.gluster.storage.management.core/src/com/gluster/storage/management/core/utils/FileUtil.java
@@ -20,7 +20,10 @@ package com.gluster.storage.management.core.utils;
import java.io.File;
import java.io.FileInputStream;
+import java.io.FileWriter;
+import java.io.IOException;
import java.io.InputStream;
+import java.util.UUID;
import com.gluster.storage.management.core.exceptions.GlusterRuntimeException;
@@ -42,4 +45,80 @@ public class FileUtil {
public InputStream loadResource(String resourcePath) {
return this.getClass().getClassLoader().getResourceAsStream(resourcePath);
}
+
+ public void createTextFile(String fileName, String contents) {
+ try {
+ FileWriter writer = new FileWriter(fileName);
+ writer.write(contents);
+ } catch (Exception e) {
+ throw new GlusterRuntimeException("Exception while trying to create text file [" + fileName + "]", e);
+ }
+ }
+
+ public String getTempDirName() {
+ return System.getProperty("java.io.tmpdir");
+ }
+
+ /**
+ * Create a new temporary directory. Use something like
+ * {@link #recursiveDelete(File)} to clean this directory up since it isn't
+ * deleted automatically
+ * @return the new directory
+ * @throws IOException if there is an error creating the temporary directory
+ */
+ public File createTempDir()
+ {
+ final File sysTempDir = new File(getTempDirName());
+ File newTempDir;
+ final int maxAttempts = 9;
+ int attemptCount = 0;
+ do
+ {
+ attemptCount++;
+ if(attemptCount > maxAttempts)
+ {
+ throw new GlusterRuntimeException(
+ "The highly improbable has occurred! Failed to " +
+ "create a unique temporary directory after " +
+ maxAttempts + " attempts.");
+ }
+ String dirName = UUID.randomUUID().toString();
+ newTempDir = new File(sysTempDir, dirName);
+ } while(newTempDir.exists());
+
+ if(newTempDir.mkdirs())
+ {
+ return newTempDir;
+ }
+ else
+ {
+ throw new GlusterRuntimeException(
+ "Failed to create temp dir named " +
+ newTempDir.getAbsolutePath());
+ }
+ }
+
+ /**
+ * Recursively delete file or directory
+ *
+ * @param fileOrDir
+ * the file or dir to delete
+ * @return true if all files are successfully deleted
+ */
+ public boolean recursiveDelete(File fileOrDir)
+ {
+ if(fileOrDir.isDirectory())
+ {
+ // recursively delete contents
+ for(File innerFile: fileOrDir.listFiles())
+ {
+ if(!recursiveDelete(innerFile))
+ {
+ return false;
+ }
+ }
+ }
+
+ return fileOrDir.delete();
+ }
}
\ No newline at end of file
diff --git a/src/com.gluster.storage.management.gui/icons/memory.png b/src/com.gluster.storage.management.gui/icons/memory.png
new file mode 100644
index 00000000..4c71a247
Binary files /dev/null and b/src/com.gluster.storage.management.gui/icons/memory.png differ
diff --git a/src/com.gluster.storage.management.gui/icons/server-warning.png b/src/com.gluster.storage.management.gui/icons/server-warning.png
new file mode 100644
index 00000000..c2888d19
Binary files /dev/null and b/src/com.gluster.storage.management.gui/icons/server-warning.png differ
diff --git a/src/com.gluster.storage.management.gui/src/com/gluster/storage/management/gui/ApplicationWorkbenchWindowAdvisor.java b/src/com.gluster.storage.management.gui/src/com/gluster/storage/management/gui/ApplicationWorkbenchWindowAdvisor.java
index 05d7443f..3a9a4531 100644
--- a/src/com.gluster.storage.management.gui/src/com/gluster/storage/management/gui/ApplicationWorkbenchWindowAdvisor.java
+++ b/src/com.gluster.storage.management.gui/src/com/gluster/storage/management/gui/ApplicationWorkbenchWindowAdvisor.java
@@ -56,6 +56,7 @@ public class ApplicationWorkbenchWindowAdvisor extends WorkbenchWindowAdvisor {
public void postWindowCreate() {
super.postWindowCreate();
guiHelper.centerShellInScreen(getWindowConfigurer().getWindow().getShell());
+ getWindowConfigurer().getWindow().getShell().setMaximized(true);
Application.getApplication().setStatusLineManager(
getWindowConfigurer().getActionBarConfigurer().getStatusLineManager());
}
diff --git a/src/com.gluster.storage.management.gui/src/com/gluster/storage/management/gui/IImageKeys.java b/src/com.gluster.storage.management.gui/src/com/gluster/storage/management/gui/IImageKeys.java
index fdcf7aac..d11decb6 100644
--- a/src/com.gluster.storage.management.gui/src/com/gluster/storage/management/gui/IImageKeys.java
+++ b/src/com.gluster.storage.management.gui/src/com/gluster/storage/management/gui/IImageKeys.java
@@ -24,6 +24,8 @@ public interface IImageKeys {
public static final String SERVERS = "icons/servers.png";
public static final String VOLUME = "icons/volume.png";
public static final String SERVER = "icons/server.png";
+ public static final String SERVER_WARNING = "icons/server-warning.png";
+ public static final String MEMORY = "icons/memory.png";
public static final String GSN = "icons/gsn.png";
public static final String SETTINGS = "icons/settings.png";
public static final String ADD = "icons/plus-white.png";
diff --git a/src/com.gluster.storage.management.gui/src/com/gluster/storage/management/gui/utils/GlusterChartPalette.java b/src/com.gluster.storage.management.gui/src/com/gluster/storage/management/gui/utils/GlusterChartPalette.java
new file mode 100644
index 00000000..e68b8870
--- /dev/null
+++ b/src/com.gluster.storage.management.gui/src/com/gluster/storage/management/gui/utils/GlusterChartPalette.java
@@ -0,0 +1,479 @@
+/***********************************************************************
+ * Copyright (c) 2004 Actuate Corporation.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * Actuate Corporation - initial API and implementation
+ ***********************************************************************/
+
+package com.gluster.storage.management.gui.utils;
+
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.List;
+
+import org.eclipse.birt.chart.engine.i18n.Messages;
+import org.eclipse.birt.chart.log.ILogger;
+import org.eclipse.birt.chart.log.Logger;
+import org.eclipse.birt.chart.model.attribute.AttributeFactory;
+import org.eclipse.birt.chart.model.attribute.AttributePackage;
+import org.eclipse.birt.chart.model.attribute.ColorDefinition;
+import org.eclipse.birt.chart.model.attribute.Fill;
+import org.eclipse.birt.chart.model.attribute.Palette;
+import org.eclipse.birt.chart.model.attribute.impl.ColorDefinitionImpl;
+import org.eclipse.emf.common.notify.Notification;
+import org.eclipse.emf.common.notify.NotificationChain;
+import org.eclipse.emf.common.util.EList;
+import org.eclipse.emf.ecore.EClass;
+import org.eclipse.emf.ecore.InternalEObject;
+import org.eclipse.emf.ecore.impl.ENotificationImpl;
+import org.eclipse.emf.ecore.impl.EObjectImpl;
+import org.eclipse.emf.ecore.util.EObjectContainmentEList;
+import org.eclipse.emf.ecore.util.InternalEList;
+
+import com.ibm.icu.util.ULocale;
+
+/**
+ * An implementation of the model object '
+ * Palette'.
+ *
+ * The following features are implemented:
+ *
+ * - {@link org.eclipse.birt.chart.model.attribute.impl.GlusterChartPalette#getName Name}
+ * - {@link org.eclipse.birt.chart.model.attribute.impl.GlusterChartPalette#getEntries Entries}
+ *
+ *
+ *
+ * @generated
+ */
+public class GlusterChartPalette extends EObjectImpl implements Palette
+{
+
+ /**
+ * The default value of the '{@link #getName() Name}' attribute.
+ *
+ * @see #getName()
+ * @generated
+ * @ordered
+ */
+ protected static final String NAME_EDEFAULT = null;
+
+ /**
+ * The cached value of the '{@link #getName() Name}' attribute.
+ *
+ * @see #getName()
+ * @generated
+ * @ordered
+ */
+ protected String name = NAME_EDEFAULT;
+
+ /**
+ * The cached value of the '{@link #getEntries() Entries}' containment reference list.
+ *
+ * @see #getEntries()
+ * @generated
+ * @ordered
+ */
+ protected EList entries;
+
+ private static ILogger logger = Logger.getLogger( "org.eclipse.birt.chart.engine/model.attribute.impl" ); //$NON-NLS-1$
+
+ private static List colorLib = new ArrayList( 32 );
+ static
+ {
+ colorLib.add( ColorDefinitionImpl.create ( 0, 1, 252) );
+ colorLib.add( ColorDefinitionImpl.create ( 255, 0, 255) );
+ //colorLib.add( ColorDefinitionImpl.BLUE() );
+ //colorLib.add( ColorDefinitionImpl.create( 232, 172, 57 ) );
+ }
+
+ /**
+ *
+ * @generated
+ */
+ public GlusterChartPalette( )
+ {
+ super( );
+ }
+
+ /**
+ *
+ * @generated
+ */
+ @Override
+ protected EClass eStaticClass( )
+ {
+ return AttributePackage.Literals.PALETTE;
+ }
+
+ /**
+ *
+ * @generated
+ */
+ public String getName( )
+ {
+ return name;
+ }
+
+ /**
+ *
+ * @generated
+ */
+ public void setName( String newName )
+ {
+ String oldName = name;
+ name = newName;
+ if ( eNotificationRequired( ) )
+ eNotify( new ENotificationImpl( this,
+ Notification.SET,
+ AttributePackage.PALETTE__NAME,
+ oldName,
+ name ) );
+ }
+
+ /**
+ *
+ * @generated
+ */
+ public EList getEntries( )
+ {
+ if ( entries == null )
+ {
+ entries = new EObjectContainmentEList( Fill.class,
+ this,
+ AttributePackage.PALETTE__ENTRIES );
+ }
+ return entries;
+ }
+
+ /**
+ *
+ *
+ * @generated
+ */
+ @Override
+ public NotificationChain eInverseRemove( InternalEObject otherEnd,
+ int featureID, NotificationChain msgs )
+ {
+ switch ( featureID )
+ {
+ case AttributePackage.PALETTE__ENTRIES :
+ return ( (InternalEList>) getEntries( ) ).basicRemove( otherEnd,
+ msgs );
+ }
+ return super.eInverseRemove( otherEnd, featureID, msgs );
+ }
+
+ /**
+ *
+ *
+ * @generated
+ */
+ @Override
+ public Object eGet( int featureID, boolean resolve, boolean coreType )
+ {
+ switch ( featureID )
+ {
+ case AttributePackage.PALETTE__NAME :
+ return getName( );
+ case AttributePackage.PALETTE__ENTRIES :
+ return getEntries( );
+ }
+ return super.eGet( featureID, resolve, coreType );
+ }
+
+ /**
+ *
+ *
+ * @generated
+ */
+ @SuppressWarnings("unchecked")
+ @Override
+ public void eSet( int featureID, Object newValue )
+ {
+ switch ( featureID )
+ {
+ case AttributePackage.PALETTE__NAME :
+ setName( (String) newValue );
+ return;
+ case AttributePackage.PALETTE__ENTRIES :
+ getEntries( ).clear( );
+ getEntries( ).addAll( (Collection extends Fill>) newValue );
+ return;
+ }
+ super.eSet( featureID, newValue );
+ }
+
+ /**
+ *
+ *
+ * @generated
+ */
+ @Override
+ public void eUnset( int featureID )
+ {
+ switch ( featureID )
+ {
+ case AttributePackage.PALETTE__NAME :
+ setName( NAME_EDEFAULT );
+ return;
+ case AttributePackage.PALETTE__ENTRIES :
+ getEntries( ).clear( );
+ return;
+ }
+ super.eUnset( featureID );
+ }
+
+ /**
+ *
+ *
+ * @generated
+ */
+ @Override
+ public boolean eIsSet( int featureID )
+ {
+ switch ( featureID )
+ {
+ case AttributePackage.PALETTE__NAME :
+ return NAME_EDEFAULT == null ? name != null
+ : !NAME_EDEFAULT.equals( name );
+ case AttributePackage.PALETTE__ENTRIES :
+ return entries != null && !entries.isEmpty( );
+ }
+ return super.eIsSet( featureID );
+ }
+
+ /**
+ *
+ * @generated
+ */
+ @Override
+ public String toString( )
+ {
+ if ( eIsProxy( ) )
+ return super.toString( );
+
+ StringBuffer result = new StringBuffer( super.toString( ) );
+ result.append( " (name: " ); //$NON-NLS-1$
+ result.append( name );
+ result.append( ')' );
+ return result.toString( );
+ }
+
+ /**
+ * A convenience method provided to create an empty or pre-initialized
+ * palette
+ *
+ * NOTE: Manually written
+ *
+ * @param bEmpty
+ */
+ public static final Palette create( int iIndex, boolean bEmpty )
+ {
+ final Palette p = AttributeFactory.eINSTANCE.createPalette( );
+
+ if ( !bEmpty )
+ {
+ p.shift( iIndex );
+ }
+ return p;
+ }
+
+ /**
+ * A convenience method provided to create a palette with a single color
+ * entry
+ *
+ * NOTE: Manually written
+ *
+ * @param f
+ */
+ public static final Palette create( Fill f )
+ {
+ final Palette p = AttributeFactory.eINSTANCE.createPalette( );
+ p.getEntries( ).add( f );
+ return p;
+ }
+
+ /**
+ * Shift the list content from tail to head.
+ *
+ * @param lst
+ * @param pos
+ */
+ private static final void shiftList( final List lst, int pos )
+ {
+ int size = lst.size( );
+
+ if ( pos < 1 )
+ {
+ pos = 0;
+ }
+
+ if ( pos >= size )
+ {
+ pos = pos % size;
+ }
+
+ if ( pos == 0 )
+ {
+ return;
+ }
+
+ Object[] array = lst.toArray( );
+
+ lst.clear( );
+
+ for ( int i = pos; i < array.length; i++ )
+ {
+ lst.add( array[i] );
+ }
+
+ for ( int i = 0; i < pos; i++ )
+ {
+ lst.add( array[i] );
+ }
+ }
+
+ /*
+ * (non-Javadoc)
+ *
+ * @see org.eclipse.birt.chart.model.attribute.Palette#update(int)
+ */
+ public final void update( int iIndex )
+ {
+ final EList el = getEntries( );
+ el.clear( );
+ if ( iIndex < 0 )
+ {
+ // a rotation version of palette-0, rataion pos is the negatvie
+ // index.
+ ArrayList al = new ArrayList( );
+
+ al.add( ColorDefinitionImpl.create( 80, 166, 218 ) );
+ al.add( ColorDefinitionImpl.create( 242, 88, 106 ) );
+ al.add( ColorDefinitionImpl.create( 232, 172, 57 ) );
+ al.add( ColorDefinitionImpl.create( 128, 255, 128 ) );
+ al.add( ColorDefinitionImpl.create( 64, 128, 128 ) );
+ al.add( ColorDefinitionImpl.create( 128, 128, 192 ) );
+ al.add( ColorDefinitionImpl.create( 170, 85, 85 ) );
+ al.add( ColorDefinitionImpl.create( 128, 128, 0 ) );
+
+ shiftList( al, -iIndex );
+
+ el.addAll( al );
+ }
+ else if ( iIndex == 0 )
+ {
+ el.add( ColorDefinitionImpl.create( 80, 166, 218 ) );
+ el.add( ColorDefinitionImpl.create( 242, 88, 106 ) );
+ el.add( ColorDefinitionImpl.create( 232, 172, 57 ) );
+ el.add( ColorDefinitionImpl.create( 128, 255, 128 ) );
+ el.add( ColorDefinitionImpl.create( 64, 128, 128 ) );
+ el.add( ColorDefinitionImpl.create( 128, 128, 192 ) );
+ el.add( ColorDefinitionImpl.create( 170, 85, 85 ) );
+ el.add( ColorDefinitionImpl.create( 128, 128, 0 ) );
+ }
+ else if ( iIndex == 1 )
+ {
+ el.add( ColorDefinitionImpl.create( 225, 225, 255 ) );
+ el.add( ColorDefinitionImpl.create( 223, 197, 41 ) );
+ el.add( ColorDefinitionImpl.create( 249, 225, 191 ) );
+ el.add( ColorDefinitionImpl.create( 255, 205, 225 ) );
+ el.add( ColorDefinitionImpl.create( 225, 255, 225 ) );
+ el.add( ColorDefinitionImpl.create( 255, 191, 255 ) );
+ el.add( ColorDefinitionImpl.create( 185, 185, 221 ) );
+ el.add( ColorDefinitionImpl.create( 40, 255, 148 ) );
+ }
+ else
+ {
+ logger.log( ILogger.WARNING,
+ Messages.getString( "error.unknown.palette", //$NON-NLS-1$
+ new Object[]{
+ Integer.valueOf( iIndex )
+ },
+ ULocale.getDefault( ) ) );
+ update( 0 );
+ }
+ }
+
+ /*
+ * (non-Javadoc)
+ *
+ * @see org.eclipse.birt.chart.model.attribute.Palette#update(org.eclipse.birt.chart.model.attribute.Fill)
+ */
+ public final void update( Fill f )
+ {
+ final EList el = getEntries( );
+ el.clear( );
+ el.add( f );
+ }
+
+ public void shift( int step )
+ {
+ shift( step, colorLib.size( ) );
+ }
+
+ public void shift( int step, int size )
+ {
+ if ( size <= 0 || size > colorLib.size( ) )
+ {
+ size = colorLib.size( );
+ }
+
+ final EList el = getEntries( );
+ el.clear( );
+
+ if ( step == 0 || Math.abs( step ) >= size )
+ {
+ // Do nothing
+ step = 0;
+ }
+ else if ( step < 0 )
+ {
+ // Move to the left side
+ step = -step;
+ }
+ else if ( step > 0 )
+ {
+ // Move to the right side
+ step = size - step;
+ }
+
+ for ( int i = step; i < size; i++ )
+ {
+ el.add( ( (ColorDefinition) colorLib.get( i ) ).copyInstance( ) );
+ }
+ for ( int i = 0; i < step; i++ )
+ {
+ el.add( ( (ColorDefinition) colorLib.get( i ) ).copyInstance( ) );
+ }
+ }
+
+ /**
+ * A convenient method to get an instance copy. This is much faster than the
+ * ECoreUtil.copy().
+ */
+ public Palette copyInstance( )
+ {
+ GlusterChartPalette dest = new GlusterChartPalette( );
+ dest.set( this );
+ return dest;
+ }
+
+ protected void set( Palette src )
+ {
+ if ( src.getEntries( ) != null )
+ {
+ EList list = getEntries( );
+ for ( Fill element : src.getEntries( ) )
+ {
+ list.add( element.copyInstance( ) );
+ }
+ }
+ name = src.getName( );
+ }
+
+} // GlusterChartPalette
diff --git a/src/com.gluster.storage.management.gui/src/com/gluster/storage/management/gui/views/ClusterSummaryView.java b/src/com.gluster.storage.management.gui/src/com/gluster/storage/management/gui/views/ClusterSummaryView.java
index 079d6bcf..4ec1f586 100644
--- a/src/com.gluster.storage.management.gui/src/com/gluster/storage/management/gui/views/ClusterSummaryView.java
+++ b/src/com.gluster.storage.management.gui/src/com/gluster/storage/management/gui/views/ClusterSummaryView.java
@@ -20,10 +20,15 @@
*/
package com.gluster.storage.management.gui.views;
+import java.util.List;
+
import org.eclipse.swt.SWT;
+import org.eclipse.swt.custom.CLabel;
+import org.eclipse.swt.graphics.Image;
import org.eclipse.swt.layout.GridData;
import org.eclipse.swt.widgets.Composite;
import org.eclipse.swt.widgets.Display;
+import org.eclipse.swt.widgets.Label;
import org.eclipse.ui.forms.events.HyperlinkAdapter;
import org.eclipse.ui.forms.events.HyperlinkEvent;
import org.eclipse.ui.forms.widgets.FormToolkit;
@@ -33,14 +38,19 @@ import org.eclipse.ui.handlers.IHandlerService;
import org.eclipse.ui.part.ViewPart;
import com.gluster.storage.management.client.GlusterDataModelManager;
+import com.gluster.storage.management.core.model.Alert;
import com.gluster.storage.management.core.model.Cluster;
+import com.gluster.storage.management.core.model.Disk;
+import com.gluster.storage.management.core.model.Disk.DISK_STATUS;
import com.gluster.storage.management.core.model.EntityGroup;
import com.gluster.storage.management.core.model.GlusterDataModel;
import com.gluster.storage.management.core.model.GlusterServer;
import com.gluster.storage.management.core.model.GlusterServer.SERVER_STATUS;
+import com.gluster.storage.management.core.model.RunningTask;
import com.gluster.storage.management.core.model.Server;
import com.gluster.storage.management.core.model.Volume;
import com.gluster.storage.management.core.model.Volume.VOLUME_STATUS;
+import com.gluster.storage.management.core.utils.NumberUtil;
import com.gluster.storage.management.gui.IImageKeys;
import com.gluster.storage.management.gui.actions.IActionConstants;
import com.gluster.storage.management.gui.utils.GUIHelper;
@@ -97,29 +107,100 @@ public class ClusterSummaryView extends ViewPart {
Double[] values = new Double[] { Double.valueOf(getVolumeCountByStatus(cluster, VOLUME_STATUS.ONLINE)),
Double.valueOf(getVolumeCountByStatus(cluster, VOLUME_STATUS.OFFLINE)) };
- createStatusChart(toolkit, section, values);
+ createDiskSpaceChart(toolkit, section, values);
}
private void createServersSection() {
- Composite section = guiHelper.createSection(form, toolkit, "Servers", null, 1, false);
+ Composite section = guiHelper.createSection(form, toolkit, "Servers", null, 2, false);
- Double[] values = new Double[] { Double.valueOf(getServerCountByStatus(cluster, SERVER_STATUS.ONLINE)),
- Double.valueOf(getServerCountByStatus(cluster, SERVER_STATUS.OFFLINE)) };
+ int onlineServerCount = getServerCountByStatus(cluster, SERVER_STATUS.ONLINE);
+ int offlineServerCount = getServerCountByStatus(cluster, SERVER_STATUS.OFFLINE);
+
+ toolkit.createLabel(section, "Online : ");
+ Label label = toolkit.createLabel(section, "" + onlineServerCount);
+ label.setForeground(Display.getCurrent().getSystemColor(SWT.COLOR_DARK_GREEN));
+
+ toolkit.createLabel(section, "Offline : ");
+ label = toolkit.createLabel(section, "" + offlineServerCount);
+ label.setForeground(Display.getCurrent().getSystemColor(SWT.COLOR_RED));
+ }
+
+ private void createDiskSpaceSection() {
+ Composite section = guiHelper.createSection(form, toolkit, "Disk Space", null, 3, false);
+
+ double totalDiskSpace = cluster.getTotalDiskSpace();
+ double diskSpaceInUse = cluster.getDiskSpaceInUse();
+ Double[] values = new Double[] { diskSpaceInUse, totalDiskSpace - diskSpaceInUse };
+ createDiskSpaceChart(toolkit, section, values);
+ }
- createStatusChart(toolkit, section, values);
+ private int getDiskCountByStatus(Cluster cluster, DISK_STATUS status) {
+ int diskCount = 0;
+ for(GlusterServer server : cluster.getServers()) {
+ for(Disk disk : server.getDisks()) {
+ if(disk.getStatus() == status) {
+ diskCount++;
+ }
+ }
+ }
+ return diskCount;
}
- private void createStatusChart(FormToolkit toolkit, Composite section, Double[] values) {
- String[] categories = new String[] { "Online", "Offline" };
+ private int getDiskCount(Cluster cluster) {
+ int diskCount = 0;
+ for(GlusterServer server : cluster.getServers()) {
+ diskCount += server.getDisks().size();
+ }
+ return diskCount;
+ }
+
+ private void createDiskSpaceChart(FormToolkit toolkit, Composite section, Double[] values) {
+ String[] categories = new String[] { "Used Space: " + NumberUtil.formatNumber(values[0]) + " GB",
+ "Free Space: " + NumberUtil.formatNumber(values[1]) + " GB"};
PieChartViewerComposite chartViewerComposite = new PieChartViewerComposite(section, SWT.NONE, categories,
values);
- GridData data = new GridData(SWT.FILL, SWT.FILL, true, true);
- data.widthHint = 250;
- data.heightHint = 250;
+ GridData data = new GridData(SWT.FILL, SWT.FILL, false, false);
+ data.widthHint = 400;
+ data.heightHint = 150;
+ data.verticalAlignment = SWT.CENTER;
chartViewerComposite.setLayoutData(data);
}
+ private void createAlertsSection() {
+ Composite section = guiHelper.createSection(form, toolkit, "Alerts", null, 1, false);
+ List alerts = GlusterDataModelManager.getInstance().getModel().getCluster().getAlerts();
+
+ for (Alert alert : alerts) {
+ addAlertLabel(section, alert);
+ }
+ }
+
+ private void addAlertLabel(Composite section, Alert alert) {
+ CLabel lblAlert = new CLabel(section, SWT.FLAT);
+ Image alertImage = null;
+ switch (alert.getType()) {
+ case OFFLINE_VOLUME_DISKS_ALERT:
+ alertImage = guiHelper.getImage(IImageKeys.DISK_OFFLINE);
+ break;
+ case DISK_USAGE_ALERT:
+ alertImage = guiHelper.getImage(IImageKeys.DISK);
+ break;
+ case OFFLINE_SERVERS_ALERT:
+ alertImage = guiHelper.getImage(IImageKeys.STATUS_OFFLINE);
+ break;
+ case MEMORY_USAGE_ALERT:
+ alertImage = guiHelper.getImage(IImageKeys.MEMORY);
+ break;
+ case CPU_USAGE_ALERT:
+ alertImage = guiHelper.getImage(IImageKeys.SERVER_WARNING);
+ break;
+ }
+ lblAlert.setImage(alertImage);
+ lblAlert.setText(alert.getMessage());
+ lblAlert.redraw();
+ }
+
private void createActionsSection() {
Composite section = guiHelper.createSection(form, toolkit, "Actions", null, 1, false);
@@ -157,13 +238,58 @@ public class ClusterSummaryView extends ViewPart {
private void createSections(Composite parent) {
form = guiHelper.setupForm(parent, toolkit, "Cluster Summary");
- createVolumesSection();
createServersSection();
+ createDiskSpaceSection();
+ createCPUUsageSection();
+ //createMemoryUsageSection();
createActionsSection();
+ createAlertsSection();
+ createRunningTasksSection();
parent.layout(); // IMP: lays out the form properly
}
+ private void createMemoryUsageSection() {
+ Composite section = guiHelper.createSection(form, toolkit, "Memory Usage (aggregated)", null, 1, false);
+ toolkit.createLabel(section, "Historical Memory Usage graph aggregated across all servers will be displayed here.");
+ }
+
+ private void createCPUUsageSection() {
+ Composite section = guiHelper.createSection(form, toolkit, "CPU Usage (aggregated)", null, 1, false);
+ toolkit.createLabel(section, "Historical CPU Usage graph aggregated across all servers will be displayed here.");
+ }
+
+ private void createRunningTasksSection() {
+ Composite section = guiHelper.createSection(form, toolkit, "Running Tasks", null, 1, false);
+
+ List runningTasks = cluster.getRunningTasks();
+
+ for (RunningTask task : runningTasks) {
+ addRunningTaskLabel(section, task);
+ }
+ }
+
+ private void addRunningTaskLabel(Composite section, RunningTask task) {
+ // Task related to Volumes context
+ CLabel lblAlert = new CLabel(section, SWT.NONE);
+ lblAlert.setText(task.getTaskInfo());
+
+ Image taskImage = null;
+ switch(task.getType()) {
+ case DISK_FORMAT:
+ taskImage = guiHelper.getImage(IImageKeys.DISK);
+ break;
+ case DISK_MIGRATE:
+ taskImage = guiHelper.getImage(IImageKeys.DISK_MIGRATE);
+ break;
+ case VOLUME_REBALANCE:
+ taskImage = guiHelper.getImage(IImageKeys.VOLUME_REBALANCE);
+ break;
+ }
+ lblAlert.setImage(taskImage);
+ lblAlert.redraw();
+ }
+
/*
* (non-Javadoc)
*
diff --git a/src/com.gluster.storage.management.gui/src/com/gluster/storage/management/gui/views/GlusterServerSummaryView.java b/src/com.gluster.storage.management.gui/src/com/gluster/storage/management/gui/views/GlusterServerSummaryView.java
index 42a14dd4..87ad17d6 100644
--- a/src/com.gluster.storage.management.gui/src/com/gluster/storage/management/gui/views/GlusterServerSummaryView.java
+++ b/src/com.gluster.storage.management.gui/src/com/gluster/storage/management/gui/views/GlusterServerSummaryView.java
@@ -114,8 +114,8 @@ public class GlusterServerSummaryView extends ViewPart {
memoryUsageBar.setMinimum(0);
memoryUsageBar.setMaximum((int) Math.round(server.getTotalMemory()));
memoryUsageBar.setSelection((int) Math.round(server.getMemoryInUse()));
- memoryUsageBar.setToolTipText("Total: " + server.getTotalMemory() + "GB, In Use: "
- + server.getMemoryInUse() + "GB");
+ memoryUsageBar.setToolTipText("Total: " + NumberUtil.formatNumber(server.getTotalMemory()) + "GB, In Use: "
+ + NumberUtil.formatNumber(server.getMemoryInUse()) + "GB");
// toolkit.createLabel(section, "Memory Usage: ", SWT.NONE);
// final CoolProgressBar bar = new CoolProgressBar(section,SWT.HORIZONTAL,
diff --git a/src/com.gluster.storage.management.gui/src/com/gluster/storage/management/gui/views/GlusterServersSummaryView.java b/src/com.gluster.storage.management.gui/src/com/gluster/storage/management/gui/views/GlusterServersSummaryView.java
index 428e55d5..bb9114b3 100644
--- a/src/com.gluster.storage.management.gui/src/com/gluster/storage/management/gui/views/GlusterServersSummaryView.java
+++ b/src/com.gluster.storage.management.gui/src/com/gluster/storage/management/gui/views/GlusterServersSummaryView.java
@@ -94,9 +94,9 @@ public class GlusterServersSummaryView extends ViewPart {
String[] categories = new String[] { "Online", "Offline" };
PieChartViewerComposite chartViewerComposite = new PieChartViewerComposite(section, SWT.NONE, categories, values);
- GridData data = new GridData(SWT.FILL, SWT.FILL, true, true);
- data.widthHint = 250;
- data.heightHint = 250;
+ GridData data = new GridData(SWT.FILL, SWT.FILL, false, false);
+ data.widthHint = 300;
+ data.heightHint = 150;
chartViewerComposite.setLayoutData(data);
}
diff --git a/src/com.gluster.storage.management.gui/src/com/gluster/storage/management/gui/views/VolumesSummaryView.java b/src/com.gluster.storage.management.gui/src/com/gluster/storage/management/gui/views/VolumesSummaryView.java
index b929a2b2..2b9d7178 100644
--- a/src/com.gluster.storage.management.gui/src/com/gluster/storage/management/gui/views/VolumesSummaryView.java
+++ b/src/com.gluster.storage.management.gui/src/com/gluster/storage/management/gui/views/VolumesSummaryView.java
@@ -157,9 +157,9 @@ public class VolumesSummaryView extends ViewPart {
PieChartViewerComposite chartViewerComposite = new PieChartViewerComposite(section, SWT.NONE, categories,
values);
- GridData data = new GridData(SWT.FILL, SWT.FILL, true, true);
- data.widthHint = 250;
- data.heightHint = 250;
+ GridData data = new GridData(SWT.FILL, SWT.FILL, false, false);
+ data.widthHint = 300;
+ data.heightHint = 150;
chartViewerComposite.setLayoutData(data);
}
diff --git a/src/com.gluster.storage.management.gui/src/com/gluster/storage/management/gui/views/details/tabcreators/PieChartViewerComposite.java b/src/com.gluster.storage.management.gui/src/com/gluster/storage/management/gui/views/details/tabcreators/PieChartViewerComposite.java
index 80c9c807..4e3d808a 100644
--- a/src/com.gluster.storage.management.gui/src/com/gluster/storage/management/gui/views/details/tabcreators/PieChartViewerComposite.java
+++ b/src/com.gluster.storage.management.gui/src/com/gluster/storage/management/gui/views/details/tabcreators/PieChartViewerComposite.java
@@ -57,6 +57,8 @@ import org.eclipse.swt.graphics.Image;
import org.eclipse.swt.graphics.Rectangle;
import org.eclipse.swt.widgets.Composite;
+import com.gluster.storage.management.gui.utils.GlusterChartPalette;
+
/**
*
*/
@@ -122,17 +124,19 @@ public final class PieChartViewerComposite extends Composite implements
ChartWithoutAxes pieChart = ChartWithoutAxesImpl.create();
// Plot
- pieChart.setSeriesThickness(2);
+ pieChart.setSeriesThickness(10);
pieChart.setDimension(ChartDimension.TWO_DIMENSIONAL_WITH_DEPTH_LITERAL);
pieChart.getBlock().setBackground(ColorDefinitionImpl.WHITE());
Plot p = pieChart.getPlot();
+
p.getClientArea().setBackground(null);
p.getClientArea().getOutline().setVisible(false);
p.getOutline().setVisible(false);
// Legend
Legend lg = pieChart.getLegend();
- lg.getText().getFont().setSize(8);
+ lg.setMaxPercent(0.7);
+ lg.getText().getFont().setSize(9);
lg.setBackground(null);
lg.getOutline().setVisible(false);
lg.setVisible(true);
@@ -151,15 +155,18 @@ public final class PieChartViewerComposite extends Composite implements
SeriesDefinition sd = SeriesDefinitionImpl.create();
pieChart.getSeriesDefinitions().add(sd);
+ sd.setSeriesPalette(new GlusterChartPalette());
sd.getSeriesPalette().shift(0);
sd.getSeries().add(seCategory);
// Orthogonal Series
PieSeries sePie = (PieSeries) PieSeriesImpl.create();
+ sePie.setRatio(0.60);
sePie.setDataSet(seriesOneValues);
- sePie.setSeriesIdentifier("Cities");//$NON-NLS-1$
- sePie.getTitle().setVisible(false);
- sePie.setExplosion(2);
+ sePie.setSeriesIdentifier("Chart");//$NON-NLS-1$
+ sePie.getTitle().setVisible(false); // no title
+ sePie.getLabel().setVisible(false); // no label (values)
+ sePie.setExplosion(0); // no gap between the pie slices
SeriesDefinition seriesDefinition = SeriesDefinitionImpl.create();
seriesDefinition.getQuery().setDefinition("query.definition");//$NON-NLS-1$
diff --git a/src/com.gluster.storage.management.server.scripts/src/nodes/PeerAgent.py b/src/com.gluster.storage.management.server.scripts/src/nodes/PeerAgent.py
index 909d24a3..6218e921 100755
--- a/src/com.gluster.storage.management.server.scripts/src/nodes/PeerAgent.py
+++ b/src/com.gluster.storage.management.server.scripts/src/nodes/PeerAgent.py
@@ -74,11 +74,10 @@ def executeCommand(command):
rv = Utils.runCommandFG(command, stdout=True, root=True)
statusCode = rv["Status"]
if statusCode != 0:
+ output = "output: [" + stripEmptyLines(rv["Stdout"]) + "] error: [" + stripEmptyLines(rv["Stderr"]) + "]";
rs = ResponseXml()
- rs.appendTagRoute("status", statusCode);
- rs.appendTagRoute("output", stripEmptyLines(rv["Stdout"]))
- rs.appendTagRoute("message", stripEmptyLines(rv["Stderr"]))
- print rs.toprettyxml()
+ rs.appendTagRoute("status.code", statusCode);
+ rs.appendTagRoute("status.message", output);
return rs.toprettyxml()
else:
return rv["Stdout"]
@@ -182,12 +181,27 @@ def main():
try:
requestString = Socket.readPacket(clientInputStream)
Utils.log('__DEBUG__ Received %s' % repr(requestString))
- responseString = executeCommand(requestString)
- if responseString:
- Socket.writePacket(clientOutputStream, responseString)
+ requestParts = requestString.split(None, 3)
+
+ if "get_file" == requestParts[0]:
+ if len(requestParts) != 2:
+ rs = ResponseXml()
+ rs.appendTagRoute("status.code", "-1")
+ rs.appendTagRoute("status.message", "File path not passed")
+ Socket.writePacket(clientOutputStream, rs.toprettyxml())
+ else:
+ filePath = requestParts[1]
+ fp = open(filePath)
+ clientSocket.sendall(fp.read())
+ fp.close()
clientOutputStream.flush()
else:
- Utils.log('__DEBUG__ empty response string')
+ responseString = executeCommand(requestString)
+ if responseString:
+ Socket.writePacket(clientOutputStream, responseString)
+ clientOutputStream.flush()
+ else:
+ Utils.log('__DEBUG__ empty response string')
Utils.log('__DEBUG__ Closing client %s' % str(clientAddress))
clientSocket.close()
except socket.error, e:
diff --git a/src/com.gluster.storage.management.server.scripts/src/nodes/get_file.py b/src/com.gluster.storage.management.server.scripts/src/nodes/get_file.py
new file mode 100755
index 00000000..826ade6e
--- /dev/null
+++ b/src/com.gluster.storage.management.server.scripts/src/nodes/get_file.py
@@ -0,0 +1,132 @@
+# Copyright (C) 2009,2010 Gluster, Inc.
+# This file is part of Gluster Storage Platform.
+#
+# Gluster Storage Platform 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; either version 3 of
+# the License, or (at your option) any later version.
+#
+# Gluster Storage Platform 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
+# .
+
+import Globals
+import syslog
+import Commands
+import Utils
+from VolumeUtils import *
+from XmlHandler import ResponseXml
+
+
+def enumLogType(logCode):
+ if "M" == logCode.upper():
+ return "EMERGENCY"
+ elif "A" == logCode.upper():
+ return "ALERT"
+ elif "C" == logCode.upper():
+ return "CRITICAL"
+ elif "E" == logCode.upper():
+ return "ERROR"
+ elif "W" == logCode.upper():
+ return "WARNING"
+ elif "N" == logCode.upper():
+ return "NOTICE"
+ elif "I" == logCode.upper():
+ return "INFO"
+ elif "D" == logCode.upper():
+ return "DEBUG"
+ elif "T" == logCode.upper():
+ return "TRACE"
+ else:
+ return "UNKNOWN"
+##--end of enumLogType()
+
+
+def addLog(responseDom, logMessageTag, loginfo):
+ logTag = responseDom.createTag("log", None)
+ logTag.appendChild(responseDom.createTag("date", loginfo[0]))
+ logTag.appendChild(responseDom.createTag("time", loginfo[1]))
+ logTag.appendChild(responseDom.createTag("type", enumLogType(loginfo[2])))
+ logTag.appendChild(responseDom.createTag("message", loginfo[3]))
+ logMessageTag.appendChild(logTag)
+ return True
+##--end of addLog()
+
+
+def logSplit(log):
+ loginfo = log.strip().split(None, 3)
+ loginfo[0] = loginfo[0][1:] #-- Remove '['
+ loginfo[1] = loginfo[1][0:-1] #-- Remove ']'
+ return loginfo
+##--end of logSplit()
+
+
+def getVolumeLog(volumeName, tailCount):
+ rs = ResponseXml()
+ if not volumeName:
+ rs.appendTagRoute("status.code", "-1")
+ rs.appendTagRoute("status.message", "No volume name given")
+ return rs.toprettyxml()
+
+ if not tailCount:
+ rs.appendTagRoute("status.code", "-1")
+ rs.appendTagRoute("status.message", "No tail count given")
+ return rs.toprettyxml()
+
+ thisServerName = getCurrentServerName()
+ if not thisServerName:
+ rs.appendTagRoute("status.code", "-2")
+ rs.appendTagRoute("status.message", "Failed to get current server name")
+ return rs.toprettyxml()
+
+ volumeDom = XDOM()
+ partitionList = getPartitionListByServerName(volumeDom, thisServerName)
+ if not partitionList:
+ rs.appendTagRoute("status.code", "-3")
+ rs.appendTagRoute("status.message", "Failed to get server partition details")
+ return rs.toprettyxml()
+
+ pattern = '\[\d{4}-\d{2}-\d{2}\s{1}\d{2}:\d{2}:\d{2}.\d+\]\s{1}([MACEWNIDT]){1}\s+'
+ logMessagesTag = rs.createTag("response.logMessages")
+ for partitionName in partitionList:
+ logMessageTag = rs.createTag("logMessage")
+ logMessageTag.appendChild("disk", "%s:%s" % (thisServerName, partitionName))
+
+ logDirectory = "%s/%s/%s/log" % (Globals.GLUSTER_LUN_DIR, partitionList[partitionName], volumeUuid)
+ logFileName = "%s/%s-%s-%s-exports-brick1.log" % (logDirectory,
+ Globals.GLUSTER_LUN_DIR[1:],
+ partitionList[partitionName],
+ volumeUuid)
+ if not os.path.exists(logFileName):
+ Utils.log("volume log file not found %s" % logFileName)
+ continue
+ fp = open(logFileName)
+ lines = [line for line in fp if re.match(pattern, line)]
+ fp.close()
+ i = len(lines) - int(tailCount)
+ if i < 0:
+ i = 0
+ for log in lines[i:]:
+ loginfo = logSplit(log)
+ addLog(rs, logMessageTag, loginfo)
+ logMessagesTag.appendChild(logMessageTag)
+ return rs.toprettyxml()
+##--end of getVolumeLog()
+
+def main():
+ if len(sys.argv) != 3:
+ print >> sys.stderr, "usage: %s " % sys.argv[0]
+ sys.exit(-1)
+
+ volumeName = sys.argv[1]
+ tailCount = sys.argv[2]
+ print getVolumeLog(volumeName, tailCount)
+ sys.exit(0)
+
+if __name__ == "__main__":
+ main()
diff --git a/src/com.gluster.storage.management.server/build/glusterserver.ant b/src/com.gluster.storage.management.server/build/glusterserver.ant
index 88602fb6..98012515 100644
--- a/src/com.gluster.storage.management.server/build/glusterserver.ant
+++ b/src/com.gluster.storage.management.server/build/glusterserver.ant
@@ -39,7 +39,8 @@
-
+
+
diff --git a/src/com.gluster.storage.management.server/src/com/gluster/storage/management/server/resources/VolumesResource.java b/src/com.gluster.storage.management.server/src/com/gluster/storage/management/server/resources/VolumesResource.java
index fd4643a6..e635510a 100644
--- a/src/com.gluster.storage.management.server/src/com/gluster/storage/management/server/resources/VolumesResource.java
+++ b/src/com.gluster.storage.management.server/src/com/gluster/storage/management/server/resources/VolumesResource.java
@@ -31,6 +31,7 @@ import static com.gluster.storage.management.core.constants.RESTConstants.PATH_P
import static com.gluster.storage.management.core.constants.RESTConstants.QUERY_PARAM_DELETE_OPTION;
import static com.gluster.storage.management.core.constants.RESTConstants.QUERY_PARAM_DISKS;
import static com.gluster.storage.management.core.constants.RESTConstants.QUERY_PARAM_DISK_NAME;
+import static com.gluster.storage.management.core.constants.RESTConstants.QUERY_PARAM_DOWNLOAD;
import static com.gluster.storage.management.core.constants.RESTConstants.QUERY_PARAM_FROM_TIMESTAMP;
import static com.gluster.storage.management.core.constants.RESTConstants.QUERY_PARAM_LINE_COUNT;
import static com.gluster.storage.management.core.constants.RESTConstants.QUERY_PARAM_LOG_SEVERITY;
@@ -39,15 +40,22 @@ import static com.gluster.storage.management.core.constants.RESTConstants.QUERY_
import static com.gluster.storage.management.core.constants.RESTConstants.RESOURCE_PATH_VOLUMES;
import static com.gluster.storage.management.core.constants.RESTConstants.SUBRESOURCE_DEFAULT_OPTIONS;
import static com.gluster.storage.management.core.constants.RESTConstants.SUBRESOURCE_DISKS;
+import static com.gluster.storage.management.core.constants.RESTConstants.SUBRESOURCE_DOWNLOAD;
import static com.gluster.storage.management.core.constants.RESTConstants.SUBRESOURCE_LOGS;
import static com.gluster.storage.management.core.constants.RESTConstants.SUBRESOURCE_OPTIONS;
+import java.io.File;
+import java.io.FileInputStream;
+import java.io.FileOutputStream;
+import java.io.IOException;
+import java.io.OutputStream;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
import java.util.Comparator;
import java.util.Date;
import java.util.List;
+import java.util.zip.GZIPOutputStream;
import javax.ws.rs.Consumes;
import javax.ws.rs.DELETE;
@@ -59,7 +67,10 @@ import javax.ws.rs.Path;
import javax.ws.rs.PathParam;
import javax.ws.rs.Produces;
import javax.ws.rs.QueryParam;
+import javax.ws.rs.WebApplicationException;
import javax.ws.rs.core.MediaType;
+import javax.ws.rs.core.Response;
+import javax.ws.rs.core.StreamingOutput;
import com.gluster.storage.management.core.constants.CoreConstants;
import com.gluster.storage.management.core.constants.RESTConstants;
@@ -73,6 +84,8 @@ import com.gluster.storage.management.core.response.LogMessageListResponse;
import com.gluster.storage.management.core.response.VolumeListResponse;
import com.gluster.storage.management.core.response.VolumeOptionInfoListResponse;
import com.gluster.storage.management.core.utils.DateUtil;
+import com.gluster.storage.management.core.utils.FileUtil;
+import com.gluster.storage.management.core.utils.ProcessUtil;
import com.gluster.storage.management.server.constants.VolumeOptionsDefaults;
import com.gluster.storage.management.server.utils.GlusterUtil;
import com.gluster.storage.management.server.utils.ServerUtil;
@@ -219,8 +232,14 @@ public class VolumesResource {
@SuppressWarnings("rawtypes")
private Status prepareBrick(String serverName, String diskName, String volumeName) {
- return (Status) ((GenericResponse) serverUtil.executeOnServer(true, serverName, PREPARE_BRICK_SCRIPT + " "
- + diskName + " " + volumeName, GenericResponse.class)).getStatus();
+ Object response = serverUtil.executeOnServer(true, serverName, PREPARE_BRICK_SCRIPT + " "
+ + diskName + " " + volumeName, GenericResponse.class);
+ if(response instanceof GenericResponse) {
+ return ((GenericResponse)response).getStatus();
+ } else {
+ // in case of script failure on server, a Status object will be returned
+ return (Status) response;
+ }
}
private Status createDirectories(List disks, String volumeName) {
@@ -232,11 +251,8 @@ public class VolumesResource {
String[] diskParts = disk.split(":");
String serverName = diskParts[0];
String diskName = diskParts[1];
- try {
- status = prepareBrick(serverName, diskName, volumeName);
- } catch (Exception e) {
- status = new Status(e);
- }
+
+ status = prepareBrick(serverName, diskName, volumeName);
if (status.isSuccess()) {
String brickDir = status.getMessage().trim();
bricks.add(serverName + ":" + brickDir);
@@ -271,15 +287,24 @@ public class VolumesResource {
diskInfo = disks.get(i).split(":");
serverName = diskInfo[0];
diskName = diskInfo[1];
- result = ((GenericResponse) serverUtil.executeOnServer(true, serverName, VOLUME_DIRECTORY_CLEANUP_SCRIPT
- + " " + diskName + " " + volumeName + " " + deleteFlag, GenericResponse.class)).getStatus();
- if (!result.isSuccess()) {
- return result;
+
+ Object response = serverUtil.executeOnServer(true, serverName, VOLUME_DIRECTORY_CLEANUP_SCRIPT
+ + " " + diskName + " " + volumeName + " " + deleteFlag, GenericResponse.class);
+ if(response instanceof GenericResponse) {
+ result = ((GenericResponse)response).getStatus();
+ if (!result.isSuccess()) {
+ // TODO: append error and continue with cleaning up of other directories
+ return result;
+ }
+ } else {
+ // TODO: append error and continue with cleaning up of other directories
+ // In case of script execution failure, a Status object will be returned.
+ return (Status)response;
}
}
return new Status(Status.STATUS_CODE_SUCCESS, "Directories cleaned up successfully!");
}
-
+
private List getBrickLogs(Volume volume, String brickName, Integer lineCount)
throws GlusterRuntimeException {
// brick name format is :
@@ -316,6 +341,61 @@ public class VolumesResource {
}
return logMessages;
}
+
+ @GET
+ @Produces(MediaType.APPLICATION_OCTET_STREAM)
+ @Path("{" + PATH_PARAM_VOLUME_NAME + "}/" + SUBRESOURCE_LOGS + "/" + SUBRESOURCE_DOWNLOAD)
+ public StreamingOutput getLogs(@PathParam(PATH_PARAM_VOLUME_NAME) final String volumeName) {
+ return new StreamingOutput() {
+
+ @Override
+ public void write(OutputStream output) throws IOException, WebApplicationException {
+ Volume volume = getVolume(volumeName);
+ try {
+ String archiveFileName = downloadLogs(volume);
+ FileInputStream inputStream = new FileInputStream(archiveFileName);
+ int size = inputStream.available();
+ byte[] data = new byte[size];
+ inputStream.read(data);
+ inputStream.close();
+ output.write(data);
+ } catch (Exception e) {
+ e.printStackTrace();
+ throw new GlusterRuntimeException("Exception while downloading/archiving volume log files!", e);
+ }
+ }
+ };
+ }
+
+ private String downloadLogs(Volume volume) {
+ FileUtil fileUtil = new FileUtil();
+
+ // create temporary directory
+ File tempDir = fileUtil.createTempDir();
+ String tempDirPath = tempDir.getPath();
+
+ for(String brickName : volume.getBricks()) {
+ // brick name format is :
+ String[] brickParts = brickName.split(":");
+ String serverName = brickParts[0];
+ String brickDir = brickParts[1];
+
+ String logDir = glusterUtil.getLogLocation(volume.getName(), brickName);
+ String logFileName = glusterUtil.getLogFileNameForBrickDir(brickDir);
+ String logFilePath = logDir + CoreConstants.FILE_SEPARATOR + logFileName;
+
+ String logContents = serverUtil.getFileFromServer(serverName, logFilePath);
+ fileUtil.createTextFile(tempDirPath + CoreConstants.FILE_SEPARATOR + logFileName, logContents);
+ }
+
+ String gzipPath = fileUtil.getTempDirName() + CoreConstants.FILE_SEPARATOR + volume.getName() + "-logs.tar.gz";
+ new ProcessUtil().executeCommand("tar", "czvf", gzipPath, tempDirPath);
+
+ // delete the temp directory
+ fileUtil.recursiveDelete(tempDir);
+
+ return gzipPath;
+ }
@GET
@Path("{" + PATH_PARAM_VOLUME_NAME + "}/" + SUBRESOURCE_LOGS)
@@ -323,7 +403,8 @@ public class VolumesResource {
@QueryParam(QUERY_PARAM_DISK_NAME) String diskName, @QueryParam(QUERY_PARAM_LOG_SEVERITY) String severity,
@QueryParam(QUERY_PARAM_FROM_TIMESTAMP) String fromTimestamp,
@QueryParam(QUERY_PARAM_TO_TIMESTAMP) String toTimestamp,
- @QueryParam(QUERY_PARAM_LINE_COUNT) Integer lineCount) {
+ @QueryParam(QUERY_PARAM_LINE_COUNT) Integer lineCount,
+ @QueryParam(QUERY_PARAM_DOWNLOAD) Boolean download) {
List logMessages = null;
try {
diff --git a/src/com.gluster.storage.management.server/src/com/gluster/storage/management/server/utils/ServerUtil.java b/src/com.gluster.storage.management.server/src/com/gluster/storage/management/server/utils/ServerUtil.java
index 5e423f1c..627882b7 100644
--- a/src/com.gluster.storage.management.server/src/com/gluster/storage/management/server/utils/ServerUtil.java
+++ b/src/com.gluster.storage.management.server/src/com/gluster/storage/management/server/utils/ServerUtil.java
@@ -22,6 +22,7 @@ package com.gluster.storage.management.server.utils;
import java.io.BufferedReader;
import java.io.ByteArrayInputStream;
+import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.PrintWriter;
import java.net.InetAddress;
@@ -38,7 +39,9 @@ import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import com.gluster.storage.management.core.constants.CoreConstants;
+import com.gluster.storage.management.core.exceptions.GlusterRuntimeException;
import com.gluster.storage.management.core.model.Status;
+import com.gluster.storage.management.core.response.GenericResponse;
import com.gluster.storage.management.core.utils.ProcessResult;
import com.gluster.storage.management.core.utils.ProcessUtil;
@@ -71,34 +74,70 @@ public class ServerUtil {
* @param runInForeground
* @param serverName
* @param commandWithArgs
- * @param expectedClass Class of the object expected from script execution
- * @return Response from remote execution of the command
+ * @param expectedClass
+ * Class of the object expected from script execution
+ * @return Object of the expected class from remote execution of the command. In case the remote execution fails
+ * ungracefully, an object of class {@link Status} will be returned.
*/
@SuppressWarnings("rawtypes")
- public Object executeOnServer(boolean runInForeground, String serverName, String commandWithArgs, Class expectedClass) {
- StringBuffer output = new StringBuffer();
+ public Object executeOnServer(boolean runInForeground, String serverName, String commandWithArgs,
+ Class expectedClass) {
+ try {
+ String output = executeOnServer(serverName, commandWithArgs);
+
+ // In case the script execution exits ungracefully, the agent would return a GenericResponse.
+ // hence pass last argument as true to try GenericResponse unmarshalling in such cases.
+ Object response = unmarshal(expectedClass, output, expectedClass != GenericResponse.class);
+ if (expectedClass != GenericResponse.class && response instanceof GenericResponse) {
+ // expected class was not GenericResponse, but that's what we got. This means the
+ // script failed ungracefully. Extract and return the status object from the response
+ return ((GenericResponse) response).getStatus();
+ }
+ return response;
+ } catch (Exception e) {
+ // any other exception means unexpected error. return status with error from exception.
+ return new Status(e);
+ }
+ }
+
+ private String executeOnServer(String serverName, String commandWithArgs) {
try {
InetAddress address = InetAddress.getByName(serverName);
Socket connection = new Socket(address, 50000);
PrintWriter writer = new PrintWriter(connection.getOutputStream(), true);
- BufferedReader reader = new BufferedReader(new InputStreamReader(connection.getInputStream(), "UTF-8"));
-
writer.println(commandWithArgs);
writer.println(); // empty line means end of request
- String line;
- while (!(line = reader.readLine()).trim().isEmpty()) {
- output.append(line + CoreConstants.NEWLINE);
+ InputStream inputStream = connection.getInputStream();
+ int available = inputStream.available();
+
+ StringBuffer output = new StringBuffer();
+ if( available > 0 ) {
+ // This happens when PeerAgent sends complete file
+ byte[] responseData = new byte[available];
+ inputStream.read(responseData);
+ output.append(new String(responseData, "UTF-8"));
+ } else {
+ // This happens in case of normal XML response from PeerAgent
+ BufferedReader reader = new BufferedReader(new InputStreamReader(inputStream, "UTF-8"));
+
+ String line;
+ while (!(line = reader.readLine()).trim().isEmpty()) {
+ output.append(line + CoreConstants.NEWLINE);
+ }
}
-
connection.close();
- return unmarshal(expectedClass, output.toString(), expectedClass != Status.class);
- } catch(Exception e) {
- // any other exception means unexpected error. return status with error from exception.
- return new Status(Status.STATUS_CODE_FAILURE, "Error during remote execution: [" + e.getMessage() + "]");
+
+ return output.toString();
+ } catch (Exception e) {
+ throw new GlusterRuntimeException("Error during remote execution: [" + e.getMessage() + "]");
}
}
+
+ public String getFileFromServer(String serverName, String fileName) {
+ return executeOnServer(serverName, "get_file " + fileName);
+ }
/**
* Unmarshals given input string into object of given class
@@ -107,22 +146,23 @@ public class ServerUtil {
* Class whose object is expected
* @param input
* Input string
- * @param tryStatusOnFailure
+ * @param tryGenericResponseOnFailure
* If true, and if the unmarshalling fails for given class, another unmarshalling will be attempted with
- * class Status. If that also fails, a status object with exception message is created and returned.
+ * class {@link GenericResponse}. If this also fails, a status object with exception message is created
+ * and returned.
* @return Object of given expected class, or a status object in case first unmarshalling fails.
*/
@SuppressWarnings("rawtypes")
- private Object unmarshal(Class expectedClass, String input, boolean tryStatusOnFailure) {
+ private Object unmarshal(Class expectedClass, String input, boolean tryGenericResponseOnFailure) {
try {
// create JAXB context and instantiate marshaller
JAXBContext context = JAXBContext.newInstance(expectedClass);
Unmarshaller um = context.createUnmarshaller();
return um.unmarshal(new ByteArrayInputStream(input.getBytes()));
} catch (JAXBException e) {
- if(tryStatusOnFailure) {
- // unmarshalling failed. try to unmarshal a Status object
- return unmarshal(Status.class, input, false);
+ if(tryGenericResponseOnFailure) {
+ // unmarshalling failed. try to unmarshal a GenericResponse object
+ return unmarshal(GenericResponse.class, input, false);
}
return new Status(Status.STATUS_CODE_FAILURE, "Error during unmarshalling string [" + input
@@ -130,9 +170,9 @@ public class ServerUtil {
}
}
- public static void main(String args[]) {
+ public static void main(String args[]) throws Exception {
// CreateVolumeExportDirectory.py md0 testvol
- System.out.println(new ServerUtil().executeOnServer(true, "localhost", "python CreateVolumeExportDirectory.py md0 testvol", Status.class));
+ System.out.println(new ServerUtil().getFileFromServer("localhost", "/tmp/python/PeerAgent.py"));
}
/**
--
cgit