/******************************************************************************* * Copyright (c) 2006-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 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 General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see * <http://www.gnu.org/licenses/>. *******************************************************************************/ package org.gluster.storage.management.console.views; import java.lang.reflect.InvocationTargetException; import java.util.ArrayList; import java.util.List; import org.eclipse.core.runtime.IProgressMonitor; import org.eclipse.jface.dialogs.MessageDialog; import org.eclipse.jface.dialogs.ProgressMonitorDialog; import org.eclipse.jface.layout.TableColumnLayout; import org.eclipse.jface.operation.IRunnableWithProgress; import org.eclipse.jface.preference.IPreferenceStore; import org.eclipse.jface.util.IPropertyChangeListener; import org.eclipse.jface.util.PropertyChangeEvent; import org.eclipse.jface.viewers.ArrayContentProvider; import org.eclipse.jface.viewers.ColumnWeightData; import org.eclipse.jface.viewers.TableViewer; import org.eclipse.swt.SWT; import org.eclipse.swt.custom.CLabel; import org.eclipse.swt.graphics.Point; import org.eclipse.swt.layout.FillLayout; 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.swt.widgets.ProgressBar; import org.eclipse.swt.widgets.Table; import org.eclipse.swt.widgets.TableColumn; import org.eclipse.ui.forms.widgets.FormToolkit; import org.eclipse.ui.forms.widgets.ScrolledForm; import org.eclipse.ui.part.ViewPart; import org.gluster.storage.management.client.GlusterServersClient; import org.gluster.storage.management.console.Activator; import org.gluster.storage.management.console.ConsoleConstants; import org.gluster.storage.management.console.GlusterDataModelManager; import org.gluster.storage.management.console.IImageKeys; import org.gluster.storage.management.console.NetworkInterfaceTableLabelProvider; import org.gluster.storage.management.console.preferences.PreferenceConstants; import org.gluster.storage.management.console.toolbar.GlusterToolbarManager; import org.gluster.storage.management.console.utils.ChartUtil; import org.gluster.storage.management.console.utils.ChartUtil.ChartPeriodLinkListener; import org.gluster.storage.management.console.utils.GUIHelper; import org.gluster.storage.management.console.utils.GlusterLogger; import org.gluster.storage.management.core.model.ClusterListener; import org.gluster.storage.management.core.model.DefaultClusterListener; import org.gluster.storage.management.core.model.Event; import org.gluster.storage.management.core.model.Event.EVENT_TYPE; import org.gluster.storage.management.core.model.GlusterServer; import org.gluster.storage.management.core.model.Server.SERVER_STATUS; import org.gluster.storage.management.core.model.ServerStats; import org.gluster.storage.management.core.utils.NumberUtil; import com.richclientgui.toolbox.gauges.CoolGauge; public class GlusterServerSummaryView extends ViewPart { public static final String ID = GlusterServerSummaryView.class.getName(); private static final GUIHelper guiHelper = GUIHelper.getInstance(); private final FormToolkit toolkit = new FormToolkit(Display.getCurrent()); private ScrolledForm form; private GlusterServer server; private ClusterListener clusterListener; private static final GlusterLogger logger = GlusterLogger.getInstance(); private static final IPreferenceStore preferenceStore = Activator.getDefault().getPreferenceStore(); public enum NETWORK_INTERFACE_TABLE_COLUMN_INDICES { INTERFACE, MODEL, SPEED, IP_ADDRESS, NETMASK, GATEWAY }; private static final String[] NETWORK_INTERFACE_TABLE_COLUMN_NAMES = { "Interface", "Model", "Speed", "IP Address", "Netmask", "Gateway" }; private CoolGauge cpuGauge; private IPropertyChangeListener propertyChangeListener; private Composite cpuUsageSection; private Composite networkUsageSection; private Composite memoryUsageSection; private static final ChartUtil chartUtil = ChartUtil.getInstance(); private Composite serverSummarySection; private Label numCpus; private ProgressBar memoryUsageBar; private ProgressBar diskUsageBar; private CLabel lblServerStatus; @Override public void createPartControl(Composite parent) { if (server == null) { server = guiHelper.getSelectedEntity(getSite(), GlusterServer.class); } setPartName("Summary"); createSections(parent); createListeners(); } private void createListeners() { // Refresh the server details whenever the server has changed createClusterListener(); GlusterDataModelManager.getInstance().addClusterListener(clusterListener); createPropertyChangeListener(); preferenceStore.addPropertyChangeListener(propertyChangeListener); } private void createPropertyChangeListener() { propertyChangeListener = new IPropertyChangeListener() { @Override public void propertyChange(PropertyChangeEvent event) { String propertyName = event.getProperty(); if(propertyName.equals(PreferenceConstants.P_CPU_CHART_PERIOD)) { refreshCpuChart(); } else if(propertyName.equals(PreferenceConstants.P_MEM_CHART_PERIOD)) { refreshMemoryChart(); } else if (propertyName.equals(PreferenceConstants.P_NETWORK_CHART_PERIOD) || propertyName.equals(PreferenceConstants.P_DEFAULT_NETWORK_INTERFACE_PFX + server.getName())) { refreshNetworkChart(); } } }; } private void createClusterListener() { final GlusterToolbarManager toolbarManager = new GlusterToolbarManager(getSite().getWorkbenchWindow()); final GlusterServer thisServer = server; clusterListener = new DefaultClusterListener() { @Override public void serverChanged(GlusterServer server, Event event) { if (event.getEventType() == EVENT_TYPE.GLUSTER_SERVER_CHANGED && server == thisServer) { updateServerDetails(); toolbarManager.updateToolbar(server); refreshCharts(); } } }; } private void refreshCharts() { refreshCpuChart(); refreshMemoryChart(); refreshNetworkChart(); } private void refreshNetworkChart() { guiHelper.clearSection(networkUsageSection); String statsPeriod = preferenceStore.getString(PreferenceConstants.P_NETWORK_CHART_PERIOD); String networkInterface = preferenceStore.getString(PreferenceConstants.P_DEFAULT_NETWORK_INTERFACE_PFX + server.getName()); if(networkInterface == null || networkInterface.isEmpty()) { networkInterface = server.getNetworkInterfaces().get(0).getName(); } ServerStats stats = new GlusterServersClient().getNetworkStats(server.getName(), networkInterface, statsPeriod); chartUtil.refreshChartSection(toolkit, networkUsageSection, stats, statsPeriod, "KiB/s", -1, 5, chartUtil.new NetworkChartPeriodLinkListener(server, statsPeriod, toolkit), 2); } private void refreshMemoryChart() { guiHelper.clearSection(memoryUsageSection); String statsPeriod = preferenceStore.getString(PreferenceConstants.P_MEM_CHART_PERIOD); ServerStats stats = new GlusterServersClient().getMemoryStats(server.getName(), statsPeriod); chartUtil.refreshChartSection(toolkit, memoryUsageSection, stats, statsPeriod, "%", 100, 4, chartUtil.new MemoryChartPeriodLinkListener(server.getName(), statsPeriod, toolkit), 0); } private void refreshCpuChart() { guiHelper.clearSection(cpuUsageSection); String statsPeriod = preferenceStore.getString(PreferenceConstants.P_CPU_CHART_PERIOD); ServerStats stats = new GlusterServersClient().getCpuStats(server.getName(), statsPeriod); chartUtil.refreshChartSection(toolkit, cpuUsageSection, stats, statsPeriod, "%", 100, 4, chartUtil.new CpuChartPeriodLinkListener(server.getName(), statsPeriod, toolkit), 2); } private void updateServerDetails() { // TODO: Update the server details (cpu usage, memory usage) populateServerSummarySection(server); } @Override public void dispose() { super.dispose(); GlusterDataModelManager.getInstance().removeClusterListener(clusterListener); preferenceStore.removePropertyChangeListener(propertyChangeListener); } private void createMemoryUsageSection() { String memStatsPeriod = preferenceStore.getString(PreferenceConstants.P_MEM_CHART_PERIOD); memoryUsageSection = guiHelper.createSection(form, toolkit, "Memory Usage", null, 1, false); ServerStats stats; try { stats = new GlusterServersClient().getMemoryStats(server.getName(), memStatsPeriod); } catch(Exception e) { logger.error("Couldn't fetch memory usage statistics for server [" + server.getName() + "]", e); toolkit.createLabel(memoryUsageSection, "Couldn't fetch memory usage statistics for server [" + server.getName() + "]! Error: [" + e.getMessage() + "]"); return; } // in case of memory usage, there are four elements in usage data: user, free, cache, buffer and total. we use "user". ChartUtil chartUtil = ChartUtil.getInstance(); chartUtil.createAreaChart(toolkit, memoryUsageSection, stats, 0, "%", chartUtil .getTimestampFormatForPeriod(memStatsPeriod), chartUtil.new MemoryChartPeriodLinkListener(server.getName(), memStatsPeriod, toolkit), 100, 4); } private void createCPUUsageSection() { String cpuStatsPeriod = preferenceStore.getString(PreferenceConstants.P_CPU_CHART_PERIOD); cpuUsageSection = guiHelper.createSection(form, toolkit, "CPU Usage", null, 1, false); ServerStats stats; try { stats = new GlusterServersClient().getCpuStats(server.getName(), cpuStatsPeriod); } catch(Exception e) { logger.error("Couldn't fetch CPU usage statistics for server [" + server.getName() + "]", e); toolkit.createLabel(cpuUsageSection, "Couldn't fetch CPU usage statistics for server [" + server.getName() + "]! Error: [" + e.getMessage() + "]"); return; } // in case of CPU usage, there are three elements in usage data: user, system and total. we use total. chartUtil.createAreaChart(toolkit, cpuUsageSection, stats, 2, "%", chartUtil .getTimestampFormatForPeriod(cpuStatsPeriod), chartUtil.new CpuChartPeriodLinkListener(server.getName(), cpuStatsPeriod, toolkit), 100, 4); } private void createNetworkUsageSection() { final String networkStatsPeriod = preferenceStore.getString(PreferenceConstants.P_NETWORK_CHART_PERIOD); networkUsageSection = guiHelper.createSection(form, toolkit, "Network Usage", null, 1, false); String networkInterface = server.getNetworkInterfaces().get(0).getName(); ServerStats stats; try { stats = new GlusterServersClient().getNetworkStats(server.getName(), networkInterface, networkStatsPeriod); } catch(Exception e) { logger.error("Couldn't fetch Network usage statistics for server [" + server.getName() + "] network interface [" + networkInterface + "]", e); toolkit.createLabel(networkUsageSection, "Couldn't fetch CPU usage statistics for server [" + server.getName() + "]! Error: [" + e.getMessage() + "]"); return; } // in case of network usage, there are three elements in usage data: received, transmitted and total. we use total. final ChartUtil chartUtil = ChartUtil.getInstance(); final ChartPeriodLinkListener networkChartPeriodLinkListener = chartUtil.new NetworkChartPeriodLinkListener(server, networkStatsPeriod, toolkit); chartUtil.createAreaChart(toolkit, networkUsageSection, stats, 2, "KiB/s", chartUtil .getTimestampFormatForPeriod(networkStatsPeriod), networkChartPeriodLinkListener , -1, 5); } 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) { try { new ProgressMonitorDialog(getSite().getShell()).run(false, false, new IRunnableWithProgress() { @Override public void run(IProgressMonitor monitor) throws InvocationTargetException, InterruptedException { monitor.beginTask("Creating Server Summary View", 4); monitor.setTaskName("Creating Memory Usage Section"); createMemoryUsageSection(); monitor.worked(1); monitor.setTaskName("Creating Network Usage Section"); createNetworkUsageSection(); monitor.worked(1); monitor.setTaskName("Creating CPU Usage Section"); createCPUUsageSection(); monitor.worked(1); monitor.setTaskName("Creating Network Interfaces Section"); createNetworkInterfacesSection(server, toolkit, form); monitor.worked(1); monitor.done(); } }); } catch (Exception e) { String errMsg = "Exception while creating the Gluster Server Summary View : [" + e.getMessage() + "]"; logger.error(errMsg, e); MessageDialog.openError(getSite().getShell(), ConsoleConstants.CONSOLE_TITLE, errMsg); } } parent.layout(); // IMP: lays out the form properly } private void createServerSummarySection(GlusterServer server, FormToolkit toolkit, final ScrolledForm form) { serverSummarySection = guiHelper.createSection(form, toolkit, "Summary", null, 2, false); // toolkit.createLabel(section, "Preferred Network: ", SWT.NONE); // toolkit.createLabel(section, server.getPreferredNetworkInterface().getName(), SWT.NONE); if (server.isOnline()) { toolkit.createLabel(serverSummarySection, "Number of CPUs: ", SWT.NONE); numCpus = toolkit.createLabel(serverSummarySection, "" + server.getNumOfCPUs(), SWT.NONE); toolkit.createLabel(serverSummarySection, "% CPU Usage (avg): ", SWT.NONE); cpuGauge = new CoolGauge(serverSummarySection, guiHelper.getImage(IImageKeys.GAUGE_SMALL)); toolkit.createLabel(serverSummarySection, "Memory Usage: ", SWT.NONE); memoryUsageBar = new ProgressBar(serverSummarySection, SWT.SMOOTH); // toolkit.createLabel(section, "Memory Usage: ", SWT.NONE); // final CoolProgressBar bar = new CoolProgressBar(section,SWT.HORIZONTAL, // guiHelper.getImage(IImageKeys.PROGRESS_BAR_LEFT), // guiHelper.getImage(IImageKeys.PROGRESS_BAR_FILLED), // guiHelper.getImage(IImageKeys.PROGRESS_BAR_EMPTY), // guiHelper.getImage(IImageKeys.PROGRESS_BAR_RIGHT)); // bar.updateProgress(server.getMemoryInUse() / server.getTotalMemory()); // toolkit.createLabel(section, "Total Disk Space (GB): ", SWT.NONE); // toolkit.createLabel(section, online ? "" + server.getTotalDiskSpace() : "NA", SWT.NONE); // // toolkit.createLabel(section, "Disk Space in Use (GB): ", SWT.NONE); // toolkit.createLabel(section, online ? "" + server.getDiskSpaceInUse() : "NA", SWT.NONE); toolkit.createLabel(serverSummarySection, "Disk Usage: ", SWT.NONE); diskUsageBar = new ProgressBar(serverSummarySection, SWT.SMOOTH); } toolkit.createLabel(serverSummarySection, "Status: ", SWT.NONE); lblServerStatus = new CLabel(serverSummarySection, SWT.NONE); populateServerSummarySection(server); } private void populateServerSummarySection(GlusterServer server) { if (server.isOnline()) { numCpus.setText("" + server.getNumOfCPUs()); numCpus.redraw(); cpuGauge.setLayoutData(new GridData(SWT.BEGINNING, SWT.BEGINNING, false, false)); cpuGauge.setGaugeNeedleColour(Display.getDefault().getSystemColor(SWT.COLOR_RED)); cpuGauge.setGaugeNeedleWidth(2); cpuGauge.setGaugeNeedlePivot(new Point(66, 65)); cpuGauge.setPoints(getPnts()); cpuGauge.setLevel(server.getCpuUsage() / 100); cpuGauge.setToolTipText(server.getCpuUsage() + "%"); cpuGauge.redraw(); memoryUsageBar.setMinimum(0); memoryUsageBar.setMaximum((int) Math.round(server.getTotalMemory())); memoryUsageBar.setSelection((int) Math.round(server.getMemoryInUse())); memoryUsageBar.setToolTipText("Total: " + NumberUtil.formatNumber((server.getTotalMemory() / 1024)) + "GB, In Use: " + NumberUtil.formatNumber((server.getMemoryInUse() / 1024)) + "GB"); diskUsageBar.setMinimum(0); diskUsageBar.setMaximum((int) Math.round(server.getTotalDiskSpace())); diskUsageBar.setSelection((int) Math.round(server.getDiskSpaceInUse())); diskUsageBar.setToolTipText("Total: " + NumberUtil.formatNumber((server.getTotalDiskSpace() / 1024)) + "GB, In Use: " + NumberUtil.formatNumber((server.getDiskSpaceInUse() / 1024)) + "GB"); } lblServerStatus.setText(server.getStatusStr()); lblServerStatus.setImage(server.getStatus() == GlusterServer.SERVER_STATUS.ONLINE ? guiHelper .getImage(IImageKeys.STATUS_ONLINE_16x16) : guiHelper.getImage(IImageKeys.STATUS_OFFLINE_16x16)); toolkit.adapt(lblServerStatus, true, true); serverSummarySection.layout(); form.reflow(true); } private List<Point> getPnts() { final List<Point> pnts = new ArrayList<Point>(); pnts.add(new Point(47, 98)); pnts.add(new Point(34, 84)); pnts.add(new Point(29, 65)); pnts.add(new Point(33, 48)); pnts.add(new Point(48, 33)); pnts.add(new Point(66, 28)); pnts.add(new Point(83, 32)); pnts.add(new Point(98, 47)); pnts.add(new Point(103, 65)); pnts.add(new Point(98, 83)); pnts.add(new Point(84, 98)); return pnts; } private Composite createNetworkInterfacesSection(GlusterServer server, FormToolkit toolkit, ScrolledForm form) { final Composite section = guiHelper.createSection(form, toolkit, "Network Interfaces", null, 1, false); createNetworkInterfacesTableViewer(createTableViewerComposite(section), server); // Hyperlink changePreferredNetworkLink = toolkit.createHyperlink(section, "Change Preferred Network", // SWT.NONE); // changePreferredNetworkLink.addHyperlinkListener(new HyperlinkAdapter() { // // @Override // public void linkActivated(HyperlinkEvent e) { // new MessageDialog( // section.getShell(), // "Gluster Storage Platform", // guiHelper.getImage(IImageKeys.SERVER), // "This will show additional controls to help user choose a new network interface. TO BE IMPLEMENTED.", // MessageDialog.INFORMATION, new String[] { "OK" }, 0).open(); // } // }); return section; } private TableViewer createNetworkInterfacesTableViewer(final Composite parent, GlusterServer server) { TableViewer tableViewer = new TableViewer(parent, SWT.FLAT | SWT.FULL_SELECTION | SWT.MULTI); // TableViewer tableViewer = new TableViewer(parent, SWT.FLAT | SWT.FULL_SELECTION | SWT.MULTI); tableViewer.setLabelProvider(new NetworkInterfaceTableLabelProvider()); tableViewer.setContentProvider(new ArrayContentProvider()); setupNetworkInterfaceTable(parent, tableViewer.getTable()); tableViewer.setInput(server.getNetworkInterfaces().toArray()); return tableViewer; } private void setupNetworkInterfaceTable(Composite parent, Table table) { table.setHeaderVisible(true); table.setLinesVisible(false); TableColumnLayout tableColumnLayout = guiHelper.createTableColumnLayout(table, NETWORK_INTERFACE_TABLE_COLUMN_NAMES); parent.setLayout(tableColumnLayout); setColumnProperties(table, NETWORK_INTERFACE_TABLE_COLUMN_INDICES.INTERFACE, SWT.CENTER, 70); setColumnProperties(table, NETWORK_INTERFACE_TABLE_COLUMN_INDICES.MODEL, SWT.CENTER, 70); setColumnProperties(table, NETWORK_INTERFACE_TABLE_COLUMN_INDICES.SPEED, SWT.CENTER, 70); setColumnProperties(table, NETWORK_INTERFACE_TABLE_COLUMN_INDICES.IP_ADDRESS, SWT.CENTER, 100); setColumnProperties(table, NETWORK_INTERFACE_TABLE_COLUMN_INDICES.NETMASK, SWT.CENTER, 70); setColumnProperties(table, NETWORK_INTERFACE_TABLE_COLUMN_INDICES.GATEWAY, SWT.CENTER, 70); } private Composite createTableViewerComposite(Composite parent) { Composite tableViewerComposite = new Composite(parent, SWT.NO); tableViewerComposite.setLayout(new FillLayout(SWT.HORIZONTAL)); GridData tableLayoutData = new GridData(SWT.FILL, SWT.FILL, true, false); tableLayoutData.widthHint = 400; tableLayoutData.minimumWidth = 400; // tableLayoutData.grabExcessHorizontalSpace = true; tableViewerComposite.setLayoutData(tableLayoutData); return tableViewerComposite; } /** * Sets properties for alignment and weight of given column of given table * * @param table * @param columnIndex * @param alignment * @param weight */ public void setColumnProperties(Table table, NETWORK_INTERFACE_TABLE_COLUMN_INDICES columnIndex, int alignment, int weight) { TableColumn column = table.getColumn(columnIndex.ordinal()); column.setAlignment(alignment); TableColumnLayout tableColumnLayout = (TableColumnLayout) table.getParent().getLayout(); tableColumnLayout.setColumnData(column, new ColumnWeightData(weight)); } @Override public void setFocus() { form.setFocus(); } }