diff options
Diffstat (limited to 'src')
16 files changed, 375 insertions, 113 deletions
diff --git a/src/com.gluster.storage.management.client/src/com/gluster/storage/management/client/DiscoveredServersClient.java b/src/com.gluster.storage.management.client/src/com/gluster/storage/management/client/DiscoveredServersClient.java index 6a22bf5f..eb6ef3a0 100644 --- a/src/com.gluster.storage.management.client/src/com/gluster/storage/management/client/DiscoveredServersClient.java +++ b/src/com.gluster.storage.management.client/src/com/gluster/storage/management/client/DiscoveredServersClient.java @@ -41,6 +41,7 @@ public class DiscoveredServersClient extends AbstractClient { return RESOURCE_NAME; } + @SuppressWarnings("rawtypes") private Object getDiscoveredServers(Boolean getDetails, Class responseClass) { MultivaluedMap<String, String> queryParams = new MultivaluedMapImpl(); queryParams.putSingle("details", getDetails.toString()); @@ -48,10 +49,12 @@ public class DiscoveredServersClient extends AbstractClient { return ((Response) fetchResource(queryParams, responseClass)).getData(); } + @SuppressWarnings("unchecked") public List<String> getDiscoveredServerNames() { return (List<String>) getDiscoveredServers(Boolean.FALSE, StringListResponse.class); } + @SuppressWarnings("unchecked") public List<Server> getDiscoveredServerDetails() { return (List<Server>) getDiscoveredServers(Boolean.TRUE, ServerListResponse.class); } 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 39141bc0..f44b24e5 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 @@ -26,17 +26,24 @@ package com.gluster.storage.management.core.constants; public class RESTConstants { // Volumes Resource public static final String RESOURCE_PATH_VOLUMES = "/cluster/volumes"; + public static final String SUBRESOURCE_DEFAULT_OPTIONS = "defaultoptions"; + public static final String SUBRESOURCE_OPTIONS = "options"; + public static final String SUBRESOURCE_LOGS = "logs"; + + public static final String FORM_PARAM_OPERATION = "operation"; public static final String FORM_PARAM_VALUE_START = "start"; public static final String FORM_PARAM_VALUE_STOP = "stop"; public static final String FORM_PARAM_OPTION_KEY = "key"; public static final String FORM_PARAM_VOLUME_NAME = "volumeName"; public static final String FORM_PARAM_OPTION_VALUE = "value"; + public static final String PATH_PARAM_VOLUME_NAME = "volumeName"; public static final String FORM_PARAM_DELETE_OPTION = "value"; - public static final String SUBRESOURCE_DEFAULT_OPTIONS = "defaultoptions"; - public static final String SUBRESOURCE_OPTIONS = "options"; + public static final String QUERY_PARAM_DISK_NAME = "diskName"; + public static final String QUERY_PARAM_LINE_COUNT = "lineCount"; + // Running tasks resource public static final String RESOURCE_PATH_RUNNING_TASKS = "/cluster/runningtasks"; public static final String RESOURCE_PATH_ALERTS = "/cluster/alerts"; diff --git a/src/com.gluster.storage.management.core/src/com/gluster/storage/management/core/model/LogMessage.java b/src/com.gluster.storage.management.core/src/com/gluster/storage/management/core/model/LogMessage.java index cc3aa043..d81b8d0f 100644 --- a/src/com.gluster.storage.management.core/src/com/gluster/storage/management/core/model/LogMessage.java +++ b/src/com.gluster.storage.management.core/src/com/gluster/storage/management/core/model/LogMessage.java @@ -20,14 +20,24 @@ package com.gluster.storage.management.core.model; import java.util.Date; +import javax.xml.bind.annotation.XmlRootElement; + import com.gluster.storage.management.core.utils.StringUtil; +@XmlRootElement public class LogMessage implements Filterable { private Date timestamp; private Disk disk; private String severity; private String message; + public LogMessage() { + } + + public LogMessage(String logMessage) { + // TODO: Parse the log message and extract fields + } + public Date getTimestamp() { return timestamp; } diff --git a/src/com.gluster.storage.management.core/src/com/gluster/storage/management/core/model/Status.java b/src/com.gluster.storage.management.core/src/com/gluster/storage/management/core/model/Status.java index 45a9842b..95075f78 100644 --- a/src/com.gluster.storage.management.core/src/com/gluster/storage/management/core/model/Status.java +++ b/src/com.gluster.storage.management.core/src/com/gluster/storage/management/core/model/Status.java @@ -59,6 +59,11 @@ public class Status { this.code = result.getExitValue(); this.message = result.getOutput(); } + + public Status(Exception e) { + this.code = STATUS_CODE_FAILURE; + this.message = e.getMessage(); + } @XmlElement(name = "code", type = Integer.class) public Integer getCode() { diff --git a/src/com.gluster.storage.management.core/src/com/gluster/storage/management/core/model/Volume.java b/src/com.gluster.storage.management.core/src/com/gluster/storage/management/core/model/Volume.java index 50966920..94b23179 100644 --- a/src/com.gluster.storage.management.core/src/com/gluster/storage/management/core/model/Volume.java +++ b/src/com.gluster.storage.management.core/src/com/gluster/storage/management/core/model/Volume.java @@ -72,12 +72,9 @@ public class Volume extends Entity { } // GlusterFS and NFS export is always enabled - // Note: logic needs to make NFS optional private Set<NAS_PROTOCOL> nasProtocols = new LinkedHashSet<NAS_PROTOCOL>(Arrays.asList(new NAS_PROTOCOL[] { NAS_PROTOCOL.GLUSTERFS, NAS_PROTOCOL.NFS })); - private String accessControlList = "*"; - public String getVolumeTypeStr() { return getVolumeTypeStr(getVolumeType()); } diff --git a/src/com.gluster.storage.management.core/src/com/gluster/storage/management/core/response/LogMessageListResponse.java b/src/com.gluster.storage.management.core/src/com/gluster/storage/management/core/response/LogMessageListResponse.java new file mode 100644 index 00000000..191334d3 --- /dev/null +++ b/src/com.gluster.storage.management.core/src/com/gluster/storage/management/core/response/LogMessageListResponse.java @@ -0,0 +1,42 @@ +/** + * + */ +package com.gluster.storage.management.core.response; + +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; + +import com.gluster.storage.management.core.model.LogMessage; +import com.gluster.storage.management.core.model.Status; + +@XmlRootElement(name = "response") +public class LogMessageListResponse extends AbstractResponse { + private List<LogMessage> logMessages = new ArrayList<LogMessage>(); + + public LogMessageListResponse() { + } + + public LogMessageListResponse(Status status, List<LogMessage> logMessages) { + setStatus(status); + setLogMessages(logMessages); + } + + @XmlElementWrapper(name = "logMessages") + @XmlElement(name = "logMessage", type = LogMessage.class) + public List<LogMessage> getLogMessages() { + return logMessages; + } + + public void setLogMessages(List<LogMessage> logMessages) { + this.logMessages = logMessages; + } + + @Override + public Object getData() { + return getLogMessages(); + } +} diff --git a/src/com.gluster.storage.management.core/src/com/gluster/storage/management/core/response/VolumeListResponse.java b/src/com.gluster.storage.management.core/src/com/gluster/storage/management/core/response/VolumeListResponse.java index fc1c9a6c..97085603 100644 --- a/src/com.gluster.storage.management.core/src/com/gluster/storage/management/core/response/VolumeListResponse.java +++ b/src/com.gluster.storage.management.core/src/com/gluster/storage/management/core/response/VolumeListResponse.java @@ -30,10 +30,6 @@ public class VolumeListResponse extends AbstractResponse { return this.volumes; } - /** - * @param volumes - * volumes to set - */ public void setVolumes(List<Volume> volumes) { this.volumes = volumes; } diff --git a/src/com.gluster.storage.management.gui.feature/feature.xml b/src/com.gluster.storage.management.gui.feature/feature.xml index 2448b3cc..7f99803e 100644 --- a/src/com.gluster.storage.management.gui.feature/feature.xml +++ b/src/com.gluster.storage.management.gui.feature/feature.xml @@ -772,4 +772,11 @@ fragment="true" unpack="false"/> + <plugin + id="org.apache.commons.lang" + download-size="0" + install-size="0" + version="0.0.0" + unpack="false"/> + </feature> diff --git a/src/com.gluster.storage.management.gui/META-INF/MANIFEST.MF b/src/com.gluster.storage.management.gui/META-INF/MANIFEST.MF index 2e59c854..076a2805 100644 --- a/src/com.gluster.storage.management.gui/META-INF/MANIFEST.MF +++ b/src/com.gluster.storage.management.gui/META-INF/MANIFEST.MF @@ -21,7 +21,8 @@ Require-Bundle: org.eclipse.ui;bundle-version="3.6.1", org.eclipse.birt.chart.device.swt;bundle-version="2.6.1", com.ibm.icu;bundle-version="4.2.1", com.richclientgui.rcptoolbox;bundle-version="1.0.5", - org.eclipse.core.resources + org.eclipse.core.resources, + org.apache.commons.lang;bundle-version="2.3.0" Bundle-RequiredExecutionEnvironment: JavaSE-1.6 Bundle-ActivationPolicy: lazy Bundle-ClassPath: . diff --git a/src/com.gluster.storage.management.gui/src/com/gluster/storage/management/gui/views/details/OptionKeyEditingSupport.java b/src/com.gluster.storage.management.gui/src/com/gluster/storage/management/gui/views/details/OptionKeyEditingSupport.java index a94ae25a..27dc8d4b 100644 --- a/src/com.gluster.storage.management.gui/src/com/gluster/storage/management/gui/views/details/OptionKeyEditingSupport.java +++ b/src/com.gluster.storage.management.gui/src/com/gluster/storage/management/gui/views/details/OptionKeyEditingSupport.java @@ -4,6 +4,7 @@ package com.gluster.storage.management.gui.views.details; import java.util.ArrayList; +import java.util.Iterator; import java.util.List; import java.util.Map; import java.util.Map.Entry; @@ -12,6 +13,7 @@ import org.eclipse.jface.viewers.CellEditor; import org.eclipse.jface.viewers.ColumnViewer; import org.eclipse.jface.viewers.ComboBoxCellEditor; import org.eclipse.jface.viewers.EditingSupport; +import org.eclipse.swt.SWT; import org.eclipse.swt.widgets.Composite; import com.gluster.storage.management.client.GlusterDataModelManager; @@ -42,7 +44,9 @@ public class OptionKeyEditingSupport extends EditingSupport { Map<String, String> volumeOptions = volume.getOptions(); for(VolumeOptionInfo optionInfo : defaults) { String optionName = optionInfo.getName(); - if(!volumeOptions.containsKey(optionName)) { + if(!volumeOptions.containsKey(optionName) || volumeOptions.get(optionName).isEmpty()) { + // key not set => available for setting + // value not set => this is the row being edited keys.add(optionName); } } @@ -61,7 +65,7 @@ public class OptionKeyEditingSupport extends EditingSupport { return; } - // value has changed. set volume option at back-end and update model accordingly + // value has changed. set new value and refresh the viewer. volume.getOptions().remove(oldEntry.getKey()); volume.setOption(newKey, ""); getViewer().refresh(); @@ -69,16 +73,49 @@ public class OptionKeyEditingSupport extends EditingSupport { @Override protected Object getValue(Object element) { - return cellEditor.getValue(); + Entry<String, String> entryBeingAdded = getEntryBeingAdded(); + if(entryBeingAdded == null) { + return cellEditor.getValue(); + } + + if(entryBeingAdded.getKey().isEmpty()) { + // editing just about to start. set first element as default. + return 0; + } + + return getIndexOfEntry(entryBeingAdded); } @Override protected CellEditor getCellEditor(Object element) { allowedKeys = getAllowedKeys(); - cellEditor = new ComboBoxCellEditor((Composite) viewer.getControl(), allowedKeys); + cellEditor = new ComboBoxCellEditor((Composite) viewer.getControl(), allowedKeys, SWT.READ_ONLY); return cellEditor; } + private int getIndexOfEntry(Entry<String, String> entryBeingAdded) { + for(int index = 0; index < allowedKeys.length; index++) { + if(allowedKeys[index].equals(entryBeingAdded.getKey())) { + return index; + } + } + return -1; + } + + protected Entry<String, String> getEntryBeingAdded() { + Entry<String, String> entryBeingAdded = null; + Iterator<Entry<String, String>> iter = volume.getOptions().entrySet().iterator(); + while(iter.hasNext()) { + Entry<String, String> nextEntry = iter.next(); + if(!iter.hasNext() && nextEntry.getValue().isEmpty()) { + // it's the LAST entry, and it's value is empty. + // means this is a new row being added in the table viewer. + entryBeingAdded = nextEntry; + } + } + return entryBeingAdded; + } + @SuppressWarnings("unchecked") @Override protected boolean canEdit(Object element) { diff --git a/src/com.gluster.storage.management.gui/src/com/gluster/storage/management/gui/views/details/OptionValueEditingSupport.java b/src/com.gluster.storage.management.gui/src/com/gluster/storage/management/gui/views/details/OptionValueEditingSupport.java index 5749c703..af1ef949 100644 --- a/src/com.gluster.storage.management.gui/src/com/gluster/storage/management/gui/views/details/OptionValueEditingSupport.java +++ b/src/com.gluster.storage.management.gui/src/com/gluster/storage/management/gui/views/details/OptionValueEditingSupport.java @@ -45,9 +45,6 @@ public class OptionValueEditingSupport extends EditingSupport { final String optionValue = (String)value; final String oldValue = entry.getValue(); - guiHelper.setStatusMessage("Setting option [" + optionKey + " = " + optionValue + "]..."); - getViewer().getControl().update(); - // It is not allowed to change value to empty string if(optionValue.isEmpty()) { MessageDialog.openError(Display.getDefault().getActiveShell(), "Set Volume Option", @@ -62,6 +59,9 @@ public class OptionValueEditingSupport extends EditingSupport { } // value has changed. set volume option at back-end and update model accordingly + guiHelper.setStatusMessage("Setting option [" + optionKey + " = " + optionValue + "]..."); + getViewer().getControl().update(); + BusyIndicator.showWhile(Display.getDefault(), new Runnable() { @Override diff --git a/src/com.gluster.storage.management.gui/src/com/gluster/storage/management/gui/views/details/VolumeLogsPage.java b/src/com.gluster.storage.management.gui/src/com/gluster/storage/management/gui/views/details/VolumeLogsPage.java index d435201e..ee7acea5 100644 --- a/src/com.gluster.storage.management.gui/src/com/gluster/storage/management/gui/views/details/VolumeLogsPage.java +++ b/src/com.gluster.storage.management.gui/src/com/gluster/storage/management/gui/views/details/VolumeLogsPage.java @@ -56,9 +56,10 @@ public class VolumeLogsPage extends Composite { private static final String[] LOG_TABLE_COLUMN_NAMES = new String[] { "Date", "Time", "Disk", "Severity", "Message" }; /** - * Create the composite. + * Create the volume logs page * @param parent * @param style + * @param volume Volume for which the logs page is to be created */ public VolumeLogsPage(Composite parent, int style, Volume volume) { super(parent, style); @@ -70,80 +71,39 @@ public class VolumeLogsPage extends Composite { toolkit.adapt(this); toolkit.paintBordersFor(this); - setLayout(new GridLayout(1, false)); - GridData layoutData = new GridData(); - layoutData.grabExcessHorizontalSpace = true; - layoutData.grabExcessVerticalSpace = true; - //layoutData.verticalIndent = 10; - setLayoutData(layoutData); + configureLayout(); Composite composite = toolkit.createComposite(this, SWT.NONE); toolkit.paintBordersFor(composite); - Label lblScanLast = toolkit.createLabel(composite, "Scan last", SWT.NONE); - lblScanLast.setBounds(0, 15, 80, 20); - - text = toolkit.createText(composite, "100", SWT.NONE); - text.setBounds(85, 15, 60, 20); - - Label lblMessagesAndFilter = toolkit.createLabel(composite, "messages, and filter on disk", SWT.NONE); - lblMessagesAndFilter.setBounds(160, 15, 200, 20); - - Combo combo = new Combo(composite, SWT.NONE); - combo.setBounds(365, 15, 100, 20); - combo.setItems(new String[] {"ALL", "sda", "sdb", "sdc", "sdd"}); - toolkit.adapt(combo); - toolkit.paintBordersFor(combo); - combo.select(0); - - Label lblSeverity = toolkit.createLabel(composite, "Severity", SWT.NONE); - lblSeverity.setBounds(480, 15, 70, 20); + createLineCountLabel(composite); + createLineCountText(composite); - Combo combo_1 = new Combo(composite, SWT.NONE); - combo_1.setBounds(555, 15, 110, 20); - combo_1.setItems(new String[] {"ALL", "SEVERE", "WARNING", "DEBUG", "INFO"}); - toolkit.adapt(combo_1); - toolkit.paintBordersFor(combo_1); - combo_1.select(1); + createDiskLabel(composite); + createDisksCombo(composite); - Label lblFrom = toolkit.createLabel(composite, "from", SWT.NONE); - lblFrom.setBounds(0, 60, 40, 20); + createSeverityLabel(composite); + createSeverityCombo(composite); - DateTime dateTime = new DateTime(composite, SWT.BORDER | SWT.DROP_DOWN); - dateTime.setBounds(45, 60, 120, 20); - toolkit.adapt(dateTime); - toolkit.paintBordersFor(dateTime); - - DateTime dateTime_1 = new DateTime(composite, SWT.BORDER | SWT.TIME); - dateTime_1.setBounds(171, 60, 120, 20); - toolkit.adapt(dateTime_1); - toolkit.paintBordersFor(dateTime_1); + createFromDateLabel(composite); + createFromDateField(composite); + createFromTimeField(composite); - Label lblTo = toolkit.createLabel(composite, "To", SWT.NONE); - lblTo.setBounds(329, 60, 26, 20); + createToDateLabel(composite); + createToDateField(composite); + createToTimeField(composite); - DateTime dateTime_2 = new DateTime(composite, SWT.BORDER | SWT.DROP_DOWN); - dateTime_2.setBounds(355, 60, 120, 20); - toolkit.adapt(dateTime_2); - toolkit.paintBordersFor(dateTime_2); + createSearchButton(composite); - DateTime dateTime_3 = new DateTime(composite, SWT.BORDER | SWT.TIME); - dateTime_3.setBounds(480, 60, 120, 20); - toolkit.adapt(dateTime_3); - toolkit.paintBordersFor(dateTime_3); + createSeparator(composite); - Button btngo = toolkit.createButton(composite, "&Go", SWT.NONE); - btngo.setBounds(605, 55, 60, 30); - - Label separator = toolkit.createLabel(composite, "", SWT.SEPARATOR | SWT.HORIZONTAL | SWT.FILL); - separator.setBounds(0, 95, 680, 2); - - Label lblFilterString = toolkit.createLabel(composite, "Filter String", SWT.LEFT); - lblFilterString.setBounds(0, 105, 85, 20); + createFilterLabel(composite); + createFilterText(composite); - text = guiHelper.createFilterText(toolkit, composite); - text.setBounds(90, 105, 250, 20); + createLogTableViewer(); + } + private void createLogTableViewer() { Composite tableViewerComposite = createTableViewerComposite(); TableViewer tableViewer = new TableViewer(tableViewerComposite, SWT.FLAT | SWT.FULL_SELECTION | SWT.MULTI); @@ -154,6 +114,111 @@ public class VolumeLogsPage extends Composite { guiHelper.createFilter(tableViewer, text, false); tableViewer.setInput(GlusterDummyModel.getDummyLogMessages().toArray()); } + + private void createFilterText(Composite composite) { + text = guiHelper.createFilterText(toolkit, composite); + text.setBounds(90, 105, 250, 20); + } + + private void createFilterLabel(Composite composite) { + Label lblFilterString = toolkit.createLabel(composite, "Filter String", SWT.LEFT); + lblFilterString.setBounds(0, 105, 85, 20); + } + + private void createSeparator(Composite composite) { + Label separator = toolkit.createLabel(composite, "", SWT.SEPARATOR | SWT.HORIZONTAL | SWT.FILL); + separator.setBounds(0, 95, 680, 2); + } + + private void createSearchButton(Composite composite) { + Button btngo = toolkit.createButton(composite, "&Go", SWT.NONE); + btngo.setBounds(605, 55, 60, 30); + } + + private void createToTimeField(Composite composite) { + DateTime toTime = new DateTime(composite, SWT.BORDER | SWT.TIME); + toTime.setBounds(480, 60, 120, 20); + toolkit.adapt(toTime); + toolkit.paintBordersFor(toTime); + } + + private void createToDateField(Composite composite) { + DateTime toDate = new DateTime(composite, SWT.BORDER | SWT.DROP_DOWN); + toDate.setBounds(355, 60, 120, 20); + toolkit.adapt(toDate); + toolkit.paintBordersFor(toDate); + } + + private void createToDateLabel(Composite composite) { + Label lblTo = toolkit.createLabel(composite, "To", SWT.NONE); + lblTo.setBounds(329, 60, 26, 20); + } + + private void createFromTimeField(Composite composite) { + DateTime fromTime = new DateTime(composite, SWT.BORDER | SWT.TIME); + fromTime.setBounds(171, 60, 120, 20); + toolkit.adapt(fromTime); + toolkit.paintBordersFor(fromTime); + } + + private void createFromDateField(Composite composite) { + DateTime fromDate = new DateTime(composite, SWT.BORDER | SWT.DROP_DOWN); + fromDate.setBounds(45, 60, 120, 20); + toolkit.adapt(fromDate); + toolkit.paintBordersFor(fromDate); + } + + private void createFromDateLabel(Composite composite) { + Label lblFrom = toolkit.createLabel(composite, "from", SWT.NONE); + lblFrom.setBounds(0, 60, 40, 20); + } + + private void createSeverityCombo(Composite composite) { + Combo severityCombo = new Combo(composite, SWT.NONE); + severityCombo.setBounds(555, 15, 110, 20); + severityCombo.setItems(new String[] {"ALL", "SEVERE", "WARNING", "DEBUG", "INFO"}); + toolkit.adapt(severityCombo); + toolkit.paintBordersFor(severityCombo); + severityCombo.select(1); + } + + private void createSeverityLabel(Composite composite) { + Label lblSeverity = toolkit.createLabel(composite, "Severity", SWT.NONE); + lblSeverity.setBounds(480, 15, 70, 20); + } + + private void createDisksCombo(Composite composite) { + Combo disksCombo = new Combo(composite, SWT.NONE); + disksCombo.setBounds(365, 15, 100, 20); + disksCombo.setItems(new String[] {"ALL", "sda", "sdb", "sdc", "sdd"}); + toolkit.adapt(disksCombo); + toolkit.paintBordersFor(disksCombo); + disksCombo.select(0); + } + + private void createDiskLabel(Composite composite) { + Label lblMessagesAndFilter = toolkit.createLabel(composite, "messages, and filter on disk", SWT.NONE); + lblMessagesAndFilter.setBounds(160, 15, 200, 20); + } + + private void createLineCountText(Composite composite) { + text = toolkit.createText(composite, "100", SWT.NONE); + text.setBounds(85, 15, 60, 20); + } + + private void createLineCountLabel(Composite composite) { + Label lblScanLast = toolkit.createLabel(composite, "Scan last", SWT.NONE); + lblScanLast.setBounds(0, 15, 80, 20); + } + + private void configureLayout() { + setLayout(new GridLayout(1, false)); + GridData layoutData = new GridData(); + layoutData.grabExcessHorizontalSpace = true; + layoutData.grabExcessVerticalSpace = true; + //layoutData.verticalIndent = 10; + setLayoutData(layoutData); + } private Composite createTableViewerComposite() { Composite tableViewerComposite = new Composite(this, SWT.NO); diff --git a/src/com.gluster.storage.management.gui/src/com/gluster/storage/management/gui/views/details/VolumeOptionsPage.java b/src/com.gluster.storage.management.gui/src/com/gluster/storage/management/gui/views/details/VolumeOptionsPage.java index b30ce379..3dadb947 100644 --- a/src/com.gluster.storage.management.gui/src/com/gluster/storage/management/gui/views/details/VolumeOptionsPage.java +++ b/src/com.gluster.storage.management.gui/src/com/gluster/storage/management/gui/views/details/VolumeOptionsPage.java @@ -20,6 +20,7 @@ package com.gluster.storage.management.gui.views.details; import java.util.Map.Entry; +import org.apache.commons.lang.WordUtils; import org.eclipse.jface.layout.TableColumnLayout; import org.eclipse.jface.viewers.ArrayContentProvider; import org.eclipse.jface.viewers.ColumnLabelProvider; @@ -32,6 +33,8 @@ import org.eclipse.jface.viewers.TableViewerColumn; import org.eclipse.swt.SWT; import org.eclipse.swt.events.DisposeEvent; import org.eclipse.swt.events.DisposeListener; +import org.eclipse.swt.events.ModifyEvent; +import org.eclipse.swt.events.ModifyListener; import org.eclipse.swt.events.PaintEvent; import org.eclipse.swt.events.PaintListener; import org.eclipse.swt.events.SelectionAdapter; @@ -64,6 +67,7 @@ public class VolumeOptionsPage extends Composite { private GUIHelper guiHelper = GUIHelper.getInstance(); private Volume volume; private DefaultClusterListener clusterListener; + private Text filterText; public enum OPTIONS_TABLE_COLUMN_INDICES { OPTION_KEY, OPTION_VALUE @@ -71,6 +75,8 @@ public class VolumeOptionsPage extends Composite { private static final String[] OPTIONS_TABLE_COLUMN_NAMES = new String[] { "Option Key", "Option Value" }; private Button addButton; + private TableViewerColumn keyColumn; + private OptionKeyEditingSupport keyEditingSupport; public VolumeOptionsPage(final Composite parent, int style, Volume volume) { super(parent, style); @@ -81,7 +87,8 @@ public class VolumeOptionsPage extends Composite { toolkit.paintBordersFor(this); setupPageLayout(); - setupDiskTableViewer(guiHelper.createFilterText(toolkit, this)); + filterText = guiHelper.createFilterText(toolkit, this); + setupOptionsTableViewer(filterText); createAddButton(); @@ -91,14 +98,6 @@ public class VolumeOptionsPage extends Composite { registerListeners(parent); } - /** - * @return - */ - private DefaultClusterListener createClusterListener() { - // TODO Auto-generated method stub - return null; - } - private void createAddButton() { addButton = toolkit.createButton(this, "&Add", SWT.FLAT); addButton.addSelectionListener(new SelectionAdapter() { @@ -109,9 +108,11 @@ public class VolumeOptionsPage extends Composite { tableViewer.refresh(); tableViewer.setSelection(new StructuredSelection(getEntry(""))); + keyColumn.getViewer().editElement(getEntry(""), 0); // edit newly created entry - // disable the add button till user fills up the new option + // disable the add button AND search filter textbox till user fills up the new option addButton.setEnabled(false); + filterText.setEnabled(false); } private Entry<String, String> getEntry(String key) { @@ -123,11 +124,29 @@ public class VolumeOptionsPage extends Composite { return null; } }); + + // Make sure that add button is enabled only when search filter textbox is empty + filterText.addModifyListener(new ModifyListener() { + @Override + public void modifyText(ModifyEvent e) { + if(filterText.getText().length() > 0) { + addButton.setEnabled(false); + } else { + addButton.setEnabled(true); + } + } + }); } private void registerListeners(final Composite parent) { addDisposeListener(new DisposeListener() { public void widgetDisposed(DisposeEvent e) { + if(!addButton.isEnabled()) { + // user has selected key, but not added value. Since this is not a valid entry, + // remove the last option (without value) from the volume + volume.getOptions().remove(keyEditingSupport.getEntryBeingAdded().getKey()); + } + GlusterDataModelManager.getInstance().removeClusterListener(clusterListener); toolkit.dispose(); } @@ -145,6 +164,20 @@ public class VolumeOptionsPage extends Composite { } }); + parent.addDisposeListener(new DisposeListener() { + + @Override + public void widgetDisposed(DisposeEvent e) { + if(!addButton.isEnabled()) { + // user has selected key, but not added value. Since this is not a valid entry, + // remove the last option (without value) from the volume + Entry<String, String> entryBeingAdded = keyEditingSupport.getEntryBeingAdded(); + volume.getOptions().remove(entryBeingAdded.getKey()); + } + } + }); + + clusterListener = new DefaultClusterListener() { @SuppressWarnings("unchecked") @Override @@ -159,8 +192,9 @@ public class VolumeOptionsPage extends Composite { if(event.getEventType() == EVENT_TYPE.VOLUME_OPTION_SET) { Entry<String, String> eventEntry = (Entry<String, String>)event.getEventData(); if (eventEntry.getKey().equals(volume.getOptions().keySet().toArray()[volume.getOptions().size()-1])) { - // option has been set successfully by the user. re-enable the add button + // option has been set successfully by the user. re-enable the add button and search filter textbox addButton.setEnabled(true); + filterText.setEnabled(true); } if(tableViewer.getTable().getItemCount() < volume.getOptions().size()) { @@ -183,7 +217,7 @@ public class VolumeOptionsPage extends Composite { setLayout(layout); } - private void setupDiskTable(Composite parent) { + private void setupOptionsTable(Composite parent) { Table table = tableViewer.getTable(); table.setHeaderVisible(true); table.setLinesVisible(false); @@ -210,6 +244,7 @@ public class VolumeOptionsPage extends Composite { valueColumn.getColumn() .setText(OPTIONS_TABLE_COLUMN_NAMES[OPTIONS_TABLE_COLUMN_INDICES.OPTION_VALUE.ordinal()]); valueColumn.setLabelProvider(new ColumnLabelProvider() { + @SuppressWarnings("unchecked") @Override public String getText(Object element) { return ((Entry<String, String>) element).getValue(); @@ -223,9 +258,10 @@ public class VolumeOptionsPage extends Composite { } private TableColumn createKeyColumn() { - TableViewerColumn keyColumn = new TableViewerColumn(tableViewer, SWT.NONE); + keyColumn = new TableViewerColumn(tableViewer, SWT.NONE); keyColumn.getColumn().setText(OPTIONS_TABLE_COLUMN_NAMES[OPTIONS_TABLE_COLUMN_INDICES.OPTION_KEY.ordinal()]); keyColumn.setLabelProvider(new ColumnLabelProvider() { + @SuppressWarnings("unchecked") @Override public String getText(Object element) { return ((Entry<String, String>) element).getKey(); @@ -234,25 +270,32 @@ public class VolumeOptionsPage extends Composite { @SuppressWarnings("unchecked") @Override public String getToolTipText(Object element) { - VolumeOptionInfo optionInfo = GlusterDataModelManager.getInstance().getVolumeOptionInfo( - ((Entry<String, String>) element).getKey()); - return optionInfo.getDescription() + CoreConstants.NEWLINE + "Default value: " + String key = ((Entry<String, String>) element).getKey(); + if(key.isEmpty()) { + return "Click to select a volume option key"; + } + + VolumeOptionInfo optionInfo = GlusterDataModelManager.getInstance().getVolumeOptionInfo(key); + // Wrap the description before adding to tooltip so that long descriptions are displayed properly + return WordUtils.wrap(optionInfo.getDescription(), 60) + CoreConstants.NEWLINE + "Default value: " + optionInfo.getDefaultValue(); } }); // Editing support required when adding new key - keyColumn.setEditingSupport(new OptionKeyEditingSupport(keyColumn.getViewer(), volume)); + keyEditingSupport = new OptionKeyEditingSupport(keyColumn.getViewer(), volume); + keyColumn.setEditingSupport(keyEditingSupport); return keyColumn.getColumn(); } - private void createDiskTableViewer(Composite parent) { + private void createOptionsTableViewer(Composite parent) { tableViewer = new TableViewer(parent, SWT.FLAT | SWT.FULL_SELECTION | SWT.SINGLE); tableViewer.setLabelProvider(new VolumeOptionsTableLabelProvider()); tableViewer.setContentProvider(new ArrayContentProvider()); + tableViewer.getTable().setLinesVisible(true); - setupDiskTable(parent); + setupOptionsTable(parent); } private Composite createTableViewerComposite() { @@ -262,23 +305,15 @@ public class VolumeOptionsPage extends Composite { return tableViewerComposite; } - private void setupDiskTableViewer(final Text filterText) { + private void setupOptionsTableViewer(final Text filterText) { Composite tableViewerComposite = createTableViewerComposite(); - createDiskTableViewer(tableViewerComposite); + createOptionsTableViewer(tableViewerComposite); ColumnViewerToolTipSupport.enableFor(tableViewer); // Create a case insensitive filter for the table viewer using the filter text field guiHelper.createFilter(tableViewer, filterText, false); } - /** - * 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, OPTIONS_TABLE_COLUMN_INDICES columnIndex, int alignment, int weight) { + private void setColumnProperties(Table table, OPTIONS_TABLE_COLUMN_INDICES columnIndex, int alignment, int weight) { TableColumn column = table.getColumn(columnIndex.ordinal()); column.setAlignment(alignment); diff --git a/src/com.gluster.storage.management.server/src/com/gluster/storage/management/server/constants/VolumeOptionsDefaults.java b/src/com.gluster.storage.management.server/src/com/gluster/storage/management/server/constants/VolumeOptionsDefaults.java index 4093a4ee..5c9a6505 100644 --- a/src/com.gluster.storage.management.server/src/com/gluster/storage/management/server/constants/VolumeOptionsDefaults.java +++ b/src/com.gluster.storage.management.server/src/com/gluster/storage/management/server/constants/VolumeOptionsDefaults.java @@ -100,9 +100,9 @@ public class VolumeOptionsDefaults { volumeOptionsInfo.add(new VolumeOptionInfo("diagnostics.dump-fd-stats", "Statistics related to file-operations would be tracked inside GlusterFS data-structures.", "off")); volumeOptionsInfo.add(new VolumeOptionInfo("diagnostics.brick-log-level", - "Changes the log-level of the bricks (servers).", "NORMAL")); + "Changes the log-level of the bricks (servers).", "INFO")); volumeOptionsInfo.add(new VolumeOptionInfo("diagnostics.client-log-level", - "Changes the log-level of the clients.", "NORMAL")); + "Changes the log-level of the clients.", "INFO")); volumeOptionsInfo.add(new VolumeOptionInfo("nfs.enable-ino32", "Use this option from the CLI to make Gluster NFS return 32-bit inode numbers instead of 64-bit.", "off")); diff --git a/src/com.gluster.storage.management.server/src/com/gluster/storage/management/server/resources/VolumesResource.java b/src/com.gluster.storage.management.server/src/com/gluster/storage/management/server/resources/VolumesResource.java index 073b8c13..92fba9f3 100644 --- a/src/com.gluster.storage.management.server/src/com/gluster/storage/management/server/resources/VolumesResource.java +++ b/src/com.gluster.storage.management.server/src/com/gluster/storage/management/server/resources/VolumesResource.java @@ -24,8 +24,11 @@ import static com.gluster.storage.management.core.constants.RESTConstants.FORM_P import static com.gluster.storage.management.core.constants.RESTConstants.FORM_PARAM_VALUE_START; import static com.gluster.storage.management.core.constants.RESTConstants.FORM_PARAM_VALUE_STOP; import static com.gluster.storage.management.core.constants.RESTConstants.PATH_PARAM_VOLUME_NAME; +import static com.gluster.storage.management.core.constants.RESTConstants.QUERY_PARAM_DISK_NAME; +import static com.gluster.storage.management.core.constants.RESTConstants.QUERY_PARAM_LINE_COUNT; import static com.gluster.storage.management.core.constants.RESTConstants.RESOURCE_PATH_VOLUMES; import static com.gluster.storage.management.core.constants.RESTConstants.SUBRESOURCE_DEFAULT_OPTIONS; +import static com.gluster.storage.management.core.constants.RESTConstants.SUBRESOURCE_LOGS; import static com.gluster.storage.management.core.constants.RESTConstants.SUBRESOURCE_OPTIONS; import java.util.ArrayList; @@ -46,10 +49,13 @@ import javax.ws.rs.core.MediaType; import com.gluster.storage.management.core.constants.CoreConstants; import com.gluster.storage.management.core.constants.RESTConstants; +import com.gluster.storage.management.core.exceptions.GlusterRuntimeException; +import com.gluster.storage.management.core.model.LogMessage; import com.gluster.storage.management.core.model.Status; import com.gluster.storage.management.core.model.Volume; import com.gluster.storage.management.core.model.Volume.TRANSPORT_TYPE; import com.gluster.storage.management.core.response.GenericResponse; +import com.gluster.storage.management.core.response.LogMessageListResponse; import com.gluster.storage.management.core.response.VolumeListResponse; import com.gluster.storage.management.core.response.VolumeOptionInfoListResponse; import com.gluster.storage.management.server.constants.VolumeOptionsDefaults; @@ -64,7 +70,7 @@ import com.sun.jersey.spi.resource.Singleton; public class VolumesResource { private static final String PREPARE_BRICK_SCRIPT = "create_volume_directory.py"; private static final String VOLUME_DIRECTORY_CLEANUP_SCRIPT = "clear_volume_directory.py"; - private static final String POST_VOLUME_DELETE_SCRIPT = "post_volume_delete.py"; + private static final String VOLUME_DISK_LOG_SCRIPT = "get_volume_disk_log.py"; @InjectParam private static ServerUtil serverUtil; @@ -251,6 +257,56 @@ public class VolumesResource { } return new Status(Status.STATUS_CODE_SUCCESS, "Directories cleaned up successfully!"); } + + private List<LogMessage> getDiskLogs(String volumeName, String diskName, Integer lineCount) + throws GlusterRuntimeException { + String[] diskParts = diskName.split(":"); + String server = diskParts[0]; + String disk = diskParts[1]; + + // Usage: get_volume_disk_log.py <volumeName> <diskName> <lineCount> + Status logStatus = (Status) serverUtil.executeOnServer(true, server, VOLUME_DISK_LOG_SCRIPT + " " + volumeName + + " " + disk + " " + lineCount, Status.class); + if(!logStatus.isSuccess()) { + throw new GlusterRuntimeException(logStatus.toString()); + } + + return extractLogMessages(logStatus.getMessage()); + } + + private List<LogMessage> extractLogMessages(String logContent) { + List<LogMessage> logMessages = new ArrayList<LogMessage>(); + for(String logMessage : logContent.split(CoreConstants.NEWLINE)) { + logMessages.add(new LogMessage(logMessage)); + } + + return logMessages; + } + + @GET + @Path("{" + PATH_PARAM_VOLUME_NAME + "}/" + SUBRESOURCE_LOGS) + public LogMessageListResponse getLogs(@PathParam(PATH_PARAM_VOLUME_NAME) String volumeName, + @QueryParam(QUERY_PARAM_DISK_NAME) String diskName, @QueryParam(QUERY_PARAM_LINE_COUNT) Integer lineCount) { + List<LogMessage> logMessages = null; + + try { + if (diskName == null || diskName.isEmpty()) { + logMessages = new ArrayList<LogMessage>(); + // fetch logs for every brick of the volume + Volume volume = getVolume(volumeName); + for (String volumeDisk : volume.getDisks()) { + logMessages.addAll(getDiskLogs(volumeName, volumeDisk, lineCount)); + } + } else { + // fetch logs for given brick of the volume + logMessages = getDiskLogs(volumeName, diskName, lineCount); + } + } catch (Exception e) { + return new LogMessageListResponse(new Status(e), null); + } + + return new LogMessageListResponse(Status.STATUS_SUCCESS, logMessages); + } public static void main(String[] args) throws ClassNotFoundException { VolumesResource vr = new VolumesResource(); 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 4f99172d..47657c2a 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 @@ -39,7 +39,6 @@ import org.springframework.stereotype.Component; import com.gluster.storage.management.core.constants.CoreConstants; import com.gluster.storage.management.core.model.Status; -import com.gluster.storage.management.core.response.GenericResponse; import com.gluster.storage.management.core.utils.ProcessResult; import com.gluster.storage.management.core.utils.ProcessUtil; @@ -75,6 +74,7 @@ public class ServerUtil { * @param expectedClass Class of the object expected from script execution * @return Response from remote execution of the command */ + @SuppressWarnings("rawtypes") public Object executeOnServer(boolean runInForeground, String serverName, String commandWithArgs, Class expectedClass) { StringBuffer output = new StringBuffer(); try { @@ -114,6 +114,7 @@ public class ServerUtil { * class Status. If that also fails, a status object with exception message is created and returned. * @return Object of given expected class, or a status object in case first unmarshalling fails. */ + @SuppressWarnings("rawtypes") private Object unmarshal(Class expectedClass, String input, boolean tryStatusOnFailure) { try { // create JAXB context and instantiate marshaller |
