diff options
| author | Shireesh Anjal <shireesh@gluster.com> | 2011-07-12 23:16:54 +0530 |
|---|---|---|
| committer | Shireesh Anjal <shireesh@gluster.com> | 2011-07-18 00:02:42 +0530 |
| commit | 4290f5519fb7480df6c5919583efc1f7feebf4b3 (patch) | |
| tree | 5930ba1eb58235ec12b897c300f7fd7bef9694d1 | |
| parent | 194d5787da03f843a4eb81f304d6f30057bb5be2 (diff) | |
Story #38 - CPU Usage graph
17 files changed, 789 insertions, 136 deletions
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 455ecc11..d4b0e43a 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 @@ -42,6 +42,7 @@ public class RESTConstants { public static final String RESOURCE_SERVERS = "servers"; public static final String RESOURCE_TASKS = "tasks"; public static final String RESOURCE_KEYS = "keys"; + public static final String RESOURCE_STATISTICS = "statistics"; public static final String TASK_START = "start"; public static final String TASK_PAUSE = "pause"; @@ -98,6 +99,11 @@ public class RESTConstants { public static final String QUERY_PARAM_DOWNLOAD = "download"; public static final String QUERY_PARAM_SERVER_NAME = "serverName"; public static final String QUERY_PARAM_DETAILS = "details"; + public static final String QUERY_PARAM_TYPE = "type"; + + public static final String STATISTICS_TYPE_CPU = "cpu"; + public static final String STATISTICS_TYPE_NETWORK = "network"; + public static final String STATISTICS_TYPE_MEMORY = "memory"; public static final String FORMAT_XML = "xml"; public static final String FORMAT_JSON = "json"; diff --git a/src/com.gluster.storage.management.core/src/com/gluster/storage/management/core/model/ServerStats.java b/src/com.gluster.storage.management.core/src/com/gluster/storage/management/core/model/ServerStats.java new file mode 100644 index 00000000..042af256 --- /dev/null +++ b/src/com.gluster.storage.management.core/src/com/gluster/storage/management/core/model/ServerStats.java @@ -0,0 +1,73 @@ +/******************************************************************************* + * Copyright (c) 2011 Gluster, Inc. <http://www.gluster.com> + * This file is part of Gluster Management Console. + * + * Gluster Management Console is free software; you can redistribute it and/or + * modify it under the terms of the GNU Affero General Public License as published + * by the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. + * + * Gluster Management Console 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 Affero General Public License + * for more details. + * + * You should have received a copy of the GNU Affero General Public License + * along with this program. If not, see + * <http://www.gnu.org/licenses/>. + *******************************************************************************/ +package com.gluster.storage.management.core.model; + +import java.util.ArrayList; +import java.util.List; + +import javax.xml.bind.annotation.XmlElement; +import javax.xml.bind.annotation.XmlElementWrapper; +import javax.xml.bind.annotation.XmlRootElement; + +/** + * + */ +@XmlRootElement(name="xport") +public class ServerStats { + private StatsMetadata metadata; + private List<ServerStatsRow> rows; + + public ServerStats() { + } + + public ServerStats(ServerStats newStats) { + copyFrom(newStats); + } + + public void setRows(List<ServerStatsRow> rows) { + this.rows = rows; + } + + @XmlElementWrapper(name="data") + @XmlElement(name="row", type=ServerStatsRow.class) + public List<ServerStatsRow> getRows() { + return rows; + } + + public void setMetadata(StatsMetadata metadata) { + this.metadata = metadata; + } + + @XmlElement(name="meta") + public StatsMetadata getMetadata() { + return metadata; + } + + public void copyFrom(ServerStats newStats) { + setMetadata(newStats.getMetadata()); + + List<ServerStatsRow> newRows = newStats.getRows(); + int rowCount = newRows.size(); + + rows = new ArrayList<ServerStatsRow>(rowCount); + for(ServerStatsRow newRow : newRows) { + rows.add(new ServerStatsRow(newRow)); + } + } +}
\ No newline at end of file diff --git a/src/com.gluster.storage.management.core/src/com/gluster/storage/management/core/model/ServerStatsRow.java b/src/com.gluster.storage.management.core/src/com/gluster/storage/management/core/model/ServerStatsRow.java new file mode 100644 index 00000000..0088cef6 --- /dev/null +++ b/src/com.gluster.storage.management.core/src/com/gluster/storage/management/core/model/ServerStatsRow.java @@ -0,0 +1,69 @@ +/******************************************************************************* + * Copyright (c) 2011 Gluster, Inc. <http://www.gluster.com> + * This file is part of Gluster Management Console. + * + * Gluster Management Console is free software; you can redistribute it and/or + * modify it under the terms of the GNU Affero General Public License as published + * by the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. + * + * Gluster Management Console 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 Affero General Public License + * for more details. + * + * You should have received a copy of the GNU Affero General Public License + * along with this program. If not, see + * <http://www.gnu.org/licenses/>. + *******************************************************************************/ +package com.gluster.storage.management.core.model; + +import java.util.ArrayList; +import java.util.List; + +import javax.xml.bind.annotation.XmlElement; +import javax.xml.bind.annotation.XmlRootElement; + +/** + * + */ +@XmlRootElement(name="row") +public class ServerStatsRow { + private Long timestamp; + private List<Double> usageData; + + public ServerStatsRow() { + } + + public ServerStatsRow(ServerStatsRow newRow) { + copyFrom(newRow); + } + + private void copyFrom(ServerStatsRow newRow) { + setTimestamp(newRow.getTimestamp()); + + List<Double> myData = new ArrayList<Double>(newRow.getUsageData().size()); + for(Double dataElement : newRow.getUsageData()) { + myData.add(dataElement); + } + setUsageData(myData); + } + + @XmlElement(name="t") + public Long getTimestamp() { + return timestamp; + } + + public void setTimestamp(Long timestamp) { + this.timestamp = timestamp; + } + + public void setUsageData(List<Double> usageData) { + this.usageData = usageData; + } + + @XmlElement(name="v") + public List<Double> getUsageData() { + return usageData; + } +} diff --git a/src/com.gluster.storage.management.core/src/com/gluster/storage/management/core/model/StatsMetadata.java b/src/com.gluster.storage.management.core/src/com/gluster/storage/management/core/model/StatsMetadata.java new file mode 100644 index 00000000..22b42671 --- /dev/null +++ b/src/com.gluster.storage.management.core/src/com/gluster/storage/management/core/model/StatsMetadata.java @@ -0,0 +1,84 @@ +/******************************************************************************* + * Copyright (c) 2011 Gluster, Inc. <http://www.gluster.com> + * This file is part of Gluster Management Console. + * + * Gluster Management Console is free software; you can redistribute it and/or + * modify it under the terms of the GNU Affero General Public License as published + * by the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. + * + * Gluster Management Console 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 Affero General Public License + * for more details. + * + * You should have received a copy of the GNU Affero General Public License + * along with this program. If not, see + * <http://www.gnu.org/licenses/>. + *******************************************************************************/ +package com.gluster.storage.management.core.model; + +import java.util.ArrayList; +import java.util.List; + +import javax.xml.bind.annotation.XmlElement; +import javax.xml.bind.annotation.XmlElementWrapper; +import javax.xml.bind.annotation.XmlRootElement; + +/** + * + */ +@XmlRootElement(name="meta") +public class StatsMetadata { + private Long startTimestamp; + private Long endTimestamp; + private Integer step; + private Integer rowCount; + private List<String> legend = new ArrayList<String>(); + + @XmlElement(name="start") + public Long getStartTimestamp() { + return startTimestamp; + } + + public void setStartTimestamp(Long startTimestamp) { + this.startTimestamp = startTimestamp; + } + + @XmlElement(name="end") + public Long getEndTimestamp() { + return endTimestamp; + } + + public void setEndTimestamp(Long endTimestamp) { + this.endTimestamp = endTimestamp; + } + + @XmlElement(name="step") + public Integer getStep() { + return step; + } + + public void setStep(Integer step) { + this.step = step; + } + + @XmlElement(name="rows") + public Integer getRowCount() { + return rowCount; + } + + public void setRowCount(Integer rowCount) { + this.rowCount = rowCount; + } + + @XmlElementWrapper(name="legend") + @XmlElement(name="entry", type=String.class) + public List<String> getLegend() { + return legend; + } + + public void setLegend(List<String> legend) { + this.legend = legend; + } +} diff --git a/src/com.gluster.storage.management.gui.feature.webstart/rootfiles/gluster-management-console.jnlp b/src/com.gluster.storage.management.gui.feature.webstart/rootfiles/gluster-management-console.jnlp index c99eece8..597adf4c 100644 --- a/src/com.gluster.storage.management.gui.feature.webstart/rootfiles/gluster-management-console.jnlp +++ b/src/com.gluster.storage.management.gui.feature.webstart/rootfiles/gluster-management-console.jnlp @@ -6,6 +6,11 @@ <homepage href="$$codebase" /> <description>Gluster Management Console</description> <icon kind="splash" href="splash.jpg"/> + + <shortcut online="true"> + <desktop/> + <menu submenu="Gluster"/> + </shortcut> </information> <security> <all-permissions/> diff --git a/src/com.gluster.storage.management.gui.feature/feature.xml b/src/com.gluster.storage.management.gui.feature/feature.xml index 0f0c9e8b..7f526f72 100644 --- a/src/com.gluster.storage.management.gui.feature/feature.xml +++ b/src/com.gluster.storage.management.gui.feature/feature.xml @@ -538,7 +538,7 @@ id="org.eclipse.core.net.win32.x86_64" os="win32" ws="win32" - arch="x86_64" + arch="x86_64, amd64" download-size="0" install-size="0" version="0.0.0" @@ -609,7 +609,7 @@ <plugin id="org.eclipse.equinox.launcher.win32.win32.x86" - os="win32" + os="Windows XP, Windows 7" ws="win32" arch="x86" download-size="0" diff --git a/src/com.gluster.storage.management.gui/src/com/gluster/storage/management/gui/utils/PieChartViewerComposite.java b/src/com.gluster.storage.management.gui/src/com/gluster/storage/management/gui/utils/ChartViewerComposite.java index ad8e2fa3..edf18011 100644 --- a/src/com.gluster.storage.management.gui/src/com/gluster/storage/management/gui/utils/PieChartViewerComposite.java +++ b/src/com.gluster.storage.management.gui/src/com/gluster/storage/management/gui/utils/ChartViewerComposite.java @@ -18,6 +18,7 @@ *******************************************************************************/ package com.gluster.storage.management.gui.utils; +import java.util.Date; import java.util.logging.Level; import java.util.logging.Logger; @@ -28,23 +29,43 @@ import org.eclipse.birt.chart.exception.ChartException; import org.eclipse.birt.chart.factory.GeneratedChartState; import org.eclipse.birt.chart.factory.Generator; import org.eclipse.birt.chart.model.Chart; +import org.eclipse.birt.chart.model.ChartWithAxes; import org.eclipse.birt.chart.model.ChartWithoutAxes; +import org.eclipse.birt.chart.model.attribute.Anchor; +import org.eclipse.birt.chart.model.attribute.AxisType; import org.eclipse.birt.chart.model.attribute.Bounds; import org.eclipse.birt.chart.model.attribute.ChartDimension; +import org.eclipse.birt.chart.model.attribute.FontDefinition; +import org.eclipse.birt.chart.model.attribute.LineAttributes; +import org.eclipse.birt.chart.model.attribute.LineStyle; +import org.eclipse.birt.chart.model.attribute.Marker; +import org.eclipse.birt.chart.model.attribute.TickStyle; import org.eclipse.birt.chart.model.attribute.impl.BoundsImpl; import org.eclipse.birt.chart.model.attribute.impl.ColorDefinitionImpl; +import org.eclipse.birt.chart.model.attribute.impl.FontDefinitionImpl; +import org.eclipse.birt.chart.model.attribute.impl.JavaDateFormatSpecifierImpl; +import org.eclipse.birt.chart.model.attribute.impl.LineAttributesImpl; +import org.eclipse.birt.chart.model.attribute.impl.TextAlignmentImpl; +import org.eclipse.birt.chart.model.component.Axis; import org.eclipse.birt.chart.model.component.Series; import org.eclipse.birt.chart.model.component.impl.SeriesImpl; +import org.eclipse.birt.chart.model.data.DateTimeDataSet; import org.eclipse.birt.chart.model.data.NumberDataSet; import org.eclipse.birt.chart.model.data.SeriesDefinition; import org.eclipse.birt.chart.model.data.TextDataSet; +import org.eclipse.birt.chart.model.data.impl.DateTimeDataSetImpl; import org.eclipse.birt.chart.model.data.impl.NumberDataSetImpl; import org.eclipse.birt.chart.model.data.impl.SeriesDefinitionImpl; import org.eclipse.birt.chart.model.data.impl.TextDataSetImpl; +import org.eclipse.birt.chart.model.impl.ChartWithAxesImpl; import org.eclipse.birt.chart.model.impl.ChartWithoutAxesImpl; import org.eclipse.birt.chart.model.layout.Legend; import org.eclipse.birt.chart.model.layout.Plot; +import org.eclipse.birt.chart.model.type.AreaSeries; +import org.eclipse.birt.chart.model.type.LineSeries; import org.eclipse.birt.chart.model.type.PieSeries; +import org.eclipse.birt.chart.model.type.impl.AreaSeriesImpl; +import org.eclipse.birt.chart.model.type.impl.LineSeriesImpl; import org.eclipse.birt.chart.model.type.impl.PieSeriesImpl; import org.eclipse.birt.core.framework.PlatformConfig; import org.eclipse.core.runtime.Platform; @@ -57,20 +78,42 @@ import org.eclipse.swt.graphics.Image; import org.eclipse.swt.graphics.Rectangle; import org.eclipse.swt.widgets.Composite; +import com.ibm.icu.util.Calendar; /** * */ -public final class PieChartViewerComposite extends Composite implements - PaintListener, IUpdateNotifier { +public final class ChartViewerComposite extends Composite implements PaintListener, IUpdateNotifier { + + public enum CHART_TYPE { + PIE, LINE + }; private IDeviceRenderer deviceReader = null; private Chart chart = null; private GeneratedChartState generatedChartState = null; private boolean needsGeneration = true; - private static Logger logger = Logger - .getLogger(PieChartViewerComposite.class.getName()); + private static Logger logger = Logger.getLogger(ChartViewerComposite.class.getName()); + + /** + * @param parent + * Parent composite of this pie chart viewer composite + * @param style + * SWT style to be used + * @param categories + * Categories of the pie chart + * @param values + * Values of each category in the pie chart Constructs a pie + * chart viewer composite for given categories and values + */ + public ChartViewerComposite(Composite parent, int style, String[] categories, Double[] values) { + super(parent, style); + init(); + + chart = createPieChart(categories, values); + addPaintListener(this); + } /** * @param parent @@ -83,17 +126,22 @@ public final class PieChartViewerComposite extends Composite implements * Values of each category in the pie chart Constructs a pie * chart viewer composite for given categories and values */ - public PieChartViewerComposite(Composite parent, int style, String[] categories, - Double[] values) { + public ChartViewerComposite(Composite parent, int style, Calendar[] categories, Double[] values) { super(parent, style); + init(); + + chart = createLineChart(categories, values); + addPaintListener(this); + } + + public void init() { try { PlatformConfig config = new PlatformConfig(); config.setBIRTHome(Platform.getInstallLocation().getURL().getPath()); // Get the connection with SWT device to render the graphics. deviceReader = ChartEngine.instance(config).getRenderer("dv.SWT");//$NON-NLS-1$ } catch (ChartException ex) { - logger.log(Level.SEVERE, "Could not create Chart Renderer for SWT", - ex); + logger.log(Level.SEVERE, "Could not create Chart Renderer for SWT", ex); } addControlListener(new ControlListener() { @@ -106,9 +154,97 @@ public final class PieChartViewerComposite extends Composite implements needsGeneration = true; } }); + } - chart = createPieChart(categories, values); - addPaintListener(this); + private Chart createLineChart(Calendar[] timestamps, Double[] values) { + return createAreaChart(timestamps, new Double[][] {values}); + } + + /** + * Creates a line chart model as a reference implementation + * + * @return An instance of the simulated runtime chart model (containing + * filled datasets) + */ + public static final Chart createAreaChart(Calendar[] timestamps, Double[][] values) { + ChartWithAxes cwaLine = ChartWithAxesImpl.create(); + + // Plot + cwaLine.getBlock().setBackground(ColorDefinitionImpl.TRANSPARENT()); + Plot p = cwaLine.getPlot(); + p.getClientArea().setBackground(ColorDefinitionImpl.TRANSPARENT()); + //p.getClientArea().setBackground(ColorDefinitionImpl.TRANSPARENT()); + + + // Title + //cwaLine.getTitle().getLabel().getCaption().setValue("Line Chart");//$NON-NLS-1$ + cwaLine.getTitle().setVisible(false); + + // Legend + cwaLine.getLegend().setVisible(false); + Legend lg = cwaLine.getLegend(); + LineAttributes lia = lg.getOutline( ); + lg.getText( ).getFont( ).setSize( 16 ); + lia.setStyle( LineStyle.SOLID_LITERAL ); + lg.getInsets( ).set( 10, 5, 0, 0 ); + lg.getOutline( ).setVisible( false ); + lg.setAnchor( Anchor.NORTH_LITERAL ); + + // X-Axis + Axis xAxisPrimary = cwaLine.getPrimaryBaseAxes()[0]; + xAxisPrimary.setType(AxisType.TEXT_LITERAL); + xAxisPrimary.getMajorGrid().setTickStyle(TickStyle.BELOW_LITERAL); + xAxisPrimary.getMajorGrid().setLineAttributes(LineAttributesImpl.create(ColorDefinitionImpl.GREY(), LineStyle.DOTTED_LITERAL, 1)); + xAxisPrimary.getTitle().setVisible(false); + xAxisPrimary.setInterval(4); + xAxisPrimary.getLabel().getCaption().setFont(createChartFont()); + xAxisPrimary.setFormatSpecifier( JavaDateFormatSpecifierImpl.create( "HH:mm" ) ); + + // Y-Axis + Axis yAxisPrimary = cwaLine.getPrimaryOrthogonalAxis(xAxisPrimary); + yAxisPrimary.getMajorGrid().setTickStyle(TickStyle.LEFT_LITERAL); + yAxisPrimary.getMajorGrid().setLineAttributes(LineAttributesImpl.create(ColorDefinitionImpl.GREY(), LineStyle.SOLID_LITERAL, 1)); + yAxisPrimary.setInterval(2); + yAxisPrimary.getLabel().setVisible(true); + yAxisPrimary.getLabel().getCaption().setFont(createChartFont()); + + // Data Set + DateTimeDataSet categoryValues = DateTimeDataSetImpl.create(timestamps); + + // X-Series + Series seCategory = SeriesImpl.create(); + seCategory.setDataSet(categoryValues); + SeriesDefinition sdX = SeriesDefinitionImpl.create(); + + xAxisPrimary.getSeriesDefinitions().add(sdX); + sdX.getSeries().add(seCategory); + + SeriesDefinition sdY = SeriesDefinitionImpl.create(); + sdY.getSeriesPalette().shift(-3); + yAxisPrimary.getSeriesDefinitions().add(sdY); + + for (int i = 0; i < values.length; i++) { + // Y-Sereis + AreaSeries ls = (AreaSeries) AreaSeriesImpl.create(); + // LineSeries ls = (LineSeries) LineSeriesImpl.create(); + + NumberDataSet orthoValues = NumberDataSetImpl.create(values[i]); + ls.setDataSet(orthoValues); + ls.getLineAttributes().setColor(ColorDefinitionImpl.create(50, 50, 255)); + for (int j = 0; j < ls.getMarkers().size(); j++) { + // ( (Marker) ls.getMarkers( ).get( j ) ).setType( MarkerType.CIRCLE_LITERAL); + ((Marker) ls.getMarkers().get(j)).setVisible(false); + } + ls.setTranslucent(true); + // don't show values on each point on the line chart + ls.getLabel().setVisible(false); + sdY.getSeries().add(ls); + } + return cwaLine; + } + + public static FontDefinition createChartFont() { + return FontDefinitionImpl.create("Serif", 8, false, false, false, false, false, 0d, TextAlignmentImpl.create()); } /** @@ -118,8 +254,7 @@ public final class PieChartViewerComposite extends Composite implements * Values of each category in the pie chart * @return The chart object created for given categories and values */ - public static final Chart createPieChart(String[] categories, - Double[] values) { + public static final Chart createPieChart(String[] categories, Double[] values) { ChartWithoutAxes pieChart = ChartWithoutAxesImpl.create(); // Plot @@ -127,7 +262,7 @@ public final class PieChartViewerComposite extends Composite implements 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); @@ -196,8 +331,7 @@ public final class PieChartViewerComposite extends Composite implements if (needsGeneration) { needsGeneration = false; try { - generatedChartState = gr.build(deviceReader.getDisplayServer(), - chart, bo, null, null, null); + generatedChartState = gr.build(deviceReader.getDisplayServer(), chart, bo, null, null, null); } catch (ChartException ce) { ce.printStackTrace(); } @@ -208,8 +342,7 @@ public final class PieChartViewerComposite extends Composite implements GC gc = e.gc; gc.drawImage(imgChart, d.x, d.y); } catch (ChartException gex) { - logger.log(Level.SEVERE, "Exception while rendering pie chart [" - + gex.getMessage() + "]", gex); + logger.log(Level.SEVERE, "Exception while rendering pie chart [" + gex.getMessage() + "]", gex); } } 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 49c55b8a..f970effd 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,8 +20,10 @@ */ package com.gluster.storage.management.gui.views; +import java.util.Date; import java.util.List; +import org.eclipse.birt.chart.util.CDateTime; import org.eclipse.swt.SWT; import org.eclipse.swt.custom.CLabel; import org.eclipse.swt.graphics.Image; @@ -40,21 +42,18 @@ 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.Device.DEVICE_STATUS; -import com.gluster.storage.management.core.model.Disk; 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.Server; import com.gluster.storage.management.core.model.TaskInfo; -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.ChartViewerComposite; import com.gluster.storage.management.gui.utils.GUIHelper; -import com.gluster.storage.management.gui.utils.PieChartViewerComposite; +import com.ibm.icu.util.Calendar; /** * @author root @@ -82,16 +81,6 @@ public class ClusterSummaryView extends ViewPart { createSections(parent); } - private int getVolumeCountByStatus(Cluster cluster, VOLUME_STATUS status) { - int count = 0; - for (Volume volume : cluster.getVolumes()) { - if (volume.getStatus() == status) { - count++; - } - } - return count; - } - private int getServerCountByStatus(Cluster cluster, SERVER_STATUS status) { int count = 0; for (GlusterServer server : cluster.getServers()) { @@ -102,14 +91,6 @@ public class ClusterSummaryView extends ViewPart { return count; } - private void createVolumesSection() { - Composite section = guiHelper.createSection(form, toolkit, "Volumes", null, 1, false); - - Double[] values = new Double[] { Double.valueOf(getVolumeCountByStatus(cluster, VOLUME_STATUS.ONLINE)), - Double.valueOf(getVolumeCountByStatus(cluster, VOLUME_STATUS.OFFLINE)) }; - createDiskSpaceChart(toolkit, section, values); - } - private void createServersSection() { Composite section = guiHelper.createSection(form, toolkit, "Servers", null, 2, false); @@ -135,34 +116,13 @@ public class ClusterSummaryView extends ViewPart { double totalDiskSpace = cluster.getTotalDiskSpace(); double diskSpaceInUse = cluster.getDiskSpaceInUse(); Double[] values = new Double[] { diskSpaceInUse, totalDiskSpace - diskSpaceInUse }; - createDiskSpaceChart(toolkit, section, values); - } - - private int getDiskCountByStatus(Cluster cluster, DEVICE_STATUS status) { - int diskCount = 0; - for(GlusterServer server : cluster.getServers()) { - for(Disk disk : server.getDisks()) { - if(disk.getStatus() == status) { - diskCount++; - } - } - } - return diskCount; + createDiskSpaceChart(section, values); } - 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) { + private void createDiskSpaceChart(Composite section, Double[] values) { String[] categories = new String[] { "Used Space: " + NumberUtil.formatNumber((values[0] / 1024)) + " GB", - "Free Space: " + NumberUtil.formatNumber((values[1] / 1024)) + " GB"}; - PieChartViewerComposite chartViewerComposite = new PieChartViewerComposite(section, SWT.NONE, categories, - values); + "Free Space: " + NumberUtil.formatNumber((values[1] / 1024)) + " GB" }; + ChartViewerComposite chartViewerComposite = new ChartViewerComposite(section, SWT.NONE, categories, values); GridData data = new GridData(SWT.FILL, SWT.FILL, false, false); data.widthHint = 400; @@ -170,6 +130,15 @@ public class ClusterSummaryView extends ViewPart { data.verticalAlignment = SWT.CENTER; chartViewerComposite.setLayoutData(data); } + + private void createLineChart(Composite section, Calendar timestamps[], Double values[]) { + ChartViewerComposite chartViewerComposite = new ChartViewerComposite(section, SWT.NONE, timestamps, values); + GridData data = new GridData(SWT.FILL, SWT.FILL, false, false); + data.widthHint = 400; + data.heightHint = 300; + data.verticalAlignment = SWT.CENTER; + chartViewerComposite.setLayoutData(data); + } private void createAlertsSection() { Composite section = guiHelper.createSection(form, toolkit, "Alerts", null, 1, false); @@ -254,23 +223,51 @@ public class ClusterSummaryView extends ViewPart { 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); if (cluster.getServers().size() == 0) { toolkit.createLabel(section, "This section will be populated after at least\none server is added to the storage cloud."); return; } - toolkit.createLabel(section, "Historical CPU Usage graph aggregated across\nall servers will be displayed here."); + //toolkit.createLabel(section, "Historical CPU Usage graph aggregated across\nall servers will be displayed here."); + +// Date[] timestamps = new Date[] { new Date(1310468100), new Date(1310468400), new Date(1310468700), +// new Date(1310469000), new Date(1310469300), new Date(1310469600), new Date(1310469900), +// new Date(1310470200), new Date(1310470500), new Date(1310470800), new Date(1310471100), +// new Date(1310471400), new Date(1310471700), new Date(1310472000), new Date(1310472300), +// new Date(1310472600), new Date(1310472900), new Date(1310473200), new Date(1310473500), +// new Date(1310473800) }; + Calendar[] timestamps = new Calendar[] { new CDateTime(1000l*1310468100), new CDateTime(1000l*1310468400), new CDateTime(1000l*1310468700), + new CDateTime(1000l*1310469000), new CDateTime(1000l*1310469300), new CDateTime(1000l*1310469600), new CDateTime(1000l*1310469900), + new CDateTime(1000l*1310470200), new CDateTime(1000l*1310470500), new CDateTime(1000l*1310470800), new CDateTime(1000l*1310471100), + new CDateTime(1000l*1310471400), new CDateTime(1000l*1310471700), new CDateTime(1000l*1310472000), new CDateTime(1000l*1310472300), + new CDateTime(1000l*1310472600), new CDateTime(1000l*1310472900), new CDateTime(1000l*1310473200), new CDateTime(1000l*1310473500), + new CDateTime(1000l*1310473800) }; + + //String[] timestampsarr = new String[] {"t1", "t2", "t3", "t4", "t5", "t6", "t7", "t8", "t9", "t10", "t11", "t12", "t13", "t14", "t15", "t16", "t17", "t18", "t19", "t20"}; + Double[] values = new Double[] { 10d, 11.23d, 17.92d, 18.69d, 78.62d, 89.11d, 92.43d, 89.31d, 57.39d, 18.46d, 10.44d, 16.28d, 13.51d, 17.53d, 12.21, 20d, 21.43d, 16.45d, 14.86d, 15.27d }; + createLineChart(section, timestamps, values); } private void createNetworkUsageSection() { Composite section = guiHelper.createSection(form, toolkit, "Network Usage", null, 1, false); - toolkit.createLabel(section, "Historical Network Usage graph will be displayed here."); + //toolkit.createLabel(section, "Historical Network Usage graph will be displayed here."); + + Calendar[] timestamps = new Calendar[] { new CDateTime(1000l*1310468100), new CDateTime(1000l*1310468400), new CDateTime(1000l*1310468700), + new CDateTime(1000l*1310469000), new CDateTime(1000l*1310469300), new CDateTime(1000l*1310469600), new CDateTime(1000l*1310469900), + new CDateTime(1000l*1310470200), new CDateTime(1000l*1310470500), new CDateTime(1000l*1310470800), new CDateTime(1000l*1310471100), + new CDateTime(1000l*1310471400), new CDateTime(1000l*1310471700), new CDateTime(1000l*1310472000), new CDateTime(1000l*1310472300), + new CDateTime(1000l*1310472600), new CDateTime(1000l*1310472900), new CDateTime(1000l*1310473200), new CDateTime(1000l*1310473500), + new CDateTime(1000l*1310473800) }; +// Date[] timestamps = new Date[] { new Date(1310468100), new Date(1310468400), new Date(1310468700), +// new Date(1310469000), new Date(1310469300), new Date(1310469600), new Date(1310469900), +// new Date(1310470200), new Date(1310470500), new Date(1310470800), new Date(1310471100), +// new Date(1310471400), new Date(1310471700), new Date(1310472000), new Date(1310472300), +// new Date(1310472600), new Date(1310472900), new Date(1310473200), new Date(1310473500), +// new Date(1310473800) }; + String[] timestampsarr = new String[] {"t1", "t2", "t3", "t4", "t5", "t6", "t7", "t8", "t9", "t10", "t11", "t12", "t13", "t14", "t15", "t16", "t17", "t18", "t19", "t20"}; + Double[] values = new Double[] { 32d, 31.23d, 27.92d, 48.69d, 58.62d, 49.11d, 72.43d, 69.31d, 87.39d, 78.46d, 60.44d, 56.28d, 33.51d, 27.53d, 12.21, 10d, 21.43d, 36.45d, 34.86d, 35.27d }; + createLineChart(section, timestamps, values); } private void createRunningTasksSection() { 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 30072b97..50da72ff 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 @@ -47,11 +47,12 @@ import com.gluster.storage.management.core.model.DefaultClusterListener; import com.gluster.storage.management.core.model.Event; 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.Volume; import com.gluster.storage.management.core.utils.NumberUtil; import com.gluster.storage.management.gui.IImageKeys; import com.gluster.storage.management.gui.NetworkInterfaceTableLabelProvider; import com.gluster.storage.management.gui.toolbar.GlusterToolbarManager; +import com.gluster.storage.management.gui.utils.ChartViewerComposite; +import com.gluster.storage.management.gui.utils.ChartViewerComposite.CHART_TYPE; import com.gluster.storage.management.gui.utils.GUIHelper; import com.richclientgui.toolbox.gauges.CoolGauge; @@ -100,12 +101,37 @@ public class GlusterServerSummaryView extends ViewPart { GlusterDataModelManager.getInstance().removeClusterListener(serverChangedListener); } + private void createLineChart(Composite section, String timestamps[], Double values[]) { + ChartViewerComposite chartViewerComposite = new ChartViewerComposite(section, SWT.NONE, timestamps, values); + GridData data = new GridData(SWT.FILL, SWT.FILL, false, false); + data.widthHint = 450; + data.heightHint = 300; + data.verticalAlignment = SWT.CENTER; + chartViewerComposite.setLayoutData(data); + } + + 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\nall servers will be displayed here."); + + String[] timestamps = new String[] {"t1", "t2", "t3", "t4", "t5", "t6", "t7", "t8", "t9", "t10", "t11", "t12", "t13", "t14", "t15", "t16", "t17", "t18", "t19", "t20"}; + Double[] values = new Double[] { 10d, 11.23d, 17.92d, 18.69d, 78.62d, 89.11d, 92.43d, 20.31d, 19.63d, 18.46d, 10.44d, 16.28d, 13.51d, 17.53d, 12.21, 20d, 40d, 10d, 90d, 40d }; + createLineChart(section, timestamps, values); + } + private void createSections(Composite parent) { String serverName = server.getName(); form = guiHelper.setupForm(parent, toolkit, "Server Summary [" + serverName + "]"); createServerSummarySection(server, toolkit, form); if (server.getStatus() == SERVER_STATUS.ONLINE) { + createMemoryUsageSection(); + createCPUUsageSection(); createNetworkInterfacesSection(server, toolkit, form); } 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 d80e3879..d703c9a7 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 @@ -33,8 +33,9 @@ import org.eclipse.ui.part.ViewPart; import com.gluster.storage.management.core.model.EntityGroup; import com.gluster.storage.management.core.model.GlusterServer; import com.gluster.storage.management.core.model.GlusterServer.SERVER_STATUS; +import com.gluster.storage.management.gui.utils.ChartViewerComposite.CHART_TYPE; import com.gluster.storage.management.gui.utils.GUIHelper; -import com.gluster.storage.management.gui.utils.PieChartViewerComposite; +import com.gluster.storage.management.gui.utils.ChartViewerComposite; /** * @@ -95,7 +96,7 @@ public class GlusterServersSummaryView extends ViewPart { private void createStatusChart(Composite section, Double[] values) { String[] categories = new String[] { "Online", "Offline" }; - PieChartViewerComposite chartViewerComposite = new PieChartViewerComposite(section, SWT.NONE, categories, values); + ChartViewerComposite chartViewerComposite = new ChartViewerComposite(section, SWT.NONE, categories, values); GridData data = new GridData(SWT.FILL, SWT.FILL, false, false); data.widthHint = 300; @@ -103,7 +104,6 @@ public class GlusterServersSummaryView extends ViewPart { chartViewerComposite.setLayoutData(data); } - private void createAlertsSection() { Composite section = guiHelper.createSection(form, toolkit, "Alerts", null, 2, false); 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 a43330c4..daeecb83 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 @@ -40,8 +40,9 @@ import com.gluster.storage.management.core.model.TaskInfo.TASK_TYPE; import com.gluster.storage.management.core.model.Volume; import com.gluster.storage.management.core.model.Volume.VOLUME_STATUS; import com.gluster.storage.management.gui.IImageKeys; +import com.gluster.storage.management.gui.utils.ChartViewerComposite.CHART_TYPE; import com.gluster.storage.management.gui.utils.GUIHelper; -import com.gluster.storage.management.gui.utils.PieChartViewerComposite; +import com.gluster.storage.management.gui.utils.ChartViewerComposite; /** * @@ -157,8 +158,7 @@ public class VolumesSummaryView extends ViewPart { private void createStatusChart(FormToolkit toolkit, Composite section, Double[] values) { String[] categories = new String[] { "Online", "Offline" }; - PieChartViewerComposite chartViewerComposite = new PieChartViewerComposite(section, SWT.NONE, categories, - values); + ChartViewerComposite chartViewerComposite = new ChartViewerComposite(section, SWT.NONE, categories, values); GridData data = new GridData(SWT.FILL, SWT.FILL, false, false); data.widthHint = 300; diff --git a/src/com.gluster.storage.management.gui/src/com/gluster/storage/management/gui/views/pages/AbstractTableTreeViewerPage.java b/src/com.gluster.storage.management.gui/src/com/gluster/storage/management/gui/views/pages/AbstractTableTreeViewerPage.java index 05a74b03..13c2ceef 100644 --- a/src/com.gluster.storage.management.gui/src/com/gluster/storage/management/gui/views/pages/AbstractTableTreeViewerPage.java +++ b/src/com.gluster.storage.management.gui/src/com/gluster/storage/management/gui/views/pages/AbstractTableTreeViewerPage.java @@ -38,7 +38,6 @@ import org.eclipse.ui.ISelectionListener; import org.eclipse.ui.IWorkbenchPart; import org.eclipse.ui.IWorkbenchSite; import org.eclipse.ui.forms.widgets.FormToolkit; -import org.eclipse.ui.forms.widgets.Hyperlink; import com.gluster.storage.management.core.model.ClusterListener; import com.gluster.storage.management.core.model.Disk; @@ -46,7 +45,6 @@ import com.gluster.storage.management.gui.utils.GUIHelper; public abstract class AbstractTableTreeViewerPage<T> extends Composite implements ISelectionListener { - protected final FormToolkit toolkit = new FormToolkit(Display.getCurrent()); protected TreeViewer treeViewer; protected GUIHelper guiHelper = GUIHelper.getInstance(); diff --git a/src/com.gluster.storage.management.server/WebContent/WEB-INF/web.xml b/src/com.gluster.storage.management.server/WebContent/WEB-INF/web.xml index 7c20d6c7..405c4e40 100644 --- a/src/com.gluster.storage.management.server/WebContent/WEB-INF/web.xml +++ b/src/com.gluster.storage.management.server/WebContent/WEB-INF/web.xml @@ -81,14 +81,14 @@ <filter-name>springSecurityFilterChain</filter-name> <url-pattern>/*</url-pattern> </filter-mapping> - + <security-constraint> - <web-resource-collection> - <web-resource-name>Gluster Management Gateway</web-resource-name> - <url-pattern>/*</url-pattern> - </web-resource-collection> - <user-data-constraint> - <transport-guarantee>CONFIDENTIAL</transport-guarantee> - </user-data-constraint> -</security-constraint> + <web-resource-collection> + <web-resource-name>Gluster Management Gateway</web-resource-name> + <url-pattern>/*</url-pattern> + </web-resource-collection> + <user-data-constraint> + <transport-guarantee>CONFIDENTIAL</transport-guarantee> + </user-data-constraint> + </security-constraint> </web-app> diff --git a/src/com.gluster.storage.management.server/src/com/gluster/storage/management/server/resources/v1_0/GenericExceptionMapper.java b/src/com.gluster.storage.management.server/src/com/gluster/storage/management/server/resources/v1_0/GenericExceptionMapper.java new file mode 100644 index 00000000..4cd7f4f9 --- /dev/null +++ b/src/com.gluster.storage.management.server/src/com/gluster/storage/management/server/resources/v1_0/GenericExceptionMapper.java @@ -0,0 +1,45 @@ +/******************************************************************************* + * Copyright (c) 2011 Gluster, Inc. <http://www.gluster.com> + * This file is part of Gluster Management Console. + * + * Gluster Management Console is free software; you can redistribute it and/or + * modify it under the terms of the GNU Affero General Public License as published + * by the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. + * + * Gluster Management Console 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 Affero General Public License + * for more details. + * + * You should have received a copy of the GNU Affero General Public License + * along with this program. If not, see + * <http://www.gnu.org/licenses/>. + *******************************************************************************/ +package com.gluster.storage.management.server.resources.v1_0; + +import javax.ws.rs.core.MediaType; +import javax.ws.rs.core.Response; +import javax.ws.rs.core.Response.ResponseBuilder; +import javax.ws.rs.ext.ExceptionMapper; +import javax.ws.rs.ext.Provider; + +import com.gluster.storage.management.core.exceptions.GlusterValidationException; + +@Provider +public class GenericExceptionMapper implements ExceptionMapper<Exception> { + + /* (non-Javadoc) + * @see javax.ws.rs.ext.ExceptionMapper#toResponse(java.lang.Throwable) + */ + @Override + public Response toResponse(Exception exception) { + ResponseBuilder builder; + if (exception instanceof GlusterValidationException) { + builder = Response.status(Response.Status.BAD_REQUEST); + } else { + builder = Response.status(Response.Status.INTERNAL_SERVER_ERROR); + } + return builder.entity(exception.getMessage()).type(MediaType.TEXT_PLAIN).build(); + } +} diff --git a/src/com.gluster.storage.management.server/src/com/gluster/storage/management/server/resources/v1_0/GlusterServersResource.java b/src/com.gluster.storage.management.server/src/com/gluster/storage/management/server/resources/v1_0/GlusterServersResource.java index a5f366a2..09391841 100644 --- a/src/com.gluster.storage.management.server/src/com/gluster/storage/management/server/resources/v1_0/GlusterServersResource.java +++ b/src/com.gluster.storage.management.server/src/com/gluster/storage/management/server/resources/v1_0/GlusterServersResource.java @@ -18,15 +18,21 @@ *******************************************************************************/ package com.gluster.storage.management.server.resources.v1_0; -import static com.gluster.storage.management.core.constants.RESTConstants.FORM_PARAM_SERVER_NAME; import static com.gluster.storage.management.core.constants.RESTConstants.FORM_PARAM_FSTYPE; +import static com.gluster.storage.management.core.constants.RESTConstants.FORM_PARAM_SERVER_NAME; import static com.gluster.storage.management.core.constants.RESTConstants.PATH_PARAM_CLUSTER_NAME; import static com.gluster.storage.management.core.constants.RESTConstants.PATH_PARAM_DISK_NAME; import static com.gluster.storage.management.core.constants.RESTConstants.PATH_PARAM_SERVER_NAME; +import static com.gluster.storage.management.core.constants.RESTConstants.QUERY_PARAM_DETAILS; +import static com.gluster.storage.management.core.constants.RESTConstants.QUERY_PARAM_TYPE; import static com.gluster.storage.management.core.constants.RESTConstants.RESOURCE_DISKS; import static com.gluster.storage.management.core.constants.RESTConstants.RESOURCE_PATH_CLUSTERS; import static com.gluster.storage.management.core.constants.RESTConstants.RESOURCE_SERVERS; +import static com.gluster.storage.management.core.constants.RESTConstants.RESOURCE_STATISTICS; import static com.gluster.storage.management.core.constants.RESTConstants.RESOURCE_TASKS; +import static com.gluster.storage.management.core.constants.RESTConstants.STATISTICS_TYPE_CPU; +import static com.gluster.storage.management.core.constants.RESTConstants.STATISTICS_TYPE_NETWORK; +import static com.gluster.storage.management.core.constants.RESTConstants.STATISTICS_TYPE_MEMORY; import java.util.ArrayList; import java.util.List; @@ -39,6 +45,7 @@ import javax.ws.rs.PUT; import javax.ws.rs.Path; import javax.ws.rs.PathParam; import javax.ws.rs.Produces; +import javax.ws.rs.QueryParam; import javax.ws.rs.core.MediaType; import javax.ws.rs.core.Response; @@ -49,14 +56,15 @@ import com.gluster.storage.management.core.constants.CoreConstants; import com.gluster.storage.management.core.constants.RESTConstants; import com.gluster.storage.management.core.exceptions.ConnectionException; import com.gluster.storage.management.core.exceptions.GlusterRuntimeException; +import com.gluster.storage.management.core.model.ServerStats; import com.gluster.storage.management.core.model.GlusterServer; import com.gluster.storage.management.core.model.GlusterServer.SERVER_STATUS; import com.gluster.storage.management.core.response.GlusterServerListResponse; +import com.gluster.storage.management.core.response.ServerNameListResponse; import com.gluster.storage.management.server.data.ClusterInfo; import com.gluster.storage.management.server.data.ServerInfo; import com.gluster.storage.management.server.services.ClusterService; import com.gluster.storage.management.server.tasks.InitializeDiskTask; -import com.gluster.storage.management.server.utils.GlusterUtil; import com.gluster.storage.management.server.utils.SshUtil; import com.sun.jersey.api.core.InjectParam; import com.sun.jersey.spi.resource.Singleton; @@ -92,17 +100,44 @@ public class GlusterServersResource extends AbstractServersResource { @GET @Produces(MediaType.APPLICATION_JSON) - public Response getGlusterServersJSON(@PathParam(PATH_PARAM_CLUSTER_NAME) String clusterName) { - return getGlusterServers(clusterName, MediaType.APPLICATION_JSON); + public Response getGlusterServersJSON(@PathParam(PATH_PARAM_CLUSTER_NAME) String clusterName, + @QueryParam(QUERY_PARAM_DETAILS) Boolean details) { + return getGlusterServers(clusterName, MediaType.APPLICATION_JSON, details); } @GET @Produces(MediaType.APPLICATION_XML) - public Response getGlusterServersXML(@PathParam(PATH_PARAM_CLUSTER_NAME) String clusterName) { - return getGlusterServers(clusterName, MediaType.APPLICATION_XML); + public Response getGlusterServersXML(@PathParam(PATH_PARAM_CLUSTER_NAME) String clusterName, + @QueryParam(QUERY_PARAM_DETAILS) Boolean details) { + return getGlusterServers(clusterName, MediaType.APPLICATION_XML, details); } + + private List<GlusterServer> getGlusterServers(String clusterName, boolean fetchDetails) { + List<GlusterServer> glusterServers; + GlusterServer onlineServer = clusterService.getOnlineServer(clusterName); + if (onlineServer == null) { + throw new GlusterRuntimeException("No online servers found in cluster [" + clusterName + "]"); + } - public Response getGlusterServers(String clusterName, String mediaType) { + try { + glusterServers = getGlusterServers(clusterName, onlineServer, fetchDetails); + } catch (ConnectionException e) { + // online server has gone offline! try with a different one. + onlineServer = clusterService.getNewOnlineServer(clusterName); + if (onlineServer == null) { + throw new GlusterRuntimeException("No online servers found in cluster [" + clusterName + "]"); + } + glusterServers = getGlusterServers(clusterName, onlineServer, fetchDetails); + } + return glusterServers; + } + + private Response getGlusterServers(String clusterName, String mediaType, Boolean fetchDetails) { + if(fetchDetails == null) { + // by default, fetch the server details + fetchDetails = true; + } + List<GlusterServer> glusterServers = new ArrayList<GlusterServer>(); if (clusterName == null || clusterName.isEmpty()) { @@ -118,37 +153,30 @@ public class GlusterServersResource extends AbstractServersResource { return okResponse(new GlusterServerListResponse(glusterServers), mediaType); } - GlusterServer onlineServer = clusterService.getOnlineServer(clusterName); - if (onlineServer == null) { - return errorResponse("No online servers found in cluster [" + clusterName + "]"); - } - try { - glusterServers = getGlusterServers(clusterName, onlineServer); - } catch (ConnectionException e) { - // online server has gone offline! try with a different one. - onlineServer = clusterService.getNewOnlineServer(clusterName); - if (onlineServer == null) { - return errorResponse("No online servers found in cluster [" + clusterName + "]"); - } - try { - glusterServers = getGlusterServers(clusterName, onlineServer); - } catch (Exception e1) { - return errorResponse(e1.getMessage()); - } + glusterServers = getGlusterServers(clusterName, fetchDetails); } catch (Exception e) { return errorResponse(e.getMessage()); } - - String errMsg = fetchDetailsOfServers(glusterServers, onlineServer); - if (!errMsg.isEmpty()) { - return errorResponse("Couldn't fetch details for server(s): " + errMsg); + + if(fetchDetails) { + return okResponse(new GlusterServerListResponse(glusterServers), mediaType); + } else { + // no details to be fetched. Return list of server names. + return okResponse(new ServerNameListResponse(getServerNames(glusterServers)), mediaType); } + } + - return okResponse(new GlusterServerListResponse(glusterServers), mediaType); + private List<String> getServerNames(List<GlusterServer> glusterServers) { + List<String> serverNames = new ArrayList<String>(); + for(GlusterServer server : glusterServers) { + serverNames.add(server.getName()); + } + return serverNames; } - public String fetchDetailsOfServers(List<GlusterServer> glusterServers, GlusterServer onlineServer) { + private String fetchDetailsOfServers(List<GlusterServer> glusterServers, GlusterServer onlineServer) { String errMsg = ""; for (GlusterServer server : glusterServers) { @@ -161,7 +189,7 @@ public class GlusterServersResource extends AbstractServersResource { return errMsg; } - public List<GlusterServer> getGlusterServers(String clusterName, GlusterServer onlineServer) { + private List<GlusterServer> getGlusterServers(String clusterName, GlusterServer onlineServer, boolean fetchDetails) { List<GlusterServer> glusterServers; try { glusterServers = glusterUtil.getGlusterServers(onlineServer); @@ -174,11 +202,18 @@ public class GlusterServersResource extends AbstractServersResource { glusterServers = glusterUtil.getGlusterServers(onlineServer); } + + if (fetchDetails) { + String errMsg = fetchDetailsOfServers(glusterServers, onlineServer); + if (!errMsg.isEmpty()) { + throw new GlusterRuntimeException("Couldn't fetch details for server(s): " + errMsg); + } + } return glusterServers; } @GET - @Path("{serverName}") + @Path("{" + PATH_PARAM_SERVER_NAME + "}") @Produces(MediaType.APPLICATION_XML) public Response getGlusterServerXML(@PathParam(PATH_PARAM_CLUSTER_NAME) String clusterName, @PathParam(PATH_PARAM_SERVER_NAME) String serverName) { @@ -186,7 +221,7 @@ public class GlusterServersResource extends AbstractServersResource { } @GET - @Path("{serverName}") + @Path("{" + PATH_PARAM_SERVER_NAME + "}") @Produces(MediaType.APPLICATION_JSON) public Response getGlusterServerJSON(@PathParam(PATH_PARAM_CLUSTER_NAME) String clusterName, @PathParam(PATH_PARAM_SERVER_NAME) String serverName) { @@ -428,20 +463,57 @@ public class GlusterServersResource extends AbstractServersResource { return errorResponse(e.getMessage()); } } + + @GET + @Produces(MediaType.APPLICATION_XML) + @Path(RESOURCE_STATISTICS) + public Response getAggregatedPerformanceDataXML(@PathParam(PATH_PARAM_CLUSTER_NAME) String clusterName, + @QueryParam(QUERY_PARAM_TYPE) String type) { + return getAggregaredPerformanceData(clusterName, type, MediaType.APPLICATION_XML); + } - private void setGlusterUtil(GlusterUtil glusterUtil) { - this.glusterUtil = glusterUtil; + @GET + @Produces(MediaType.APPLICATION_JSON) + @Path(RESOURCE_STATISTICS) + public Response getAggregaredPerformanceDataJSON(@PathParam(PATH_PARAM_CLUSTER_NAME) String clusterName, + @QueryParam(QUERY_PARAM_TYPE) String type) { + return getAggregaredPerformanceData(clusterName, type, MediaType.APPLICATION_JSON); } - public static void main(String[] args) { - GlusterServersResource glusterServersResource = new GlusterServersResource(); - GlusterUtil glusterUtil = new GlusterUtil(); - glusterUtil.setSshUtil(new SshUtil()); - glusterServersResource.setGlusterUtil(glusterUtil); - // System.out.println(glusterServersResource.getServerDetails("127.0.0.1").size()); + @GET + @Produces(MediaType.APPLICATION_XML) + @Path("{" + PATH_PARAM_SERVER_NAME + "}/" + RESOURCE_STATISTICS) + public Response getPerformanceDataXML(@PathParam(PATH_PARAM_SERVER_NAME) String serverName, @QueryParam(QUERY_PARAM_TYPE) String type) { + return getPerformanceData(serverName, type, MediaType.APPLICATION_XML); + } - // To add a server - // GlusterServerResponse response = glusterServersResource.addServer("my-server"); - // System.out.println(response.getData().getName()); + @GET + @Produces(MediaType.APPLICATION_JSON) + @Path("{" + PATH_PARAM_SERVER_NAME + "}/" + RESOURCE_STATISTICS) + public Response getPerformanceDataJSON(@PathParam(PATH_PARAM_SERVER_NAME) String serverName, @QueryParam(QUERY_PARAM_TYPE) String type) { + return getPerformanceData(serverName, type, MediaType.APPLICATION_JSON); + } + + private Response getAggregaredPerformanceData(String clusterName, String type, String mediaType) { + List<String> serverNames = getServerNames(getGlusterServers(clusterName, false)); + if(type.equals(STATISTICS_TYPE_CPU)) { + return okResponse(serverUtil.fetchAggregatedCPUStats(serverNames), mediaType); + } else { + return badRequestResponse("Server Statistics for [" + type + "] not supported! Valid values are [" + + STATISTICS_TYPE_CPU + ", " + STATISTICS_TYPE_NETWORK + ", " + STATISTICS_TYPE_MEMORY + "]"); + } + } + + private Response getPerformanceData(String serverName, String type, String mediaType) { + if(type.equals(STATISTICS_TYPE_CPU)) { + return okResponse(serverUtil.fetchCPUUsageData(serverName), mediaType); + } else if(type.equals(STATISTICS_TYPE_NETWORK)) { + return okResponse(serverUtil.fetchCPUUsageData(serverName), mediaType); + } else if(type.equals(STATISTICS_TYPE_MEMORY)) { + return okResponse(serverUtil.fetchCPUUsageData(serverName), mediaType); + } else { + return badRequestResponse("Server Statistics for [" + type + "] not supported! Valid values are [" + + STATISTICS_TYPE_CPU + ", " + STATISTICS_TYPE_NETWORK + ", " + STATISTICS_TYPE_MEMORY + "]"); + } } } diff --git a/src/com.gluster.storage.management.server/src/com/gluster/storage/management/server/resources/v1_0/ValidationExceptionMapper.java b/src/com.gluster.storage.management.server/src/com/gluster/storage/management/server/resources/v1_0/ValidationExceptionMapper.java new file mode 100644 index 00000000..cab6cc62 --- /dev/null +++ b/src/com.gluster.storage.management.server/src/com/gluster/storage/management/server/resources/v1_0/ValidationExceptionMapper.java @@ -0,0 +1,39 @@ +/******************************************************************************* + * Copyright (c) 2011 Gluster, Inc. <http://www.gluster.com> + * This file is part of Gluster Management Console. + * + * Gluster Management Console is free software; you can redistribute it and/or + * modify it under the terms of the GNU Affero General Public License as published + * by the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. + * + * Gluster Management Console 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 Affero General Public License + * for more details. + * + * You should have received a copy of the GNU Affero General Public License + * along with this program. If not, see + * <http://www.gnu.org/licenses/>. + *******************************************************************************/ +package com.gluster.storage.management.server.resources.v1_0; + +import javax.ws.rs.core.MediaType; +import javax.ws.rs.core.Response; +import javax.ws.rs.ext.ExceptionMapper; +import javax.ws.rs.ext.Provider; + +import com.gluster.storage.management.core.exceptions.GlusterValidationException; + +@Provider +public class ValidationExceptionMapper implements ExceptionMapper<GlusterValidationException> { + + /* (non-Javadoc) + * @see javax.ws.rs.ext.ExceptionMapper#toResponse(java.lang.Throwable) + */ + @Override + public Response toResponse(GlusterValidationException exception) { + return Response.status(Response.Status.BAD_REQUEST).entity(exception.getMessage()) + .type(MediaType.TEXT_PLAIN).build(); + } +} 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 ae4bc919..55be59b4 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,8 @@ package com.gluster.storage.management.server.utils; import java.io.ByteArrayInputStream; import java.util.ArrayList; +import java.util.Collection; +import java.util.Date; import java.util.List; import javax.servlet.ServletContext; @@ -29,12 +31,15 @@ import javax.xml.bind.JAXBContext; import javax.xml.bind.JAXBException; import javax.xml.bind.Unmarshaller; +import org.apache.log4j.Logger; 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.ConnectionException; import com.gluster.storage.management.core.exceptions.GlusterRuntimeException; +import com.gluster.storage.management.core.model.ServerStatsRow; +import com.gluster.storage.management.core.model.ServerStats; import com.gluster.storage.management.core.model.Server; import com.gluster.storage.management.core.model.Status; import com.gluster.storage.management.core.response.GenericResponse; @@ -48,6 +53,8 @@ public class ServerUtil { @Autowired private SshUtil sshUtil; + + private static final Logger logger = Logger.getLogger(ServerUtil.class); private static final String SCRIPT_DIR = "scripts"; private static final String SCRIPT_COMMAND = "python"; @@ -216,4 +223,103 @@ public class ServerUtil { public Status getDiskForDir(String serverName, String brickDir) { return (Status) executeOnServer(true, serverName, REMOTE_SCRIPT_GET_DISK_FOR_DIR + " " + brickDir, Status.class); } + + public ServerStats fetchCPUUsageData(String serverName) { + String cpuUsageData = "<?xml version=\"1.0\" encoding=\"ISO-8859-1\"?> <xport> <meta> <start>1310468100</start> <step>300</step> <end>1310471700</end> <rows>13</rows> <columns>3</columns> <legend> <entry>user</entry> <entry>system</entry> <entry>total</entry> </legend> </meta> <data> <row><t>1310468100</t><v>NaN</v><v>4.3747778209e-01</v><v>6.6128073384e-01</v></row> <row><t>1310468400</t><v>2.3387347338e-01</v><v>4.4642717442e-01</v><v>6.8030064780e-01</v></row> <row><t>1310468700</t><v>5.5043873220e+00</v><v>6.2462376636e+00</v><v>1.1750624986e+01</v></row> <row><t>1310469000</t><v>2.4350593653e+01</v><v>2.6214585217e+01</v><v>5.0565178869e+01</v></row> <row><t>1310469300</t><v>4.0786489953e+01</v><v>4.6784713828e+01</v><v>8.7571203781e+01</v></row> <row><t>1310469600</t><v>4.1459955508e+01</v><v>5.2546309044e+01</v><v>9.4006264551e+01</v></row> <row><t>1310469900</t><v>4.2312286165e+01</v><v>5.2390588332e+01</v><v>9.4702874497e+01</v></row> <row><t>1310470200</t><v>4.2603794982e+01</v><v>5.1598861493e+01</v><v>9.4202656475e+01</v></row> <row><t>1310470500</t><v>3.8238751290e+01</v><v>4.5312089966e+01</v><v>8.3550841256e+01</v></row> <row><t>1310470800</t><v>1.7949961224e+01</v><v>2.1282058418e+01</v><v>3.9232019642e+01</v></row> <row><t>1310471100</t><v>1.2330371421e-01</v><v>4.6347832868e-01</v><v>5.8678204289e-01</v></row> <row><t>1310471400</t><v>1.6313260492e-01</v><v>5.4088119561e-01</v><v>7.0401380052e-01</v></row> <row><t>1310471700</t><v>NaN</v><v>NaN</v><v>NaN</v></row> </data> </xport>"; + Object output = unmarshal(ServerStats.class, cpuUsageData, false); + if(output instanceof Status) { + throw new GlusterRuntimeException(((Status)output).toString()); + } + return (ServerStats) output; + } + + private ServerStats getFirstOnlineServerCPUStats(List<String> serverNames, boolean removeServerOnError, boolean removeOnlineServer) { + for(String serverName : serverNames) { + try { + ServerStats stats = fetchCPUUsageData(serverName); + if(removeOnlineServer) { + serverNames.remove(serverName); + } + } catch(Exception e) { + // server might be offline - continue with next one + logger.warn("Couldn't fetch CPU stats from server [" + serverName + "]!", e); + if(removeServerOnError) { + serverNames.remove(serverName); + } + continue; + } + } + throw new GlusterRuntimeException("All servers offline!"); + } + + public Object fetchAggregatedCPUStats(List<String> serverNames) { + if(serverNames == null || serverNames.size() == 0) { + throw new GlusterRuntimeException("No server names passed to fetchAggregaredCPUUsageData!"); + } + + ServerStats firstServerStats = getFirstOnlineServerCPUStats(serverNames, true, true); + + ServerStats aggregatedStats = new ServerStats(firstServerStats); + aggregateCPUStats(serverNames, aggregatedStats); + return aggregatedStats; + } + + private void aggregateCPUStats(List<String> serverNames, ServerStats aggregatedStats) { + int[][] dataCount = new int[aggregatedStats.getMetadata().getRowCount()][aggregatedStats.getMetadata() + .getLegend().size()]; + + for (String serverName : serverNames) { + ServerStats serverStats; + try { + serverStats = fetchCPUUsageData(serverName); + } catch(Exception e) { + // server might be offline - continue with next one + logger.warn("Couldn't fetch CPU stats from server [" + serverName + "]!", e); + continue; + } + List<ServerStatsRow> serverStatsRows = addServerStats(serverStats, aggregatedStats, dataCount); + } + + List<ServerStatsRow> rows = aggregatedStats.getRows(); + for(int rowNum = 0; rowNum < rows.size(); rowNum++) { + List<Double> data = rows.get(rowNum).getUsageData(); + for(int columnNum = 0; columnNum < data.size(); columnNum++) { + data.set(columnNum, data.get(columnNum) / dataCount[rowNum][columnNum]); + } + } + } + + /** + * + * @param statsToBeAdded + * @param targetStats + * @param dataCount Each element of this matrix will be incremented for every valid element added + * @return + */ + private List<ServerStatsRow> addServerStats(ServerStats statsToBeAdded, ServerStats targetStats, int[][] dataCount) { + List<ServerStatsRow> serverStatsRows = statsToBeAdded.getRows(); + for (int rowNum = 0; rowNum < serverStatsRows.size() + && rowNum < targetStats.getMetadata().getRowCount(); rowNum++) { + ServerStatsRow row = serverStatsRows.get(rowNum); + List<Double> rowData = row.getUsageData(); + + List<Double> aggregatedStatsRowData = targetStats.getRows().get(rowNum).getUsageData(); + for(int i = 1; i < targetStats.getMetadata().getLegend().size(); i++) { + // Add the data + Double data = rowData.get(i); + if(!data.isNaN()) { + // data is available. add it. + aggregatedStatsRowData.set(i, aggregatedStatsRowData.get(i) + data); + // increment record count. this will be used for calculating average of aggregated data. + dataCount[rowNum][i]++; + } + } + } + return serverStatsRows; + } + + public static void main(String[] args) { + ServerStats stats = new ServerUtil().fetchCPUUsageData("s1"); + System.out.println(stats.getMetadata().getLegend()); + } } |
