/* * This file is part of DRBD Management Console by LINBIT HA-Solutions GmbH * written by Rasto Levrinc. * * Copyright (C) 2009, LINBIT HA-Solutions GmbH. * Copyright (C) 2011-2012, Rastislav Levrinc. * * DRBD Management Console is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License as published * by the Free Software Foundation; either version 2, or (at your option) * any later version. * * DRBD Management Console is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with drbd; see the file COPYING. If not, write to * the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */ package lcmc.drbd.domain; import java.util.ArrayList; import java.util.Arrays; import java.util.Collection; import java.util.Collections; import java.util.HashSet; import java.util.List; import java.util.Set; import lcmc.common.domain.ResourceValue; import lcmc.host.domain.Host; import lcmc.logger.Logger; import lcmc.logger.LoggerFactory; import lcmc.common.domain.util.Tools; /** * This class holds data of one block device. */ public class BlockDevice extends ResourceValue { private static final Logger LOG = LoggerFactory.getLogger(BlockDevice.class); private final Host host; private final String deviceName; private static final Set<String> CONNECTED_STATES = Collections.unmodifiableSet(new HashSet<String>(Arrays.asList("Connected", "SyncTarget", "SyncSource", "StartingSyncS", "StartingSyncT", "WFBitMapS", "WFBitMapT", "WFSyncUUID", "PausedSyncS", "PausedSyncT", "VerifyS", "VerifyT"))); private static final Set<String> SYNCING_STATES = Collections.unmodifiableSet(new HashSet<String>(Arrays.asList("SyncTarget", "SyncSource", "PausedSyncS", "PausedSyncT"))); private String blockSize; private String diskUuid; private Collection<String> diskIds = new HashSet<String>(); private String mountedOn; private String fsType; private boolean drbd = false; private boolean isUsedByCRM; private BlockDevice metaDisk = null; /** Block device of which this block device is a meta disk. */ private List<BlockDevice> metaDiskOfBlockDevices = new ArrayList<BlockDevice>(); private boolean splitBrain = false; private String connectionState = null; private String nodeState = null; private String diskState = null; private String nodeStateOther = null; private String diskStateOther = null; private String syncedProgress = null; private String drbdFlags = null; /** How much of the file system is used in percents. */ private int used = -1; private String volumeGroup = null; private String vgOnPhysicalVolume = null; private String logicalVolume = null; private BlockDevice drbdBlockDevice = null; private String drbdBackingDisk = null; public BlockDevice(final Host host, final String device) { super(device); this.host = host; this.deviceName = device; } public void updateFrom(final BlockDevice blockDevice) { setDiskUuid(blockDevice.getDiskUuid()); setBlockSize(blockDevice.getBlockSize()); setMountedOn(blockDevice.getMountedOn()); setFsType(blockDevice.getFsType()); setVolumeGroup(blockDevice.getVolumeGroup()); setLogicalVolume(blockDevice.getLogicalVolume()); setVgOnPhysicalVolume(blockDevice.getVgOnPhysicalVolume()); setDiskIds(blockDevice.getDiskIds()); } public String getBlockSize() { return blockSize; } public String getMountedOn() { return mountedOn; } public String getFsType() { return fsType; } public boolean isMounted() { return mountedOn != null; } public boolean isDrbd() { return drbd; } /** * Returns how much of the file system is used in percents. -1 denotes that * there is no usage information. */ public int getUsed() { return used; } /** Resets all drbd info. E.g. after status failure. */ public void resetDrbd() { splitBrain = false; connectionState = null; nodeState = null; diskState = null; syncedProgress = null; drbdFlags = null; } public boolean isUsedByCRM() { return isUsedByCRM; } public boolean isDrbdMetaDisk() { return !metaDiskOfBlockDevices.isEmpty(); } public List<BlockDevice> getMetaDiskOfBlockDevices() { return metaDiskOfBlockDevices; } /** * Returns whether this block device is available for * drbd. That is if this device is not mounted and is * not used by CRM. */ public boolean isAvailable() { return !isMounted() && !isUsedByCRM && !isDrbdMetaDisk() && !isVolumeGroupOnPhysicalVolume(); } /** Sets or unsets drbd flag. */ public void setDrbd(final boolean drbd) { this.drbd = drbd; if (!drbd) { connectionState = null; nodeState = null; diskState = null; syncedProgress = null; drbdFlags = null; if (metaDisk != null) { metaDisk.removeMetadiskOfBlockDevice(this); metaDisk = null; } metaDiskOfBlockDevices = new ArrayList<BlockDevice>(); } } /** * Returns whether the specified data are different than the stored data. */ public boolean isDifferent(final String connectionState, final String nodeState, final String diskState, final String drbdFlags) { return !Tools.areEqual(this.connectionState, connectionState) || !Tools.areEqual(this.nodeState, nodeState) || !Tools.areEqual(this.diskState, diskState) || !Tools.areEqual(this.drbdFlags, drbdFlags); } public void setUsedByCRM(final boolean isUsedByCRM) { this.isUsedByCRM = isUsedByCRM; } /** * Adds metaDiskOfBlockDevice which is a block device of which block device * is this meta disk. */ void addMetaDiskOfBlockDevice(final BlockDevice metaDiskOfBlockDevice) { if (!metaDiskOfBlockDevices.contains(metaDiskOfBlockDevice)) { metaDiskOfBlockDevices.add(metaDiskOfBlockDevice); } } public void setMetaDisk(final BlockDevice metaDisk) { this.metaDisk = metaDisk; if (metaDisk != null) { metaDisk.addMetaDiskOfBlockDevice(this); } } public void removeMetadiskOfBlockDevice(final BlockDevice metaDiskOfBlockDevice) { metaDiskOfBlockDevices.remove(metaDiskOfBlockDevice); } public BlockDevice getMetaDisk() { return metaDisk; } public void setConnectionState(final String connectionState) { this.connectionState = connectionState; } public void setDrbdFlags(final String drbdFlags) { this.drbdFlags = drbdFlags; } public void setNodeState(final String nodeState) { this.nodeState = nodeState; } public void setNodeStateOther(final String nodeStateOther) { this.nodeStateOther = nodeStateOther; } public void setDiskState(final String diskState) { this.diskState = diskState; } /** Sets disk node state of the other block device as it is in /proc/drbd. */ public void setDiskStateOther(final String diskStateOther) { this.diskStateOther = diskStateOther; } public void setDiskUuid(final String diskUuid) { this.diskUuid = diskUuid; } public void setBlockSize(final String blockSize) { this.blockSize = blockSize; } public void setMountedOn(final String mountedOn) { this.mountedOn = mountedOn; } public void setFsType(final String fsType) { this.fsType = fsType; } public void setVolumeGroup(final String volumeGroup) { this.volumeGroup = volumeGroup; } public void setLogicalVolume(final String logicalVolume) { this.logicalVolume = logicalVolume; } public void setVgOnPhysicalVolume(final String vgOnPhysicalVolume) { this.vgOnPhysicalVolume = vgOnPhysicalVolume; } public void setDiskIds(final Collection<String> diskIds) { this.diskIds = diskIds; } public String getConnectionState() { return connectionState; } public String getNodeState() { return nodeState; } public String getNodeStateOther() { return nodeStateOther; } public String getDiskState() { return diskState; } public String getDiskStateOther() { return diskStateOther; } public void setSyncedProgressInPercents(final String syncedProgress) { this.syncedProgress = syncedProgress; } public String getSyncedProgress() { return syncedProgress; } public boolean isAttached() { if (!drbd) { return true; } if (diskState == null) { return false; } return !"Diskless".equals(diskState); } public boolean isDiskless() { if (!drbd) { return false; } if (diskState == null) { return true; } return "Diskless".equals(diskState); } /** * Returns whether this block device is connected and resets the split * brain flag if it is. */ public boolean isConnected() { if (connectionState == null) { return false; } if (CONNECTED_STATES.contains(connectionState)) { setSplitBrain(false); return true; } return false; } /** Returns whether the device is connected or is waiting for connection. */ public boolean isConnectedOrWF() { return isWFConnection() || isConnected(); } public boolean isWFConnection() { if (connectionState == null) { return false; } return "WFConnection".equals(connectionState); } public boolean isPrimary() { if (nodeState == null) { return false; } return "Primary".equals(nodeState); } public boolean isSecondary() { if (nodeState == null) { return false; } return "Secondary".equals(nodeState); } private boolean checkDrbdFlag(final int flag) { return drbdFlags.indexOf(flag) >= 0; } public boolean isPausedSync() { if (drbdFlags == null) { return false; } return checkDrbdFlag('u'); } public boolean isSyncing() { if (nodeState == null) { syncedProgress = null; return false; } if (SYNCING_STATES.contains(connectionState)) { return true; } syncedProgress = null; return false; } public boolean isVerifying() { if (nodeState == null) { return false; } return "VerifyS".equals(connectionState) || "VerifyT".equals(connectionState); } /** * Returns true if this node is source of the data, false if this node gets * data from other node. */ public boolean isSyncSource() { if (connectionState == null) { return false; } return "SyncSource".equals(connectionState); } /** Returns true if this node is target for the data, otherwise false. */ public boolean isSyncTarget() { if (connectionState == null) { return false; } return "SyncTarget".equals(connectionState); } public void setSplitBrain(final boolean splitBrain) { this.splitBrain = splitBrain; } public boolean isSplitBrain() { return splitBrain; } /** Returns string with meta disk and index in the parenthesis. */ public String getMetaDiskString(final String md, final String mdi) { if (md == null || mdi == null) { return null; } final StringBuilder metaDiskString = new StringBuilder(); if ("Flexible".equals(mdi)) { metaDiskString.append("flexible-meta-disk\t"); metaDiskString.append(md); } else { metaDiskString.append("meta-disk\t"); metaDiskString.append(md); if (!"internal".equals(md)) { metaDiskString.append('['); metaDiskString.append(mdi); metaDiskString.append(']'); } } return metaDiskString.toString(); } /** Returns string with stored meta disk and index in the parenthesis. */ String getMetaDiskString() { return getMetaDiskString(getValue("DrbdMetaDisk").getValueForConfig(), getValue("DrbdMetaDiskIndex").getValueForConfig()); } public String getSection(final String parameter) { return Tools.getString("BlockDevice.MetaDiskSection"); } public boolean isSwap() { return fsType != null && "swap".equals(fsType); } public String getDiskUuid() { return diskUuid; } public Collection<String> getDiskIds() { return diskIds; } public String getVolumeGroup() { return volumeGroup; } public boolean isPhysicalVolume() { return vgOnPhysicalVolume != null; } public String getVgOnPhysicalVolume() { return vgOnPhysicalVolume; } public boolean isVolumeGroupOnPhysicalVolume() { return vgOnPhysicalVolume != null && !"".equals(vgOnPhysicalVolume); } /** Set volume group that is on this physical volume. * "", for no VG, but still it's physical volume. */ public void setVolumeGroupOnPhysicalVolume(final String vgOnPhysicalVolume) { this.vgOnPhysicalVolume = vgOnPhysicalVolume; } public String getLogicalVolume() { return logicalVolume; } public BlockDevice getDrbdBlockDevice() { return drbdBlockDevice; } public boolean isDrbdPhysicalVolume() { return drbdBlockDevice != null && drbdBlockDevice.isPhysicalVolume(); } public boolean isDrbdVolumeGroupOnPhysicalVolume() { return drbdBlockDevice != null && drbdBlockDevice.isVolumeGroupOnPhysicalVolume(); } public void setDrbdBlockDevice(final BlockDevice drbdBlockDevice) { this.drbdBlockDevice = drbdBlockDevice; } public String getDrbdBackingDisk() { return drbdBackingDisk; } public void setDrbdBackingDisk(final String drbdBackingDisk) { this.drbdBackingDisk = drbdBackingDisk; } public void setUsed(final String usedStr) { if (usedStr != null) { this.used = Integer.parseInt(usedStr); } } @Override public boolean equals(Object o) { if (this == o) return true; if (o == null || getClass() != o.getClass()) return false; BlockDevice that = (BlockDevice) o; if (!deviceName.equals(that.deviceName)) return false; if (!host.equals(that.host)) return false; return true; } @Override public int hashCode() { int result = deviceName.hashCode(); result = 31 * result + host.hashCode(); return result; } }