/******************************************************************************* * 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.util.List; import org.eclipse.jface.fieldassist.ControlDecoration; import org.eclipse.jface.preference.IPreferenceStore; import org.eclipse.jface.util.IPropertyChangeListener; import org.eclipse.jface.util.PropertyChangeEvent; 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.Control; 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; import org.eclipse.ui.forms.widgets.ImageHyperlink; import org.eclipse.ui.forms.widgets.ScrolledForm; import org.eclipse.ui.handlers.IHandlerService; import org.eclipse.ui.part.ViewPart; import org.gluster.storage.management.console.Activator; import org.gluster.storage.management.console.GlusterDataModelManager; import org.gluster.storage.management.console.IImageKeys; import org.gluster.storage.management.console.actions.ActionConstants; import org.gluster.storage.management.console.preferences.PreferenceConstants; import org.gluster.storage.management.console.utils.ChartUtil; import org.gluster.storage.management.console.utils.ChartViewerComposite; import org.gluster.storage.management.console.utils.GUIHelper; import org.gluster.storage.management.console.utils.ChartUtil.ChartPeriodLinkListener; import org.gluster.storage.management.core.constants.CoreConstants; import org.gluster.storage.management.core.constants.GlusterConstants; import org.gluster.storage.management.core.model.Alert; import org.gluster.storage.management.core.model.Cluster; import org.gluster.storage.management.core.model.ClusterListener; import org.gluster.storage.management.core.model.DefaultClusterListener; import org.gluster.storage.management.core.model.EntityGroup; import org.gluster.storage.management.core.model.GlusterDataModel; import org.gluster.storage.management.core.model.GlusterServer; import org.gluster.storage.management.core.model.Server; import org.gluster.storage.management.core.model.ServerStats; import org.gluster.storage.management.core.model.Status; import org.gluster.storage.management.core.model.TaskInfo; import org.gluster.storage.management.core.model.Server.SERVER_STATUS; /** * */ public class ClusterSummaryView extends ViewPart { public static final String ID = ClusterSummaryView.class.getName(); private static final GUIHelper guiHelper = GUIHelper.getInstance(); private final FormToolkit toolkit = new FormToolkit(Display.getCurrent()); private ScrolledForm form; private Cluster cluster; private Composite cpuChartSection; private Composite networkChartSection; private GlusterDataModel model = GlusterDataModelManager.getInstance().getModel(); private ClusterListener clusterListener; private static final IPreferenceStore preferenceStore = Activator.getDefault().getPreferenceStore(); private Composite alertsSection; private Composite tasksSection; private static final ChartUtil chartUtil = ChartUtil.getInstance(); private IPropertyChangeListener propertyChangeListener; private Label onlineServerCountLabel; private Label offlineServerCountLabel; /* * (non-Javadoc) * * @see org.eclipse.ui.part.WorkbenchPart#createPartControl(org.eclipse.swt.widgets.Composite) */ @Override public void createPartControl(Composite parent) { if (cluster == null) { cluster = model.getCluster(); } setPartName("Summary"); createSections(parent); createListeners(); } private void createListeners() { createClusterListener(); GlusterDataModelManager.getInstance().addClusterListener(clusterListener); createPropertyChangeListener(); preferenceStore.addPropertyChangeListener(propertyChangeListener ); } private void createPropertyChangeListener() { propertyChangeListener = new IPropertyChangeListener() { @Override public void propertyChange(PropertyChangeEvent event) { String preferenceName = event.getProperty(); GlusterDataModelManager modelManager = GlusterDataModelManager.getInstance(); if(preferenceName.equals(PreferenceConstants.P_CPU_AGGREGATED_CHART_PERIOD)) { modelManager.initializeAggregatedCpuStats(cluster); String cpuStatsPeriod = (String)event.getNewValue(); refreshChartSection(cpuChartSection, cluster.getAggregatedCpuStats(), cpuStatsPeriod, "%", 100, 4, chartUtil.new CpuChartPeriodLinkListener(null, cpuStatsPeriod, toolkit), 2); } else if(preferenceName.equals(PreferenceConstants.P_NETWORK_AGGREGATED_CHART_PERIOD)) { modelManager.initializeAggregatedNetworkStats(cluster); String networkStatsPeriod = (String)event.getNewValue(); refreshChartSection(networkChartSection, cluster.getAggregatedNetworkStats(), networkStatsPeriod, "KiB/s", -1, 4, chartUtil.new NetworkChartPeriodLinkListener(null, networkStatsPeriod, toolkit), 2); } } }; } private void createClusterListener() { clusterListener = new DefaultClusterListener() { @Override public void aggregatedStatsChanged() { super.aggregatedStatsChanged(); refreshCharts(); populateOnlineOfflineServerCount(); } @Override public void alertsGenerated() { super.alertsGenerated(); guiHelper.clearSection(alertsSection); populateAlerts(); } @Override public void taskAdded(TaskInfo taskInfo) { super.taskAdded(taskInfo); updateTaskSection(); } @Override public void taskRemoved(TaskInfo taskInfo) { super.taskRemoved(taskInfo); updateTaskSection(); } @Override public void taskUpdated(TaskInfo taskInfo) { super.taskUpdated(taskInfo); updateTaskSection(); } private void updateTaskSection() { guiHelper.clearSection(tasksSection); populateTasksSection(); } }; } @Override public void dispose() { super.dispose(); GlusterDataModelManager.getInstance().removeClusterListener(clusterListener); preferenceStore.removePropertyChangeListener(propertyChangeListener); } private void refreshCharts() { String cpuStatsPeriod = preferenceStore.getString(PreferenceConstants.P_CPU_AGGREGATED_CHART_PERIOD); String networkStatsPeriod = preferenceStore.getString(PreferenceConstants.P_NETWORK_AGGREGATED_CHART_PERIOD); refreshChartSection(cpuChartSection, cluster.getAggregatedCpuStats(), cpuStatsPeriod, "%", 100, 4, chartUtil.new CpuChartPeriodLinkListener(null, cpuStatsPeriod, toolkit), 2); refreshChartSection(networkChartSection, cluster.getAggregatedNetworkStats(), networkStatsPeriod, "KiB/s", -1, 4, chartUtil.new NetworkChartPeriodLinkListener(null, networkStatsPeriod, toolkit), 2); } private int getServerCountByStatus(Cluster cluster, SERVER_STATUS status) { int count = 0; for (GlusterServer server : cluster.getServers()) { if (server.getStatus() == status) { count++; } } return count; } private void createServersSection() { Composite section = guiHelper.createSection(form, toolkit, "Servers", null, 2, false); toolkit.createLabel(section, "Online : "); onlineServerCountLabel = toolkit.createLabel(section, ""); toolkit.createLabel(section, "Offline : "); offlineServerCountLabel = toolkit.createLabel(section, ""); populateOnlineOfflineServerCount(); } private void populateOnlineOfflineServerCount() { int onlineServerCount = getServerCountByStatus(cluster, SERVER_STATUS.ONLINE); int offlineServerCount = getServerCountByStatus(cluster, SERVER_STATUS.OFFLINE); onlineServerCountLabel.setText("" + onlineServerCount); onlineServerCountLabel.setForeground(Display.getCurrent().getSystemColor(SWT.COLOR_DARK_GREEN)); offlineServerCountLabel.setText("" + offlineServerCount); offlineServerCountLabel.setForeground(Display.getCurrent().getSystemColor(SWT.COLOR_RED)); } private void createDiskSpaceSection() { Composite section = guiHelper.createSection(form, toolkit, "Disk Space", null, 3, false); if (cluster.getServers().size() == 0) { toolkit.createLabel(section, "This section will be populated after at least" + CoreConstants.NEWLINE + "one server is added to the storage cloud."); return; } double totalDiskSpace = cluster.getTotalDiskSpace(); double diskSpaceInUse = cluster.getDiskSpaceInUse(); Double[] values = new Double[] { diskSpaceInUse / 1024, (totalDiskSpace - diskSpaceInUse) / 1024 }; createDiskSpaceChart(section, values); } private void createDiskSpaceChart(Composite section, Double[] values) { String[] categories = new String[] { "Used Space (GB)", "Free Space (GB)" }; ChartViewerComposite chartViewerComposite = new ChartViewerComposite(section, SWT.NONE, categories, values); GridData data = new GridData(SWT.FILL, SWT.FILL, false, false); data.widthHint = 400; data.heightHint = 180; data.verticalAlignment = SWT.CENTER; chartViewerComposite.setLayoutData(data); } private void createAlertsSection() { alertsSection = guiHelper.createSection(form, toolkit, "Alerts", null, 1, false); populateAlerts(); } private void populateAlerts() { List<Alert> alerts = cluster.getAlerts(); for (Alert alert : alerts) { addAlertLabel(alertsSection, alert); } alertsSection.layout(); form.reflow(true); } private void addAlertLabel(Composite section, Alert alert) { CLabel lblAlert = new CLabel(section, SWT.FLAT); GridData layoutData = new GridData(); layoutData.widthHint = 400; layoutData.horizontalIndent = 20; lblAlert.setLayoutData(layoutData); Image alertImage = null; switch (alert.getType()) { case OFFLINE_VOLUME_BRICKS_ALERT: alertImage = guiHelper.getImage(IImageKeys.BRICK_OFFLINE_22x22); break; case DISK_USAGE_ALERT: alertImage = guiHelper.getImage(IImageKeys.LOW_DISK_SPACE_22x22); break; case OFFLINE_SERVERS_ALERT: alertImage = guiHelper.getImage(IImageKeys.SERVER_OFFLINE_22x22); break; case MEMORY_USAGE_ALERT: alertImage = guiHelper.getImage(IImageKeys.MEMORY_USAGE_ALERT_22x22); break; case CPU_USAGE_ALERT: alertImage = guiHelper.getImage(IImageKeys.SERVER_WARNING_22x22); break; case OFFLINE_VOLUME_ALERT: alertImage = guiHelper.getImage(IImageKeys.VOLUME_OFFLINE_22x22); break; } lblAlert.setText(alert.getMessage()); ControlDecoration dec = new ControlDecoration(lblAlert, SWT.LEFT); dec.setImage(alertImage); lblAlert.redraw(); } private void createActionsSection() { Composite section = guiHelper.createSection(form, toolkit, "Actions", null, 1, false); ImageHyperlink imageHyperlink = toolkit.createImageHyperlink(section, SWT.NONE); imageHyperlink.setText("Create Volume"); imageHyperlink.setImage(guiHelper.getImage(IImageKeys.CREATE_VOLUME_48x48)); imageHyperlink.addHyperlinkListener(new HyperlinkAdapter() { @Override public void linkActivated(HyperlinkEvent e) { IHandlerService hs = (IHandlerService) getSite().getService(IHandlerService.class); try { hs.executeCommand(ActionConstants.COMMAND_CREATE_VOLUME, null); } catch (Exception e1) { e1.printStackTrace(); } } }); imageHyperlink = toolkit.createImageHyperlink(section, SWT.NONE); imageHyperlink.setText("Add Server(s)"); imageHyperlink.setImage(guiHelper.getImage(IImageKeys.ADD_SERVER_48x48)); imageHyperlink.addHyperlinkListener(new HyperlinkAdapter() { @Override public void linkActivated(HyperlinkEvent e) { // Open the "discovered servers" view by selecting the corresponding entity in the navigation view EntityGroup<Server> autoDiscoveredServersEntityGroup = GlusterDataModelManager.getInstance().getModel() .getCluster().getEntityGroup(Server.class); NavigationView navigationView = (NavigationView) guiHelper.getView(NavigationView.ID); navigationView.selectEntity(autoDiscoveredServersEntityGroup); } }); } private void createSections(Composite parent) { form = guiHelper.setupForm(parent, toolkit, "Cluster Summary"); if (cluster.getServers().size() > 0 && (cluster.getAggregatedCpuStats().getRows() == null || cluster.getAggregatedNetworkStats().getRows() == null)) { // cluster has servers, but stats are null. Happens when user logs in to a new cluster, ' // and then adds the first server. GlusterDataModelManager.getInstance().initializeAggregatedCpuStats(cluster); GlusterDataModelManager.getInstance().initializeAggregatedNetworkStats(cluster); } createServersSection(); createDiskSpaceSection(); createCPUUsageSection(); createNetworkUsageSection(); createActionsSection(); createAlertsSection(); createTasksSection(); parent.layout(); // IMP: lays out the form properly } private Composite createAreaChartSection(ServerStats stats, String sectionTitle, int dataColumnIndex, String unit, String timestampFormat, ChartPeriodLinkListener listener, double maxValue, int chartLinkColumnCount) { Composite section = guiHelper.createSection(form, toolkit, sectionTitle, null, 1, false); if (cluster.getServers().size() == 0) { toolkit.createLabel(section, "This section will be populated after at least" + CoreConstants.NEWLINE + "one server is added to the storage cloud."); return section; } ChartUtil.getInstance().createAreaChart(toolkit, section, stats, dataColumnIndex, unit, timestampFormat, listener, maxValue, chartLinkColumnCount); return section; } private void createCPUUsageSection() { IPreferenceStore preferenceStore = Activator.getDefault().getPreferenceStore(); String cpuStatsPeriod = preferenceStore.getString(PreferenceConstants.P_CPU_AGGREGATED_CHART_PERIOD); // in case of CPU usage, there are three elements in usage data: user, system and total. we use total. cpuChartSection = createAreaChartSection(cluster.getAggregatedCpuStats(), "CPU Usage (Aggregated)", 2, "%", getTimestampFormatForPeriod(cpuStatsPeriod), chartUtil.new CpuChartPeriodLinkListener(null, cpuStatsPeriod, toolkit), 100, 4); } private String getTimestampFormatForPeriod(String statsPeriod) { if(statsPeriod.equals(GlusterConstants.STATS_PERIOD_1DAY)) { return "HH:mm"; } else if (statsPeriod.equals(GlusterConstants.STATS_PERIOD_1WEEK)) { return "dd-MMM HH:mm"; } else { return "dd-MMM"; } } private void createNetworkUsageSection() { IPreferenceStore preferenceStore = Activator.getDefault().getPreferenceStore(); String networkStatsPeriod = preferenceStore.getString(PreferenceConstants.P_NETWORK_AGGREGATED_CHART_PERIOD); // in case of network usage, there are three elements in usage data: received, transmitted and total. we use total. networkChartSection = createAreaChartSection(cluster.getAggregatedNetworkStats(), "Network Usage (Aggregated)", 2, "KiB/s", getTimestampFormatForPeriod(networkStatsPeriod), chartUtil.new NetworkChartPeriodLinkListener(null, networkStatsPeriod, toolkit), -1, 4); } private void createTasksSection() { tasksSection = guiHelper.createSection(form, toolkit, CoreConstants.RUNNING_TASKS, null, 1, false); populateTasksSection(); } private void populateTasksSection() { for (TaskInfo taskInfo : cluster.getTaskInfoList()) { if (taskInfo.getStatus().getCode() != Status.STATUS_CODE_SUCCESS) { addTaskLabel(tasksSection, taskInfo); } } tasksSection.layout(); form.reflow(true); } private void addTaskLabel(Composite section, TaskInfo taskInfo) { //TODO: create link and open the task progress view CLabel lblAlert = new CLabel(section, SWT.NONE); Image taskImage = null; switch(taskInfo.getType()) { case DISK_FORMAT: taskImage = guiHelper.getImage(IImageKeys.DISK_INITIALIZING_22x22); break; case BRICK_MIGRATE: taskImage = guiHelper.getImage(IImageKeys.BRICK_MIGRATE_22x22); break; case VOLUME_REBALANCE: taskImage = guiHelper.getImage(IImageKeys.VOLUME_REBALANCE_22x22); break; } String description = taskInfo.getDescription(); switch (taskInfo.getStatus().getCode()) { case Status.STATUS_CODE_PAUSE: description += " (paused)"; break; case Status.STATUS_CODE_COMMIT_PENDING: description += " (commit pending)"; break; case Status.STATUS_CODE_FAILURE: description += " (failed)"; break; } lblAlert.setText(description); lblAlert.setImage(taskImage); lblAlert.redraw(); } /* * (non-Javadoc) * * @see org.eclipse.ui.part.WorkbenchPart#setFocus() */ @Override public void setFocus() { if (form != null) { form.setFocus(); } } private void refreshChartSection(Composite section, ServerStats stats, String statsPeriod, String unit, double maxValue, int columnCount, ChartPeriodLinkListener linkListener, int dataColumnIndex) { if(stats == null) { return; } for (Control control : section.getChildren()) { if (!control.isDisposed()) { control.dispose(); } } chartUtil.createAreaChart(toolkit, section, stats, dataColumnIndex, unit, getTimestampFormatForPeriod(statsPeriod), linkListener, maxValue, columnCount); section.layout(); } }