From 7e6efca549922972ab18074af8337b5105f0cfcd Mon Sep 17 00:00:00 2001 From: Selvam Date: Fri, 15 Apr 2011 16:10:10 +0530 Subject: [Bug 2693] New: Volumes are not listed in the Volumes node Alert section implemented in the volume summary page --- .../management/client/GlusterDataModelManager.java | 33 +- .../storage/management/core/model/Volume.java | 5 +- .../storage/management/core/utils/GlusterUtil.java | 383 -------------------- .../management/gui/views/VolumeSummaryView.java | 25 +- .../management/gui/views/VolumesSummaryView.java | 2 +- .../server/resources/AlertsResource.java | 2 +- .../server/resources/GlusterServersResource.java | 2 +- .../server/resources/VolumesResource.java | 3 +- .../management/server/utils/GlusterUtil.java | 402 +++++++++++++++++++++ .../management/server/utils/ServerUtil.java | 11 + 10 files changed, 450 insertions(+), 418 deletions(-) delete mode 100644 src/com.gluster.storage.management.core/src/com/gluster/storage/management/core/utils/GlusterUtil.java create mode 100644 src/com.gluster.storage.management.server/src/com/gluster/storage/management/server/utils/GlusterUtil.java 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 8d6d5002..815ba853 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 @@ -118,13 +118,10 @@ public class GlusterDataModelManager { setSecurityToken(securityToken); Cluster cluster = new Cluster("Home", model); - VolumesClient volumeClient = new VolumesClient(securityToken); initializeGlusterServers(cluster); - - // initializeVolumes(cluster); - VolumeListResponse response = volumeClient.getAllVolumes(); - cluster.setVolumes(response.getVolumes()); + initializeVolumes(cluster); + initializeAutoDiscoveredServers(cluster); initializeDisks(); @@ -167,26 +164,12 @@ public class GlusterDataModelManager { } private void initializeVolumes(Cluster cluster) { - List volumes = new ArrayList(); - - volume1 = addVolume(volumes, "Volume1", cluster, VOLUME_TYPE.PLAIN_DISTRIBUTE, TRANSPORT_TYPE.ETHERNET, - VOLUME_STATUS.ONLINE); - - volume2 = addVolume(volumes, "Volume2", cluster, VOLUME_TYPE.PLAIN_DISTRIBUTE, TRANSPORT_TYPE.ETHERNET, - VOLUME_STATUS.ONLINE); - - volume3 = addVolume(volumes, "Volume3", cluster, VOLUME_TYPE.DISTRIBUTED_MIRROR, TRANSPORT_TYPE.ETHERNET, - VOLUME_STATUS.OFFLINE); - volume3.setReplicaCount(2); - - volume4 = addVolume(volumes, "Volume4", cluster, VOLUME_TYPE.PLAIN_DISTRIBUTE, TRANSPORT_TYPE.ETHERNET, - VOLUME_STATUS.ONLINE); - - volume5 = addVolume(volumes, "Volume5", cluster, VOLUME_TYPE.DISTRIBUTED_STRIPE, TRANSPORT_TYPE.INFINIBAND, - VOLUME_STATUS.OFFLINE); - volume5.setStripeCount(3); - - cluster.setVolumes(volumes); + VolumesClient volumeClient = new VolumesClient(securityToken); + VolumeListResponse response = volumeClient.getAllVolumes(); + if(!response.getStatus().isSuccess()) { + throw new GlusterRuntimeException("Error fetching volume list: [" + response.getStatus() + "]"); + } + cluster.setVolumes(response.getVolumes()); } private void initializeDisks() { 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 daa96cd4..054df413 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 @@ -71,9 +71,10 @@ public class Volume extends Entity { public Volume() { } - // GlusterFS export is always enabled + // GlusterFS and NFS export is always enabled + // Note: logic needs to make NFS optional private Set nasProtocols = new LinkedHashSet( - Arrays.asList(new NAS_PROTOCOL[] { NAS_PROTOCOL.GLUSTERFS })); + Arrays.asList(new NAS_PROTOCOL[] { NAS_PROTOCOL.GLUSTERFS, NAS_PROTOCOL.NFS })); private String accessControlList = "*"; diff --git a/src/com.gluster.storage.management.core/src/com/gluster/storage/management/core/utils/GlusterUtil.java b/src/com.gluster.storage.management.core/src/com/gluster/storage/management/core/utils/GlusterUtil.java deleted file mode 100644 index 5bfe01c8..00000000 --- a/src/com.gluster.storage.management.core/src/com/gluster/storage/management/core/utils/GlusterUtil.java +++ /dev/null @@ -1,383 +0,0 @@ -/** - * GlusterUtil.java - * - * Copyright (c) 2011 Gluster, Inc. - * 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 - * . - */ -package com.gluster.storage.management.core.utils; - -import java.util.ArrayList; -import java.util.List; -import java.util.Map; -import java.util.Map.Entry; - -import com.gluster.storage.management.core.constants.CoreConstants; -import com.gluster.storage.management.core.exceptions.GlusterRuntimeException; -import com.gluster.storage.management.core.model.GlusterServer; -import com.gluster.storage.management.core.model.GlusterServer.SERVER_STATUS; -import com.gluster.storage.management.core.model.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.model.Volume.VOLUME_STATUS; -import com.gluster.storage.management.core.model.Volume.VOLUME_TYPE; - -public class GlusterUtil { - private static final String glusterFSminVersion = "3.1"; - - private static final String HOSTNAME_PFX = "Hostname:"; - private static final String UUID_PFX = "Uuid:"; - private static final String STATE_PFX = "State:"; - private static final String GLUSTER_SERVER_STATUS_ONLINE = "Connected"; - - private static final String VOLUME_NAME_PFX = "Volume Name:"; - private static final String VOLUME_TYPE_PFX = "Type:"; - private static final String VOLUME_STATUS_PFX = "Status:"; - private static final String VOLUME_TRANSPORT_TYPE_PFX = "Transport-type:"; - 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 ProcessUtil processUtil = new ProcessUtil(); - - /** - * Extract value of given token from given line. It is assumed that the token, if present, will be of the following - * form: token: value - * - * @param line - * Line to be analyzed - * @param token - * Token whose value is to be extracted - * @return Value of the token, if present in the line - */ - private final String extractToken(String line, String token) { - if (line.contains(token)) { - return line.split(token)[1].trim(); - } - return null; - } - - public List getGlusterServers() { - String output = getPeerStatus(); - if (output == null) { - return null; - } - - List glusterServers = new ArrayList(); - GlusterServer server = null; - boolean foundHost = false; - boolean foundUuid = false; - for (String line : output.split(CoreConstants.NEWLINE)) { - if (foundHost && foundUuid) { - // Host and UUID is found, we should look for state - String state = extractToken(line, STATE_PFX); - if (state != null) { - server.setStatus(state.contains(GLUSTER_SERVER_STATUS_ONLINE) ? SERVER_STATUS.ONLINE - : SERVER_STATUS.OFFLINE); - // Completed populating current server. Add it to the list - // and reset all related variables. - glusterServers.add(server); - - foundHost = false; - foundUuid = false; - server = null; - } - } else if (foundHost) { - // Host is found, look for UUID - String uuid = extractToken(line, UUID_PFX); - if (uuid != null) { - server.setUuid(uuid); - foundUuid = true; - } - } else { - // Look for the next host - if (server == null) { - server = new GlusterServer(); - } - String hostName = extractToken(line, HOSTNAME_PFX); - if (hostName != null) { - server.setName(hostName); - foundHost = true; - } - } - - } - return glusterServers; - } - - public List getGlusterServerNames() { - String output = getPeerStatus(); - if (output == null) { - return null; - } - - List glusterServerNames = new ArrayList(); - for (String line : output.split(CoreConstants.NEWLINE)) { - String hostName = extractToken(line, HOSTNAME_PFX); - if (hostName != null) { - glusterServerNames.add(hostName); - } - } - return glusterServerNames; - } - - private String getPeerStatus() { - String output; - ProcessResult result = processUtil.executeCommand("gluster", "peer", "status"); - if (!result.isSuccess()) { - output = null; - } - output = result.getOutput(); - return output; - } - - public Status addServer(String serverName) { - return new Status(processUtil.executeCommand("gluster", "peer", "probe", serverName)); - } - - public Status startVolume(String volumeName) { - return new Status(processUtil.executeCommand("gluster", "volume", "start", volumeName)); - } - - public Status stopVolume(String volumeName) { - return new Status(processUtil.executeCommand("gluster", "--mode=script", "volume", "stop", volumeName)); - } - - public Status resetOptions(String volumeName) { - return new Status(processUtil.executeCommand("gluster", "volume", "reset", volumeName)); - } - - public Status createVolume(Volume volume, List bricks) { - int count = 1; // replica or stripe count - String volumeType = null; - VOLUME_TYPE volType = volume.getVolumeType(); - if (volType == VOLUME_TYPE.DISTRIBUTED_MIRROR) { - volumeType = "replica"; - count = 2; - } else if (volType == VOLUME_TYPE.DISTRIBUTED_STRIPE) { - volumeType = "stripe"; - count = 4; - } - - String transportTypeStr = null; - TRANSPORT_TYPE transportType = volume.getTransportType(); - transportTypeStr = (transportType == TRANSPORT_TYPE.ETHERNET) ? "tcp" : "rdma"; - - List command = prepareVolumeCreateCommand(volume, bricks, count, volumeType, transportTypeStr); - ProcessResult result = processUtil.executeCommand(command); - if(!result.isSuccess()) { - // TODO: Perform cleanup on all nodes before returning - return new Status(result); - } - - return createOptions(volume); - } - - private List prepareVolumeCreateCommand(Volume volume, List bricks, int count, String volumeType, - String transportTypeStr) { - List command = new ArrayList(); - command.add("gluster"); - command.add("volume"); - command.add("create"); - command.add(volume.getName()); - if (volumeType != null) { - command.add(volumeType); - command.add("" + count); - } - command.add("transport"); - command.add(transportTypeStr); - command.addAll(bricks); - return command; - } - - public Status createOptions(Volume volume) { - Map options = volume.getOptions(); - if (options != null) { - for (Entry option : options.entrySet()) { - String key = option.getKey(); - String value = option.getValue(); - Status status = setOption(volume.getName(), key, value); - if (!status.isSuccess()) { - return status; - } - } - } - return Status.STATUS_SUCCESS; - } - - public Status setOption(String volumeName, String key, String value) { - List command = new ArrayList(); - command.add("gluster"); - command.add("volume"); - command.add("set"); - command.add(volumeName); - command.add(key); - command.add(value); - - return new Status(processUtil.executeCommand(command)); - } - - private String getVolumeInfo(String volumeName) { - ProcessResult result = new ProcessUtil().executeCommand("gluster", "volume", "info", volumeName); - if (!result.isSuccess()) { - throw new GlusterRuntimeException("Command [gluster volume info] failed with error: [" - + result.getExitValue() + "][" + result.getOutput() + "]"); - } - return result.getOutput(); - } - - private String getVolumeInfo() { - ProcessResult result = new ProcessUtil().executeCommand("gluster", "volume", "info"); - if (!result.isSuccess()) { - throw new GlusterRuntimeException("Command [gluster volume info] failed with error: [" - + result.getExitValue() + "][" + result.getOutput() + "]"); - } - return result.getOutput(); - } - - private boolean readVolumeType(Volume volume, String line) { - String volumeType = extractToken(line, VOLUME_TYPE_PFX); - if (volumeType != null) { - volume.setVolumeType((volumeType.equals("Distribute")) ? VOLUME_TYPE.PLAIN_DISTRIBUTE - : VOLUME_TYPE.DISTRIBUTED_MIRROR); // TODO: for Stripe - return true; - } - return false; - } - - private boolean readVolumeStatus(Volume volume, String line) { - String volumeStatus = extractToken(line, VOLUME_STATUS_PFX); - if (volumeStatus != null) { - volume.setStatus(volumeStatus.equals("Started") ? VOLUME_STATUS.ONLINE : VOLUME_STATUS.OFFLINE); - return true; - } - return false; - } - - private boolean readTransportType(Volume volume, String line) { - String transportType = extractToken(line, VOLUME_TRANSPORT_TYPE_PFX); - if (transportType != null) { - volume.setTransportType(transportType.equals("tcp") ? TRANSPORT_TYPE.ETHERNET - : TRANSPORT_TYPE.INFINIBAND); - return true; - } - return false; - } - - private boolean readBrick(Volume volume, String line) { - if (line.matches("Brick[0-9]+:.*")) { - // line: "Brick1: server1:/export/md0/volume-name" - volume.addDisk(line.split(":")[2].trim().split("/")[2].trim()); - return true; - } - return false; - } - - private boolean readBrickGroup(String line) { - return extractToken(line, VOLUME_BRICKS_GROUP_PFX) != null; - } - - private boolean readOptionReconfigGroup(String line) { - return extractToken(line, VOLUME_OPTIONS_RECONFIG_PFX) != null; - } - - private boolean readOption(Volume volume, String line) { - if (line.matches("^[^:]*:.*$")) { - int index = line.indexOf(':'); - volume.setOption(line.substring(0, index).trim(), line.substring(index + 1, line.length()).trim()); - return true; - } - return false; - } - - public Volume getVolume(String volumeName) { - List volumes = parseVolumeInfo(getVolumeInfo(volumeName)); - if(volumes.size() > 0) { - return volumes.get(0); - } - return null; - } - - public List getAllVolumes() { - return parseVolumeInfo(getVolumeInfo()); - } - - private List parseVolumeInfo(String volumeInfoText) { - List volumes = new ArrayList(); - boolean isBricksGroupFound = false; - boolean isOptionReconfigFound = false; - Volume volume = null; - - for (String line : volumeInfoText.split(CoreConstants.NEWLINE)) { - String volumeName = extractToken(line, VOLUME_NAME_PFX); - if (volumeName != null) { - if (volume != null) { - - volumes.add(volume); - } - - // prepare next volume to be read - volume = new Volume(); - volume.setName(volumeName); - isBricksGroupFound = isOptionReconfigFound = false; - continue; - } - - if (readVolumeType(volume, line)) - continue; - if (readVolumeStatus(volume, line)) - continue; - if(readTransportType(volume, line)) - continue; - - if (readBrickGroup(line)) { - isBricksGroupFound = true; - continue; - } - - if (isBricksGroupFound) { - if (readBrick(volume, line)) { - continue; - } else { - isBricksGroupFound = false; - } - } - - if (readOptionReconfigGroup(line)) { - isOptionReconfigFound = true; - continue; - } - - if (isOptionReconfigFound) { - if(readOption(volume, line)) { - continue; - } else { - isOptionReconfigFound = false; - } - } - } - - if (volume != null) {// Adding the last volume parsed - volumes.add(volume); - } - return volumes; - } - - public static void main(String args[]) { - // List names = new GlusterUtil().getGlusterServerNames(); - // System.out.println(names); - } -} diff --git a/src/com.gluster.storage.management.gui/src/com/gluster/storage/management/gui/views/VolumeSummaryView.java b/src/com.gluster.storage.management.gui/src/com/gluster/storage/management/gui/views/VolumeSummaryView.java index fe583a67..d837c8a4 100644 --- a/src/com.gluster.storage.management.gui/src/com/gluster/storage/management/gui/views/VolumeSummaryView.java +++ b/src/com.gluster.storage.management.gui/src/com/gluster/storage/management/gui/views/VolumeSummaryView.java @@ -1,5 +1,6 @@ package com.gluster.storage.management.gui.views; +import java.util.List; import java.util.Map; import org.eclipse.jface.dialogs.ErrorDialog; @@ -22,6 +23,8 @@ import org.eclipse.ui.part.ViewPart; import com.gluster.storage.management.client.GlusterDataModelManager; import com.gluster.storage.management.client.VolumesClient; +import com.gluster.storage.management.core.model.Alert; +import com.gluster.storage.management.core.model.Cluster; import com.gluster.storage.management.core.model.DefaultClusterListener; import com.gluster.storage.management.core.model.Event; import com.gluster.storage.management.core.model.Event.EVENT_TYPE; @@ -38,13 +41,13 @@ import com.gluster.storage.management.gui.utils.GUIHelper; public class VolumeSummaryView extends ViewPart { public static final String ID = VolumeSummaryView.class.getName(); private static final GUIHelper guiHelper = GUIHelper.getInstance(); + private static final String VOLUME_OPTION_AUTH_ALLOW = "auth.allow"; + private final FormToolkit toolkit = new FormToolkit(Display.getCurrent()); private ScrolledForm form; private Volume volume; private CLabel lblStatusValue; private DefaultClusterListener volumeChangedListener; - - private static final String VOLUME_OPTION_AUTH_ALLOW = "auth.allow"; @Override public void createPartControl(Composite parent) { @@ -89,8 +92,22 @@ public class VolumeSummaryView extends ViewPart { } private void createVolumeAlertsSection() { - Composite section = guiHelper.createSection(form, toolkit, "Alerts", null, 3, false); - toolkit.createLabel(section, "Volume related alerts will be displayed here"); + Composite section = guiHelper.createSection(form, toolkit, "Alerts", null, 1, false); + List alerts = GlusterDataModelManager.getInstance().getModel().getCluster().getAlerts(); + + for (int i = 0; i < alerts.size(); i++) { + if (alerts.get(i).getType() == Alert.ALERT_TYPES.OFFLINE_VOLUME_DISKS_ALERT + && alerts.get(i).getReference().split(":")[0].trim().equals(volume.getName())) { + addAlertLabel(section, alerts.get(i)); + } + } + } + + private void addAlertLabel(Composite section, Alert alert) { + CLabel lblAlert = new CLabel(section, SWT.NONE); + lblAlert.setImage(guiHelper.getImage(IImageKeys.DISK_OFFLINE)); + lblAlert.setText(alert.getMessage()); + lblAlert.redraw(); } private void createVolumeMountingInfoSection() { diff --git a/src/com.gluster.storage.management.gui/src/com/gluster/storage/management/gui/views/VolumesSummaryView.java b/src/com.gluster.storage.management.gui/src/com/gluster/storage/management/gui/views/VolumesSummaryView.java index 8c39fbeb..0d8f114a 100644 --- a/src/com.gluster.storage.management.gui/src/com/gluster/storage/management/gui/views/VolumesSummaryView.java +++ b/src/com.gluster.storage.management.gui/src/com/gluster/storage/management/gui/views/VolumesSummaryView.java @@ -99,9 +99,9 @@ public class VolumesSummaryView extends ViewPart { if (alert.getType() == Alert.ALERT_TYPES.DISK_USAGE_ALERT || alert.getType() == Alert.ALERT_TYPES.OFFLINE_VOLUME_DISKS_ALERT) { CLabel lblAlert = new CLabel(section, SWT.NONE); - lblAlert.setText(alert.getMessage()); lblAlert.setImage((alert.getType() == Alert.ALERT_TYPES.DISK_USAGE_ALERT) ? guiHelper .getImage(IImageKeys.LOW_DISK_SPACE) : guiHelper.getImage(IImageKeys.DISK_OFFLINE)); + lblAlert.setText(alert.getMessage()); lblAlert.redraw(); } } diff --git a/src/com.gluster.storage.management.server/src/com/gluster/storage/management/server/resources/AlertsResource.java b/src/com.gluster.storage.management.server/src/com/gluster/storage/management/server/resources/AlertsResource.java index c4948596..e33e06c9 100644 --- a/src/com.gluster.storage.management.server/src/com/gluster/storage/management/server/resources/AlertsResource.java +++ b/src/com.gluster.storage.management.server/src/com/gluster/storage/management/server/resources/AlertsResource.java @@ -53,7 +53,7 @@ public class AlertsResource { // Alert #4 alert = new Alert(); alert.setId("0004"); - alert.setReference("Volume2:server2:sda1"); // volume:[Disk name] + alert.setReference("Volume3:server2:sda1"); // volume:[Disk name] alert.setType(Alert.ALERT_TYPES.OFFLINE_VOLUME_DISKS_ALERT); alert.setMessage(alert.getAlertType(alert.getType()) + " in volume [" + alert.getReference().split(":")[0] + "] disk [" + alert.getReference().split(":")[1] + ":" + alert.getReference().split(":")[2] + "]"); diff --git a/src/com.gluster.storage.management.server/src/com/gluster/storage/management/server/resources/GlusterServersResource.java b/src/com.gluster.storage.management.server/src/com/gluster/storage/management/server/resources/GlusterServersResource.java index 42f7760e..c1f0435c 100644 --- a/src/com.gluster.storage.management.server/src/com/gluster/storage/management/server/resources/GlusterServersResource.java +++ b/src/com.gluster.storage.management.server/src/com/gluster/storage/management/server/resources/GlusterServersResource.java @@ -37,8 +37,8 @@ import com.gluster.storage.management.core.model.Status; import com.gluster.storage.management.core.response.GenericResponse; import com.gluster.storage.management.core.response.GlusterServerListResponse; import com.gluster.storage.management.core.response.GlusterServerResponse; -import com.gluster.storage.management.core.utils.GlusterUtil; import com.gluster.storage.management.core.utils.ProcessResult; +import com.gluster.storage.management.server.utils.GlusterUtil; import com.sun.jersey.spi.resource.Singleton; @Component 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 73aa60d8..a4ecfcc6 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 @@ -50,8 +50,8 @@ 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.VolumeListResponse; import com.gluster.storage.management.core.response.VolumeOptionInfoListResponse; -import com.gluster.storage.management.core.utils.GlusterUtil; import com.gluster.storage.management.server.constants.VolumeOptionsDefaults; +import com.gluster.storage.management.server.utils.GlusterUtil; import com.gluster.storage.management.server.utils.ServerUtil; import com.sun.jersey.api.core.InjectParam; import com.sun.jersey.spi.resource.Singleton; @@ -76,6 +76,7 @@ public class VolumesResource { return new VolumeListResponse(Status.STATUS_SUCCESS, glusterUtil.getAllVolumes()); } catch (Exception e) { // TODO: log the error + e.printStackTrace(); return new VolumeListResponse(new Status(Status.STATUS_CODE_FAILURE, e.getMessage()), null); } } 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 new file mode 100644 index 00000000..dd72ab86 --- /dev/null +++ b/src/com.gluster.storage.management.server/src/com/gluster/storage/management/server/utils/GlusterUtil.java @@ -0,0 +1,402 @@ +/** + * GlusterUtil.java + * + * Copyright (c) 2011 Gluster, Inc. + * 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 + * . + */ +package com.gluster.storage.management.server.utils; + +import java.util.ArrayList; +import java.util.List; +import java.util.Map; +import java.util.Map.Entry; + +import com.gluster.storage.management.core.constants.CoreConstants; +import com.gluster.storage.management.core.exceptions.GlusterRuntimeException; +import com.gluster.storage.management.core.model.GlusterServer; +import com.gluster.storage.management.core.model.GlusterServer.SERVER_STATUS; +import com.gluster.storage.management.core.model.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.model.Volume.VOLUME_STATUS; +import com.gluster.storage.management.core.model.Volume.VOLUME_TYPE; +import com.gluster.storage.management.core.utils.ProcessResult; +import com.gluster.storage.management.core.utils.ProcessUtil; + +public class GlusterUtil { + private static final String glusterFSminVersion = "3.1"; + + private static final String HOSTNAME_PFX = "Hostname:"; + private static final String UUID_PFX = "Uuid:"; + private static final String STATE_PFX = "State:"; + private static final String GLUSTER_SERVER_STATUS_ONLINE = "Connected"; + + private static final String VOLUME_NAME_PFX = "Volume Name:"; + private static final String VOLUME_TYPE_PFX = "Type:"; + private static final String VOLUME_STATUS_PFX = "Status:"; + private static final String VOLUME_TRANSPORT_TYPE_PFX = "Transport-type:"; + 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 ProcessUtil processUtil = new ProcessUtil(); + + /** + * Extract value of given token from given line. It is assumed that the token, if present, will be of the following + * form: token: value + * + * @param line + * Line to be analyzed + * @param token + * Token whose value is to be extracted + * @return Value of the token, if present in the line + */ + private final String extractToken(String line, String token) { + if (line.contains(token)) { + return line.split(token)[1].trim(); + } + return null; + } + + public List getGlusterServers() { + String output = getPeerStatus(); + if (output == null) { + return null; + } + + List glusterServers = new ArrayList(); + GlusterServer server = null; + boolean foundHost = false; + boolean foundUuid = false; + for (String line : output.split(CoreConstants.NEWLINE)) { + if (foundHost && foundUuid) { + // Host and UUID is found, we should look for state + String state = extractToken(line, STATE_PFX); + if (state != null) { + server.setStatus(state.contains(GLUSTER_SERVER_STATUS_ONLINE) ? SERVER_STATUS.ONLINE + : SERVER_STATUS.OFFLINE); + // Completed populating current server. Add it to the list + // and reset all related variables. + glusterServers.add(server); + + foundHost = false; + foundUuid = false; + server = null; + } + } else if (foundHost) { + // Host is found, look for UUID + String uuid = extractToken(line, UUID_PFX); + if (uuid != null) { + server.setUuid(uuid); + foundUuid = true; + } + } else { + // Look for the next host + if (server == null) { + server = new GlusterServer(); + } + String hostName = extractToken(line, HOSTNAME_PFX); + if (hostName != null) { + server.setName(hostName); + foundHost = true; + } + } + + } + return glusterServers; + } + + public List getGlusterServerNames() { + String output = getPeerStatus(); + if (output == null) { + return null; + } + + List glusterServerNames = new ArrayList(); + for (String line : output.split(CoreConstants.NEWLINE)) { + String hostName = extractToken(line, HOSTNAME_PFX); + if (hostName != null) { + glusterServerNames.add(hostName); + } + } + return glusterServerNames; + } + + private String getPeerStatus() { + String output; + ProcessResult result = processUtil.executeCommand("gluster", "peer", "status"); + if (!result.isSuccess()) { + output = null; + } + output = result.getOutput(); + return output; + } + + public Status addServer(String serverName) { + return new Status(processUtil.executeCommand("gluster", "peer", "probe", serverName)); + } + + public Status startVolume(String volumeName) { + return new Status(processUtil.executeCommand("gluster", "volume", "start", volumeName)); + } + + public Status stopVolume(String volumeName) { + return new Status(processUtil.executeCommand("gluster", "--mode=script", "volume", "stop", volumeName)); + } + + public Status resetOptions(String volumeName) { + return new Status(processUtil.executeCommand("gluster", "volume", "reset", volumeName)); + } + + public Status createVolume(Volume volume, List bricks) { + int count = 1; // replica or stripe count + String volumeType = null; + VOLUME_TYPE volType = volume.getVolumeType(); + if (volType == VOLUME_TYPE.DISTRIBUTED_MIRROR) { + volumeType = "replica"; + count = 2; + } else if (volType == VOLUME_TYPE.DISTRIBUTED_STRIPE) { + volumeType = "stripe"; + count = 4; + } + + String transportTypeStr = null; + TRANSPORT_TYPE transportType = volume.getTransportType(); + transportTypeStr = (transportType == TRANSPORT_TYPE.ETHERNET) ? "tcp" : "rdma"; + + List command = prepareVolumeCreateCommand(volume, bricks, count, volumeType, transportTypeStr); + ProcessResult result = processUtil.executeCommand(command); + if(!result.isSuccess()) { + // TODO: Perform cleanup on all nodes before returning + return new Status(result); + } + + return createOptions(volume); + } + + private List prepareVolumeCreateCommand(Volume volume, List bricks, int count, String volumeType, + String transportTypeStr) { + List command = new ArrayList(); + command.add("gluster"); + command.add("volume"); + command.add("create"); + command.add(volume.getName()); + if (volumeType != null) { + command.add(volumeType); + command.add("" + count); + } + command.add("transport"); + command.add(transportTypeStr); + command.addAll(bricks); + return command; + } + + public Status createOptions(Volume volume) { + Map options = volume.getOptions(); + if (options != null) { + for (Entry option : options.entrySet()) { + String key = option.getKey(); + String value = option.getValue(); + Status status = setOption(volume.getName(), key, value); + if (!status.isSuccess()) { + return status; + } + } + } + return Status.STATUS_SUCCESS; + } + + public Status setOption(String volumeName, String key, String value) { + List command = new ArrayList(); + command.add("gluster"); + command.add("volume"); + command.add("set"); + command.add(volumeName); + command.add(key); + command.add(value); + + return new Status(processUtil.executeCommand(command)); + } + + private String getVolumeInfo(String volumeName) { + ProcessResult result = new ProcessUtil().executeCommand("gluster", "volume", "info", volumeName); + if (!result.isSuccess()) { + throw new GlusterRuntimeException("Command [gluster volume info] failed with error: [" + + result.getExitValue() + "][" + result.getOutput() + "]"); + } + return result.getOutput(); + } + + private String getVolumeInfo() { + ProcessResult result = new ProcessUtil().executeCommand("gluster", "volume", "info"); + if (!result.isSuccess()) { + throw new GlusterRuntimeException("Command [gluster volume info] failed with error: [" + + result.getExitValue() + "][" + result.getOutput() + "]"); + } + return result.getOutput(); + } + + private boolean readVolumeType(Volume volume, String line) { + String volumeType = extractToken(line, VOLUME_TYPE_PFX); + if (volumeType != null) { + volume.setVolumeType((volumeType.equals("Distribute")) ? VOLUME_TYPE.PLAIN_DISTRIBUTE + : VOLUME_TYPE.DISTRIBUTED_MIRROR); // TODO: for Stripe + return true; + } + return false; + } + + private boolean readVolumeStatus(Volume volume, String line) { + String volumeStatus = extractToken(line, VOLUME_STATUS_PFX); + if (volumeStatus != null) { + volume.setStatus(volumeStatus.equals("Started") ? VOLUME_STATUS.ONLINE : VOLUME_STATUS.OFFLINE); + return true; + } + return false; + } + + private boolean readTransportType(Volume volume, String line) { + String transportType = extractToken(line, VOLUME_TRANSPORT_TYPE_PFX); + if (transportType != null) { + volume.setTransportType(transportType.equals("tcp") ? TRANSPORT_TYPE.ETHERNET + : TRANSPORT_TYPE.INFINIBAND); + return true; + } + return false; + } + + private boolean readBrick(Volume volume, String line) { + if (line.matches("Brick[0-9]+:.*")) { + // line: "Brick1: server1:/export/md0/volume-name" + String[] brickParts = line.split(":"); + String serverName = brickParts[1].trim(); + String brickDir = brickParts[2].trim(); + // brick directory should be of the form /export//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"); + } + } + return true; + } + return false; + } + + private boolean readBrickGroup(String line) { + return extractToken(line, VOLUME_BRICKS_GROUP_PFX) != null; + } + + private boolean readOptionReconfigGroup(String line) { + return extractToken(line, VOLUME_OPTIONS_RECONFIG_PFX) != null; + } + + private boolean readOption(Volume volume, String line) { + if (line.matches("^[^:]*:.*$")) { + int index = line.indexOf(':'); + volume.setOption(line.substring(0, index).trim(), line.substring(index + 1, line.length()).trim()); + return true; + } + return false; + } + + public Volume getVolume(String volumeName) { + List volumes = parseVolumeInfo(getVolumeInfo(volumeName)); + if(volumes.size() > 0) { + return volumes.get(0); + } + return null; + } + + public List getAllVolumes() { + return parseVolumeInfo(getVolumeInfo()); + } + + private List parseVolumeInfo(String volumeInfoText) { + List volumes = new ArrayList(); + boolean isBricksGroupFound = false; + boolean isOptionReconfigFound = false; + Volume volume = null; + + for (String line : volumeInfoText.split(CoreConstants.NEWLINE)) { + String volumeName = extractToken(line, VOLUME_NAME_PFX); + if (volumeName != null) { + if (volume != null) { + + volumes.add(volume); + } + + // prepare next volume to be read + volume = new Volume(); + volume.setName(volumeName); + isBricksGroupFound = isOptionReconfigFound = false; + continue; + } + + if (readVolumeType(volume, line)) + continue; + if (readVolumeStatus(volume, line)) + continue; + if(readTransportType(volume, line)) + continue; + + if (readBrickGroup(line)) { + isBricksGroupFound = true; + continue; + } + + if (isBricksGroupFound) { + if (readBrick(volume, line)) { + continue; + } else { + isBricksGroupFound = false; + } + } + + if (readOptionReconfigGroup(line)) { + isOptionReconfigFound = true; + continue; + } + + if (isOptionReconfigFound) { + if(readOption(volume, line)) { + continue; + } else { + isOptionReconfigFound = false; + } + } + } + + if (volume != null) {// Adding the last volume parsed + volumes.add(volume); + } + return volumes; + } + + public static void main(String args[]) { + // List 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 645b7991..4f99172d 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,6 +39,7 @@ 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; @@ -49,6 +50,7 @@ public class ServerUtil { private static final String SCRIPT_DIR = "scripts"; private static final String SCRIPT_COMMAND = "python"; + private static final String REMOTE_SCRIPT_GET_DISK_FOR_DIR = "get_disk_for_dir.py"; public ProcessResult executeGlusterScript(boolean runInForeground, String scriptName, List arguments) { List command = new ArrayList(); @@ -133,4 +135,13 @@ public class ServerUtil { // CreateVolumeExportDirectory.py md0 testvol System.out.println(new ServerUtil().executeOnServer(true, "localhost", "python CreateVolumeExportDirectory.py md0 testvol", Status.class)); } + + /** + * @param serverName Server on which the directory is present + * @param brickDir Directory whose disk is to be fetched + * @return Status object containing the disk name, or error message in case the remote script fails. + */ + public Status getDiskForDir(String serverName, String brickDir) { + return (Status) executeOnServer(true, serverName, REMOTE_SCRIPT_GET_DISK_FOR_DIR + " " + brickDir, Status.class); + } } \ No newline at end of file -- cgit