summaryrefslogtreecommitdiffstats
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/com.gluster.storage.management.client/src/com/gluster/storage/management/client/AbstractClient.java18
-rw-r--r--src/com.gluster.storage.management.client/src/com/gluster/storage/management/client/GlusterDataModelManager.java2
-rw-r--r--src/com.gluster.storage.management.client/src/com/gluster/storage/management/client/VolumesClient.java12
-rw-r--r--src/com.gluster.storage.management.core/src/com/gluster/storage/management/core/model/GlusterDummyModel.java2
-rw-r--r--src/com.gluster.storage.management.core/src/com/gluster/storage/management/core/model/LogMessage.java17
-rw-r--r--src/com.gluster.storage.management.core/src/com/gluster/storage/management/core/model/Volume.java20
-rw-r--r--src/com.gluster.storage.management.core/src/com/gluster/storage/management/core/model/adapters/VolumeLogDateAdapter.java53
-rw-r--r--src/com.gluster.storage.management.core/src/com/gluster/storage/management/core/utils/DateUtil.java2
-rw-r--r--src/com.gluster.storage.management.gui/src/com/gluster/storage/management/gui/VolumeLogTableLabelProvider.java10
-rw-r--r--src/com.gluster.storage.management.gui/src/com/gluster/storage/management/gui/views/details/VolumeLogsPage.java52
-rw-r--r--src/com.gluster.storage.management.server.scripts/src/nodes/GlusterdUtils.py250
-rw-r--r--src/com.gluster.storage.management.server.scripts/src/nodes/VolumeUtils.py610
-rwxr-xr-xsrc/com.gluster.storage.management.server.scripts/src/nodes/get_disk_mount_point.py (renamed from src/com.gluster.storage.management.server.scripts/src/nodes/get-disk-mount-point.py)0
-rwxr-xr-xsrc/com.gluster.storage.management.server.scripts/src/nodes/get_disk_name_by_path.py69
-rwxr-xr-xsrc/com.gluster.storage.management.server.scripts/src/nodes/get_volume_brick_log.py109
-rwxr-xr-xsrc/com.gluster.storage.management.server.scripts/src/nodes/get_volume_log.py132
-rw-r--r--src/com.gluster.storage.management.server/src/com/gluster/storage/management/server/resources/VolumesResource.java58
-rw-r--r--src/com.gluster.storage.management.server/src/com/gluster/storage/management/server/utils/GlusterUtil.java62
-rw-r--r--src/com.gluster.storage.management.server/src/com/gluster/storage/management/server/utils/ServerUtil.java2
19 files changed, 1406 insertions, 74 deletions
diff --git a/src/com.gluster.storage.management.client/src/com/gluster/storage/management/client/AbstractClient.java b/src/com.gluster.storage.management.client/src/com/gluster/storage/management/client/AbstractClient.java
index e1a42de1..a4df0e58 100644
--- a/src/com.gluster.storage.management.client/src/com/gluster/storage/management/client/AbstractClient.java
+++ b/src/com.gluster.storage.management.client/src/com/gluster/storage/management/client/AbstractClient.java
@@ -93,6 +93,24 @@ public abstract class AbstractClient {
}
/**
+ * Fetches the resource whose name is arrived at by appending the "subResourceName" parameter to the default
+ * resource (the one returned by {@link AbstractClient#getResourceName()})
+ *
+ * @param subResourceName
+ * Name of the sub-resource
+ * @param queryParams
+ * Query parameters to be sent for the GET request
+ * @param responseClass
+ * Expected class of the response
+ * @return Object of responseClass received as a result of the GET request on the sub-resource
+ */
+ @SuppressWarnings("rawtypes")
+ protected Object fetchSubResource(String subResourceName, MultivaluedMap<String, String> queryParams,
+ Class responseClass) {
+ return fetchResource(resource.path(subResourceName), queryParams, responseClass);
+ }
+
+ /**
* Submits given Form using POST method to the resource and returns the object received as response
*
* @param responseClass
diff --git a/src/com.gluster.storage.management.client/src/com/gluster/storage/management/client/GlusterDataModelManager.java b/src/com.gluster.storage.management.client/src/com/gluster/storage/management/client/GlusterDataModelManager.java
index 9e031ad3..da3ac279 100644
--- a/src/com.gluster.storage.management.client/src/com/gluster/storage/management/client/GlusterDataModelManager.java
+++ b/src/com.gluster.storage.management.client/src/com/gluster/storage/management/client/GlusterDataModelManager.java
@@ -244,7 +244,7 @@ public class GlusterDataModelManager {
private void addMessages(List<LogMessage> messages, Disk disk, String severity, int count) {
for (int i = 1; i <= count; i++) {
String message = severity + "message" + i;
- messages.add(new LogMessage(new Date(), disk, severity, message));
+ messages.add(new LogMessage(new Date(), disk.getQualifiedName(), severity, message));
}
}
diff --git a/src/com.gluster.storage.management.client/src/com/gluster/storage/management/client/VolumesClient.java b/src/com.gluster.storage.management.client/src/com/gluster/storage/management/client/VolumesClient.java
index 05b89306..5cba6be8 100644
--- a/src/com.gluster.storage.management.client/src/com/gluster/storage/management/client/VolumesClient.java
+++ b/src/com.gluster.storage.management.client/src/com/gluster/storage/management/client/VolumesClient.java
@@ -20,12 +20,16 @@
*/
package com.gluster.storage.management.client;
+import javax.ws.rs.core.MultivaluedMap;
+
import com.gluster.storage.management.core.constants.RESTConstants;
import com.gluster.storage.management.core.model.Status;
import com.gluster.storage.management.core.model.Volume;
+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.sun.jersey.api.representation.Form;
+import com.sun.jersey.core.util.MultivaluedMapImpl;
public class VolumesClient extends AbstractClient {
@@ -84,6 +88,14 @@ public class VolumesClient extends AbstractClient {
return ((VolumeOptionInfoListResponse) fetchSubResource(RESTConstants.SUBRESOURCE_DEFAULT_OPTIONS,
VolumeOptionInfoListResponse.class));
}
+
+ public LogMessageListResponse getLogs(String volumeName, int lineCount) {
+ MultivaluedMap<String, String> queryParams = new MultivaluedMapImpl();
+ queryParams.add(RESTConstants.QUERY_PARAM_LINE_COUNT, "" + lineCount);
+ // TODO: Add other filte criteria as query parameters
+ return (LogMessageListResponse) fetchSubResource(volumeName + "/" + RESTConstants.SUBRESOURCE_LOGS,
+ queryParams, LogMessageListResponse.class);
+ }
public static void main(String[] args) {
UsersClient usersClient = new UsersClient();
diff --git a/src/com.gluster.storage.management.core/src/com/gluster/storage/management/core/model/GlusterDummyModel.java b/src/com.gluster.storage.management.core/src/com/gluster/storage/management/core/model/GlusterDummyModel.java
index f25999f0..09137014 100644
--- a/src/com.gluster.storage.management.core/src/com/gluster/storage/management/core/model/GlusterDummyModel.java
+++ b/src/com.gluster.storage.management.core/src/com/gluster/storage/management/core/model/GlusterDummyModel.java
@@ -218,7 +218,7 @@ public class GlusterDummyModel {
private void addMessages(List<LogMessage> messages, Disk disk, String severity, int count) {
for (int i = 1; i <= count; i++) {
String message = severity + "message" + i;
- messages.add(new LogMessage(new Date(), disk, severity, message));
+ messages.add(new LogMessage(new Date(), disk.getQualifiedName(), severity, message));
}
}
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 d81b8d0f..4f6347dc 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,17 @@ package com.gluster.storage.management.core.model;
import java.util.Date;
+import javax.xml.bind.annotation.XmlElement;
import javax.xml.bind.annotation.XmlRootElement;
+import javax.xml.bind.annotation.adapters.XmlJavaTypeAdapter;
+import com.gluster.storage.management.core.model.adapters.VolumeLogDateAdapter;
import com.gluster.storage.management.core.utils.StringUtil;
@XmlRootElement
public class LogMessage implements Filterable {
private Date timestamp;
- private Disk disk;
+ private String disk;
private String severity;
private String message;
@@ -38,6 +41,8 @@ public class LogMessage implements Filterable {
// TODO: Parse the log message and extract fields
}
+ @XmlElement(name = "timestamp", required = true)
+ @XmlJavaTypeAdapter(VolumeLogDateAdapter.class)
public Date getTimestamp() {
return timestamp;
}
@@ -46,11 +51,11 @@ public class LogMessage implements Filterable {
this.timestamp = timestamp;
}
- public Disk getDisk() {
+ public String getDisk() {
return disk;
}
- public void setDisk(Disk disk) {
+ public void setDisk(String disk) {
this.disk = disk;
}
@@ -70,7 +75,7 @@ public class LogMessage implements Filterable {
this.message = message;
}
- public LogMessage(Date timestamp, Disk disk, String severity, String message) {
+ public LogMessage(Date timestamp, String disk, String severity, String message) {
setTimestamp(timestamp);
setDisk(disk);
setSeverity(severity);
@@ -79,7 +84,7 @@ public class LogMessage implements Filterable {
@Override
public boolean filter(String filterString, boolean caseSensitive) {
- return StringUtil.filterString(getSeverity() + getTimestamp() + getDisk().getServerName()
- + getDisk().getQualifiedName() + getMessage(), filterString, caseSensitive);
+ return StringUtil.filterString(getSeverity() + getTimestamp() + getDisk() + getMessage(), filterString,
+ caseSensitive);
}
}
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 94b23179..83bdd166 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
@@ -67,6 +67,7 @@ public class Volume extends Entity {
private double totalDiskSpace = 0;
private List<String> disks = new ArrayList<String>();
+ private List<String> bricks = new ArrayList<String>();
public Volume() {
}
@@ -202,9 +203,6 @@ public class Volume extends Entity {
}
public void addDisk(String disk) {
- // if (disks.add(disk) && disk.getStatus() != DISK_STATUS.OFFLINE) {
- // totalDiskSpace += disk.getSpace();
- // }
disks.add(disk);
}
@@ -215,9 +213,7 @@ public class Volume extends Entity {
}
public void removeDisk(String disk) {
- // if (disks.remove(disk)) {
- // totalDiskSpace -= disk.getSpace();
- // }
+ disks.remove(disk);
}
public void removeAllDisks() {
@@ -225,6 +221,18 @@ public class Volume extends Entity {
totalDiskSpace = 0;
}
+ public void addBrick(String brick) {
+ bricks.add(brick);
+ }
+
+ public void removeBrick(String brick) {
+ bricks.remove(brick);
+ }
+
+ public List<String> getBricks() {
+ return bricks;
+ }
+
public void setDisks(List<String> disks) {
removeAllDisks();
addDisks(disks);
diff --git a/src/com.gluster.storage.management.core/src/com/gluster/storage/management/core/model/adapters/VolumeLogDateAdapter.java b/src/com.gluster.storage.management.core/src/com/gluster/storage/management/core/model/adapters/VolumeLogDateAdapter.java
new file mode 100644
index 00000000..254d5efd
--- /dev/null
+++ b/src/com.gluster.storage.management.core/src/com/gluster/storage/management/core/model/adapters/VolumeLogDateAdapter.java
@@ -0,0 +1,53 @@
+/*******************************************************************************
+ * 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.adapters;
+
+import java.text.SimpleDateFormat;
+import java.util.Date;
+
+import javax.xml.bind.annotation.adapters.XmlAdapter;
+
+/**
+ * Adapter class used for converting timestamp from Gluster volume log files to Date object.
+ */
+public class VolumeLogDateAdapter extends XmlAdapter<String, Date> {
+ private static final String DATE_FORMAT = "yyyy-MM-dd HH:mm:ss.SSS";
+ private SimpleDateFormat dateFormatter = new SimpleDateFormat(DATE_FORMAT);
+
+ /* (non-Javadoc)
+ * @see javax.xml.bind.annotation.adapters.XmlAdapter#unmarshal(java.lang.Object)
+ */
+ @Override
+ public Date unmarshal(String input) throws Exception {
+ input = input.trim();
+ if(input.length() > DATE_FORMAT.length()) {
+ input = input.substring(0, DATE_FORMAT.length());
+ }
+ return dateFormatter.parse(input);
+ }
+
+ /* (non-Javadoc)
+ * @see javax.xml.bind.annotation.adapters.XmlAdapter#marshal(java.lang.Object)
+ */
+ @Override
+ public String marshal(Date input) throws Exception {
+ return dateFormatter.format(input);
+ }
+}
diff --git a/src/com.gluster.storage.management.core/src/com/gluster/storage/management/core/utils/DateUtil.java b/src/com.gluster.storage.management.core/src/com/gluster/storage/management/core/utils/DateUtil.java
index 1b284cb8..d4529a00 100644
--- a/src/com.gluster.storage.management.core/src/com/gluster/storage/management/core/utils/DateUtil.java
+++ b/src/com.gluster.storage.management.core/src/com/gluster/storage/management/core/utils/DateUtil.java
@@ -29,7 +29,7 @@ public class DateUtil {
}
public static final String formatTime(Date inputDate) {
- DateFormat formatter = new SimpleDateFormat("HH:mm:ss z");
+ DateFormat formatter = new SimpleDateFormat("HH:mm:ss.SSS");
return formatter.format(inputDate);
}
}
diff --git a/src/com.gluster.storage.management.gui/src/com/gluster/storage/management/gui/VolumeLogTableLabelProvider.java b/src/com.gluster.storage.management.gui/src/com/gluster/storage/management/gui/VolumeLogTableLabelProvider.java
index 399cdc65..9858a25b 100644
--- a/src/com.gluster.storage.management.gui/src/com/gluster/storage/management/gui/VolumeLogTableLabelProvider.java
+++ b/src/com.gluster.storage.management.gui/src/com/gluster/storage/management/gui/VolumeLogTableLabelProvider.java
@@ -19,19 +19,11 @@
package com.gluster.storage.management.gui;
-import com.gluster.storage.management.core.model.Disk;
import com.gluster.storage.management.core.model.LogMessage;
import com.gluster.storage.management.core.utils.DateUtil;
-import com.gluster.storage.management.gui.utils.GUIHelper;
import com.gluster.storage.management.gui.views.details.VolumeLogsPage.LOG_TABLE_COLUMN_INDICES;
public class VolumeLogTableLabelProvider extends TableLabelProviderAdapter {
- private GUIHelper guiHelper = GUIHelper.getInstance();
-
- private String getFormattedDiskName(Disk disk) {
- return disk.getServerName() + ":" + disk.getName();
- }
-
@Override
public String getColumnText(Object element, int columnIndex) {
if (!(element instanceof LogMessage)) {
@@ -41,7 +33,7 @@ public class VolumeLogTableLabelProvider extends TableLabelProviderAdapter {
LogMessage logMessage = (LogMessage) element;
return (columnIndex == LOG_TABLE_COLUMN_INDICES.DATE.ordinal() ? DateUtil.formatDate(logMessage.getTimestamp())
: columnIndex == LOG_TABLE_COLUMN_INDICES.TIME.ordinal() ? DateUtil.formatTime(logMessage.getTimestamp())
- : columnIndex == LOG_TABLE_COLUMN_INDICES.DISK.ordinal() ? getFormattedDiskName(logMessage.getDisk())
+ : columnIndex == LOG_TABLE_COLUMN_INDICES.DISK.ordinal() ? logMessage.getDisk()
: columnIndex == LOG_TABLE_COLUMN_INDICES.SEVERITY.ordinal() ? "" + logMessage.getSeverity()
: columnIndex == LOG_TABLE_COLUMN_INDICES.MESSAGE.ordinal() ? logMessage.getMessage() : "Invalid");
}
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 ee7acea5..80fd092d 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
@@ -18,6 +18,9 @@
*******************************************************************************/
package com.gluster.storage.management.gui.views.details;
+import java.util.List;
+
+import org.eclipse.jface.dialogs.MessageDialog;
import org.eclipse.jface.layout.TableColumnLayout;
import org.eclipse.jface.viewers.ArrayContentProvider;
import org.eclipse.jface.viewers.ColumnWeightData;
@@ -25,6 +28,8 @@ import org.eclipse.jface.viewers.TableViewer;
import org.eclipse.swt.SWT;
import org.eclipse.swt.events.DisposeEvent;
import org.eclipse.swt.events.DisposeListener;
+import org.eclipse.swt.events.SelectionAdapter;
+import org.eclipse.swt.events.SelectionEvent;
import org.eclipse.swt.layout.FillLayout;
import org.eclipse.swt.layout.GridData;
import org.eclipse.swt.layout.GridLayout;
@@ -39,8 +44,12 @@ import org.eclipse.swt.widgets.TableColumn;
import org.eclipse.swt.widgets.Text;
import org.eclipse.ui.forms.widgets.FormToolkit;
-import com.gluster.storage.management.core.model.GlusterDummyModel;
+import com.gluster.storage.management.client.GlusterDataModelManager;
+import com.gluster.storage.management.client.VolumesClient;
+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.response.LogMessageListResponse;
import com.gluster.storage.management.gui.VolumeLogTableLabelProvider;
import com.gluster.storage.management.gui.utils.GUIHelper;
@@ -48,12 +57,16 @@ public class VolumeLogsPage extends Composite {
private final FormToolkit toolkit = new FormToolkit(Display.getCurrent());
private final GUIHelper guiHelper = GUIHelper.getInstance();
- private Text text;
+ private Text filterText;
+ private Text lineCountText;
+ private Volume volume;
+
public enum LOG_TABLE_COLUMN_INDICES {
DATE, TIME, DISK, SEVERITY, MESSAGE
};
private static final String[] LOG_TABLE_COLUMN_NAMES = new String[] { "Date", "Time", "Disk", "Severity", "Message" };
+ private TableViewer tableViewer;
/**
* Create the volume logs page
@@ -63,6 +76,8 @@ public class VolumeLogsPage extends Composite {
*/
public VolumeLogsPage(Composite parent, int style, Volume volume) {
super(parent, style);
+ this.volume = volume;
+
addDisposeListener(new DisposeListener() {
public void widgetDisposed(DisposeEvent e) {
toolkit.dispose();
@@ -106,18 +121,17 @@ public class VolumeLogsPage extends Composite {
private void createLogTableViewer() {
Composite tableViewerComposite = createTableViewerComposite();
- TableViewer tableViewer = new TableViewer(tableViewerComposite, SWT.FLAT | SWT.FULL_SELECTION | SWT.MULTI);
+ tableViewer = new TableViewer(tableViewerComposite, SWT.FLAT | SWT.FULL_SELECTION | SWT.MULTI);
tableViewer.setLabelProvider(new VolumeLogTableLabelProvider());
tableViewer.setContentProvider(new ArrayContentProvider());
setupLogsTable(tableViewerComposite, tableViewer.getTable());
- guiHelper.createFilter(tableViewer, text, false);
- tableViewer.setInput(GlusterDummyModel.getDummyLogMessages().toArray());
+ guiHelper.createFilter(tableViewer, filterText, false);
}
private void createFilterText(Composite composite) {
- text = guiHelper.createFilterText(toolkit, composite);
- text.setBounds(90, 105, 250, 20);
+ filterText = guiHelper.createFilterText(toolkit, composite);
+ filterText.setBounds(90, 105, 250, 20);
}
private void createFilterLabel(Composite composite) {
@@ -131,8 +145,24 @@ public class VolumeLogsPage extends Composite {
}
private void createSearchButton(Composite composite) {
- Button btngo = toolkit.createButton(composite, "&Go", SWT.NONE);
- btngo.setBounds(605, 55, 60, 30);
+ Button btnGo = toolkit.createButton(composite, "&Go", SWT.NONE);
+ btnGo.setBounds(605, 55, 60, 30);
+ btnGo.addSelectionListener(new SelectionAdapter() {
+ @Override
+ public void widgetSelected(SelectionEvent e) {
+ VolumesClient client = new VolumesClient(GlusterDataModelManager.getInstance().getSecurityToken());
+ LogMessageListResponse response = client.getLogs(volume.getName(), Integer.parseInt(lineCountText.getText()));
+ Status status = response.getStatus();
+ if(status.isSuccess()) {
+ List<LogMessage> logMessages = response.getLogMessages();
+ tableViewer.setInput(logMessages.toArray(new LogMessage[0]));
+ tableViewer.refresh();
+ } else {
+ MessageDialog.openError(getShell(), "Volume Logs", "Error while fetching volume logs: [" + status
+ + "]");
+ }
+ }
+ });
}
private void createToTimeField(Composite composite) {
@@ -202,8 +232,8 @@ public class VolumeLogsPage extends Composite {
}
private void createLineCountText(Composite composite) {
- text = toolkit.createText(composite, "100", SWT.NONE);
- text.setBounds(85, 15, 60, 20);
+ lineCountText = toolkit.createText(composite, "100", SWT.NONE);
+ lineCountText.setBounds(85, 15, 60, 20);
}
private void createLineCountLabel(Composite composite) {
diff --git a/src/com.gluster.storage.management.server.scripts/src/nodes/GlusterdUtils.py b/src/com.gluster.storage.management.server.scripts/src/nodes/GlusterdUtils.py
new file mode 100644
index 00000000..7c0e899c
--- /dev/null
+++ b/src/com.gluster.storage.management.server.scripts/src/nodes/GlusterdUtils.py
@@ -0,0 +1,250 @@
+# Copyright (c) 2010 Gluster, Inc. <http://www.gluster.com>
+# This file is part of Gluster Storage Platform.
+#
+# Gluster Storage Platform is free software; you can redistribute it
+# and/or modify it under the terms of the GNU General Public License
+# as published by the Free Software Foundation; either version 3 of
+# the License, or (at your option) any later version.
+#
+# Gluster Storage Platform is distributed in the hope that it will be
+# useful, but WITHOUT ANY WARRANTY; without even the implied warranty
+# of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program. If not, see
+# <http://www.gnu.org/licenses/>.
+
+import os
+import Utils
+
+import ServerUtils
+
+
+def getGlusterVolumeInfo(volumeName=None):
+ volumeNameList = None
+ if Utils.isString(volumeName):
+ volumeNameList = [volumeName]
+ if type(volumeName) == type([]):
+ volumeNameList = volumeName
+
+ status = Utils.runCommand("gluster volume info", output=True, root=True)
+ if status["Status"] != 0:
+ Utils.log("Failed to execute 'gluster volume info' command")
+ return None
+
+ volumeInfoDict = {}
+ volumeInfo = {}
+ volumeName = None
+ brickList = []
+ for line in status['Stdout'].split("\n"):
+ if not line:
+ if volumeName and volumeInfo:
+ volumeInfo["Bricks"] = brickList
+ volumeInfoDict[volumeName] = volumeInfo
+ volumeInfo = {}
+ volumeName = None
+ brickList = []
+ continue
+
+ tokens = line.split(":")
+ if tokens[0].strip().upper() == "BRICKS":
+ continue
+ elif tokens[0].strip().upper() == "VOLUME NAME":
+ volumeName = tokens[1].strip()
+ volumeInfo["VolumeName"] = volumeName
+ elif tokens[0].strip().upper() == "TYPE":
+ volumeInfo["VolumeType"] = tokens[1].strip()
+ elif tokens[0].strip().upper() == "STATUS":
+ volumeInfo["VolumeStatus"] = tokens[1].strip()
+ elif tokens[0].strip().upper() == "TRANSPORT-TYPE":
+ volumeInfo["TransportType"] = tokens[1].strip()
+ elif tokens[0].strip().upper().startswith("BRICK"):
+ brickList.append(":".join(tokens[1:]).strip())
+
+ if volumeName and volumeInfo:
+ volumeInfoDict[volumeName] = volumeInfo
+
+ if not volumeNameList:
+ return volumeInfoDict
+
+ # remove unwanted volume info
+ for volumeName in list(set(volumeInfoDict.keys()) - set(volumeNameList)):
+ del volumeInfoDict[volumeName]
+
+ return volumeInfoDict
+
+
+def isVolumeRunning(volumeName):
+ if not volumeName:
+ return False
+ volumeInfo = getGlusterVolumeInfo(volumeName)
+ if not volumeInfo:
+ return False
+ status = volumeInfo[volumeName]["VolumeStatus"]
+ if not status:
+ return False
+ if status.upper() == "STARTED":
+ return True
+ return False
+
+
+def isVolumeExist(volumeName):
+ if not volumeName:
+ return False
+ if getGlusterVolumeInfo(volumeName):
+ return True
+ return False
+
+
+def peerProbe(serverName):
+ command = "gluster peer probe %s" % serverName
+ status = Utils.runCommand(command, output=True, root=True)
+ if status["Status"] == 0:
+ return True
+ Utils.log("command [%s] failed with [%d:%s]" % (command, status["Status"], os.strerror(status["Status"])))
+ return False
+
+
+def setAuthAllow(volumeName, authList, includeServers=True):
+ if not (volumeName and authList):
+ return False
+ vacl = []
+ if includeServers:
+ for serverName in ServerUtils.getAllServerList():
+ vacl += ServerUtils.getServerIpList(serverName)
+ vacl += authList
+
+ command = "gluster volume set %s auth.allow %s" % (volumeName, ",".join(list(set(vacl))))
+ status = Utils.runCommand(command, output=True, root=True)
+ if status["Status"] == 0:
+ return True
+ Utils.log("command [%s] failed with [%d:%s]" % (command, status["Status"], os.strerror(status["Status"])))
+ return False
+
+
+def volumeCreate(volumeName, volumeType, transportTypeList, brickList):
+ command = "gluster volume create %s" % volumeName
+
+ if volumeType.upper() == "MIRROR":
+ command += " replica 2"
+ elif volumeType.upper() == "STRIPE":
+ command += " stripe 4"
+
+ if "RDMA" in transportTypeList:
+ command += " transport rdma"
+
+ command += " " + " ".join(brickList)
+
+ status = Utils.runCommand(command, output=True, root=True)
+ if status["Status"] == 0:
+ return True
+ Utils.log("command [%s] failed with [%d:%s]" % (command, status["Status"], os.strerror(status["Status"])))
+ return False
+
+
+def volumeDelete(volumeName):
+ command = "gluster --mode=script volume delete %s" % volumeName
+ status = Utils.runCommand(command, output=True, root=True)
+ if status["Status"] == 0:
+ return True
+ Utils.log("command [%s] failed with [%d:%s]" % (command, status["Status"], os.strerror(status["Status"])))
+ return False
+
+
+def volumeLogFileName(volumeName, brick, logDir):
+ command = "gluster volume log filename %s %s %s" % (volumeName, brick, logDir)
+ status = Utils.runCommand(command, output=True, root=True)
+ if status["Status"] == 0:
+ return True
+ Utils.log("command [%s] failed with [%d:%s]" % (command, status["Status"], os.strerror(status["Status"])))
+ return False
+
+
+def startVolumeMigration(volumeName, sourcePath, destinationPath):
+ command = "gluster volume replace-brick %s %s %s start" % (volumeName, sourcePath, destinationPath)
+ status = Utils.runCommand(command, output=True, root=True)
+ if status["Status"] == 0:
+ lines = status["Stdout"].split("\n")
+ if lines[0].split()[-1] == "successfully":
+ return True
+ Utils.log("command [%s] failed with [%d:%s]" % (command, status["Status"], os.strerror(status["Status"])))
+ return False
+
+
+def stopVolumeMigration(volumeName, sourcePath, destinationPath):
+ command = "gluster volume replace-brick %s %s %s abort" % (volumeName, sourcePath, destinationPath)
+ status = Utils.runCommand(command, output=True, root=True)
+ if status["Status"] == 0:
+ lines = status["Stdout"].split("\n")
+ if lines[0].split()[-1] == "successful":
+ return True
+ Utils.log("command [%s] failed with [%d:%s]" % (command, status["Status"], os.strerror(status["Status"])))
+ return False
+
+
+def commitVolumeMigration(volumeName, sourcePath, destinationPath):
+ command = "gluster volume replace-brick %s %s %s commit" % (volumeName, sourcePath, destinationPath)
+ status = Utils.runCommand(command, output=True, root=True)
+ if status["Status"] == 0:
+ lines = status["Stdout"].split("\n")
+ if lines[0].split()[-1] == "successful":
+ return True
+ Utils.log("command [%s] failed with [%d:%s]" % (command, status["Status"], os.strerror(status["Status"])))
+ return False
+
+
+def getMigrationStatus(volumeName, sourcePath, destinationPath):
+ command = "gluster volume replace-brick %s %s %s status" % (volumeName, sourcePath, destinationPath)
+ status = Utils.runCommand(command, output=True, root=True)
+ if status['Status'] == 0 and status['Stdout']:
+ lines = status["Stdout"].split("\n")
+ if "Current file" in lines[0]:
+ return "started"
+ if "Migration complete" in lines[0]:
+ return "completed"
+ Utils.log("command [%s] returns unknown status:%s" % (command, lines[0]))
+ return "failed"
+ #if status['Status'] == 0 and status['Stdout']:
+ # for line in status['Stdout'].split('\n'):
+ # words = line.split()
+ # if words and words[0].upper() == "STATUS:":
+ # return " ".join(words[1:]).upper()
+ Utils.log("command [%s] failed with [%d:%s]" % (command, status["Status"], os.strerror(status["Status"])))
+ return None
+
+
+def volumeRebalanceStart(volumeName):
+ command = "gluster volume rebalance %s start" % volumeName
+ status = Utils.runCommand(command, output=True, root=True)
+ if status["Status"] == 0:
+ lines = status["Stdout"].split("\n")
+ if lines[0].split()[-1] == "successful":
+ return True
+ Utils.log("command [%s] failed with [%d:%s]" % (command, status["Status"], os.strerror(status["Status"])))
+ return False
+
+
+def volumeRebalanceStop(volumeName):
+ command = "gluster volume rebalance %s stop" % volumeName
+ status = Utils.runCommand(command, output=True, root=True)
+ if status["Status"] == 0:
+ lines = status["Stdout"].split("\n")
+ if lines[0].split()[0] == "stopped":
+ return True
+ Utils.log("command [%s] failed with [%d:%s]" % (command, status["Status"], os.strerror(status["Status"])))
+ return False
+
+
+def volumeRebalanceStatus(volumeName):
+ command = "gluster volume rebalance %s status" % volumeName
+ status = Utils.runCommand(command, output=True, root=True)
+ if status["Status"] == 0:
+ lines = status["Stdout"].split("\n")
+ if "rebalance not started" in lines[0]:
+ return "not started"
+ if "rebalance completed" in lines[0]:
+ return "completed"
+ return "running"
+ Utils.log("command [%s] failed with [%d:%s]" % (command, status["Status"], os.strerror(status["Status"])))
+ return False
diff --git a/src/com.gluster.storage.management.server.scripts/src/nodes/VolumeUtils.py b/src/com.gluster.storage.management.server.scripts/src/nodes/VolumeUtils.py
new file mode 100644
index 00000000..a19ccd62
--- /dev/null
+++ b/src/com.gluster.storage.management.server.scripts/src/nodes/VolumeUtils.py
@@ -0,0 +1,610 @@
+# Copyright (c) 2010 Gluster, Inc. <http://www.gluster.com>
+# This file is part of Gluster Storage Platform.
+#
+# Gluster Storage Platform is free software; you can redistribute it
+# and/or modify it under the terms of the GNU General Public License
+# as published by the Free Software Foundation; either version 3 of
+# the License, or (at your option) any later version.
+#
+# Gluster Storage Platform is distributed in the hope that it will be
+# useful, but WITHOUT ANY WARRANTY; without even the implied warranty
+# of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program. If not, see
+# <http://www.gnu.org/licenses/>.
+
+import os
+import glob
+import tempfile
+from operator import itemgetter
+import Globals
+from Protocol import *
+from Utils import *
+from DiskUtils import *
+from ServerUtils import *
+import GlusterdUtils as Glusterd
+
+
+def isVolumeExist(volumeName):
+ volumeDom = XDOM()
+ return volumeDom.parseFile("%s/%s.xml" % (Globals.VOLUME_CONF_DIR, volumeName)) and \
+ Glusterd.isVolumeExist(volumeName)
+
+
+def getVolumeUuid(volumeName):
+ fileName = "%s/%s.xml" % (Globals.VOLUME_CONF_DIR, volumeName)
+ volumeDom = XDOM()
+ if not volumeDom.parseFile(fileName):
+ log("Failed to parse volume configuration file %s of %s" % (fileName, volumeName))
+ return None
+ return volumeDom.getTextByTagRoute("uuid")
+
+
+def readVolumeSmbConfFile(fileName=Globals.VOLUME_SMBCONF_FILE):
+ entryList = []
+ try:
+ fp = open(fileName)
+ for line in fp:
+ tokens = line.split("#")[0].strip().split(";")[0].strip().split("=")
+ if len(tokens) != 2:
+ continue
+ if tokens[0].strip().upper() == "INCLUDE":
+ entryList.append(tokens[1].strip())
+ fp.close()
+ except IOError, e:
+ log("Failed to open file %s: %s" % (fileName, str(e)))
+ return entryList
+
+
+def writeVolumeSmbConfFile(entryList, fileName=Globals.VOLUME_SMBCONF_FILE):
+ try:
+ fp = open(fileName, "w")
+ for entry in entryList:
+ fp.write("include = %s\n" % entry)
+ fp.close()
+ return True
+ except IOError, e:
+ log("Failed to write file %s: %s" % (fileName, str(e)))
+ return False
+
+
+def includeVolume(volumeName, fileName=Globals.VOLUME_SMBCONF_FILE):
+ volumeFile = "%s/%s.smbconf" % (Globals.VOLUME_CONF_DIR, volumeName)
+ if not os.path.exists(volumeFile):
+ return False
+ entryList = readVolumeSmbConfFile(fileName)
+ if volumeFile in entryList:
+ return True
+ entryList.append(volumeFile)
+ return writeVolumeSmbConfFile(entryList, fileName)
+
+
+def excludeVolume(volumeName, fileName=Globals.VOLUME_SMBCONF_FILE):
+ volumeFile = "%s/%s.smbconf" % (Globals.VOLUME_CONF_DIR, volumeName)
+ if not os.path.exists(volumeFile):
+ return False
+ entryList = readVolumeSmbConfFile(fileName)
+ if volumeFile not in entryList:
+ return True
+ entryList.remove(volumeFile)
+ log("entryList = %s" % entryList)
+ return writeVolumeSmbConfFile(entryList, fileName)
+
+
+def writeVolumeCifsConfiguration(volumeName, userList, adminUser=None):
+ volumeFile = "%s/%s.smbconf" % (Globals.VOLUME_CONF_DIR, volumeName)
+ try:
+ fp = open(volumeFile, "w")
+ fp.write("[%s]\n" % volumeName)
+ fp.write(" comment = %s volume served by Gluster\n" % volumeName)
+ fp.write(" path = %s/%s\n" % (Globals.CIFS_EXPORT_DIR, volumeName))
+ fp.write(" guest ok = yes\n")
+ fp.write(" public = yes\n")
+ fp.write(" writable = yes\n")
+ if adminUser:
+ fp.write(" admin users = %s, %s\n" % (adminUser, ", ".join(userList)))
+ fp.write(" valid users = %s, %s\n" % (adminUser, ", ".join(userList)))
+ else:
+ fp.write(" admin users = %s\n" % (", ".join(userList)))
+ fp.write(" valid users = %s\n" % (", ".join(userList)))
+ fp.close()
+ return True
+ except IOError, e:
+ log("Failed to write file %s: %s" % (volumeFile, str(e)))
+ return False
+
+
+def removeVolumeCifsConfiguration(volumeName):
+ volumeFile = "%s/%s.smbconf" % (Globals.VOLUME_CONF_DIR, volumeName)
+ try:
+ os.remove(volumeFile)
+ except OSError, e:
+ log("Failed to remove file %s: %s" % (volumeFile, str(e)))
+
+
+def getVolumeListByPartitionName(partitionName):
+ volumeConfigFileList = glob.glob(Globals.VOLUME_CONF_DIR + "/*.xml")
+ if not volumeConfigFileList:
+ return None
+
+ volumeList = []
+ for volumeXmlFile in volumeConfigFileList:
+ volumeDom = XDOM()
+ volumeDom.parseFile(volumeXmlFile)
+ serverTopology = volumeDom.getElementsByTagRoute("volume.topology.group")
+ serverPartitionFound = False
+ for topology in serverTopology:
+ partitionDom = XDOM()
+ for partition in topology.getElementsByTagName("partition"):
+ partitionDom.setDomObj(partition)
+ if partitionDom.getTextByTagRoute("name") == partitionName:
+ serverPartitionFound = True
+ break
+ if serverPartitionFound:
+ volumeList.append(volumeDom.getElementsByTagRoute("volume")[0])
+ break
+ return volumeList
+
+
+def addServerPartitionConfig(inputDom, groupOrder, partitionTag):
+ if not(inputDom and groupOrder and partitionTag):
+ return False
+ groupDom = XDOM()
+ for group in inputDom.getElementsByTagRoute("topology.group"):
+ groupDom.setDomObj(group)
+ order = groupDom.getTextByTagRoute("order")
+ if order and int(order) == groupOrder:
+ group.appendChild(partitionTag)
+ return inputDom
+ return False
+
+
+def removeServerPartitionConfig(inputDom, partitionName):
+ if not(inputDom and partitionName):
+ return False
+ for group in inputDom.getElementsByTagRoute("topology.group"):
+ partitionDom = XDOM()
+ for partition in group.getElementsByTagName("partition"):
+ partitionDom.setDomObj(partition)
+ if partitionDom.getTextByTagRoute("name") == partitionName:
+ group.removeChild(partition)
+ return inputDom
+ return False
+
+
+def updateServerPartitionConfig(inputDom, partitionName, partitionTag):
+ if not(inputDom and partitionName and partitionTag):
+ return False
+ for group in inputDom.getElementsByTagRoute("topology.group"):
+ partitionDom = XDOM()
+ for partition in group.getElementsByTagName("partition"):
+ partitionDom.setDomObj(partition)
+ if partitionDom.getTextByTagRoute("name") == partitionName:
+ try:
+ group.replaceChild(partitionTag, partition)
+ return inputDom
+ except AttributeError:
+ return False
+ return False
+
+
+def getServerPartitionConfigUuid(serverGroupList, serverPartition):
+ for group in serverGroupList:
+ if not group:
+ continue
+ partitionDom = XDOM()
+ for partition in group.getElementsByTagName("partition"):
+ partitionDom.setDomObj(partition)
+ partitionName = partition.getTextByTagName("name")
+ if not partitionName:
+ continue
+ if partitionName == serverPartition:
+ return partitionDom.getTextByTagName("uuid")
+ return False
+
+
+def setServerPartitionConfigProperty(inputDom, partitionName, propertyDict):
+ if not(inputDom and partitionName and propertyDict):
+ return False
+ for group in inputDom.getElementsByTagRoute("topology.group"):
+ partitionDom = XDOM()
+ for partition in group.getElementsByTagName("partition"):
+ partitionDom.setDomObj(partition)
+ if partitionDom.getTextByTagRoute("name") == partitionName:
+ for part in propertyDict.keys():
+ x = partition.getElementsByTagName(part)
+ if x:
+ x[0].childNodes[0].nodeValue = propertyDict[part]
+ return inputDom
+ return False
+
+
+def getSortedServerPartitionConfigProperty(inputDom):
+ groupDict = {}
+ if not inputDom:
+ return None
+ groupDom = XDOM()
+ for group in inputDom.getElementsByTagRoute("topology.group"):
+ groupDom.setDomObj(group)
+ groupOrder = groupDom.getTextByTagRoute("order")
+ if not groupOrder:
+ return None
+ groupOrder = int(groupOrder)
+ if groupOrder < 1:
+ return None
+ partitionDom = XDOM()
+ partitionDict = {}
+ for partition in group.getElementsByTagName("partition"):
+ partitionDom.setDomObj(partition)
+ partitionName = partitionDom.getTextByTagRoute("name")
+ if not partitionName:
+ return None
+ partitionOrder = partitionDom.getTextByTagRoute("order")
+ if not partitionOrder:
+ return None
+ partitionUuid = partitionDom.getTextByTagRoute("uuid")
+ partitionOrder = int(partitionOrder)
+ if partitionOrder < 1:
+ return None
+ partitionDetails = partitionName.split(":")
+ if not partitionDetails or len(partitionDetails) < 1:
+ return None
+ partitionDict[partitionOrder] = { "order":partitionOrder,
+ "servername":partitionDetails[0],
+ "name":partitionDetails[1],
+ "uuid":partitionUuid}
+ groupDict[groupOrder] = partitionDict
+
+ serverList = []
+ groupOrderList = groupDict.keys()
+ groupOrderList.sort()
+ for groupOrder in groupOrderList:
+ partitionOrderList = groupDict[groupOrder].keys()
+ partitionOrderList.sort()
+ for partitionOrder in partitionOrderList:
+ serverList.append(groupDict[groupOrder][partitionOrder])
+
+ return serverList
+
+
+def getSortedServerPartitionList(serverGroupElements):
+ serverPartitionDict = {}
+ groupOrderList = []
+ serverList = []
+ partitionDom = XDOM()
+ for group in serverGroupElements:
+ if not group:
+ continue
+ groupOrderE = group.getElementsByTagName("order")
+ if not (groupOrderE and groupOrderE[0].childNodes):
+ return None
+ value = int(XDOM.getText(groupOrderE[0].childNodes))
+ if value > 0:
+ groupOrderList.append(value)
+ partitionDict = {}
+ for partition in group.getElementsByTagName("partition"):
+ partitionDom.setDomObj(partition)
+
+ partitionName = partitionDom.getTextByTagRoute("name")
+ if not partitionName:
+ return None
+ partitionOrder = partitionDom.getTextByTagRoute("order")
+ if not partitionOrder:
+ return None
+ partitionUuid = partitionDom.getTextByTagRoute("uuid")
+ partitionDict[int(partitionOrder)] = [partitionName, partitionUuid]
+ serverPartitionDict[value] = partitionDict
+ groupOrderList.sort()
+
+ for groupOrder in groupOrderList:
+ items = serverPartitionDict[groupOrder].items()
+ items.sort(key = itemgetter(0))
+ serverList = serverList + [ items[i][1] for i in range(0,len(items))]
+ return serverList
+
+
+def clearExportDirectory(serverList, volumeName, volumeUuid):
+ thisServerName = getCurrentServerName()
+ for exportServer in serverList:
+ serverName, partition = exportServer[0].split(":")
+ if thisServerName != serverName:
+ continue
+ partitionUuid = getUuidByDiskPartition(getDevice(partition))
+ if not partitionUuid:
+ log("unable to find uuid of partition %s" % partition)
+ return False
+ volumeDirName = "%s/%s/%s" % (Globals.GLUSTER_LUN_DIR, partitionUuid, volumeUuid)
+ if os.path.exists(volumeDirName):
+ ## Removing /data/PARTITION-UUID/VOLUME-UUID/
+ ## TODO: Get an option to remove it at this time
+ if runCommandFG("mv -f %s %s.delete" % (volumeDirName, volumeDirName), root=True) != 0:
+ return False
+ if runCommandFG("rm -f %s/%s/volumes/%s" % (Globals.GLUSTER_LUN_DIR, partitionUuid, volumeName), root=True) != 0:
+ return False
+ return True
+
+
+def createExportDirectory(serverList, volumeName, volumeUuid):
+ thisServerName = getCurrentServerName()
+ tempVolumeNameFile = getTempFileName()
+
+ try:
+ fp = open(tempVolumeNameFile, "w")
+ fp.write("VOLUME_NAME=%s\n" % volumeName)
+ fp.write("VOLUME_UUID=%s\n" % volumeUuid)
+ fp.close()
+ except IOError, e:
+ log("failed to create temporary file for volume-name: %s" % (volumeName, str(e)))
+ return False
+
+ for exportServer in serverList:
+ serverName, partition = exportServer[0].split(":")
+ if thisServerName != serverName:
+ continue
+ partitionUuid = getUuidByDiskPartition(getDevice(partition))
+ if not partitionUuid:
+ log("unable to find uuid of partition %s" % partition)
+ return False
+
+ volumeDirName = "%s/%s/%s" % (Globals.GLUSTER_LUN_DIR, partitionUuid, volumeUuid)
+ ## Creating /data/PARTITION-UUID/VOLUME-UUID/
+ if runCommandFG("mkdir %s" % volumeDirName, root=True) != 0:
+ return False
+
+ ## Creating /data/PARTITION-UUID/VOLUME-UUID/exports/
+ ## Creating /data/PARTITION-UUID/VOLUME-UUID/exports/brick1/
+ if runCommandFG("mkdir -p %s/exports/brick1" % volumeDirName, root=True) != 0:
+ return False
+
+ ## Creating /data/PARTITION-UUID/VOLUME-UUID/log/
+ if runCommandFG("mkdir %s/log" % volumeDirName, root=True) != 0:
+ return False
+
+ ## Creating /data/PARTITION-UUID/VOLUME-UUID/config/
+ if runCommandFG("mkdir %s/config" % volumeDirName, root=True) != 0:
+ return False
+
+ volumeLinkDirName = "%s/%s/volumes" % (Globals.GLUSTER_LUN_DIR, partitionUuid)
+ if not os.path.exists(volumeLinkDirName):
+ if runCommandFG("mkdir %s" % volumeLinkDirName, root=True) != 0:
+ return False
+
+ ## Creating symlink
+ ## /data/PARTITION-UUID/volumes/VOLUME-NAME -> /data/PARTITION-UUID/VOLUME-UUID/
+ command = "ln -fTs %s %s/%s" % (volumeDirName,
+ volumeLinkDirName, volumeName)
+ if runCommandFG(command, root=True) != 0:
+ return False
+
+ if runCommandFG("cp -f %s %s/config/volume-name" % (tempVolumeNameFile, volumeDirName), root=True) != 0:
+ return False
+
+ try:
+ os.remove(tempVolumeNameFile)
+ except OSError, e:
+ log("Failed to remove file %s: %s" % (tempVolumeNameFile, str(e)))
+
+ return True
+
+
+def getPartitionListByServerName(volumeDom, serverName, serverPartitionList=None):
+ partitionList = {}
+ if serverPartitionList:
+ for partitionName in serverPartitionList:
+ partitionUuid = getServerDiskPartitionUuid(serverName, partitionName)
+ if not partitionUuid:
+ log(syslog.LOG_ERR, "failed to get disk partition %s uuid of server %s" % (partitionName, serverName))
+ return None
+ partitionList[partitionName] = partitionUuid
+ return partitionList
+ for group in volumeDom.getElementsByTagRoute("topology.group"):
+ for partitionTag in group.getElementsByTagName("partition"):
+ nameE = partitionTag.getElementsByTagName("name")
+ if not nameE:
+ continue
+ partition = XDOM.getText(nameE[0].childNodes)
+ if not partition:
+ continue
+ server, partitionName = partition.split(":")
+ if server != serverName:
+ continue
+ partitionUuid = getServerDiskPartitionUuid(serverName, partitionName)
+ if not partitionUuid:
+ log(syslog.LOG_ERR, "failed to get disk partition %s uuid of server %s" % (partitionName, serverName))
+ return None
+ partitionList[partitionName] = partitionUuid
+ return partitionList
+
+
+def isVolumeRunning(volumeName):
+ return Glusterd.isVolumeRunning(volumeName)
+
+def addVolumeMigrationDetails(sourcePartition, destinationPartition, volumeName):
+ migrationDom = XDOM()
+ if not os.path.exists(Globals.VOLUME_MIGRATION_LIST_FILE):
+ migrationDom.appendTagRoute("volume-migration")
+ else:
+ if not migrationDom.parseFile(Globals.VOLUME_MIGRATION_LIST_FILE):
+ log("Failed to load volume-migration.xml file")
+ return None
+ migrationList = migrationDom.getElementsByTagRoute("volume-migration.migration")
+ for tagE in migrationList:
+ dom = XDOM()
+ dom.setDomObj(tagE)
+ if dom.getTextByTagRoute("source-partition") == sourcePartition and \
+ dom.getTextByTagRoute("destination-partition") == destinationPartition and \
+ dom.getTextByTagRoute("volume-name") == volumeName:
+ return False
+ migrationTag = migrationDom.getElementsByTagRoute("volume-migration")
+ if not migrationTag:
+ return None
+ partitionTag = migrationDom.createTag("migration")
+ partitionTag.appendChild(migrationDom.createTag("source-partition", sourcePartition))
+ partitionTag.appendChild(migrationDom.createTag("destination-partition", destinationPartition))
+ partitionTag.appendChild(migrationDom.createTag("volume-name", volumeName))
+ migrationTag[0].appendChild(partitionTag)
+ if not migrationDom.writexml(Globals.VOLUME_MIGRATION_LIST_FILE):
+ log("Unable to write disk migration details into %s/volume-migration.xml" % Globals.GLUSTER_BASE_DIR)
+ return False
+ return True
+
+
+def removeVolumeMigrationDetails(sourcePartition, destinationPartition, volumeName):
+ migrationDom = XDOM()
+ if not os.path.exists(Globals.VOLUME_MIGRATION_LIST_FILE):
+ return None
+ if not migrationDom.parseFile(Globals.VOLUME_MIGRATION_LIST_FILE):
+ log("Failed to load volume-migration.xml file")
+ return None
+ migrationList = migrationDom.getElementsByTagRoute("volume-migration.migration")
+ for tagE in migrationList:
+ dom = XDOM()
+ dom.setDomObj(tagE)
+ if dom.getTextByTagRoute("source-partition") == sourcePartition and \
+ dom.getTextByTagRoute("destination-partition") == destinationPartition and \
+ dom.getTextByTagRoute("volume-name") == volumeName:
+ migrationDom.getElementsByTagRoute("volume-migration")[0].removeChild(tagE)
+ if not migrationDom.writexml(Globals.VOLUME_MIGRATION_LIST_FILE):
+ log("Unable to write disk migration details into %s/volume-migration.xml" % Globals.GLUSTER_BASE_DIR)
+ return False
+ return True
+
+
+def addPartitionMigrationDetails(sourcePartition, destinationPartition, volumeList=None):
+ migrationDom = XDOM()
+ if not os.path.exists(Globals.MIGRATE_PARTITION_LIST_FILE):
+ migrationDom.appendTagRoute("partition-migration")
+ else:
+ if not migrationDom.parseFile(Globals.MIGRATE_PARTITION_LIST_FILE):
+ log("Failed to load migration.xml file")
+ return None
+ migrationList = migrationDom.getElementsByTagRoute("partition-migration.migration")
+ for tagE in migrationList:
+ dom = XDOM()
+ dom.setDomObj(tagE)
+ if dom.getTextByTagRoute("source-partition") == sourcePartition:
+ return False
+ if dom.getTextByTagRoute("destination-partition") == destinationPartition:
+ return False
+ migrationTag = migrationDom.getElementsByTagRoute("partition-migration")
+ if not migrationTag:
+ return None
+ partitionTag = migrationDom.createTag("migration")
+ partitionTag.appendChild(migrationDom.createTag("source-partition", sourcePartition))
+ partitionTag.appendChild(migrationDom.createTag("destination-partition", destinationPartition))
+ migrationTag[0].appendChild(partitionTag)
+ if not migrationDom.writexml(Globals.MIGRATE_PARTITION_LIST_FILE):
+ log("Unable to write disk migration details into %s/migration.xml" % Globals.GLUSTER_BASE_DIR)
+ return False
+ if volumeList:
+ for volumeName in volumeList:
+ addVolumeMigrationDetails(sourcePartition, destinationPartition, volumeName)
+ return True
+
+
+def removePartitionMigrationDetails(sourcePartition, destinationPartition, volumeList=None):
+ migrationDom = XDOM()
+ if not os.path.exists(Globals.MIGRATE_PARTITION_LIST_FILE):
+ return None
+ if not migrationDom.parseFile(Globals.MIGRATE_PARTITION_LIST_FILE):
+ log("Failed to load migration.xml file")
+ return None
+ migrationList = migrationDom.getElementsByTagRoute("partition-migration.migration")
+ for tagE in migrationList:
+ dom = XDOM()
+ dom.setDomObj(tagE)
+ if dom.getTextByTagRoute("source-partition") == sourcePartition and \
+ dom.getTextByTagRoute("destination-partition") == destinationPartition:
+ migrationDom.getElementsByTagRoute("partition-migration")[0].removeChild(tagE)
+ if not migrationDom.writexml(Globals.MIGRATE_PARTITION_LIST_FILE):
+ log("Unable to write disk migration details into %s/migration.xml" % Globals.GLUSTER_BASE_DIR)
+ return False
+ if volumeList:
+ for volumeName in volumeList:
+ removeVolumeMigrationDetails(sourcePartition, destinationPartition, volumeName)
+ return True
+
+
+def isMigrationInProgress(partition):
+ migrationDom = XDOM()
+ if not os.path.exists(Globals.MIGRATE_PARTITION_LIST_FILE):
+ return None
+ if not migrationDom.parseFile(Globals.MIGRATE_PARTITION_LIST_FILE):
+ log("Failed to load migration.xml file")
+ return None
+ migrationList = migrationDom.getElementsByTagRoute("partition-migration.migration")
+ for tagE in migrationList:
+ dom = XDOM()
+ dom.setDomObj(tagE)
+ if migrationDom.getTextByTagRoute("source-partition") == partition or \
+ migrationDom.getTextByTagRoute("destination-partition") == partition:
+ return True
+ return False
+
+
+def getServerDiskPartitionUuid(serverName, partition):
+ diskConfigDom = XDOM()
+ if not diskConfigDom.parseFile("%s/%s/disk.xml" % (Globals.SERVER_CONF_DIR, serverName)):
+ return None
+ for disk in diskConfigDom.getElementsByTagRoute("disks.disk"):
+ diskDom = XDOM()
+ diskDom.setDomObj(disk)
+ partitionList = diskDom.getElementsByTagRoute("partition")
+ for tagE in partitionList:
+ partitionDom = XDOM()
+ partitionDom.setDomObj(tagE)
+ if partitionDom.getTextByTagRoute("device") == partition:
+ return partitionDom.getTextByTagRoute("uuid")
+
+
+def getVolumeServerList(requestDom, requestFlag=True):
+ if requestFlag:
+ serverGroupElementList = requestDom.getElementsByTagRoute("command.volume.topology.group")
+ else:
+ serverGroupElementList = requestDom.getElementsByTagRoute("volume.topology.group")
+ if not serverGroupElementList:
+ return None
+ serverList = []
+ partitionDom = XDOM()
+ for group in serverGroupElementList:
+ for partition in group.getElementsByTagName("partition"):
+ partitionDom.setDomObj(partition)
+ partitionName = partitionDom.getTextByTagRoute("name")
+ if not partitionName:
+ continue
+ serverPartition = partitionName.split(":")
+ if not(len(serverPartition) > 1 and serverPartition[1]):
+ return None
+ if serverPartition[0] not in serverList:
+ serverList.append(serverPartition[0])
+ return serverList
+
+
+def getVolumeServerListByName(volumeName):
+ serverList = []
+ serverDom = XDOM()
+ volumeDom = XDOM()
+ if not os.path.exists("%s/%s.xml" % (Globals.VOLUME_CONF_DIR, volumeName)):
+ return False
+ if not volumeDom.parseFile("%s/%s.xml" % (Globals.VOLUME_CONF_DIR, volumeName)):
+ return False
+ return getVolumeServerList(volumeDom, False)
+
+
+def getMigrateVolumeServerPartitionInfo(volumeName):
+ volumeMigrationDom = XDOM()
+ if not volumeMigrationDom.parseFile(Globals.VOLUME_MIGRATION_LIST_FILE):
+ Utils.log("Failed to parse file %s" % Globals.VOLUME_MIGRATION_LIST_FILE)
+ return None
+ volumeInfo = {}
+ dom = XDOM()
+ for tagE in volumeMigrationDom.getElementsByTagRoute("volume-migration.migration"):
+ dom.setDomObj(tagE)
+ if dom.getTextByTagRoute("volume-name") == volumeName:
+ volumeInfo['Name'] = volumeName
+ volumeInfo['SourcePartition'] = dom.getTextByTagRoute("source-partition")
+ volumeInfo['DestinationPartition'] = dom.getTextByTagRoute("destination-partition")
+ return volumeInfo
+ return None
diff --git a/src/com.gluster.storage.management.server.scripts/src/nodes/get-disk-mount-point.py b/src/com.gluster.storage.management.server.scripts/src/nodes/get_disk_mount_point.py
index b2274b4d..b2274b4d 100755
--- a/src/com.gluster.storage.management.server.scripts/src/nodes/get-disk-mount-point.py
+++ b/src/com.gluster.storage.management.server.scripts/src/nodes/get_disk_mount_point.py
diff --git a/src/com.gluster.storage.management.server.scripts/src/nodes/get_disk_name_by_path.py b/src/com.gluster.storage.management.server.scripts/src/nodes/get_disk_name_by_path.py
new file mode 100755
index 00000000..72eb80dd
--- /dev/null
+++ b/src/com.gluster.storage.management.server.scripts/src/nodes/get_disk_name_by_path.py
@@ -0,0 +1,69 @@
+#!/usr/bin/python
+# Copyright (C) 2010 Gluster, Inc. <http://www.gluster.com>
+# This file is part of Gluster Storage Platform.
+#
+# Gluster Storage Platform is free software; you can redistribute it
+# and/or modify it under the terms of the GNU General Public License
+# as published by the Free Software Foundation; either version 3 of
+# the License, or (at your option) any later version.
+#
+# Gluster Storage Platform is distributed in the hope that it will be
+# useful, but WITHOUT ANY WARRANTY; without even the implied warranty
+# of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program. If not, see
+# <http://www.gnu.org/licenses/>.
+
+import os
+import syslog
+import Common
+from DiskUtils import *
+from XmlHandler import ResponseXml
+
+
+def getmountpoint(path):
+ if not path:
+ Common.log(syslog.LOG_ERR, "Not a valid path:%s" % path)
+ rs.appendTagRoute("status.code", "-1")
+ rs.appendTagRoute("status.message", "Error: given path name is empty")
+ return rs.toprettyxml()
+
+ rs = ResponseXml()
+ mountPoint = None
+ fsTabEntry = None
+ for line in readFsTab():
+ if path.startswith(line['MountPoint']):
+ if not mountPoint:
+ mountPoint = line['MountPoint']
+ fsTabEntry = line
+ if len(line['MountPoint']) > len(mountPoint):
+ mountPoint = line['MountPoint']
+ fsTabEntry = line
+
+ if "/" == mountPoint or not mountPoint:
+ Common.log(syslog.LOG_ERR, "failed to find mount point of the given path:%s" % path)
+ rs.appendTagRoute("status.code", "-1")
+ rs.appendTagRoute("status.message", "Error: Unable to find disk mount point")
+ return rs.toprettyxml()
+
+ rs.appendTagRoute("status.code", "0")
+ if fsTabEntry["Device"].startswith("UUID="):
+ rs.appendTagRoute("status.message", getDiskPartitionByUuid(fsTabEntry["Device"].split("UUID=")[-1]))
+ else:
+ rs.appendTagRoute("status.message", "Unable to find disk name")
+ return rs.toprettyxml()
+
+def main():
+ if len(sys.argv) != 2:
+ print >> sys.stderr, "usage: %s <path>" % sys.argv[0]
+ sys.exit(-1)
+
+ path = sys.argv[1]
+ print getmountpoint(path)
+ sys.exit(0)
+
+if __name__ == "__main__":
+ main()
+
diff --git a/src/com.gluster.storage.management.server.scripts/src/nodes/get_volume_brick_log.py b/src/com.gluster.storage.management.server.scripts/src/nodes/get_volume_brick_log.py
new file mode 100755
index 00000000..7c912412
--- /dev/null
+++ b/src/com.gluster.storage.management.server.scripts/src/nodes/get_volume_brick_log.py
@@ -0,0 +1,109 @@
+#!/usr/bin/python
+# Copyright (C) 2009,2010 Gluster, Inc. <http://www.gluster.com>
+# This file is part of Gluster Storage Platform.
+#
+# Gluster Storage Platform is free software; you can redistribute it
+# and/or modify it under the terms of the GNU General Public License
+# as published by the Free Software Foundation; either version 3 of
+# the License, or (at your option) any later version.
+#
+# Gluster Storage Platform is distributed in the hope that it will be
+# useful, but WITHOUT ANY WARRANTY; without even the implied warranty
+# of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program. If not, see
+# <http://www.gnu.org/licenses/>.
+
+import re
+import os
+import sys
+from XmlHandler import ResponseXml
+
+def enumLogType(logCode):
+ if "M" == logCode.upper():
+ return "EMERGENCY"
+ elif "A" == logCode.upper():
+ return "ALERT"
+ elif "C" == logCode.upper():
+ return "CRITICAL"
+ elif "E" == logCode.upper():
+ return "ERROR"
+ elif "W" == logCode.upper():
+ return "WARNING"
+ elif "N" == logCode.upper():
+ return "NOTICE"
+ elif "I" == logCode.upper():
+ return "INFO"
+ elif "D" == logCode.upper():
+ return "DEBUG"
+ elif "T" == logCode.upper():
+ return "TRACE"
+ else:
+ return "UNKNOWN"
+##--end of enumLogType()
+
+def addLog(responseDom, logMessageTag, loginfo):
+ logTag = responseDom.createTag("logMessage", None)
+ logTag.appendChild(responseDom.createTag("timestamp", loginfo[0] + " " + loginfo[1]))
+ logTag.appendChild(responseDom.createTag("severity", enumLogType(loginfo[2])))
+ logTag.appendChild(responseDom.createTag("message", loginfo[3]))
+ logMessageTag.appendChild(logTag)
+ return True
+##--end of addLog()
+
+def logSplit(log):
+ loginfo = log.strip().split(None, 3)
+ loginfo[0] = loginfo[0][1:] #-- Remove '['
+ loginfo[1] = loginfo[1][0:-1] #-- Remove ']'
+ return loginfo
+##--end of logSplit()
+
+def getVolumeLog(logFilePath, tailCount):
+ rs = ResponseXml()
+ if not logFilePath:
+ rs.appendTagRoute("status.code", "-1")
+ rs.appendTagRoute("status.message", "No log file path given")
+ return rs.toprettyxml()
+
+ if not tailCount:
+ rs.appendTagRoute("status.code", "-1")
+ rs.appendTagRoute("status.message", "No tail count given")
+ return rs.toprettyxml()
+
+ pattern = '\[\d{4}-\d{2}-\d{2}\s{1}\d{2}:\d{2}:\d{2}.\d+\]\s{1}([MACEWNIDT]){1}\s+'
+ logMessagesTag = rs.createTag("logMessages")
+ if not os.path.exists(logFilePath):
+ rs.appendTagRoute("status.code", "-1")
+ rs.appendTagRoute("status.message", "volume log file [%s] not found!" % logFilePath)
+ return rs.toprettyxml
+
+ fp = open(logFilePath)
+ #lines = [line for line in fp]
+ lines = [line for line in fp if re.match(pattern, line)]
+ fp.close()
+ i = len(lines) - int(tailCount)
+ if i < 0:
+ i = 0
+ for log in lines[i:]:
+ loginfo = logSplit(log)
+ addLog(rs, logMessagesTag, loginfo)
+ rs.appendTagRoute("status.code", "0")
+ rs.appendTagRoute("status.message", "Success")
+ rs.appendTag(logMessagesTag)
+ return rs.toprettyxml()
+##--end of getVolumeLog()
+
+def main():
+ if len(sys.argv) != 3:
+ print >> sys.stderr, "usage: %s <Log File Path> <Line Count>" % sys.argv[0]
+ sys.exit(-1)
+
+ logFilePath = sys.argv[1]
+ tailCount = sys.argv[2]
+ print getVolumeLog(logFilePath, tailCount)
+ sys.exit(0)
+
+if __name__ == "__main__":
+ main()
diff --git a/src/com.gluster.storage.management.server.scripts/src/nodes/get_volume_log.py b/src/com.gluster.storage.management.server.scripts/src/nodes/get_volume_log.py
new file mode 100755
index 00000000..826ade6e
--- /dev/null
+++ b/src/com.gluster.storage.management.server.scripts/src/nodes/get_volume_log.py
@@ -0,0 +1,132 @@
+# Copyright (C) 2009,2010 Gluster, Inc. <http://www.gluster.com>
+# This file is part of Gluster Storage Platform.
+#
+# Gluster Storage Platform is free software; you can redistribute it
+# and/or modify it under the terms of the GNU General Public License
+# as published by the Free Software Foundation; either version 3 of
+# the License, or (at your option) any later version.
+#
+# Gluster Storage Platform is distributed in the hope that it will be
+# useful, but WITHOUT ANY WARRANTY; without even the implied warranty
+# of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program. If not, see
+# <http://www.gnu.org/licenses/>.
+
+import Globals
+import syslog
+import Commands
+import Utils
+from VolumeUtils import *
+from XmlHandler import ResponseXml
+
+
+def enumLogType(logCode):
+ if "M" == logCode.upper():
+ return "EMERGENCY"
+ elif "A" == logCode.upper():
+ return "ALERT"
+ elif "C" == logCode.upper():
+ return "CRITICAL"
+ elif "E" == logCode.upper():
+ return "ERROR"
+ elif "W" == logCode.upper():
+ return "WARNING"
+ elif "N" == logCode.upper():
+ return "NOTICE"
+ elif "I" == logCode.upper():
+ return "INFO"
+ elif "D" == logCode.upper():
+ return "DEBUG"
+ elif "T" == logCode.upper():
+ return "TRACE"
+ else:
+ return "UNKNOWN"
+##--end of enumLogType()
+
+
+def addLog(responseDom, logMessageTag, loginfo):
+ logTag = responseDom.createTag("log", None)
+ logTag.appendChild(responseDom.createTag("date", loginfo[0]))
+ logTag.appendChild(responseDom.createTag("time", loginfo[1]))
+ logTag.appendChild(responseDom.createTag("type", enumLogType(loginfo[2])))
+ logTag.appendChild(responseDom.createTag("message", loginfo[3]))
+ logMessageTag.appendChild(logTag)
+ return True
+##--end of addLog()
+
+
+def logSplit(log):
+ loginfo = log.strip().split(None, 3)
+ loginfo[0] = loginfo[0][1:] #-- Remove '['
+ loginfo[1] = loginfo[1][0:-1] #-- Remove ']'
+ return loginfo
+##--end of logSplit()
+
+
+def getVolumeLog(volumeName, tailCount):
+ rs = ResponseXml()
+ if not volumeName:
+ rs.appendTagRoute("status.code", "-1")
+ rs.appendTagRoute("status.message", "No volume name given")
+ return rs.toprettyxml()
+
+ if not tailCount:
+ rs.appendTagRoute("status.code", "-1")
+ rs.appendTagRoute("status.message", "No tail count given")
+ return rs.toprettyxml()
+
+ thisServerName = getCurrentServerName()
+ if not thisServerName:
+ rs.appendTagRoute("status.code", "-2")
+ rs.appendTagRoute("status.message", "Failed to get current server name")
+ return rs.toprettyxml()
+
+ volumeDom = XDOM()
+ partitionList = getPartitionListByServerName(volumeDom, thisServerName)
+ if not partitionList:
+ rs.appendTagRoute("status.code", "-3")
+ rs.appendTagRoute("status.message", "Failed to get server partition details")
+ return rs.toprettyxml()
+
+ pattern = '\[\d{4}-\d{2}-\d{2}\s{1}\d{2}:\d{2}:\d{2}.\d+\]\s{1}([MACEWNIDT]){1}\s+'
+ logMessagesTag = rs.createTag("response.logMessages")
+ for partitionName in partitionList:
+ logMessageTag = rs.createTag("logMessage")
+ logMessageTag.appendChild("disk", "%s:%s" % (thisServerName, partitionName))
+
+ logDirectory = "%s/%s/%s/log" % (Globals.GLUSTER_LUN_DIR, partitionList[partitionName], volumeUuid)
+ logFileName = "%s/%s-%s-%s-exports-brick1.log" % (logDirectory,
+ Globals.GLUSTER_LUN_DIR[1:],
+ partitionList[partitionName],
+ volumeUuid)
+ if not os.path.exists(logFileName):
+ Utils.log("volume log file not found %s" % logFileName)
+ continue
+ fp = open(logFileName)
+ lines = [line for line in fp if re.match(pattern, line)]
+ fp.close()
+ i = len(lines) - int(tailCount)
+ if i < 0:
+ i = 0
+ for log in lines[i:]:
+ loginfo = logSplit(log)
+ addLog(rs, logMessageTag, loginfo)
+ logMessagesTag.appendChild(logMessageTag)
+ return rs.toprettyxml()
+##--end of getVolumeLog()
+
+def main():
+ if len(sys.argv) != 3:
+ print >> sys.stderr, "usage: %s <disk name> <volume name>" % sys.argv[0]
+ sys.exit(-1)
+
+ volumeName = sys.argv[1]
+ tailCount = sys.argv[2]
+ print getVolumeLog(volumeName, tailCount)
+ sys.exit(0)
+
+if __name__ == "__main__":
+ main()
diff --git a/src/com.gluster.storage.management.server/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 e30462f2..11e12977 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,10 +24,10 @@ 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_DELETE_OPTION;
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.QUERY_PARAM_VOLUME_NAME;
-import static com.gluster.storage.management.core.constants.RESTConstants.QUERY_PARAM_DELETE_OPTION;
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;
@@ -72,7 +72,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 VOLUME_DISK_LOG_SCRIPT = "get_volume_disk_log.py";
+ private static final String VOLUME_BRICK_LOG_SCRIPT = "get_volume_brick_log.py";
@InjectParam
private static ServerUtil serverUtil;
@@ -261,28 +261,32 @@ public class VolumesResource {
return new Status(Status.STATUS_CODE_SUCCESS, "Directories cleaned up successfully!");
}
- private List<LogMessage> getDiskLogs(String volumeName, String diskName, Integer lineCount)
+ private List<LogMessage> getBrickLogs(Volume volume, String brickName, Integer lineCount)
throws GlusterRuntimeException {
- String[] diskParts = diskName.split(":");
- String server = diskParts[0];
- String disk = diskParts[1];
+ // brick name format is <serverName>:<brickDirectory>
+ String[] brickParts = brickName.split(":");
+ String serverName = brickParts[0];
+ String brickDir = brickParts[1];
+
+ String logDir = glusterUtil.getLogLocation(volume.getName(), brickName);
+ String logFileName = glusterUtil.getLogFileNameForBrickDir(brickDir);
+ String logFilePath = logDir + CoreConstants.FILE_SEPARATOR + logFileName;
// 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());
+ LogMessageListResponse response = ((LogMessageListResponse) serverUtil.executeOnServer(true, serverName, VOLUME_BRICK_LOG_SCRIPT
+ + " " + logFilePath + " " + lineCount, LogMessageListResponse.class));
+ Status status = response.getStatus();
+ if (!response.getStatus().isSuccess()) {
+ throw new GlusterRuntimeException(status.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));
+ // populate disk and trim other fields
+ List<LogMessage> logMessages = response.getLogMessages();
+ for(LogMessage logMessage : logMessages) {
+ logMessage.setDisk(getDiskForBrick(volume, brickName));
+ logMessage.setMessage(logMessage.getMessage().trim());
+ logMessage.setSeverity(logMessage.getSeverity().trim());
}
-
return logMessages;
}
@@ -293,16 +297,16 @@ public class VolumesResource {
List<LogMessage> logMessages = null;
try {
+ Volume volume = getVolume(volumeName);
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));
+ for (String brick : volume.getBricks()) {
+ logMessages.addAll(getBrickLogs(volume, brick, lineCount));
}
} else {
// fetch logs for given brick of the volume
- logMessages = getDiskLogs(volumeName, diskName, lineCount);
+ logMessages = getBrickLogs(volume, getBrickForDisk(volume, diskName), lineCount);
}
} catch (Exception e) {
return new LogMessageListResponse(new Status(e), null);
@@ -311,6 +315,16 @@ public class VolumesResource {
return new LogMessageListResponse(Status.STATUS_SUCCESS, logMessages);
}
+ private String getBrickForDisk(Volume volume, String diskName) {
+ int index = volume.getDisks().indexOf(diskName);
+ return volume.getBricks().get(index);
+ }
+
+ private String getDiskForBrick(Volume volume, String brickName) {
+ int index = volume.getBricks().indexOf(brickName);
+ return volume.getDisks().get(index);
+ }
+
public static void main(String[] args) throws ClassNotFoundException {
VolumesResource vr = new VolumesResource();
// VolumeListResponse response = vr.getAllVolumes();
diff --git a/src/com.gluster.storage.management.server/src/com/gluster/storage/management/server/utils/GlusterUtil.java b/src/com.gluster.storage.management.server/src/com/gluster/storage/management/server/utils/GlusterUtil.java
index 6a60962f..6e6e7e14 100644
--- a/src/com.gluster.storage.management.server/src/com/gluster/storage/management/server/utils/GlusterUtil.java
+++ b/src/com.gluster.storage.management.server/src/com/gluster/storage/management/server/utils/GlusterUtil.java
@@ -52,6 +52,7 @@ public class GlusterUtil {
private static final String VOLUME_BRICKS_GROUP_PFX = "Bricks";
private static final String VOLUME_OPTIONS_RECONFIG_PFX = "Options Reconfigured";
private static final String VOLUME_OPTION_AUTH_ALLOW = "auth.allow:";
+ private static final String VOLUME_LOG_LOCATION_PFX = "log file location:";
private static final ProcessUtil processUtil = new ProcessUtil();
@@ -289,25 +290,31 @@ public class GlusterUtil {
String[] brickParts = line.split(":");
String serverName = brickParts[1].trim();
String brickDir = brickParts[2].trim();
- // brick directory should be of the form /export/<diskname>/volume-name
- try {
- volume.addDisk(serverName + ":" + brickDir.split("/")[2].trim());
- } catch(ArrayIndexOutOfBoundsException e) {
- // brick directory of a different form, most probably created manually
- // connect to the server and get disk for the brick directory
- Status status = new ServerUtil().getDiskForDir(serverName, brickDir);
- if(status.isSuccess()) {
- volume.addDisk(serverName + ":" + status.getMessage());
- } else {
- // Couldn't fetch disk for the brick directory. Log error and add "unknown" as disk name.
- System.out.println("Couldn't fetch disk name for brick [" + serverName + ":" + brickDir + "]");
- volume.addDisk(serverName + ":unknown");
- }
- }
+
+ volume.addBrick(serverName + ":" + brickDir);
+ detectAndAddDiskToVolume(volume, serverName, brickDir);
return true;
}
return false;
}
+
+ private void detectAndAddDiskToVolume(Volume volume, String serverName, String brickDir) {
+ // brick directory should be of the form /export/<diskname>/volume-name
+ try {
+ volume.addDisk(serverName + ":" + brickDir.split("/")[2].trim());
+ } catch(ArrayIndexOutOfBoundsException e) {
+ // brick directory of a different form, most probably created manually
+ // connect to the server and get disk for the brick directory
+ Status status = new ServerUtil().getDiskForDir(serverName, brickDir);
+ if(status.isSuccess()) {
+ volume.addDisk(serverName + ":" + status.getMessage());
+ } else {
+ // Couldn't fetch disk for the brick directory. Log error and add "unknown" as disk name.
+ System.out.println("Couldn't fetch disk name for brick [" + serverName + ":" + brickDir + "]");
+ volume.addDisk(serverName + ":unknown");
+ }
+ }
+ }
private boolean readBrickGroup(String line) {
return extractToken(line, VOLUME_BRICKS_GROUP_PFX) != null;
@@ -399,6 +406,31 @@ public class GlusterUtil {
return volumes;
}
+ public String getLogLocation(String volumeName, String brickName) {
+ ProcessResult result = new ProcessUtil().executeCommand("gluster", "volume", "log", "locate", volumeName,
+ brickName);
+ if (!result.isSuccess()) {
+ throw new GlusterRuntimeException("Command [gluster volume info] failed with error: ["
+ + result.getExitValue() + "][" + result.getOutput() + "]");
+ }
+ String output = result.getOutput();
+ if (output.startsWith(VOLUME_LOG_LOCATION_PFX)) {
+ return output.substring(VOLUME_LOG_LOCATION_PFX.length()).trim();
+ }
+
+ throw new GlusterRuntimeException("Couldn't parse output of [volume log locate] command. [" + output
+ + "] doesn't start with prefix [" + VOLUME_LOG_LOCATION_PFX + "]");
+ }
+
+ public String getLogFileNameForBrickDir(String brickDir) {
+ String logFileName = brickDir;
+ if(logFileName.startsWith(CoreConstants.FILE_SEPARATOR)) {
+ logFileName = logFileName.replaceFirst(CoreConstants.FILE_SEPARATOR, "");
+ }
+ logFileName = logFileName.replaceAll(CoreConstants.FILE_SEPARATOR, "-") + ".log";
+ return logFileName;
+ }
+
public static void main(String args[]) {
// List<String> names = new GlusterUtil().getGlusterServerNames();
// System.out.println(names);
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 47657c2a..5e423f1c 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
@@ -93,8 +93,6 @@ public class ServerUtil {
}
connection.close();
- System.out.println("The ouput string is : " + output.toString());
-
return unmarshal(expectedClass, output.toString(), expectedClass != Status.class);
} catch(Exception e) {
// any other exception means unexpected error. return status with error from exception.